Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Assimilated CS code from ERR01-J

...

Note that even though the application reacts to the exception by printing out a stack trace, it proceeds as though the exception were not thrown. That is, the future behavior of the application is unaffected by the throwing of the exception, other than the fact that statements in the try block after the statement that caused the exception are skipped. The IOException indicates that an I/O operation attempted by the application failed; it is unlikely that assuming that the attempted operation succeeded will permit the application to operate correctly.

Compliant Solution (User-corrected data)

This compliant solution attempts to recover from a FileNotFoundException by forcing the user to specify another file when a particular file cannot be found in the user-specific directory.

...

The user is allowed to access only files in a user-specific directory. This prevents any other IOException that escapes the loop from leaking potentially sensitive file system information. See guideline ERR06-J. Do not allow exceptions to expose sensitive information for additional information.

Compliant Solution (Skeletal Implementation of Exception Reporter)

Proper reporting of exceptional conditions is context-dependent. For example, GUI applications should report the exception in a graphical way, such as through error dialog boxes or status windows. To preserve modularity, most library classes should be able to objectively determine how an exception should be reported; they cannot rely on System.err, on any particular logger, or on the availability of the windowing environment. As a result, library classes that wish to report exceptions should specify the API they will use to report exceptions:

Code Block
bgColor#ccccff

public interface Reporter {
  public void report(Throwable t);
}

public class ExceptionReporter {

  // Exception reporter that prints the exception to the console (used as default)
  private static final Reporter PrintException = new Reporter() {
    public void report(Throwable t) {
      System.err.println(t.toString());
    }
  };

  // Stores the default reporter. The default reporter can be changed by the user.
  private static Reporter Default = PrintException;  
 
  // Helps change the default reporter back to PrintException in the future
  public static Reporter getPrintException() {
    return PrintException;
  }

  public static Reporter getExceptionReporter() {
    return Default;
  }
  
  public static void setExceptionReporter(Reporter reporter) {
    try {
      ExceptionReporterPermission perm = new ExceptionReporterPermission("exc.reporter"); // Custom permission
      SecurityManager sm = System.getSecurityManager();
        if (sm != null) { 
          // Check whether the caller has appropriate permissions
          sm.checkPermission(perm);
        } 

      Default = reporter; // Change the default exception reporter
    } catch (SecurityException se) { 
      System.out.println("Not allowed"); // or log 
    }
  }
}

This compliant solution specifies both an interface for reporting exceptions which exports the report() method, and also a default exception reporter class that the library can use. The exception reporter can be overridden by subclasses.

The setExceptionReporter method prevents hostile code from maliciously installing a more verbose reporter that leaks sensitive information or that directs exception reports to an inappropriate location, such as the attacker's computer, by limiting attempts to change the exception reporter to callers that have the custom permission ExceptionReporterPermission with target exc.reporter. Refer to guideline SEC10-J. Define custom security permissions for fine grained security for additional information regarding defining custom permissions. Note that it would be inappropriate to use a default permission such as java.util.logging.LoggingPermission here because the logging permission's purpose is to control execution of specific logging methods (such as Logger.setLevel), rather than to control setting the exception reporter itself.

The library may subsequently use the exception reporter in catch clauses:

Code Block
bgColor#ccccff

try {
  // ...
} catch (IOException warning) {
  ExceptionReporter.getExceptionReporter().report(warning);
  // Recover from the exception...
}

Any client code that possesses the required permissions can override the ExceptionReporter with a handler that logs the error, or provides a dialog box, or both. For instance a GUI client using Swing may require exceptions to be reported using a dialog box:

Code Block
bgColor#ccccff

ExceptionReporters.setExceptionReporter(new ExceptionReporter() {
  public void report(Throwable exception) {
    JOptionPane.showMessageDialog(frame,
                                  exception.toString,
                                  exception.getClass().getName(),
                                  JOptionPane.ERROR_MESSAGE);
  });
}

Compliant Solution (Subclass Exception Reporter and Filter Sensitive Exceptions)

Sometimes exceptions must be hidden from the user for security reasons; see guideline ERR06-J. Do not allow exceptions to expose sensitive information. In such cases, one acceptable approach is to subclass the ExceptionReporter class and add a filter() method in addition to overriding the default report() method.

Code Block
bgColor#ccccff

class MyExceptionReporter extends ExceptionReporter {
  private static final Logger logger = Logger.getLogger("com.organization.Log");
  
  public static void report(Throwable t) {
    try {
      final Throwable filteredException = (t instanceof NonSensitiveException_1) ? t : filter(t);
    } finally {
      // Do any necessary user reporting (show dialog box or send to console) 
      if (filteredException instanceof NonSensitiveCommonException)
        logger.log(Level.FINEST, "Loggable exception occurred", t); 
    }
  }

  public static Exception filter(Throwable t) {
    if (t instanceof SensitiveForLoggingException_1) { // Do not log sensitive information (blacklist)
      return SensitiveCommonException();
    }  
    // ...
    return new NonSensitiveCommonException(); // Return for reporting to the user
  }
}

Wiki Markup
The {{report()}} method accepts a {{Throwable}} instance and consequently handles all errors, checked exceptions, as well as unchecked exceptions. The filtering mechanism is based on a _white listing_ approach wherein only non-sensitive exceptions are propagated to the user. Exceptions that are forbidden to appear in a log file can be filtered in the same fashion; see guideline [FIO08-J. Do not log sensitive information outside a trust boundary]. This approach provides the benefits of exception chaining by reporting exceptions tailored to the abstraction, while also logging the low level cause for later failure analysis \[[Bloch 2008|AA. Bibliography#Bloch 08]\]. 

Noncompliant Code Example

...

Wiki Markup
This code prevents callers higher up the call stack from determining that an interrupted exception occurred; consequently, they are unable to act on the exception \[[Goetz 2006|AA. Bibliography#Goetz 06]\].  Likewise, if this code was called in its own thread, it prevents the calling thread from knowing that this thread was interrupted.

Compliant Solution

This compliant solution catches the InterruptedException and restores the interrupted status by calling the interrupt() method on the current thread.

...