| 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 | /** |
| 143 | * Create a {@link Key} with the given debug name. |
nothing calls this directly
no test coverage detected