001: /*
002: * The contents of this file are subject to the
003: * Mozilla Public License Version 1.1 (the "License");
004: * you may not use this file except in compliance with the License.
005: * You may obtain a copy of the License at http://www.mozilla.org/MPL/
006: *
007: * Software distributed under the License is distributed on an "AS IS"
008: * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
009: * See the License for the specific language governing rights and
010: * limitations under the License.
011: *
012: * The Initial Developer of the Original Code is Simulacra Media Ltd.
013: * Portions created by Simulacra Media Ltd are Copyright (C) Simulacra Media Ltd, 2004.
014: *
015: * All Rights Reserved.
016: *
017: * Contributor(s):
018: */
019: package org.openharmonise.rm;
020:
021: import java.io.*;
022: import java.text.*;
023: import java.util.*;
024:
025: import javax.servlet.http.*;
026:
027: import org.openharmonise.commons.net.*;
028: import org.openharmonise.rm.config.*;
029:
030: /**
031: * A class to handle exceptions thrown within Harmonise.
032: * @author Michael Bell
033: * @version $Revision: 1.1 $
034: *
035: */
036: public class HarmoniseExceptionHandler {
037: /**
038: * Email address configuration parameter name
039: */
040: static final String EMAIL_ADDRESS_PNAME = "ERROR_EMAIL_ADDRESS";
041: /**
042: * Email errors switch configuration parameter name
043: */
044: static final String EMAIL_ERRORS_PNAME = "EMAIL_ERRORS";
045: /**
046: * Redirect address configuration parameter name
047: */
048: static final String REDIRECT_URL_PNAME = "ERROR_REDIRECT_URL";
049: /**
050: * Redirect on error switch configuration parameter name
051: */
052: static final String USE_REDIRECT_PNAME = "REDIRECT_ON_ERROR";
053: /**
054: * The from address for sent emails
055: */
056: static final String ERRORS_FROMADDRESS = "ErrorMail@simulacramedia.com";
057:
058: /**
059: * Array of address to email errors to
060: */
061: private String[] m_error_email_toaddresses = new String[1];
062: /**
063: * <code>boolean</code> switch which determines whether errors are emailed
064: */
065: private boolean m_bEmailErrors = false;
066: /**
067: * The URI context for the error being handled
068: */
069: private String m_reporting_URL = "Not known";
070: /**
071: * The 'from' address for emails sent by this error handler
072: */
073: private String m_originator_email_address = ERRORS_FROMADDRESS;
074: /**
075: * The string representation of date this exception was recorded
076: */
077: private String m_exception_date_string = "Not known";
078: /**
079: * Any additional information to be included in the exception report
080: */
081: private String m_additional_info = "None provided";
082: /**
083: * <code>boolean</code> switch which determines whether the redirect URI is used
084: */
085: private boolean m_use_redirect = false;
086: /**
087: * The redirect URI
088: */
089: private String m_redirect_URL = "/errors/404.htm";
090: /**
091: * The importance email header value
092: */
093: protected String m_sImportance = null;
094:
095: /**
096: * Constructs a new exception handler with the settings taken from
097: * the <code>ConfigSettings</code> class
098: *
099: * @throws Exception if any errors occur
100: */
101: public HarmoniseExceptionHandler() throws Exception {
102: String error_email_toaddress = ConfigSettings
103: .getProperty(EMAIL_ADDRESS_PNAME);
104: m_error_email_toaddresses[0] = error_email_toaddress;
105:
106: m_use_redirect = ConfigSettings.getBoolProperty(
107: USE_REDIRECT_PNAME, "false");
108:
109: m_redirect_URL = ConfigSettings.getProperty(REDIRECT_URL_PNAME,
110: m_redirect_URL);
111:
112: m_bEmailErrors = ConfigSettings.getBoolProperty(
113: EMAIL_ERRORS_PNAME, "false");
114:
115: this .updateExceptionDate();
116: }
117:
118: /**
119: * Handle the specified exception, emailing a report and/or redirecting
120: * the reponse object
121: *
122: * @param additional_info the additional information to be included in the report
123: * @param e the exception to be 'handled'
124: * @param request the servlet request
125: * @param response the servlet response
126: * @param out the <code>PrintWriter</code> to print the report to if redirecting
127: * has been switched off
128: * @throws Exception if any errors occur
129: */
130: public void handle(String additional_info, Throwable e,
131: HttpServletRequest request, HttpServletResponse response,
132: PrintWriter out) throws Exception {
133: m_additional_info = additional_info;
134:
135: m_reporting_URL = request.getRequestURI();
136:
137: String exception_description = describeException(request, e);
138:
139: if (m_bEmailErrors) {
140: emailError(exception_description, e);
141: } // email errors
142:
143: // always put a note in the log
144: //cat.fatal("** Exception:" + exception_description);
145:
146: if (m_use_redirect) {
147: response.sendRedirect(m_redirect_URL);
148: } else {
149: if (out != null) {
150: out.println("<pre>");
151: out.println(exception_description);
152: out.println("</pre>");
153: }
154: }
155: }
156:
157: /**
158: * Emails the given exception with no importance heading value set
159: * and a standard subject heading
160: *
161: * @param exception_description a description of the exception
162: * @param e the exception
163: * @throws Exception if any errors occur
164: */
165: public void emailError(String exception_description, Throwable e)
166: throws Exception {
167: emailError(exception_description, e, false);
168: }
169:
170: /**
171: * Emails the given exception with the specified importance heading value
172: * set and a standard subject heading
173: *
174: * @param exception_description a description of the exception
175: * @param e the exception
176: * @param bEmphasize the importance heading value
177: * @throws Exception if any errors occur
178: */
179: public void emailError(String exception_description, Throwable e,
180: boolean bEmphasize) throws Exception {
181: String sSubject = "Error for " + m_reporting_URL + " ["
182: + m_exception_date_string + "]";
183:
184: emailError(sSubject, exception_description, e, bEmphasize);
185: }
186:
187: /**
188: * Emails the given exception with no importance heading value
189: * set and the specified subject heading
190: *
191: * @param sSubject the email subject
192: * @param exception_description a description of the exception
193: * @param e the exception
194: * @throws Exception if any errors occur
195: */
196: public void emailError(String sSubject,
197: String exception_description, Throwable e) throws Exception {
198: emailError(sSubject, exception_description, e, false);
199: }
200:
201: /**
202: * Emails the given exception with the specified importance heading value
203: * set and subject heading
204: *
205: * @param sSubject the email subject
206: * @param exception_description a description of the exception
207: * @param e the exception
208: * @param bEmphasize the importance heading value
209: * @throws Exception if any errors occur
210: */
211: public void emailError(String sSubject,
212: String exception_description, Throwable e,
213: boolean bEmphasize) throws Exception {
214:
215: if (bEmphasize == true) {
216: sSubject = sSubject.toUpperCase();
217: }
218:
219: Email email = new Email(ConfigSettings
220: .getProperty("EMAIL_HOST"),
221: m_error_email_toaddresses[0],
222: m_originator_email_address, sSubject,
223: exception_description);
224:
225: if (m_sImportance != null) {
226: email.setImportance(m_sImportance);
227: }
228:
229: for (int i = 0; i < m_error_email_toaddresses.length; i++) {
230: email.SetEmailAddress(m_error_email_toaddresses[i]);
231: email.send();
232: }
233:
234: }
235:
236: /**
237: * Sets this handler's formatted date field
238: *
239: */
240: private void updateExceptionDate() {
241: SimpleDateFormat formatter = new SimpleDateFormat(
242: "EEEE yyyyy-MMMM-dd 'at' hh:mm:ss zzzz");
243:
244: java.util.Date current_time = new java.util.Date();
245: m_exception_date_string = formatter.format(current_time);
246: }
247:
248: /**
249: * Sets the email importance heading value
250: *
251: * @param sImportance the email importance heading value
252: */
253: public void setImportance(String sImportance) {
254: this .m_sImportance = sImportance;
255: }
256:
257: /**
258: * Returns a string decription of the specified exception
259: *
260: * @param e the exception
261: * @return a string description of the specified exception
262: */
263: public String describeException(Exception e) {
264: StringBuffer strbuf = new StringBuffer();
265: String EOL = "\n";
266:
267: strbuf.append("[").append(m_reporting_URL).append("]").append(
268: EOL);
269: strbuf.append(m_exception_date_string).append(EOL);
270: strbuf.append(EOL);
271:
272: strbuf.append("The following error occured:").append(EOL);
273: strbuf.append(" '").append(e).append("'").append(EOL);
274: strbuf.append(EOL);
275:
276: // Additional info
277: strbuf.append("Additional information:").append(EOL);
278: strbuf.append(m_additional_info).append(EOL);
279: strbuf.append(EOL);
280:
281: // Stacktrace
282: strbuf.append("-- Stacktrace:").append(EOL);
283: ;
284: strbuf.append(getStackTraceAsString(e));
285:
286: return (strbuf.toString());
287: }
288:
289: /**
290: * Returns a string description of the specified exception, including
291: * contextual information taken from the servlet request
292: *
293: * @param request the servlet request
294: * @param e the exception
295: * @return a string description
296: */
297: public String describeException(HttpServletRequest request,
298: Throwable e) {
299: StringBuffer strbuf = new StringBuffer();
300: String EOL = "\n";
301:
302: strbuf.append("[").append(m_reporting_URL).append("]").append(
303: EOL);
304: strbuf.append(m_exception_date_string).append(EOL);
305: strbuf.append(EOL);
306:
307: strbuf.append("The following error occured:").append(EOL);
308: strbuf.append(" '").append(e).append("'").append(EOL);
309: strbuf.append(EOL);
310:
311: // Additional info
312: strbuf.append("Additional information:").append(EOL);
313: strbuf.append(m_additional_info).append(EOL);
314: strbuf.append(EOL);
315:
316: // Reguest info
317: strbuf.append("-- Request:\n");
318: strbuf.append("URI :").append(request.getRequestURI()).append(
319: EOL);
320: strbuf.append("Query :?").append(request.getQueryString())
321: .append(EOL);
322: strbuf.append("Path info :").append(request.getPathInfo())
323: .append(EOL);
324: strbuf.append("User IP :").append(request.getRemoteAddr())
325: .append(EOL);
326: strbuf.append("Remote Host :").append(request.getRemoteHost())
327: .append(EOL);
328: strbuf.append("Remote User :").append(request.getRemoteUser())
329: .append(EOL);
330: strbuf.append("Request method :").append(request.getMethod())
331: .append(EOL);
332: strbuf.append("Servlet Path :")
333: .append(request.getServletPath()).append(EOL);
334:
335: strbuf.append(EOL);
336:
337: // Header info
338: strbuf.append("-- Header Info:").append(EOL);
339:
340: Enumeration header_names = request.getHeaderNames();
341:
342: while (header_names.hasMoreElements()) {
343: String name = (String) header_names.nextElement();
344: strbuf.append(" ");
345: strbuf.append(name);
346: strbuf.append(": ");
347: strbuf.append(request.getHeader(name));
348: strbuf.append(EOL);
349: }
350:
351: strbuf.append(EOL);
352:
353: // Cookies
354: Cookie[] cookies = request.getCookies();
355:
356: if (cookies != null) {
357: strbuf.append("-- Cookies:").append(EOL);
358:
359: for (int i = 0; i < cookies.length; i++) {
360: Cookie this _cookie = cookies[i];
361: strbuf.append(" ");
362: strbuf.append(this _cookie.getName());
363: strbuf.append(": ");
364: strbuf.append(this _cookie.getValue());
365: strbuf.append(EOL);
366: }
367: }
368:
369: strbuf.append(EOL);
370:
371: // Stacktrace
372: strbuf.append("-- Stacktrace:").append(EOL);
373: ;
374: strbuf.append(getStackTraceAsString(e));
375:
376: return (strbuf.toString());
377: }
378:
379: /**
380: * Returns a <code>String</code> representation of the given <code>Exception</code>
381: *
382: * @param e the exception
383: * @return a <code>String</code> representation of the given <code>Exception</code>
384: */
385: private static String getStackTraceAsString(Throwable e) {
386: StringWriter sw = new StringWriter();
387: PrintWriter pw = new PrintWriter(sw);
388: e.printStackTrace(pw);
389: pw.close();
390:
391: return sw.toString();
392: }
393: }
|