Coverage Report - org.crosswire.common.util.Reporter
 
Classes in this File Line Coverage Branch Coverage Complexity
Reporter
0%
0/41
0%
0/18
2
Reporter$CustomAWTExceptionHandler
0%
0/5
0%
0/2
2
 
 1  
 /**
 2  
  * Distribution License:
 3  
  * JSword is free software; you can redistribute it and/or modify it under
 4  
  * the terms of the GNU Lesser General Public License, version 2.1 or later
 5  
  * as published by the Free Software Foundation. This program is distributed
 6  
  * in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
 7  
  * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 8  
  * See the GNU Lesser General Public License for more details.
 9  
  *
 10  
  * The License is available on the internet at:
 11  
  *      http://www.gnu.org/copyleft/lgpl.html
 12  
  * or by writing to:
 13  
  *      Free Software Foundation, Inc.
 14  
  *      59 Temple Place - Suite 330
 15  
  *      Boston, MA 02111-1307, USA
 16  
  *
 17  
  * © CrossWire Bible Society, 2005 - 2016
 18  
  *
 19  
  */
 20  
 package org.crosswire.common.util;
 21  
 
 22  
 import java.util.List;
 23  
 import java.util.Properties;
 24  
 import java.util.concurrent.CopyOnWriteArrayList;
 25  
 
 26  
 import org.crosswire.jsword.JSMsg;
 27  
 import org.slf4j.Logger;
 28  
 import org.slf4j.LoggerFactory;
 29  
 
 30  
 /**
 31  
  * This package looks after Exceptions and messages as they happen. It would be
 32  
  * nice not to need this class - the principle being that any library that
 33  
  * encounters an error can throw an exception to indicate that there is a
 34  
  * problem. However this is not always the case. For example:
 35  
  * <ul>
 36  
  * <li>static class constructors should not throw, unless the class really is of
 37  
  * no use given the error, and yet we may want to tell the user that there was a
 38  
  * (non-critical) error.</li>
 39  
  * <li>Any library routine that works in a loop, applying some (potentially
 40  
  * failing) functionality, may want to continue the work without throwing in
 41  
  * response to a single error.</li>
 42  
  * <li>The class being implemented may implement an interface that disallows
 43  
  * nested exceptions and yet does not want to loose the root cause error
 44  
  * information. (This is the weakest of the above arguments, but probably still
 45  
  * valid.)</li>
 46  
  * </ul>
 47  
  * However in many of the times this class is used, this is the
 48  
  * reason:
 49  
  * <ul>
 50  
  * <li>Within UI specific code - to throw up a dialog box (or whatever). Now
 51  
  * this use is currently tolerated, however it is probably a poor idea to use
 52  
  * GUI agnostic messaging in a GUI specific context. But I'm not bothered enough
 53  
  * to change it now. Specifically this use is deprecated because it makes the
 54  
  * app more susceptible to the configuration of the things that listen to
 55  
  * reports.</li>
 56  
  * </ul>
 57  
  * 
 58  
  * @see gnu.lgpl.License The GNU Lesser General Public License for details.
 59  
  * @author Joe Walker
 60  
  */
 61  
 public final class Reporter {
 62  
     /**
 63  
      * Enforce Singleton
 64  
      */
 65  0
     private Reporter() {
 66  0
     }
 67  
 
 68  
     /**
 69  
      * Something has gone wrong. We need to tell the user or someone, but we can
 70  
      * carry on. In general having caught an exception and passed it to
 71  
      * Reporter.informUser(), you should not throw another Exception. Called to
 72  
      * fire a commandEntered event to all the Listeners
 73  
      * 
 74  
      * @param source
 75  
      *            The cause of the problem, a Component if possible.
 76  
      * @param prob
 77  
      *            The Exception that was thrown
 78  
      */
 79  
     public static void informUser(Object source, Throwable prob) {
 80  0
         Class<?> cat = (source != null) ? source.getClass() : Reporter.class;
 81  0
         Logger templog = LoggerFactory.getLogger(cat);
 82  
 
 83  0
         templog.warn(prob.getMessage(), prob);
 84  
 
 85  0
         fireCapture(new ReporterEvent(source, prob));
 86  0
     }
 87  
 
 88  
     /**
 89  
      * Something has gone wrong. We need to tell the user or someone, but we can
 90  
      * carry on. In general having caught an exception and passed it to
 91  
      * Reporter.informUser(), you should not throw another Exception. Called to
 92  
      * fire a commandEntered event to all the Listeners
 93  
      * 
 94  
      * @param source
 95  
      *            The cause of the problem, a Component if possible.
 96  
      * @param prob
 97  
      *            The Exception that was thrown
 98  
      */
 99  
     public static void informUser(Object source, LucidException prob) {
 100  0
         Class<?> cat = (source != null) ? source.getClass() : Reporter.class;
 101  0
         Logger templog = LoggerFactory.getLogger(cat);
 102  
 
 103  0
         templog.warn(prob.getMessage(), prob);
 104  
 
 105  0
         fireCapture(new ReporterEvent(source, prob));
 106  0
     }
 107  
 
 108  
     /**
 109  
      * Something has gone wrong. We need to tell the user or someone, but we can
 110  
      * carry on. In general having caught an exception and passed it to
 111  
      * Reporter.informUser(), you should not throw another Exception. Called to
 112  
      * fire a commandEntered event to all the Listeners
 113  
      * 
 114  
      * @param source
 115  
      *            The cause of the problem, a Component if possible.
 116  
      * @param prob
 117  
      *            The Exception that was thrown
 118  
      */
 119  
     public static void informUser(Object source, LucidRuntimeException prob) {
 120  0
         Class<?> cat = (source != null) ? source.getClass() : Reporter.class;
 121  0
         Logger templog = LoggerFactory.getLogger(cat);
 122  
 
 123  0
         templog.warn(prob.getMessage(), prob);
 124  
 
 125  0
         fireCapture(new ReporterEvent(source, prob));
 126  0
     }
 127  
 
 128  
     /**
 129  
      * Something has happened. We need to tell the user or someone.
 130  
      * 
 131  
      * @param source
 132  
      *            The cause of the message, a Component if possible.
 133  
      * @param message
 134  
      *            The message to pass to the user
 135  
      */
 136  
     public static void informUser(Object source, String message) {
 137  0
         LOGGER.debug(message);
 138  
 
 139  0
         fireCapture(new ReporterEvent(source, message));
 140  0
     }
 141  
 
 142  
     /**
 143  
      * Add an Exception listener to the list of things wanting to know whenever
 144  
      * we capture an Exception
 145  
      * 
 146  
      * @param li the interested listener
 147  
      */
 148  
     public static void addReporterListener(ReporterListener li) {
 149  0
         LISTENERS.add(li);
 150  0
     }
 151  
 
 152  
     /**
 153  
      * Remove an Exception listener from the list of things wanting to know
 154  
      * whenever we capture an Exception
 155  
      * 
 156  
      * @param li the disinterested listener
 157  
      */
 158  
     public static void removeReporterListener(ReporterListener li) {
 159  0
         LISTENERS.remove(li);
 160  0
     }
 161  
 
 162  
     /**
 163  
      * Log a message.
 164  
      * 
 165  
      * @param ev the event to capture
 166  
      */
 167  
     protected static void fireCapture(ReporterEvent ev) {
 168  0
         if (LISTENERS.size() == 0) {
 169  0
             LOGGER.warn("Nothing to listen to report: message={}", ev.getMessage(), ev.getException());
 170  
         }
 171  
 
 172  0
         for (ReporterListener listener : LISTENERS) {
 173  0
             if (ev.getException() != null) {
 174  0
                 listener.reportException(ev);
 175  
             } else {
 176  0
                 listener.reportMessage(ev);
 177  
             }
 178  
         }
 179  0
     }
 180  
 
 181  
     /**
 182  
      * Sets the parent of any exception windows.
 183  
      * 
 184  
      * @param grab whether to grab AWT exceptions or not
 185  
      */
 186  
     public static void grabAWTExecptions(boolean grab) {
 187  0
         if (grab) {
 188  
             // register ourselves
 189  0
             System.setProperty(AWT_HANDLER_PROPERTY, OUR_NAME);
 190  
         } else {
 191  
             // unregister ourselves
 192  0
             String current = System.getProperty(AWT_HANDLER_PROPERTY);
 193  0
             if (current != null && current.equals(OUR_NAME)) {
 194  0
                 Properties prop = System.getProperties();
 195  0
                 prop.remove(AWT_HANDLER_PROPERTY);
 196  
             }
 197  
         }
 198  0
     }
 199  
 
 200  
     /**
 201  
      * A class to handle AWT caught Exceptions
 202  
      */
 203  0
     public static final class CustomAWTExceptionHandler {
 204  
         /**
 205  
          * Its important that we have a no-arg ctor to make this work. So if we
 206  
          * ever create an arged ctor then we need to add:
 207  
          * public CustomAWTExceptionHandler() { }
 208  
          */
 209  
 
 210  
         /**
 211  
          * Handle AWT exceptions
 212  
          * 
 213  
          * @param ex the exception to handle
 214  
          */
 215  
         public void handle(Throwable ex) {
 216  
             // Only allow one to be reported every so often.
 217  
             // This interval control was needed because AWT exceptions
 218  
             // were causing recursive AWT exceptions
 219  
             // and way too many dialogs were being thrown up on the screen.
 220  0
             if (gate.open()) {
 221  
                 // TRANSLATOR: Very frequent error condition: The program has encountered a severe problem and it is likely that the program is unusable.
 222  0
                 Reporter.informUser(this, new LucidException(JSMsg.gettext("Unexpected internal problem. You may need to restart."), ex));
 223  
             }
 224  0
         }
 225  
 
 226  0
         private static TimeGate gate = new TimeGate(2000);
 227  
     }
 228  
 
 229  
     /**
 230  
      * The system property name for registering AWT exceptions
 231  
      */
 232  
     private static final String AWT_HANDLER_PROPERTY = "sun.awt.exception.handler";
 233  
 
 234  
     /**
 235  
      * The name of the class to register for AWT exceptions
 236  
      */
 237  0
     private static final String OUR_NAME = CustomAWTExceptionHandler.class.getName();
 238  
 
 239  
     /**
 240  
      * The list of listeners
 241  
      */
 242  0
     private static final List<ReporterListener> LISTENERS = new CopyOnWriteArrayList<ReporterListener>();
 243  
 
 244  
     /**
 245  
      * The log stream
 246  
      */
 247  0
     private static final Logger LOGGER = LoggerFactory.getLogger(Reporter.class);
 248  
 }