File Source: ErrorManager.java

     1  /*
     2   * Copyright (c) 2006-2009 Chris Smith, Shane Mc Cormack, Gregory Holmes
     3   *
     4   * Permission is hereby granted, free of charge, to any person obtaining a copy
     5   * of this software and associated documentation files (the "Software"), to deal
     6   * in the Software without restriction, including without limitation the rights
     7   * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     8   * copies of the Software, and to permit persons to whom the Software is
     9   * furnished to do so, subject to the following conditions:
    10   *
    11   * The above copyright notice and this permission notice shall be included in
    12   * all copies or substantial portions of the Software.
    13   *
    14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    20   * SOFTWARE.
    21   */
    22  
    23  package com.dmdirc.logger;
    24  
    25  import com.dmdirc.config.ConfigManager;
    26  import com.dmdirc.config.IdentityManager;
    27  import com.dmdirc.interfaces.ConfigChangeListener;
    28  import com.dmdirc.ui.FatalErrorDialog;
    29  import com.dmdirc.util.ListenerList;
    30  
    31  import java.awt.GraphicsEnvironment;
    32  import java.io.Serializable;
    33  import java.util.Date;
    34  import java.util.LinkedList;
    35  import java.util.List;
    36  import java.util.concurrent.BlockingQueue;
    37  import java.util.concurrent.LinkedBlockingQueue;
    38  import java.util.concurrent.atomic.AtomicLong;
    39  
    40  /**
    41   * Error manager.
    42   */
    43  public final class ErrorManager implements Serializable, ConfigChangeListener {
    44  
    45      /**
    46       * A version number for this class. It should be changed whenever the class
    47       * structure is changed (or anything else that would prevent serialized
    48       * objects being unserialized with the new class).
    49       */
    50      private static final long serialVersionUID = 4;
    51  
    52      /** Previously instantiated instance of ErrorManager. */
             /* 
    P/P       *  Method: com.dmdirc.logger.ErrorManager__static_init
              * 
              *  Postconditions:
              *    BANNED_EXCEPTIONS == &new Class[](ErrorManager__static_init#2)
              *    me == &new ErrorManager(ErrorManager__static_init#1)
              *    new AtomicLong(ErrorManager#4) num objects == 1
              *    new Class[](ErrorManager__static_init#2) num objects == 1
              *    new ErrorManager(ErrorManager__static_init#1) num objects == 1
              *    new LinkedBlockingQueue(ErrorManager#1) num objects == 1
              *    new LinkedList(ErrorManager#3) num objects == 1
              *    new ListenerList(ErrorManager#2) num objects == 1
              *    BANNED_EXCEPTIONS.length == 5
              *    me.errorListeners == &new ListenerList(ErrorManager#2)
              *    ...
              */
    53      private static final ErrorManager me = new ErrorManager();
    54  
    55      /** A list of exceptions which we don't consider bugs and thus don't report. */
    56      private static final Class[] BANNED_EXCEPTIONS = new Class[]{
    57          NoSuchMethodError.class, NoClassDefFoundError.class,
    58          UnsatisfiedLinkError.class, AbstractMethodError.class,
    59          IllegalAccessError.class,
    60      };
    61  
    62      /** Whether or not to send error reports. */
    63      private boolean sendReports;
    64  
    65      /** Whether or not to log error reports. */
    66      private boolean logReports;
    67  
    68      /** Queue of errors to be reported. */
    69      private final BlockingQueue<ProgramError> reportQueue = new LinkedBlockingQueue<ProgramError>();
    70  
    71      /** Thread used for sending errors. */
    72      private volatile Thread reportThread;
    73  
    74      /** Error list. */
    75      private final List<ProgramError> errors;
    76  
    77      /** Listener list. */
    78      private final ListenerList errorListeners = new ListenerList();
    79  
    80      /** Next error ID. */
    81      private AtomicLong nextErrorID;
    82  
    83      /** Creates a new instance of ErrorListDialog. */
             /* 
    P/P       *  Method: void com.dmdirc.logger.ErrorManager()
              * 
              *  Presumptions:
              *    com.dmdirc.config.IdentityManager:getGlobalConfig(...)@88 != null
              * 
              *  Postconditions:
              *    this.errorListeners == &amp;new ListenerList(ErrorManager#2)
              *    this.errors == &amp;new LinkedList(ErrorManager#3)
              *    init'ed(this.logReports)
              *    this.nextErrorID == &amp;new AtomicLong(ErrorManager#4)
              *    this.reportQueue == &amp;new LinkedBlockingQueue(ErrorManager#1)
              *    init'ed(this.sendReports)
              *    new AtomicLong(ErrorManager#4) num objects == 1
              *    new LinkedBlockingQueue(ErrorManager#1) num objects == 1
              *    new LinkedList(ErrorManager#3) num objects == 1
              *    new ListenerList(ErrorManager#2) num objects == 1
              */
    84      private ErrorManager() {
    85          errors = new LinkedList<ProgramError>();
    86          nextErrorID = new AtomicLong();
    87  
    88          final ConfigManager config = IdentityManager.getGlobalConfig();
    89  
    90          config.addChangeListener("general", "logerrors", this);
    91          config.addChangeListener("general", "submitErrors", this);
    92          config.addChangeListener("temp", "noerrorreporting", this);
    93  
    94          updateSettings();
    95      }
    96  
    97      /**
    98       * Returns the instance of ErrorManager.
    99       *
   100       * @return Instance of ErrorManager
   101       */
   102      public static ErrorManager getErrorManager() {
                 /* 
    P/P           *  Method: ErrorManager getErrorManager()
                  * 
                  *  Postconditions:
                  *    return_value == &amp;new ErrorManager(ErrorManager__static_init#1)
                  */
   103          synchronized (me) {
   104              return me;
   105          }
   106      }
   107  
   108      /**
   109       * Adds a new error to the manager with the specified details. It is
   110       * assumed that errors without exceptions or details are not application
   111       * errors.
   112       *
   113       * @param level The severity of the error
   114       * @param message The error message
   115       * @since 0.6.3m1
   116       */
   117      protected void addError(final ErrorLevel level, final String message) {
                 /* 
    P/P           *  Method: void addError(ErrorLevel, String)
                  * 
                  *  Preconditions:
                  *    level != null
                  *    message != null
                  *    this.errors != null
                  *    init'ed(this.logReports)
                  *    this.nextErrorID != null
                  *    (soft) init'ed(com.dmdirc.ui.FatalErrorDialog$4__static_init.new int[](FatalErrorDialog$4__static_init#1)[...])
                  *    (soft) init'ed(com/dmdirc/logger/ProgramError.errorDir)
                  *    (soft) init'ed(this.reportThread)
                  *    (soft) this.errorListeners != null
                  *    (soft) this.reportQueue != null
                  *    ...
                  * 
                  *  Postconditions:
                  *    com/dmdirc/logger/ProgramError.errorDir == One-of{old com/dmdirc/logger/ProgramError.errorDir, &amp;new File(getErrorFile#1)}
                  *    init'ed(com/dmdirc/logger/ProgramError.errorDir)
                  *    this.reportThread == old this.reportThread
                  *    init'ed(this.reportThread)
                  *    new ErrorReportingThread(sendError#1) num objects == 0
                  *    init'ed(new ErrorReportingThread(sendError#1).queue)
                  *    new File(getErrorFile#1) num objects <= 1
                  */
   118          addError(level, message, new String[0], false);
   119      }
   120  
   121      /**
   122       * Adds a new error to the manager with the specified details.
   123       *
   124       * @param level The severity of the error
   125       * @param message The error message
   126       * @param exception The exception that caused this error
   127       * @param appError Whether or not this is an application error
   128       * @since 0.6.3m1
   129       */
   130      protected void addError(final ErrorLevel level, final String message,
   131              final Throwable exception, final boolean appError) {
                 /* 
    P/P           *  Method: void addError(ErrorLevel, String, Throwable, bool)
                  * 
                  *  Preconditions:
                  *    level != null
                  *    message != null
                  *    this.errors != null
                  *    init'ed(this.logReports)
                  *    this.nextErrorID != null
                  *    (soft) init'ed(com.dmdirc.ui.FatalErrorDialog$4__static_init.new int[](FatalErrorDialog$4__static_init#1)[...])
                  *    (soft) BANNED_EXCEPTIONS[...] != null
                  *    (soft) init'ed(com/dmdirc/logger/ProgramError.errorDir)
                  *    (soft) init'ed(this.reportThread)
                  *    (soft) this.errorListeners != null
                  *    ...
                  * 
                  *  Presumptions:
                  *    getTrace(...).length <= 232-1
                  * 
                  *  Postconditions:
                  *    com/dmdirc/logger/ProgramError.errorDir == One-of{old com/dmdirc/logger/ProgramError.errorDir, &amp;new File(getErrorFile#1)}
                  *    init'ed(com/dmdirc/logger/ProgramError.errorDir)
                  *    this.reportThread == One-of{old this.reportThread, &amp;new ErrorReportingThread(sendError#1)}
                  *    init'ed(this.reportThread)
                  *    new ErrorReportingThread(sendError#1) num objects <= 1
                  *    init'ed(new ErrorReportingThread(sendError#1).queue)
                  *    new File(getErrorFile#1) num objects <= 1
                  */
   132          addError(level, message, getTrace(exception), appError, isValidError(exception));
   133      }
   134  
   135      /**
   136       * Adds a new error to the manager with the specified details.
   137       *
   138       * @param level The severity of the error
   139       * @param message The error message
   140       * @param details The details of the exception
   141       * @param appError Whether or not this is an application error
   142       * @since 0.6.3m1
   143       */
   144      protected void addError(final ErrorLevel level, final String message,
   145              final String[] details, final boolean appError) {
                 /* 
    P/P           *  Method: void addError(ErrorLevel, String, String[], bool)
                  * 
                  *  Preconditions:
                  *    details != null
                  *    details.length <= 232-1
                  *    level != null
                  *    message != null
                  *    this.errors != null
                  *    init'ed(this.logReports)
                  *    this.nextErrorID != null
                  *    (soft) init'ed(com.dmdirc.ui.FatalErrorDialog$4__static_init.new int[](FatalErrorDialog$4__static_init#1)[...])
                  *    (soft) init'ed(com/dmdirc/logger/ProgramError.errorDir)
                  *    (soft) init'ed(this.reportThread)
                  *    ...
                  * 
                  *  Postconditions:
                  *    com/dmdirc/logger/ProgramError.errorDir == One-of{old com/dmdirc/logger/ProgramError.errorDir, &amp;new File(getErrorFile#1)}
                  *    init'ed(com/dmdirc/logger/ProgramError.errorDir)
                  *    this.reportThread == One-of{old this.reportThread, &amp;new ErrorReportingThread(sendError#1)}
                  *    init'ed(this.reportThread)
                  *    new ErrorReportingThread(sendError#1) num objects <= 1
                  *    init'ed(new ErrorReportingThread(sendError#1).queue)
                  *    new File(getErrorFile#1) num objects <= 1
                  */
   146          addError(level, message, details, appError, true);
   147      }
   148  
   149      /**
   150       * Adds a new error to the manager with the specified details.
   151       *
   152       * @param level The severity of the error
   153       * @param message The error message
   154       * @param details The details of the exception
   155       * @param appError Whether or not this is an application error
   156       * @param canReport Whether or not this error can be reported
   157       * @since 0.6.3m1
   158       */
   159      protected void addError(final ErrorLevel level, final String message,
   160              final String[] details, final boolean appError, final boolean canReport) {
                 /* 
    P/P           *  Method: void addError(ErrorLevel, String, String[], bool, bool)
                  * 
                  *  Preconditions:
                  *    details != null
                  *    details.length <= 232-1
                  *    level != null
                  *    message != null
                  *    this.errors != null
                  *    init'ed(this.logReports)
                  *    this.nextErrorID != null
                  *    (soft) init'ed(com.dmdirc.ui.FatalErrorDialog$4__static_init.new int[](FatalErrorDialog$4__static_init#1)[...])
                  *    (soft) init'ed(com/dmdirc/logger/ProgramError.errorDir)
                  *    (soft) init'ed(this.reportThread)
                  *    ...
                  * 
                  *  Presumptions:
                  *    error.trace.length in {1..232-1}
                  *    error.trace[0] != null
                  *    error.trace[...] != null
                  * 
                  *  Postconditions:
                  *    com/dmdirc/logger/ProgramError.errorDir == One-of{old com/dmdirc/logger/ProgramError.errorDir, &amp;new File(getErrorFile#1)}
                  *    init'ed(com/dmdirc/logger/ProgramError.errorDir)
                  *    this.reportThread == One-of{old this.reportThread, &amp;new ErrorReportingThread(sendError#1)}
                  *    init'ed(this.reportThread)
                  *    new ErrorReportingThread(sendError#1) num objects <= 1
                  *    init'ed(new ErrorReportingThread(sendError#1).queue)
                  *    new File(getErrorFile#1) num objects <= 1
                  * 
                  *  Test Vectors:
                  *    appError: {0}, {1}
                  *    canReport: {0}, {1}
                  *    this.logReports: {0}, {1}
                  *    this.sendReports: {0}, {1}
                  */
   161          final ProgramError error = getError(level, message, details, appError);
   162  
   163          if (addError(error) && canReport) {
   164              error.setReportStatus(ErrorReportStatus.NOT_APPLICABLE);
   165              error.setFixedStatus(ErrorFixedStatus.KNOWN);
   166          } else if (!canReport || (appError && !error.isValidSource())) {
   167              error.setReportStatus(ErrorReportStatus.NOT_APPLICABLE);
   168              error.setFixedStatus(ErrorFixedStatus.INVALID);
   169          } else if (!appError) {
   170              error.setReportStatus(ErrorReportStatus.NOT_APPLICABLE);
   171              error.setFixedStatus(ErrorFixedStatus.UNREPORTED);
   172          } else if (sendReports) {
   173              sendError(error);
   174          }
   175  
   176          if (logReports) {
   177              error.save();
   178          }
   179  
   180          if (level == ErrorLevel.FATAL) {
   181              fireFatalError(error);
   182          } else {
   183              fireErrorAdded(error);
   184          }
   185      }
   186  
   187      /**
   188       * Adds the specified error to the list of known errors and determines if
   189       * it was previously added.
   190       *
   191       * @param error The error to be added
   192       * @return True if a duplicate error has already been registered, false
   193       * otherwise
   194       */
   195      protected boolean addError(final ProgramError error) {
                 /* 
    P/P           *  Method: bool addError(ProgramError)
                  * 
                  *  Preconditions:
                  *    this.errors != null
                  * 
                  *  Postconditions:
                  *    init'ed(return_value)
                  */
   196          boolean res = false;
   197  
   198          synchronized (errors) {
   199              res = errors.contains(error);
   200              errors.add(error);
   201          }
   202  
   203          return res;
   204      }
   205  
   206      /**
   207       * Retrieves a {@link ProgramError} that represents the specified details.
   208       *
   209       * @param level The severity of the error
   210       * @param message The error message
   211       * @param details The details of the exception
   212       * @param appError Whether or not this is an application error
   213       * @since 0.6.3m1
   214       * @return A corresponding ProgramError
   215       */
   216      protected ProgramError getError(final ErrorLevel level, final String message,
   217              final String[] details, final boolean appError) {
                 /* 
    P/P           *  Method: ProgramError getError(ErrorLevel, String, String[], bool)
                  * 
                  *  Preconditions:
                  *    details != null
                  *    details.length <= 232-1
                  *    level != null
                  *    message != null
                  *    this.nextErrorID != null
                  * 
                  *  Presumptions:
                  *    java.util.concurrent.atomic.AtomicLong:getAndIncrement(...)@218 >= 0
                  * 
                  *  Postconditions:
                  *    return_value == &amp;new ProgramError(getError#1)
                  *    new ProgramError(getError#1) num objects == 1
                  *    return_value.date != null
                  *    return_value.fixedStatus == &amp;com.dmdirc.logger.ErrorFixedStatus__static_init.new ErrorFixedStatus(ErrorFixedStatus__static_init#7)
                  *    return_value.id >= 0
                  *    return_value.level == level
                  *    return_value.level != null
                  *    return_value.message == message
                  *    return_value.message != null
                  *    return_value.reportStatus == &amp;com.dmdirc.logger.ErrorReportStatus__static_init.new ErrorReportStatus(ErrorReportStatus__static_init#6)
                  *    ...
                  */
   218          return new ProgramError(nextErrorID.getAndIncrement(), level, message,
   219                  details, new Date());
   220      }
   221  
   222      /**
   223       * Determines whether or not the specified exception is one that we are
   224       * willing to report.
   225       *
   226       * @param exception The exception to test
   227       * @since 0.6.3m1
   228       * @return True if the exception may be reported, false otherwise
   229       */
   230      protected boolean isValidError(final Throwable exception) {
                 /* 
    P/P           *  Method: bool isValidError(Throwable)
                  * 
                  *  Preconditions:
                  *    (soft) BANNED_EXCEPTIONS[...] != null
                  * 
                  *  Postconditions:
                  *    init'ed(return_value)
                  * 
                  *  Test Vectors:
                  *    java.lang.Object:equals(...)@235: {0}, {1}
                  */
   231          Throwable target = exception;
   232  
   233          while (target != null) {
   234              for (Class bad : BANNED_EXCEPTIONS) {
   235                  if (bad.equals(target.getClass())) {
   236                      return false;
   237                  }
   238              }
   239  
   240              target = target.getCause();
   241          }
   242  
   243          return true;
   244      }
   245  
   246      /**
   247       * Converts an exception into a string array.
   248       *
   249       * @param throwable Exception to convert
   250       * @since 0.6.3m1
   251       * @return Exception string array
   252       */
   253      protected String[] getTrace(final Throwable throwable) {
   254          String[] trace;
   255  
                 /* 
    P/P           *  Method: String[] getTrace(Throwable)
                  * 
                  *  Presumptions:
                  *    java.lang.Throwable:getStackTrace(...)@259 != null
                  *    traceElements.length@259 <= 232-1
                  *    traceElements[i]@259 != null
                  * 
                  *  Postconditions:
                  *    java.lang.StackTraceElement:toString(...)._tainted == 0
                  *    possibly_updated(java.lang.StackTraceElement:toString(...)._tainted)
                  *    init'ed(java.lang.StringBuilder:toString(...)._tainted)
                  *    java.lang.StringBuilder:toString(...)._tainted == 0
                  *    possibly_updated(java.lang.StringBuilder:toString(...)._tainted)
                  *    init'ed(java.lang.Throwable:toString(...)._tainted)
                  *    java.lang.Throwable:toString(...)._tainted == 0
                  *    possibly_updated(java.lang.Throwable:toString(...)._tainted)
                  *    return_value == One-of{&amp;new String[](getTrace#1), &amp;new String[](getTrace#2), &amp;new String[](getTrace#3)}
                  *    return_value in Addr_Set{&amp;new String[](getTrace#2),&amp;new String[](getTrace#3),&amp;new String[](getTrace#1)}
                  *    ...
                  * 
                  *  Test Vectors:
                  *    throwable: Inverse{null}, Addr_Set{null}
                  *    java.lang.Throwable:getCause(...)@268: Addr_Set{null}, Inverse{null}
                  */
   256          if (throwable == null) {
   257              trace = new String[0];
   258          } else {
   259              final StackTraceElement[] traceElements = throwable.getStackTrace();
   260              trace = new String[traceElements.length + 1];
   261  
   262              trace[0] = throwable.toString();
   263  
   264              for (int i = 0; i < traceElements.length; i++) {
   265                  trace[i + 1] = traceElements[i].toString();
   266              }
   267  
   268              if (throwable.getCause() != null) {
   269                  final String[] causeTrace = getTrace(throwable.getCause());
   270                  final String[] newTrace = new String[trace.length + causeTrace.length];
   271                  trace[0] = "\nWhich caused: " + trace[0];
   272  
   273                  System.arraycopy(causeTrace, 0, newTrace, 0, causeTrace.length);
   274                  System.arraycopy(trace, 0, newTrace, causeTrace.length, trace.length);
   275  
   276                  trace = newTrace;
   277              }
   278          }
   279  
   280          return trace;
   281      }
   282  
   283      /**
   284       * Sends an error to the developers.
   285       *
   286       * @param error error to be sent
   287       */
   288      public void sendError(final ProgramError error) {
                 /* 
    P/P           *  Method: void sendError(ProgramError)
                  * 
                  *  Preconditions:
                  *    error != null
                  *    init'ed(error.reportStatus)
                  *    (soft) init'ed(com.dmdirc.ui.FatalErrorDialog$4__static_init.new int[](FatalErrorDialog$4__static_init#1)[...])
                  *    (soft) init'ed(this.reportThread)
                  *    (soft) this.reportQueue != null
                  * 
                  *  Postconditions:
                  *    error.reportStatus == One-of{old error.reportStatus, &amp;com.dmdirc.logger.ErrorReportStatus__static_init.new ErrorReportStatus(ErrorReportStatus__static_init#5)}
                  *    init'ed(error.reportStatus)
                  *    this.reportThread == One-of{old this.reportThread, &amp;new ErrorReportingThread(sendError#1)}
                  *    init'ed(this.reportThread)
                  *    new ErrorReportingThread(sendError#1) num objects <= 1
                  *    new ErrorReportingThread(sendError#1).queue == this.reportQueue
                  *    new ErrorReportingThread(sendError#1).queue != null
                  * 
                  *  Test Vectors:
                  *    this.reportThread: Addr_Set{null}, Inverse{null}
                  *    java.lang.Thread:isAlive(...)@298: {1}, {0}
                  */
   289          if (error.getReportStatus() != ErrorReportStatus.ERROR
   290                  && error.getReportStatus() != ErrorReportStatus.WAITING) {
   291              return;
   292          }
   293  
   294          error.setReportStatus(ErrorReportStatus.QUEUED);
   295  
   296          reportQueue.add(error);
   297  
   298          if (reportThread == null || !reportThread.isAlive()) {
   299              reportThread = new ErrorReportingThread(reportQueue);
   300              reportThread.start();
   301          }
   302      }
   303  
   304      /**
   305       * Called when an error needs to be deleted from the list.
   306       *
   307       * @param error ProgramError that changed
   308       */
   309      public void deleteError(final ProgramError error) {
                 /* 
    P/P           *  Method: void deleteError(ProgramError)
                  * 
                  *  Preconditions:
                  *    this.errorListeners != null
                  *    this.errors != null
                  */
   310          synchronized (errors) {
   311              errors.remove(error);
   312          }
   313  
   314          fireErrorDeleted(error);
   315      }
   316  
   317      /**
   318       * Deletes all errors from the manager.
   319       *
   320       * @since 0.6.3m1
   321       */
   322      public void deleteAll() {
                 /* 
    P/P           *  Method: void deleteAll()
                  * 
                  *  Preconditions:
                  *    this.errors != null
                  *    (soft) this.errorListeners != null
                  * 
                  *  Test Vectors:
                  *    java.util.Iterator:hasNext(...)@324: {0}, {1}
                  */
   323          synchronized (errors) {
   324              for (ProgramError error : errors) {
   325                  fireErrorDeleted(error);
   326              }
   327  
   328              errors.clear();
   329          }
   330      }
   331  
   332      /**
   333       * Returns the number of errors.
   334       *
   335       * @return Number of ProgramErrors
   336       */
   337      public int getErrorCount() {
                 /* 
    P/P           *  Method: int getErrorCount()
                  * 
                  *  Preconditions:
                  *    this.errors != null
                  * 
                  *  Postconditions:
                  *    init'ed(return_value)
                  */
   338          return errors.size();
   339      }
   340  
   341      /**
   342       * Returns the list of program errors.
   343       *
   344       * @return Program error list
   345       */
   346      public List<ProgramError> getErrors() {
                 /* 
    P/P           *  Method: List getErrors()
                  * 
                  *  Postconditions:
                  *    return_value == &amp;new LinkedList(getErrors#1)
                  *    new LinkedList(getErrors#1) num objects == 1
                  */
   347          synchronized (errors) {
   348              return new LinkedList<ProgramError>(errors);
   349          }
   350      }
   351  
   352      /**
   353       * Adds an ErrorListener to the listener list.
   354       *
   355       * @param listener Listener to add
   356       */
   357      public void addErrorListener(final ErrorListener listener) {
                 /* 
    P/P           *  Method: void addErrorListener(ErrorListener)
                  * 
                  *  Preconditions:
                  *    (soft) this.errorListeners != null
                  * 
                  *  Test Vectors:
                  *    listener: Inverse{null}, Addr_Set{null}
                  */
   358          if (listener == null) {
   359              return;
   360          }
   361  
   362          errorListeners.add(ErrorListener.class, listener);
   363      }
   364  
   365      /**
   366       * Removes an ErrorListener from the listener list.
   367       *
   368       * @param listener Listener to remove
   369       */
   370      public void removeErrorListener(final ErrorListener listener) {
                /* 
    P/P          *  Method: void removeErrorListener(ErrorListener)
                 * 
                 *  Preconditions:
                 *    this.errorListeners != null
                 */
   371         errorListeners.remove(ErrorListener.class, listener);
   372      }
   373  
   374      /**
   375       * Fired when the program encounters an error.
   376       *
   377       * @param error Error that occurred
   378       */
   379      protected void fireErrorAdded(final ProgramError error) {
                 /* 
    P/P           *  Method: void fireErrorAdded(ProgramError)
                  * 
                  *  Preconditions:
                  *    error != null
                  *    error.trace != null
                  *    error.trace.length <= 232-1
                  *    this.errorListeners != null
                  * 
                  *  Presumptions:
                  *    arr$.length <= 232-1
                  *    com.dmdirc.util.ListenerList:get(...)@382 != null
                  *    java.lang.System.err != null
                  *    java.util.Arrays:copyOf(...)@148 != null
                  *    java.util.Iterator:next(...)@382 != null
                  * 
                  *  Test Vectors:
                  *    java.util.Iterator:hasNext(...)@382: {0}, {1}
                  */
   380          int firedListeners = 0;
   381  
   382          for (ErrorListener listener : errorListeners.get(ErrorListener.class)) {
   383              if (listener.isReady()) {
   384                  listener.errorAdded(error);
   385                  firedListeners++;
   386              }
   387          }
   388  
   389          if (firedListeners == 0) {
   390              System.err.println("An error has occurred: " + error.getLevel()
   391                      + ": " + error.getMessage());
   392  
   393              for (String line : error.getTrace()) {
   394                  System.err.println("\t" + line);
   395              }
   396          }
   397      }
   398  
   399      /**
   400       * Fired when the program encounters a fatal error.
   401       *
   402       * @param error Error that occurred
   403       */
   404      protected void fireFatalError(final ProgramError error) {
                 /* 
    P/P           *  Method: void fireFatalError(ProgramError)
                  *    fireFatalError does not return
                  * 
                  *  Preconditions:
                  *    error != null
                  *    error.reportStatus != null
                  *    (soft) error.trace != null
                  *    (soft) error.trace.length <= 232-1
                  * 
                  *  Presumptions:
                  *    arr$.length <= 232-1
                  *    java.lang.System.err != null
                  *    java.util.Arrays:copyOf(...)@148 != null
                  * 
                  *  Test Vectors:
                  *    java.awt.GraphicsEnvironment:isHeadless(...)@405: {0}, {1}
                  */
   405          if (GraphicsEnvironment.isHeadless()) {
   406              System.err.println("A fatal error has occurred: " + error.getMessage());
   407              for (String line : error.getTrace()) {
   408                  System.err.println("\t" + line);
   409              }
   410          } else {
   411              FatalErrorDialog.displayBlocking(error);
   412          }
   413  
   414          while (!error.getReportStatus().isTerminal()) {
   415              try {
   416                  synchronized (error) {
   417                      error.wait();
   418                  }
   419              } catch (InterruptedException ex) {
   420                  // Do nothing
   421              }
   422          }
   423  
   424          System.exit(-1);
   425      }
   426  
   427      /**
   428       * Fired when an error is deleted.
   429       *
   430       * @param error Error that has been deleted
   431       */
   432      protected void fireErrorDeleted(final ProgramError error) {
                 /* 
    P/P           *  Method: void fireErrorDeleted(ProgramError)
                  * 
                  *  Preconditions:
                  *    this.errorListeners != null
                  * 
                  *  Presumptions:
                  *    com.dmdirc.util.ListenerList:get(...)@433 != null
                  *    java.util.Iterator:next(...)@433 != null
                  * 
                  *  Test Vectors:
                  *    java.util.Iterator:hasNext(...)@433: {0}, {1}
                  */
   433          for (ErrorListener listener : errorListeners.get(ErrorListener.class)) {
   434              listener.errorDeleted(error);
   435          }
   436      }
   437  
   438      /**
   439       * Fired when an error's status is changed.
   440       *
   441       * @param error Error that has been altered
   442       */
   443      protected void fireErrorStatusChanged(final ProgramError error) {
                 /* 
    P/P           *  Method: void fireErrorStatusChanged(ProgramError)
                  * 
                  *  Preconditions:
                  *    this.errorListeners != null
                  *    (soft) init'ed(com.dmdirc.ui.FatalErrorDialog$4__static_init.new int[](FatalErrorDialog$4__static_init#1)[...])
                  *    (soft) error.reportStatus != null
                  * 
                  *  Presumptions:
                  *    com.dmdirc.util.ListenerList:get(...)@444 != null
                  *    java.util.Iterator:next(...)@444 != null
                  *    listener.error.message@444 != null
                  *    listener.error@444 != null
                  *    listener.okButton@444 != null
                  *    ...
                  * 
                  *  Test Vectors:
                  *    java.util.Iterator:hasNext(...)@444: {0}, {1}
                  */
   444          for (ErrorListener listener : errorListeners.get(ErrorListener.class)) {
   445              listener.errorStatusChanged(error);
   446          }
   447      }
   448  
   449      /** {@inheritDoc} */
   450      @Override
   451      public void configChanged(final String domain, final String key) {
                 /* 
    P/P           *  Method: void configChanged(String, String)
                  * 
                  *  Postconditions:
                  *    init'ed(this.logReports)
                  *    init'ed(this.sendReports)
                  */
   452          updateSettings();
   453      }
   454  
   455      /** Updates the settings used by this error manager. */
   456      protected void updateSettings() {
                 /* 
    P/P           *  Method: void updateSettings()
                  * 
                  *  Presumptions:
                  *    com.dmdirc.config.IdentityManager:getGlobalConfig(...)@457 != null
                  * 
                  *  Postconditions:
                  *    init'ed(this.logReports)
                  *    init'ed(this.sendReports)
                  */
   457          final ConfigManager config = IdentityManager.getGlobalConfig();
   458  
   459          try {
   460              sendReports = config.getOptionBool("general", "submitErrors")
   461                      && !config.getOptionBool("temp", "noerrorreporting");
   462              logReports = config.getOptionBool("general", "logerrors");
   463          } catch (IllegalArgumentException ex) {
   464              sendReports = false;
   465              logReports = true;
   466          }
   467      }
   468  
   469  }








SofCheck Inspector Build Version : 2.17854
ErrorManager.java 2009-Jun-25 01:54:24
ErrorManager.class 2009-Sep-02 17:04:14