/*
 * Copyright (C) 2017-2017 DataStax Inc.
 *
 * 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.datastax.oss.driver.internal.core.util.concurrent;

import java.util.concurrent.ThreadFactory;

/**
 * Safeguards against bad usage patterns in client code that could introduce deadlocks in the
 * driver.
 *
 * <p>The driver internals are fully asynchronous, nothing should ever block. On the other hand, our
 * API exposes synchronous wrappers, that call async methods and wait on the result (as a
 * convenience for clients that don't want to do async). These methods should never be called on a
 * driver thread, because this can lead to deadlocks. This can happen from client code if it uses
 * callbacks.
 */
public class BlockingOperation {
  private static ThreadLocal<Boolean> isDriverThread = ThreadLocal.withInitial(() -> false);

  /**
   * This method is invoked from each synchronous driver method, and checks that we are not on a
   * driver thread.
   *
   * <p>For this to work, all driver threads must be created by {@link SafeThreadFactory} (which is
   * the case by default).
   *
   * @throws IllegalStateException if a driver thread is executing this.
   */
  public static void checkNotDriverThread() {
    if (isDriverThread.get()) {
      throw new IllegalStateException(
          "Detected a synchronous API call on a driver thread, "
              + "failing because this can cause deadlocks.");
    }
  }

  /**
   * Marks threads as driver threads, so that they will be detected by {@link
   * #checkNotDriverThread()}
   */
  public static class SafeThreadFactory implements ThreadFactory {
    @Override
    public Thread newThread(Runnable r) {
      return new Thread(r) {
        @Override
        public void run() {
          isDriverThread.set(true);
          super.run();
        }
      };
    }
  }
}

@@ -1257,101 +1257,8 @@
 on %7B
-%0A  private static ThreadLocal%3CBoolean%3E isDriverThread = ThreadLocal.withInitial(() -%3E false);
 %0A%0A  
@@ -1652,28 +1652,56 @@
 if (
-isDriverThread.get()
+Thread.currentThread() instanceof InternalThread
 ) %7B%0A
@@ -2137,16 +2137,24 @@
 urn new 
+Internal
 Thread(r
@@ -2158,133 +2158,145 @@
 d(r)
- %7B
+;
 %0A    
-    @Override%0A        public void run() %7B%0A          isDriverThread.set(true);%0A   
+%7D%0A  %7D%0A%0A  private static class InternalThread extends Thread %7B%0A    private InternalThread(Runnable runnable) %7B%0A
       
- 
 super
-.run();%0A        %7D%0A      %7D
+(runnable)
 ;%0A  

Replace ThreadLocal with an instanceof check in BlockingOperation