X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=binding%2Fmdsal-binding-dom-codec%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fmdsal%2Fbinding%2Fdom%2Fcodec%2Fimpl%2FDataContainerCodecContext.java;h=eade7cdcdce201f135140c5880faa839409702b5;hb=733da7ad2bfb1ad7e484291fa1e913ae8e8cd0bd;hp=c14693f0d6ac3ae143aaaa3d385b99b9af103c9d;hpb=aca16b3faf92cc529d8cfbcee871a51043393526;p=mdsal.git diff --git a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataContainerCodecContext.java b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataContainerCodecContext.java index c14693f0d6..eade7cdcdc 100644 --- a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataContainerCodecContext.java +++ b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataContainerCodecContext.java @@ -16,7 +16,10 @@ import java.io.IOException; import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.lang.reflect.Method; +import java.lang.reflect.Modifier; import java.lang.reflect.ParameterizedType; +import java.util.Arrays; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Optional; @@ -34,6 +37,7 @@ import org.opendaylight.mdsal.binding.model.api.Type; import org.opendaylight.mdsal.binding.runtime.api.BindingRuntimeContext; import org.opendaylight.mdsal.binding.runtime.api.CompositeRuntimeType; import org.opendaylight.mdsal.binding.runtime.api.RuntimeTypeContainer; +import org.opendaylight.mdsal.binding.spec.reflect.BindingReflections; import org.opendaylight.yangtools.util.ClassLoaderUtils; import org.opendaylight.yangtools.yang.binding.Augmentation; import org.opendaylight.yangtools.yang.binding.BindingObject; @@ -170,10 +174,6 @@ abstract class DataContainerCodecContext(this, ImmutableSet.copyOf(cacheSpecifier)); } - @NonNull BindingStreamEventWriter createWriter(final NormalizedNodeStreamWriter domWriter) { - return BindingToNormalizedStreamWriter.create(this, domWriter); - } - protected final @NonNull V childNonNull(final @Nullable V nullable, final YangInstanceIdentifier.PathArgument child, final String message, final Object... args) { if (nullable == null) { @@ -262,7 +262,7 @@ abstract class DataContainerCodecContext> optionalDataContainer(final Class type) { return Optional.of(type.asSubclass(DataContainer.class)); } + + + /** + * Determines if two augmentation classes or case classes represents same data. + * + *

+ * Two augmentations or cases could be substituted only if and if: + *

    + *
  • Both implements same interfaces
  • + *
  • Both have same children
  • + *
  • If augmentations: Both have same augmentation target class. Target class was generated for data node in a + * grouping.
  • + *
  • If cases: Both are from same choice. Choice class was generated for data node in grouping.
  • + *
+ * + *

+ * Explanation: + * Binding Specification reuses classes generated for groupings as part of normal data tree, this classes from + * grouping could be used at various locations and user may not be aware of it and may use incorrect case or + * augmentation in particular subtree (via copy constructors, etc). + * + * @param potential Class which is potential substitution + * @param target Class which should be used at particular subtree + * @return true if and only if classes represents same data. + * @throws NullPointerException if any argument is {@code null} + */ + // FIXME: MDSAL-785: this really should live in BindingRuntimeTypes and should not be based on reflection. The only + // user is binding-dom-codec and the logic could easily be performed on GeneratedType instead. For + // a particular world this boils down to a matrix, which can be calculated either on-demand or + // when we create BindingRuntimeTypes. Achieving that will bring us one step closer to being able + // to have a pre-compiled Binding Runtime. + @SuppressWarnings({ "rawtypes", "unchecked" }) + static boolean isSubstitutionFor(final Class potential, final Class target) { + Set subImplemented = new HashSet<>(Arrays.asList(potential.getInterfaces())); + Set targetImplemented = new HashSet<>(Arrays.asList(target.getInterfaces())); + if (!subImplemented.equals(targetImplemented)) { + return false; + } + if (Augmentation.class.isAssignableFrom(potential) + && !BindingReflections.findAugmentationTarget(potential).equals( + BindingReflections.findAugmentationTarget(target))) { + return false; + } + for (Method potentialMethod : potential.getMethods()) { + if (Modifier.isStatic(potentialMethod.getModifiers())) { + // Skip any static methods, as we are not interested in those + continue; + } + + try { + Method targetMethod = target.getMethod(potentialMethod.getName(), potentialMethod.getParameterTypes()); + if (!potentialMethod.getReturnType().equals(targetMethod.getReturnType())) { + return false; + } + } catch (NoSuchMethodException e) { + // Counterpart method is missing, so classes could not be substituted. + return false; + } catch (SecurityException e) { + throw new IllegalStateException("Could not compare methods", e); + } + } + return true; + } }