Move common bridging code
[mdsal.git] / binding / mdsal-binding-dom-codec / src / main / java / org / opendaylight / mdsal / binding / dom / codec / impl / ClassGeneratorBridge.java
index cc6dcca7d776abcf9c52b1e16af6581dc9def813..d5791d7534981b063cd9b970d180105d9ae89835 100644 (file)
@@ -10,8 +10,10 @@ package org.opendaylight.mdsal.binding.dom.codec.impl;
 import static com.google.common.base.Verify.verifyNotNull;
 
 import com.google.common.annotations.Beta;
+import com.google.common.base.Supplier;
 import org.eclipse.jdt.annotation.NonNull;
 import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.mdsal.binding.dom.codec.loader.CodecClassLoader.ClassGenerator;
 
 /**
  * Bridge for initializing generated instance constants during class loading time. This class is public only due to
@@ -19,21 +21,45 @@ import org.eclipse.jdt.annotation.Nullable;
  */
 @Beta
 public final class ClassGeneratorBridge {
-    interface BridgeProvider {
-
+    interface BridgeProvider<T> extends ClassGenerator<T> {
+        @Override
+        default Class<T> customizeLoading(final @NonNull Supplier<Class<T>> loader) {
+            final BridgeProvider<?> prev = ClassGeneratorBridge.setup(this);
+            try {
+                final Class<T> result = loader.get();
+
+                /*
+                 * This a bit of magic to support NodeContextSupplier constants. These constants need to be resolved
+                 * while we have the information needed to find them -- that information is being held in this instance
+                 * and we leak it to a thread-local variable held by CodecDataObjectBridge.
+                 *
+                 * By default the JVM will defer class initialization to first use, which unfortunately is too late for
+                 * us, and hence we need to force class to initialize.
+                 */
+                try {
+                    Class.forName(result.getName(), true, result.getClassLoader());
+                } catch (ClassNotFoundException e) {
+                    throw new LinkageError("Failed to find newly-defined " + result, e);
+                }
+
+                return result;
+            } finally {
+                ClassGeneratorBridge.tearDown(prev);
+            }
+        }
     }
 
-    interface LocalNameProvider extends BridgeProvider {
+    interface LocalNameProvider<T> extends BridgeProvider<T> {
 
         @NonNull String resolveLocalName(@NonNull String methodName);
     }
 
-    interface NodeContextSupplierProvider extends BridgeProvider {
+    interface NodeContextSupplierProvider<T> extends BridgeProvider<T> {
 
         @NonNull NodeContextSupplier resolveNodeContextSupplier(@NonNull String methodName);
     }
 
-    private static final ThreadLocal<BridgeProvider> CURRENT_CUSTOMIZER = new ThreadLocal<>();
+    private static final ThreadLocal<BridgeProvider<?>> CURRENT_CUSTOMIZER = new ThreadLocal<>();
 
     private ClassGeneratorBridge() {
 
@@ -47,13 +73,13 @@ public final class ClassGeneratorBridge {
         return current(LocalNameProvider.class).resolveLocalName(methodName);
     }
 
-    static @Nullable BridgeProvider setup(final @NonNull BridgeProvider next) {
-        final BridgeProvider prev = CURRENT_CUSTOMIZER.get();
+    static @Nullable BridgeProvider<?> setup(final @NonNull BridgeProvider<?> next) {
+        final BridgeProvider<?> prev = CURRENT_CUSTOMIZER.get();
         CURRENT_CUSTOMIZER.set(verifyNotNull(next));
         return prev;
     }
 
-    static void tearDown(final @Nullable BridgeProvider prev) {
+    static void tearDown(final @Nullable BridgeProvider<?> prev) {
         if (prev == null) {
             CURRENT_CUSTOMIZER.remove();
         } else {
@@ -61,7 +87,7 @@ public final class ClassGeneratorBridge {
         }
     }
 
-    private static <T extends BridgeProvider> @NonNull T current(final Class<T> requested) {
+    private static <T extends BridgeProvider<?>> @NonNull T current(final Class<T> requested) {
         return requested.cast(verifyNotNull(CURRENT_CUSTOMIZER.get(), "No customizer attached"));
     }
 }