001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: /*
043: * ExceptionHandler.java
044: * Created on October 10, 2003, 2:06 PM
045: */
046:
047: package com.sun.errorhandler;
048:
049: import java.io.BufferedReader;
050: import java.io.File;
051: import java.util.ArrayList;
052: import javax.servlet.http.HttpServlet;
053: import javax.servlet.http.HttpServletRequest;
054: import javax.servlet.http.HttpServletResponse;
055: import java.io.IOException;
056: import java.io.InputStream;
057: import java.io.InputStreamReader;
058: import java.io.LineNumberReader;
059: import java.io.PrintWriter;
060: import java.lang.StackTraceElement;
061: import java.net.URL;
062:
063: import com.sun.errorhandler.DebugClientThread;
064: import java.util.ResourceBundle;
065: import java.util.Locale;
066:
067: /**
068: * @author Winston Prakash
069: * jfbrown for the debugging control and lovely l10n-ization.
070: */
071: public class ExceptionHandler extends HttpServlet {
072:
073: private static ResourceBundle rb = ResourceBundle.getBundle(
074: "com.sun.errorhandler.Bundle", // NOI18N
075: Locale.getDefault());
076:
077: private static int debugLevel = 0;
078:
079: public static int getDebugLevel() {
080: return debugLevel;
081: }
082:
083: public void init(javax.servlet.ServletConfig sc) {
084: try {
085: super .init(sc);
086: } catch (Exception ex) {
087: ex.printStackTrace();
088: }
089: }
090:
091: private boolean readPropertiesAlready = false;
092:
093: public void initProps() {
094: if (!readPropertiesAlready) {
095: readPropertiesAlready = true;
096:
097: String errH = this .getInitParameter("errorHost"); // NOI18N
098: if (errH != null) {
099: DebugClientThread.errorHost = errH; //NOI18N
100: String errP = this .getInitParameter("errorPort"); // NOI18N
101: if (errP != null) {
102: DebugClientThread.setErrorPort(errP);
103: } else {
104: DebugClientThread.setErrorPort("0"); // NOI18N
105: }
106: }
107: }
108: }
109:
110: public void doPost(HttpServletRequest request,
111: HttpServletResponse response) throws IOException {
112: initProps();
113: generateResponse(request, response);
114: }
115:
116: public void doGet(HttpServletRequest request,
117: HttpServletResponse response) throws IOException {
118: initProps();
119: // only test for params in the doGet().
120: if (request.getParameter("debug") != null //NOI18N
121: || request.getParameter("errorHost") != null //NOI18N
122: || request.getParameter("errorPort") != null) { //NOI18N
123: setDebugVars(request);
124: }
125: generateResponse(request, response);
126: }
127:
128: public void generateResponse(HttpServletRequest request,
129: HttpServletResponse response) throws IOException {
130: Throwable exception = (Throwable) request
131: .getAttribute("javax.servlet.error.exception");
132: String request_uri = (String) request
133: .getAttribute("javax.servlet.error.request_uri");
134:
135: // Specify the content type is HTML
136: response.setContentType("text/html;charset=UTF-8"); // NOI18N
137: PrintWriter out = response.getWriter();
138:
139: // Generate the HTML response
140: out.println("<HTML>"); // NOI18N
141: out.println("<HEAD>"); // NOI18N
142: out.println("<TITLE>"); // NOI18N
143: out.println(rb.getString("EH_pagetitle")); // NOI18N
144: out.println("</TITLE>"); // NOI18N
145: out.print("<style>I{font-family:"); // NOI18N
146: out.print("Verdana,UTF-8"); //TODO - needs to be for the project! // NOI18N
147: out
148: .println(";font-weight:italic;font-size:8pt;color:maroon}</style>"); // NOI18N
149: out.println("</HEAD>"); // NOI18N
150: out.println("<BODY BGCOLOR='white'>"); // NOI18N
151: out.println("<CENTER><B>"); // NOI18N
152: out.println(rb.getString("EH_pagetitle")); // NOI18N
153: out.println("</B></CENTER>"); // NOI18N
154: out.println("<P>"); // NOI18N
155: out.println("<FONT COLOR='blue'>"); // NOI18N
156:
157: out.println("<BR><B>"); // NOI18N
158: out.println(rb.getString("EH_Description")); // NOI18N
159: out.println("</B> "); // NOI18N
160: out.println(rb.getString("EH_Reason")); // NOI18N
161: out.println("<BR>"); // NOI18N
162:
163: // output the causes in reverse order
164: ArrayList eList = new ArrayList();
165: while (exception != null) {
166: eList.add(exception);
167: exception = exception.getCause();
168: }
169: for (int ecnt = eList.size() - 1; ecnt >= 0; ecnt--) {
170: displayMessage((Throwable) eList.get(ecnt), out);
171: }
172:
173: out.println("</FONT>"); // NOI18N
174: out.println("</P>"); // NOI18N
175: if (getDebugLevel() > 0) {
176: out.println("<HR><P>Debugging on.</P>");
177: out.println("<P>Errors will be sent to "
178: + DebugClientThread.errorHost + " port "
179: + DebugClientThread.getErrorPort() + "</P>");
180: }
181: out.println("</BODY>"); // NOI18N
182: out.println("</HTML>"); // NOI18N
183: out.close();
184: }
185:
186: private void displayMessage(Throwable exception, PrintWriter out) {
187: String expTypeFullName = exception.getClass().getName();
188: String expTypeName = expTypeFullName.substring(expTypeFullName
189: .lastIndexOf(".") + 1);
190: StackTraceElement[] ste = exception.getStackTrace();
191:
192: // Browse through the stack trace and find the first trace
193: // that has the file name (non-null)
194:
195: int stackCount = -1;
196: String fileName = null;
197: for (int i = 0; i < ste.length; i++) {
198: fileName = ste[i].getFileName();
199: if (fileName != null) {
200: // Check if the java file actually exists
201: String className = ste[i].getClassName();
202: try {
203: Class clazz = Class.forName(className);
204: URL url = clazz.getResource(fileName);
205: InputStream is1 = url.openStream();
206: if (is1 != null) {
207: is1.close();
208: stackCount = i;
209: break;
210: }
211: } catch (Exception ex) {
212: } finally {
213: }
214: }
215: }
216:
217: out.println("<BR><B>"); // NOI18N
218: out.println(rb.getString("EH_ExceptionDetails")); // NOI18N
219: out.println("</B> "); // NOI18N
220: out.println(expTypeFullName);
221: out.println("<BR>"); // NOI18N
222: String xmsg = exception.getLocalizedMessage();
223: if (xmsg == null)
224: xmsg = exception.getMessage();
225: out.println(" " + xmsg + "<BR>"); // NOI18N
226:
227: out.println("<BR><B>"); // NOI18N
228: out.println(rb.getString("EH_PossibleSource")); // NOI18N
229: out.println("</B><BR>"); // NOI18N
230:
231: out.println(" "); // NOI18N
232: out.println(rb.getString("EH_ClassName")); // NOI18N
233: out.println(" <I>"
234: + (ste.length < 1 ? rb.getString("EH_unknownValue")
235: : ste[0].getClassName()) + "</I> <BR>"); // NOI18N
236:
237: out.println(" "); // NOI18N
238: out.println(rb.getString("EH_FileName")); // NOI18N
239: out.println(" <I>"
240: + (ste.length < 1 ? rb.getString("EH_unknownValue")
241: : ste[0].getFileName()) + "</I> <BR>"); // NOI18N
242:
243: out.println(" "); // NOI18N
244: out.println(rb.getString("EH_MethodName")); // NOI18N
245: out.println(" <I>"
246: + (ste.length < 1 ? rb.getString("EH_unknownValue")
247: : ste[0].getMethodName()) + "</I> <BR>"); // NOI18N
248:
249: out.println(" "); // NOI18N
250: out.println(rb.getString("EH_LineNumber")); // NOI18N
251: out.println(" <I>"
252: + (ste.length < 1 ? rb.getString("EH_unknownValue")
253: : Integer.toString((ste[0].getLineNumber())))
254: + "</I> <BR>"); // NOI18N
255: out.println("<BR>"); // NOI18N
256:
257: if (stackCount != -1) {
258: int lineNumber = ste[stackCount].getLineNumber();
259:
260: String className = ste[stackCount].getClassName();
261: fileName = ste[stackCount].getFileName();
262: try {
263: Class clazz = Class.forName(className);
264: URL url = clazz.getResource(fileName);
265: if (url != null) {
266: InputStream is = url.openStream();
267: LineNumberReader reader = new LineNumberReader(
268: new InputStreamReader(is));
269: out
270: .println("<table width=100% bgcolor=\"#ffffcc\"><tr><td><code>"); // NOI18N
271: for (int i = 0; i < lineNumber + 3; i++) {
272: String line = reader.readLine();
273: int lineNo = reader.getLineNumber();
274: if (lineNo >= lineNumber - 3) {
275: if (lineNo == lineNumber) {
276: out
277: .println("<FONT COLOR='red' BGCOLOR='white'><B>"); // NOI18N
278: out
279: .println(lineNo + ": "
280: + appendHTMLChar(line)
281: + "<BR>"); // NOI18N
282: out.println("</B></FONT>"); // NOI18N
283: } else {
284: out
285: .println(lineNo + ": "
286: + appendHTMLChar(line)
287: + "<BR>"); // NOI18N
288: }
289: }
290: }
291: out.println("</code></td></tr></table>"); // NOI18N
292: is.close();
293: reader.close();
294: }
295: } catch (Exception ex) {
296: }
297: } else {
298: out
299: .println("<table width=100% bgcolor=\"#ffffcc\"><tr><td><code>"); // NOI18N
300: out.println(rb.getString("EH_NoSourceLong")); // NOI18N
301: out.println("<BR></code></td></tr></table>"); // NOI18N
302: }
303:
304: out.println("<BR><B>"); // NOI18N
305: out.println(rb.getString("EH_StackTrace")); // NOI18N
306: out.println(" </B><BR><BR>"); // NOI18N
307: out
308: .println("<table width=100% bgcolor=\"#eeddff\"><tr><td><code>"); // NOI18N
309: for (int i = 0; i < ste.length; i++) {
310: int lineNumber = ste[i].getLineNumber();
311: String cName = ste[i].getClassName();
312: String fName = ste[i].getFileName();
313: String mName = ste[i].getMethodName();
314: if (i == stackCount)
315: out.println("<FONT COLOR='brown' BGCOLOR='white'><B>"); // NOI18N
316: if (fName != null) {
317: out.println(cName + "." + mName + "(" + fName + ":"
318: + lineNumber + ")<BR>"); // NOI18N
319: } else {
320: out.println(cName + "." + mName + "(");
321: out.println(rb.getString("EH_NoSourceShort")); // NOI18N
322: out.println(")<BR>"); // NOI18N
323: }
324: if (i == stackCount)
325: out.println("</B></FONT>"); // NOI18N
326: }
327: out.println("</code></td></tr></table>"); // NOI18N
328:
329: if (stackCount == -1)
330: stackCount = 0;
331: if (DebugClientThread.errorHost != null && ste.length > 0) {
332: DebugClientThread clientThread = new DebugClientThread();
333: DebugProtocol debugprotocol = new DebugProtocol();
334: clientThread.start();
335: if (clientThread.testConnected()) {
336: clientThread.sendMessage(debugprotocol.DEBUG_CLIENT_ID
337: + debugprotocol.DEBUG_DELIMITER
338: + debugprotocol.DEBUG_CLIENT_NAME);
339: clientThread
340: .sendMessage(debugprotocol.DEBUG_REQUEST_START);
341: clientThread.sendMessage(debugprotocol.DEBUG_CLASS_NAME
342: + debugprotocol.DEBUG_DELIMITER
343: + ste[stackCount].getClassName());
344: clientThread.sendMessage(debugprotocol.DEBUG_FILE_NAME
345: + debugprotocol.DEBUG_DELIMITER
346: + ste[stackCount].getFileName());
347: clientThread
348: .sendMessage(debugprotocol.DEBUG_METHOD_NAME
349: + debugprotocol.DEBUG_DELIMITER
350: + ste[stackCount].getMethodName());
351: clientThread
352: .sendMessage(debugprotocol.DEBUG_LINE_NUMBER
353: + debugprotocol.DEBUG_DELIMITER
354: + ste[stackCount].getLineNumber());
355: clientThread
356: .sendMessage(debugprotocol.DEBUG_REQUEST_END);
357: clientThread.disconnect();
358: }
359: }
360: }
361:
362: /** Append a character to a StringBuffer intended for HTML
363: * display - it will escape <, >, etc. such that the char is
364: * shown properly in HTML.
365: */
366: public String appendHTMLChar(String str) {
367: StringBuffer sb = new StringBuffer();
368: int len = str.length();
369: for (int i = 0; i < len; i++) {
370: char chr = str.charAt(i);
371: switch (chr) {
372: case '<':
373: sb.append("<");
374: break; // NOI18N
375: case '>':
376: sb.append(">");
377: break; // NOI18N
378: case '&':
379: sb.append("&");
380: break; // NOI18N
381: case '"':
382: sb.append(""");
383: break; // NOI18N
384: case ' ':
385: sb.append(" ");
386: break; // NOI18N
387: case '\n':
388: sb.append("<br>");
389: break; // NOI18N
390: default:
391: sb.append(chr);
392: }
393: }
394: return sb.toString();
395: }
396:
397: /****
398: * HACK - sets debug variables.
399: * possible HttpServletRequest paramaters:
400: * debug = turn on/off misc logging statements to app server log
401: * errorHost = for sending exceptions back to Creator, this is the hostname.
402: * errorPort = for sending exceptions back to Creator, this is the port.
403: */
404: private void setDebugVars(HttpServletRequest request) {
405: String val = request.getParameter("debug"); //NOI18N
406: if (val != null) {
407: val = val.trim();
408: if ("1".equals(val) //NOI18N
409: || "true".equalsIgnoreCase(val) //NOI18N
410: || "yes".equalsIgnoreCase(val)) //NOI18N
411: debugLevel = 1;
412: else
413: debugLevel = 0;
414: }
415:
416: // HACK: allow setting of errorHost and errorPort too.
417: val = request.getParameter("errorHost"); //NOI18N
418: if (val != null) {
419: if (!"".equals(val))
420: DebugClientThread.errorHost = null; //NOI18N
421: else
422: DebugClientThread.errorHost = val;
423: }
424: val = request.getParameter("errorPort"); //NOI18N
425: if (val != null) {
426: DebugClientThread.setErrorPort(val);
427: }
428: }
429: }
|