/**
 * Copyright (C) 2011 - present by OpenGamma Inc. and the OpenGamma group of companies
 *
 * Please see distribution for license.
 */
package com.opengamma.util.async;

/**
 * Utility allowing operations to be implemented in blocking forms by default with a non-blocking mode. If blocking operations (the default) are off then a method may throw this exception in order to
 * indicate a non-blocking failure. The stack frame that most recently disabled blocking exceptions on that thread may then handle the exception.
 * <p>
 * It is only normally wise to disable blocking operations for tasks that are read-only as an otherwise atomic write task could leave the system in an inconsistent state if the blocking exception is
 * thrown by one of its component tasks.
 */
public final class BlockingOperation extends RuntimeException {

  private static final long serialVersionUID = 1L;

  private static final class TLS {

    private int _offCount;

  }

  private static final ThreadLocal<TLS> s_tls = new ThreadLocal<TLS>() {
    @Override
    protected TLS initialValue() {
      return new TLS();
    }
  };

  private BlockingOperation() {
  }

  /**
   * Disable blocking operations for the calling thread. This must be matched by a later call to {@link #on}. If blocking operations are already disabled they remain disabled and an internal counter
   * will ensure they will stay off after the corresponding call to {@code on}.
   */
  public static void off() {
    assert s_tls.get()._offCount >= 0;
    s_tls.get()._offCount++;
  }

  /**
   * Restore blocking operations for the calling thread. This must be matched by an earlier call to {@link #off}. If blocking operations were already disabled at the preceding call to {@code off} they
   * will remain off.
   */
  public static void on() {
    assert s_tls.get()._offCount > 0;
    s_tls.get()._offCount--;
  }

  /**
   * If blocking operations are disabled this will throw a {@link BlockingOperation} exception instance. Otherwise this is a no-op.
   */
  public static void wouldBlock() {
    if (isOff()) {
      throw block();
    }
  }

  /**
   * Tests if blocking operations (the default) are enabled.
   * 
   * @return true if operations must block, false if they may throw an exception instead.
   */
  public static boolean isOn() {
    return s_tls.get()._offCount == 0;
  }

  /**
   * Tests if blocking operations are disabled.
   * 
   * @return true if operations may throw an exception, false if they must block
   */
  public static boolean isOff() {
    return s_tls.get()._offCount != 0;
  }

  public static BlockingOperation block() {
    assert isOff();
    return new BlockingOperation();
  }

}

/**
 * Copyright (C) 2011 - present by OpenGamma Inc. and the OpenGamma group of companies
 *
 * Please see distribution for license.
 */
package com.opengamma.util.async;

/**
 * Utility allowing operations to be implemented in blocking forms by default with a non-blocking mode. If blocking operations (the default) are off then a method may throw this exception in order to
 * indicate a non-blocking failure. The stack frame that most recently disabled blocking exceptions on that thread may then handle the exception.
 * <p>
 * It is only normally wise to disable blocking operations for tasks that are read-only as an otherwise atomic write task could leave the system in an inconsistent state if the blocking exception is
 * thrown by one of its component tasks.
 */
public final class BlockingOperation extends Error {

  private static final long serialVersionUID = 1L;

  private static final class TLS {

    private int _offCount;

  }

  private static final ThreadLocal<TLS> s_tls = new ThreadLocal<TLS>() {
    @Override
    protected TLS initialValue() {
      return new TLS();
    }
  };

  private BlockingOperation() {
  }

  /**
   * Disable blocking operations for the calling thread. This must be matched by a later call to {@link #on}. If blocking operations are already disabled they remain disabled and an internal counter
   * will ensure they will stay off after the corresponding call to {@code on}.
   */
  public static void off() {
    assert s_tls.get()._offCount >= 0;
    s_tls.get()._offCount++;
  }

  /**
   * Restore blocking operations for the calling thread. This must be matched by an earlier call to {@link #off}. If blocking operations were already disabled at the preceding call to {@code off} they
   * will remain off.
   */
  public static void on() {
    assert s_tls.get()._offCount > 0;
    s_tls.get()._offCount--;
  }

  /**
   * If blocking operations are disabled this will throw a {@link BlockingOperation} exception instance. Otherwise this is a no-op.
   */
  public static void wouldBlock() {
    if (isOff()) {
      throw block();
    }
  }

  /**
   * Tests if blocking operations (the default) are enabled.
   * 
   * @return true if operations must block, false if they may throw an exception instead.
   */
  public static boolean isOn() {
    return s_tls.get()._offCount == 0;
  }

  /**
   * Tests if blocking operations are disabled.
   * 
   * @return true if operations may throw an exception, false if they must block
   */
  public static boolean isOff() {
    return s_tls.get()._offCount != 0;
  }

  public static BlockingOperation block() {
    assert isOff();
    return new BlockingOperation();
  }

}

Make the BlockingException an Error so it won't be cached like RuntimeExceptions are from the sources