GriffonExceptionHandler.java
001 /*
002  * Copyright 2008-2013 the original author or authors.
003  *
004  * Licensed under the Apache License, Version 2.0 (the "License");
005  * you may not use this file except in compliance with the License.
006  * You may obtain a copy of the License at
007  *
008  *      http://www.apache.org/licenses/LICENSE-2.0
009  *
010  * Unless required by applicable law or agreed to in writing, software
011  * distributed under the License is distributed on an "AS IS" BASIS,
012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013  * See the License for the specific language governing permissions and
014  * limitations under the License.
015  */
016 package griffon.util;
017 
018 import griffon.core.GriffonApplication;
019 import org.codehaus.groovy.runtime.StackTraceUtils;
020 import org.slf4j.Logger;
021 import org.slf4j.LoggerFactory;
022 
023 import java.util.Map;
024 
025 import static java.util.Arrays.asList;
026 
027 /**
028  * Catches and sanitizes all uncaught exceptions.
029  *
030  @author Danno Ferrin
031  @author Andres Almiray
032  */
033 public class GriffonExceptionHandler implements Thread.UncaughtExceptionHandler {
034     /**
035      * "griffon.full.stacktrace"
036      */
037     public static final String GRIFFON_FULL_STACKTRACE = "griffon.full.stacktrace";
038     /**
039      * "griffon.exception.output"
040      */
041     public static final String GRIFFON_EXCEPTION_OUTPUT = "griffon.exception.output";
042 
043     private static final Logger LOG = LoggerFactory.getLogger(GriffonExceptionHandler.class);
044     private static final String[] CONFIG_OPTIONS = {
045             GRIFFON_FULL_STACKTRACE,
046             GRIFFON_EXCEPTION_OUTPUT
047     };
048 
049     public void uncaughtException(Thread t, Throwable e) {
050         handle(e);
051     }
052 
053     public void handle(Throwable throwable) {
054         try {
055             sanitize(throwable);
056             if (isOutputEnabled()) throwable.printStackTrace(System.err);
057             GriffonApplication app = ApplicationHolder.getApplication();
058             if (app != null) {
059                 LOG.error("Uncaught Exception", throwable);
060                 app.event("Uncaught" + GriffonNameUtils.getShortName(throwable.getClass()), asList(throwable));
061                 app.event(GriffonApplication.Event.UNCAUGHT_EXCEPTION_THROWN.getName(), asList(throwable));
062             }
063         catch (Throwable t) {
064             sanitize(t);
065             if (isOutputEnabled()) t.printStackTrace(System.err);
066             LOG.error("An error occurred while handling uncaught exception " + throwable, t);
067         }
068     }
069 
070     public static Throwable sanitize(Throwable throwable) {
071         try {
072             if (!Boolean.getBoolean(GRIFFON_FULL_STACKTRACE)) StackTraceUtils.deepSanitize(throwable);
073         catch (Throwable t) {
074             // don't let the exception get thrown out, will cause infinite looping!
075         }
076         return throwable;
077     }
078 
079     public static StackTraceElement[] sanitize(StackTraceElement[] stackTrace) {
080         try {
081             if (!Boolean.getBoolean(GRIFFON_FULL_STACKTRACE)) {
082                 Throwable t = new Throwable();
083                 t.setStackTrace(stackTrace);
084                 sanitize(t);
085                 stackTrace = t.getStackTrace();
086             }
087         catch (Throwable o) {
088             // don't let the exception get thrown out, will cause infinite looping!
089         }
090         return stackTrace;
091     }
092 
093     public static boolean isOutputEnabled() {
094         return Boolean.getBoolean(GRIFFON_EXCEPTION_OUTPUT);
095     }
096 
097     public static void configure(Map config) {
098         for (String option : CONFIG_OPTIONS) {
099             if (config.containsKey(option)) {
100                 System.setProperty(option, String.valueOf(config.get(option)));
101             }
102         }
103     }
104 
105     public static void registerExceptionHandler() {
106         Thread.setDefaultUncaughtExceptionHandler(new GriffonExceptionHandler());
107         System.setProperty("sun.awt.exception.handler", GriffonExceptionHandler.class.getName());
108     }
109 
110     public static void handleThrowable(Throwable t) {
111         Thread.getDefaultUncaughtExceptionHandler().uncaughtException(
112                 Thread.currentThread(),
113                 t
114         );
115     }
116 }