content: /*
   * Copyright (C) 2007 The Android Open Source Project
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package com.taobao.android.dex.util;
  
  import java.io.PrintStream;
  import java.io.PrintWriter;
  
  /**
   * Exception which carries around structured context.
   */
  public class ExceptionWithContext extends RuntimeException {
      /** {@code non-null;} human-oriented context of the exception */
      private StringBuffer context;
  
      /**
       * Augments the given exception with the given context, and return the
       * result. The result is either the given exception if it was an
       * {@link ExceptionWithContext}, or a newly-constructed exception if it
       * was not.
       *
       * @param ex {@code non-null;} the exception to augment
       * @param str {@code non-null;} context to add
       * @return {@code non-null;} an appropriate instance
       */
      public static ExceptionWithContext withContext(Throwable ex, String str) {
          ExceptionWithContext ewc;
  
          if (ex instanceof ExceptionWithContext) {
              ewc = (ExceptionWithContext) ex;
          } else {
              ewc = new ExceptionWithContext(ex);
          }
  
          ewc.addContext(str);
          return ewc;
      }
  
      /**
       * Constructs an instance.
       *
       * @param message human-oriented message
       */
      public ExceptionWithContext(String message) {
          this(message, null);
      }
  
      /**
       * Constructs an instance.
       *
       * @param cause {@code null-ok;} exception that caused this one
       */
      public ExceptionWithContext(Throwable cause) {
          this(null, cause);
      }
  
      /**
       * Constructs an instance.
       *
       * @param message human-oriented message
       * @param cause {@code null-ok;} exception that caused this one
       */
      public ExceptionWithContext(String message, Throwable cause) {
          super((message != null) ? message :
                (cause != null) ? cause.getMessage() : null,
                cause);
  
          if (cause instanceof ExceptionWithContext) {
              String ctx = ((ExceptionWithContext) cause).context.toString();
              context = new StringBuffer(ctx.length() + 200);
              context.append(ctx);
          } else {
              context = new StringBuffer(200);
          }
      }
  
      /** {@inheritDoc} */
      @Override
      public void printStackTrace(PrintStream out) {
          super.printStackTrace(out);
          out.println(context);
      }
  
      /** {@inheritDoc} */
      @Override
      public void printStackTrace(PrintWriter out) {
          super.printStackTrace(out);
          out.println(context);
      }
  
      /**
       * Adds a line of context to this instance.
       *
       * @param str {@code non-null;} new context
       */
      public void addContext(String str) {
          if (str == null) {
              throw new NullPointerException("str == null");
          }
  
          context.append(str);
          if (!str.endsWith("\n")) {
              context.append('\n');
          }
      }
  
      /**
       * Gets the context.
       *
       * @return {@code non-null;} the context
       */
      public String getContext() {
          return context.toString();
      }
  
      /**
       * Prints the message and context.
       *
       * @param out {@code non-null;} where to print to
       */
      public void printContext(PrintStream out) {
          out.println(getMessage());
          out.print(context);
      }
  
      /**
       * Prints the message and context.
       *
       * @param out {@code non-null;} where to print to
       */
      public void printContext(PrintWriter out) {
          out.println(getMessage());
          out.print(context);
      }
  }
  