Merge "Fix checkListKey not checking actual/expected values"
[yangtools.git] / code-generator / binding-data-codec / src / main / java / org / opendaylight / yangtools / binding / data / codec / impl / DataObjectCodecContext.java
index 19a9600f62705ee7a3e0878c5386a582192f4266..e5d58cc82f3cd15e60fcae946e588d9e20bcd47b 100644 (file)
@@ -9,13 +9,24 @@ package org.opendaylight.yangtools.binding.data.codec.impl;
 
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
+import com.google.common.base.Throwables;
 import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSortedMap;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodHandles.Lookup;
+import java.lang.invoke.MethodType;
+import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
 import java.util.Collection;
+import java.util.Comparator;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.SortedMap;
+import java.util.TreeMap;
 import org.opendaylight.yangtools.sal.binding.generator.api.ClassLoadingStrategy;
 import org.opendaylight.yangtools.sal.binding.model.api.Type;
 import org.opendaylight.yangtools.yang.binding.Augmentable;
@@ -40,13 +51,25 @@ import org.slf4j.LoggerFactory;
 
 abstract class DataObjectCodecContext<T extends DataNodeContainer> extends DataContainerCodecContext<T> {
     private static final Logger LOG = LoggerFactory.getLogger(DataObjectCodecContext.class);
+    private static final Lookup LOOKUP = MethodHandles.publicLookup();
+    private static final MethodType CONSTRUCTOR_TYPE = MethodType.methodType(void.class, InvocationHandler.class);
+    private static final MethodType DATAOBJECT_TYPE = MethodType.methodType(DataObject.class, InvocationHandler.class);
+    private static final Comparator<Method> METHOD_BY_ALPHABET = new Comparator<Method>() {
+        @Override
+        public int compare(final Method o1, final Method o2) {
+            return o1.getName().compareTo(o2.getName());
+        }
+    };
 
     private final ImmutableMap<String, LeafNodeCodecContext> leafChild;
     private final ImmutableMap<YangInstanceIdentifier.PathArgument, NodeContextSupplier> byYang;
-    private final ImmutableMap<Method, NodeContextSupplier> byMethod;
+    private final ImmutableSortedMap<Method, NodeContextSupplier> byMethod;
     private final ImmutableMap<Class<?>, DataContainerCodecPrototype<?>> byStreamClass;
     private final ImmutableMap<Class<?>, DataContainerCodecPrototype<?>> byBindingArgClass;
-    protected final Method augmentationGetter;
+    private final MethodHandle proxyConstructor;
+
+    // FIXME: this field seems to be unused
+    private final Method augmentationGetter;
 
     protected DataObjectCodecContext(final DataContainerCodecPrototype<T> prototype) {
         super(prototype);
@@ -56,7 +79,7 @@ abstract class DataObjectCodecContext<T extends DataNodeContainer> extends DataC
         Map<Class<?>, Method> clsToMethod = BindingReflections.getChildrenClassToMethod(bindingClass());
 
         Map<YangInstanceIdentifier.PathArgument, NodeContextSupplier> byYangBuilder = new HashMap<>();
-        Map<Method, NodeContextSupplier> byMethodBuilder = new HashMap<>();
+        SortedMap<Method, NodeContextSupplier> byMethodBuilder = new TreeMap<>(METHOD_BY_ALPHABET);
         Map<Class<?>, DataContainerCodecPrototype<?>> byStreamClassBuilder = new HashMap<>();
         Map<Class<?>, DataContainerCodecPrototype<?>> byBindingArgClassBuilder = new HashMap<>();
 
@@ -78,7 +101,7 @@ abstract class DataObjectCodecContext<T extends DataNodeContainer> extends DataC
                 }
             }
         }
-        this.byMethod = ImmutableMap.copyOf(byMethodBuilder);
+        this.byMethod = ImmutableSortedMap.copyOfSorted(byMethodBuilder);
         if (Augmentable.class.isAssignableFrom(bindingClass())) {
             try {
                 augmentationGetter = bindingClass().getMethod("getAugmentation", Class.class);
@@ -102,6 +125,13 @@ abstract class DataObjectCodecContext<T extends DataNodeContainer> extends DataC
         this.byStreamClass = ImmutableMap.copyOf(byStreamClassBuilder);
         byBindingArgClassBuilder.putAll(byStreamClass);
         this.byBindingArgClass = ImmutableMap.copyOf(byBindingArgClassBuilder);
+
+        final Class<?> proxyClass = Proxy.getProxyClass(bindingClass().getClassLoader(),  new Class[] { bindingClass() });
+        try {
+            proxyConstructor = LOOKUP.findConstructor(proxyClass, CONSTRUCTOR_TYPE).asType(DATAOBJECT_TYPE);
+        } catch (NoSuchMethodException | IllegalAccessException e) {
+            throw new IllegalStateException("Failed to find contructor for class " + proxyClass);
+        }
     }
 
     @Override
@@ -244,6 +274,14 @@ abstract class DataObjectCodecContext<T extends DataNodeContainer> extends DataC
         return null;
     }
 
+    protected final DataObject createBindingProxy(final NormalizedNodeContainer<?, ?, ?> node) {
+        try {
+            return (DataObject) proxyConstructor.invokeExact((InvocationHandler)new LazyDataObject(this, node));
+        } catch (Throwable e) {
+            throw Throwables.propagate(e);
+        }
+    }
+
     public Map<Class<? extends Augmentation<?>>, Augmentation<?>> getAllAugmentationsFrom(
             final NormalizedNodeContainer<?, PathArgument, NormalizedNode<?, ?>> data) {
 
@@ -266,4 +304,4 @@ abstract class DataObjectCodecContext<T extends DataNodeContainer> extends DataC
         return byMethod.keySet();
     }
 
-}
\ No newline at end of file
+}