| 83 | */ |
| 84 | /* @DoNotMock("Use ROOT for a non-null Context") // commented out to avoid dependencies */ |
| 85 | @CheckReturnValue |
| 86 | public class Context { |
| 87 | |
| 88 | static final Logger log = Logger.getLogger(Context.class.getName()); |
| 89 | |
| 90 | // Long chains of contexts are suspicious and usually indicate a misuse of Context. |
| 91 | // The threshold is arbitrarily chosen. |
| 92 | // VisibleForTesting |
| 93 | static final int CONTEXT_DEPTH_WARN_THRESH = 1000; |
| 94 | |
| 95 | /** |
| 96 | * The logical root context which is the ultimate ancestor of all contexts. This context |
| 97 | * is not cancellable and so will not cascade cancellation or retain listeners. |
| 98 | * |
| 99 | * <p>Never assume this is the default context for new threads, because {@link Storage} may define |
| 100 | * a default context that is different from ROOT. |
| 101 | */ |
| 102 | public static final Context ROOT = new Context(); |
| 103 | |
| 104 | // Visible For testing |
| 105 | static Storage storage() { |
| 106 | return LazyStorage.storage; |
| 107 | } |
| 108 | |
| 109 | // Lazy-loaded storage. Delaying storage initialization until after class initialization makes it |
| 110 | // much easier to avoid circular loading since there can still be references to Context as long as |
| 111 | // they don't depend on storage, like key() and currentContextExecutor(). It also makes it easier |
| 112 | // to handle exceptions. |
| 113 | private static final class LazyStorage { |
| 114 | static final Storage storage; |
| 115 | |
| 116 | static { |
| 117 | AtomicReference<Throwable> deferredStorageFailure = new AtomicReference<>(); |
| 118 | storage = createStorage(deferredStorageFailure); |
| 119 | Throwable failure = deferredStorageFailure.get(); |
| 120 | // Logging must happen after storage has been set, as loggers may use Context. |
| 121 | if (failure != null) { |
| 122 | log.log(Level.FINE, "Storage override doesn't exist. Using default", failure); |
| 123 | } |
| 124 | } |
| 125 | |
| 126 | private static Storage createStorage( |
| 127 | AtomicReference<? super ClassNotFoundException> deferredStorageFailure) { |
| 128 | try { |
| 129 | Class<?> clazz = Class.forName("io.grpc.override.ContextStorageOverride"); |
| 130 | // The override's constructor is prohibited from triggering any code that can loop back to |
| 131 | // Context |
| 132 | return clazz.asSubclass(Storage.class).getConstructor().newInstance(); |
| 133 | } catch (ClassNotFoundException e) { |
| 134 | deferredStorageFailure.set(e); |
| 135 | return new ThreadLocalContextStorage(); |
| 136 | } catch (Exception e) { |
| 137 | throw new RuntimeException("Storage override failed to initialize", e); |
| 138 | } |
| 139 | } |
| 140 | } |
| 141 | |
| 142 | /** |