Revert "BUG-1425: Integrated new Binding to Normalized Node codec for write path"
[controller.git] / opendaylight / md-sal / sal-binding-broker / src / main / java / org / opendaylight / controller / md / sal / binding / impl / BindingToNormalizedNodeCodec.java
index 1e2d2b17f0b1846ab9272f6683f2a0f00cd1c070..66caaea7083af18f1ffaedc3113f4e35d167b4ff 100644 (file)
  */
 package org.opendaylight.controller.md.sal.binding.impl;
 
-import com.google.common.base.Function;
-import com.google.common.base.Optional;
+import java.lang.reflect.Method;
 import java.util.AbstractMap.SimpleEntry;
+import java.util.Collection;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Map.Entry;
+import java.util.Set;
+
+import javax.annotation.Nullable;
+
 import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationException;
 import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationOperation;
 import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizer;
-import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry;
-import org.opendaylight.yangtools.sal.binding.generator.impl.GeneratedClassLoadingStrategy;
-import org.opendaylight.yangtools.sal.binding.generator.util.BindingRuntimeContext;
+import org.opendaylight.yangtools.yang.binding.Augmentation;
+import org.opendaylight.yangtools.yang.binding.BindingMapping;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.YangModuleInfo;
+import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
 import org.opendaylight.yangtools.yang.data.impl.codec.DeserializationException;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class BindingToNormalizedNodeCodec implements SchemaContextListener,AutoCloseable {
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+
+public class BindingToNormalizedNodeCodec implements SchemaContextListener {
 
     private static final Logger LOG = LoggerFactory.getLogger(BindingToNormalizedNodeCodec.class);
 
     private final BindingIndependentMappingService bindingToLegacy;
-    private final BindingNormalizedNodeCodecRegistry codecRegistry;
     private DataNormalizer legacyToNormalized;
-    private final GeneratedClassLoadingStrategy classLoadingStrategy;
 
-    public BindingToNormalizedNodeCodec(final GeneratedClassLoadingStrategy classLoadingStrategy, final BindingIndependentMappingService mappingService, final BindingNormalizedNodeCodecRegistry codecRegistry) {
+    public BindingToNormalizedNodeCodec(final BindingIndependentMappingService mappingService) {
         super();
         this.bindingToLegacy = mappingService;
-        this.classLoadingStrategy = classLoadingStrategy;
-        this.codecRegistry = codecRegistry;
-
     }
 
     public org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier toNormalized(
             final InstanceIdentifier<? extends DataObject> binding) {
-        return codecRegistry.toYangInstanceIdentifier(binding);
+
+        // Used instance-identifier codec do not support serialization of last
+        // path
+        // argument if it is Augmentation (behaviour expected by old datastore)
+        // in this case, we explicitly check if last argument is augmentation
+        // to process it separately
+        if (isAugmentationIdentifier(binding)) {
+            return toNormalizedAugmented(binding);
+        }
+        return toNormalizedImpl(binding);
     }
 
-    @SuppressWarnings({ "unchecked", "rawtypes" })
     public Entry<org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier, NormalizedNode<?, ?>> toNormalizedNode(
             final InstanceIdentifier<? extends DataObject> bindingPath, final DataObject bindingObject) {
-        return codecRegistry.toNormalizedNode((InstanceIdentifier) bindingPath, bindingObject);
+        return toNormalizedNode(toBindingEntry(bindingPath, bindingObject));
 
     }
 
     public Entry<org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier, NormalizedNode<?, ?>> toNormalizedNode(
             final Entry<org.opendaylight.yangtools.yang.binding.InstanceIdentifier<? extends DataObject>, DataObject> binding) {
-        return toNormalizedNode(binding.getKey(),binding.getValue());
+        Entry<org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier, CompositeNode> legacyEntry = bindingToLegacy
+                .toDataDom(binding);
+        Entry<org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier, NormalizedNode<?, ?>> normalizedEntry = legacyToNormalized
+                .toNormalized(legacyEntry);
+        LOG.trace("Serialization of {}, Legacy Representation: {}, Normalized Representation: {}", binding,
+                legacyEntry, normalizedEntry);
+        if (isAugmentation(binding.getKey().getTargetType())) {
+
+            for (DataContainerChild<? extends PathArgument, ?> child : ((DataContainerNode<?>) normalizedEntry
+                    .getValue()).getValue()) {
+                if (child instanceof AugmentationNode) {
+                    ImmutableList<PathArgument> childArgs = ImmutableList.<PathArgument> builder()
+                            .addAll(normalizedEntry.getKey().getPathArguments()).add(child.getIdentifier()).build();
+                    org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier childPath = org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier
+                            .create(childArgs);
+                    return toDOMEntry(childPath, child);
+                }
+            }
+
+        }
+        return normalizedEntry;
+
     }
 
     /**
@@ -75,13 +125,109 @@ public class BindingToNormalizedNodeCodec implements SchemaContextListener,AutoC
     public Optional<InstanceIdentifier<? extends DataObject>> toBinding(
             final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier normalized)
                     throws DeserializationException {
+
+        PathArgument lastArgument = Iterables.getLast(normalized.getPathArguments());
+        // Used instance-identifier codec do not support serialization of last
+        // path
+        // argument if it is AugmentationIdentifier (behaviour expected by old
+        // datastore)
+        // in this case, we explicitly check if last argument is augmentation
+        // to process it separately
+        if (lastArgument instanceof AugmentationIdentifier) {
+            return toBindingAugmented(normalized);
+        }
+        return toBindingImpl(normalized);
+    }
+
+    private Optional<InstanceIdentifier<? extends DataObject>> toBindingAugmented(
+            final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier normalized)
+                    throws DeserializationException {
+        Optional<InstanceIdentifier<? extends DataObject>> potential = toBindingImpl(normalized);
+        // Shorthand check, if codec already supports deserialization
+        // of AugmentationIdentifier we will return
+        if (potential.isPresent() && isAugmentationIdentifier(potential.get())) {
+            return potential;
+        }
+
+        int normalizedCount = getAugmentationCount(normalized);
+        AugmentationIdentifier lastArgument = (AugmentationIdentifier) Iterables.getLast(normalized.getPathArguments());
+
+        // Here we employ small trick - Binding-aware Codec injects an pointer
+        // to augmentation class
+        // if child is referenced - so we will reference child and then shorten
+        // path.
+        LOG.trace("Looking for candidates to match {}", normalized);
+        for (QName child : lastArgument.getPossibleChildNames()) {
+            org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier childPath = normalized.node(child);
+            try {
+                if (isNotRepresentable(childPath)) {
+                    LOG.trace("Path {} is not BI-representable, skipping it", childPath);
+                    continue;
+                }
+            } catch (DataNormalizationException e) {
+                LOG.warn("Failed to denormalize path {}, skipping it", childPath, e);
+                continue;
+            }
+
+            Optional<InstanceIdentifier<? extends DataObject>> baId = toBindingImpl(childPath);
+            if (!baId.isPresent()) {
+                LOG.debug("No binding-aware identifier found for path {}, skipping it", childPath);
+                continue;
+            }
+
+            InstanceIdentifier<? extends DataObject> potentialPath = shortenToLastAugment(baId.get());
+            int potentialAugmentCount = getAugmentationCount(potentialPath);
+            if (potentialAugmentCount == normalizedCount) {
+                LOG.trace("Found matching path {}", potentialPath);
+                return Optional.<InstanceIdentifier<? extends DataObject>> of(potentialPath);
+            }
+
+            LOG.trace("Skipping mis-matched potential path {}", potentialPath);
+        }
+
+        LOG.trace("Failed to find augmentation matching {}", normalized);
+        return Optional.absent();
+    }
+
+    private Optional<InstanceIdentifier<? extends DataObject>> toBindingImpl(
+            final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier normalized)
+                    throws DeserializationException {
+        org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier legacyPath;
+
         try {
-            return  Optional.<InstanceIdentifier<? extends DataObject>>of(codecRegistry.fromYangInstanceIdentifier(normalized));
-        } catch (IllegalArgumentException e) {
-            return Optional.absent();
+            if (isNotRepresentable(normalized)) {
+                return Optional.absent();
+            }
+            legacyPath = legacyToNormalized.toLegacy(normalized);
+        } catch (DataNormalizationException e) {
+            throw new IllegalStateException("Could not denormalize path.", e);
+        }
+        LOG.trace("InstanceIdentifier Path Deserialization: Legacy representation {}, Normalized representation: {}",
+                legacyPath, normalized);
+        return Optional.<InstanceIdentifier<? extends DataObject>> of(bindingToLegacy.fromDataDom(legacyPath));
+    }
+
+    private boolean isNotRepresentable(final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier normalized)
+            throws DataNormalizationException {
+        DataNormalizationOperation<?> op = findNormalizationOperation(normalized);
+        if (op.isMixin() && op.getIdentifier() instanceof NodeIdentifier) {
+            return true;
+        }
+        if (op.isLeaf()) {
+            return true;
         }
+        return false;
     }
 
+    private DataNormalizationOperation<?> findNormalizationOperation(
+            final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier normalized)
+                    throws DataNormalizationException {
+        DataNormalizationOperation<?> current = legacyToNormalized.getRootOperation();
+        for (PathArgument arg : normalized.getPathArguments()) {
+            current = current.getChild(arg);
+        }
+        return current;
+    }
 
     private static final Entry<org.opendaylight.yangtools.yang.binding.InstanceIdentifier<? extends DataObject>, DataObject> toBindingEntry(
             final org.opendaylight.yangtools.yang.binding.InstanceIdentifier<? extends DataObject> key,
@@ -90,19 +236,45 @@ public class BindingToNormalizedNodeCodec implements SchemaContextListener,AutoC
                 key, value);
     }
 
+    private static final Entry<org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier, NormalizedNode<?, ?>> toDOMEntry(
+            final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier key, final NormalizedNode<?, ?> value) {
+        return new SimpleEntry<org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier, NormalizedNode<?, ?>>(key,
+                value);
+    }
+
+    public DataObject toBinding(final InstanceIdentifier<?> path, final NormalizedNode<?, ?> normalizedNode)
+            throws DeserializationException {
+        CompositeNode legacy = null;
+        if (isAugmentationIdentifier(path) && normalizedNode instanceof AugmentationNode) {
+            QName augIdentifier = BindingReflections.findQName(path.getTargetType());
+            ContainerNode virtualNode = Builders.containerBuilder() //
+                    .withNodeIdentifier(new NodeIdentifier(augIdentifier)) //
+                    .withChild((DataContainerChild<?, ?>) normalizedNode) //
+                    .build();
+            legacy = (CompositeNode) DataNormalizer.toLegacy(virtualNode);
+        } else {
+            legacy = (CompositeNode) DataNormalizer.toLegacy(normalizedNode);
+        }
+
+        return bindingToLegacy.dataObjectFromDataDom(path, legacy);
+    }
+
     public DataNormalizer getDataNormalizer() {
         return legacyToNormalized;
     }
 
-    @SuppressWarnings("unchecked")
     public Optional<Entry<org.opendaylight.yangtools.yang.binding.InstanceIdentifier<? extends DataObject>, DataObject>> toBinding(
             final Entry<org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier, ? extends NormalizedNode<?, ?>> normalized)
                     throws DeserializationException {
-        try {
-            @SuppressWarnings("rawtypes")
-            Entry binding = codecRegistry.fromNormalizedNode(normalized.getKey(), normalized.getValue());
-            return Optional.<Entry<org.opendaylight.yangtools.yang.binding.InstanceIdentifier<? extends DataObject>, DataObject>>fromNullable(binding);
-        } catch (IllegalArgumentException e) {
+        Optional<InstanceIdentifier<? extends DataObject>> potentialPath = toBinding(normalized.getKey());
+        if (potentialPath.isPresent()) {
+            InstanceIdentifier<? extends DataObject> bindingPath = potentialPath.get();
+            DataObject bindingData = toBinding(bindingPath, normalized.getValue());
+            if (bindingData == null) {
+                LOG.warn("Failed to deserialize {} to Binding format. Binding path is: {}", normalized, bindingPath);
+            }
+            return Optional.of(toBindingEntry(bindingPath, bindingData));
+        } else {
             return Optional.absent();
         }
     }
@@ -110,11 +282,269 @@ public class BindingToNormalizedNodeCodec implements SchemaContextListener,AutoC
     @Override
     public void onGlobalContextUpdated(final SchemaContext arg0) {
         legacyToNormalized = new DataNormalizer(arg0);
-        codecRegistry.onBindingRuntimeContextUpdated(BindingRuntimeContext.create(classLoadingStrategy, arg0));
     }
 
+    private org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier toNormalizedAugmented(
+            final InstanceIdentifier<?> augPath) {
+        org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier processed = toNormalizedImpl(augPath);
+        // If used instance identifier codec added supports for deserialization
+        // of last AugmentationIdentifier we will just reuse it
+        if (isAugmentationIdentifier(processed)) {
+            return processed;
+        }
+        Optional<org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier> additionalSerialized;
+        additionalSerialized = toNormalizedAugmentedUsingChildContainers(augPath, processed);
+
+        if (additionalSerialized.isPresent()) {
+            return additionalSerialized.get();
+        }
+        additionalSerialized = toNormalizedAugmentedUsingChildLeafs(augPath, processed);
+        if (additionalSerialized.isPresent()) {
+            return additionalSerialized.get();
+        }
+        throw new IllegalStateException("Unabled to construct augmentation identfier for " + augPath);
+    }
+
+    /**
+     * Tries to find correct augmentation identifier using children leafs
+     *
+     * This method uses normalized Instance Identifier of parent node to fetch
+     * schema and {@link BindingReflections#getModuleInfo(Class)} to learn about
+     * augmentation namespace, specificly, in which module it was defined.
+     *
+     * Then it uses it to filter all available augmentations for parent by
+     * module. After that it walks augmentations in particular module and
+     * pick-up first which at least one leaf name matches supplied augmentation.
+     * We could do this safely since YANG explicitly states that no any existing
+     * augmentations must differ in leaf fully qualified names.
+     *
+     *
+     * @param augPath
+     *            Binding Aware Path which ends with augment
+     * @param parentPath
+     *            Processed path
+     * @return
+     */
+    private Optional<org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier> toNormalizedAugmentedUsingChildLeafs(
+            final InstanceIdentifier<?> augPath,
+            final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier parentPath) {
+        try {
+            DataNormalizationOperation<?> parentOp = legacyToNormalized.getOperation(parentPath);
+            if(!parentOp.getDataSchemaNode().isPresent()) {
+                return Optional.absent();
+            }
+            DataSchemaNode parentSchema = parentOp.getDataSchemaNode().get();
+            if (parentSchema instanceof AugmentationTarget) {
+                Set<AugmentationSchema> augmentations = ((AugmentationTarget) parentSchema).getAvailableAugmentations();
+                LOG.info("Augmentations for {}, {}", augPath, augmentations);
+                Optional<AugmentationSchema> schema = findAugmentation(augPath.getTargetType(), augmentations);
+                if (schema.isPresent()) {
+                    AugmentationIdentifier augmentationIdentifier = DataNormalizationOperation
+                            .augmentationIdentifierFrom(schema.get());
+                    return Optional.of(parentPath.node(augmentationIdentifier));
+                }
+            }
+        } catch (DataNormalizationException e) {
+            throw new IllegalArgumentException(e);
+        }
+        return Optional.absent();
+    }
+
+    /**
+     * Creates instance identifier for augmentation child, tries to serialize it
+     * Instance Identifier is then shortened to last augmentation.
+     *
+     * This is for situations, where underlying codec is implementing hydrogen
+     * style DOM APIs (which did not supported {@link AugmentationIdentifier}.)
+     *
+     * @param augPath
+     * @param parentPath
+     *            Path to parent node
+     * @return
+     */
+    @SuppressWarnings("rawtypes")
+    private Optional<org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier> toNormalizedAugmentedUsingChildContainers(
+            final InstanceIdentifier<?> augPath,
+            final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier parentPath) {
+        for (Class augChild : BindingReflections.getChildrenClasses(augPath.getTargetType())) {
+            @SuppressWarnings("unchecked")
+            InstanceIdentifier<?> childPath = augPath.child(augChild);
+            org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier normalized = toNormalizedImpl(childPath);
+            org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier potentialDiscovered = shortenToLastAugmentation(
+                    normalized, parentPath);
+            if (potentialDiscovered != null) {
+                return Optional.of(potentialDiscovered);
+            }
+        }
+        return Optional.absent();
+    }
+
+    private Optional<AugmentationSchema> findAugmentation(final Class<?> targetType,
+            final Set<AugmentationSchema> augmentations) {
+        YangModuleInfo moduleInfo;
+        try {
+            moduleInfo = BindingReflections.getModuleInfo(targetType);
+        } catch (Exception e) {
+            throw new IllegalStateException(e);
+        }
+        Iterable<AugmentationSchema> filtered = filteredByModuleInfo(augmentations,
+                BindingReflections.getModuleQName(moduleInfo).getModule());
+        filtered.toString();
+        Set<String> targetTypeGetters = getYangModeledGetters(targetType);
+        for (AugmentationSchema schema : filtered) {
+            for (DataSchemaNode child : schema.getChildNodes()) {
+                String getterName = "get" + BindingMapping.getClassName(child.getQName());
+                if (targetTypeGetters.contains(getterName)) {
+                    return Optional.of(schema);
+                }
+            }
+        }
+        return Optional.absent();
+    }
+
+    private static Iterable<AugmentationSchema> filteredByModuleInfo(final Iterable<AugmentationSchema> augmentations,
+            final QNameModule module) {
+        return Iterables.filter(augmentations, new Predicate<AugmentationSchema>() {
+            @Override
+            public boolean apply(final AugmentationSchema schema) {
+                final Collection<DataSchemaNode> childNodes = schema.getChildNodes();
+                return !childNodes.isEmpty() && module.equals(Iterables.get(childNodes, 0).getQName().getModule());
+            }
+        });
+    }
+
+    public static final Set<String> getYangModeledGetters(final Class<?> targetType) {
+        HashSet<String> ret = new HashSet<String>();
+        for (Method method : targetType.getMethods()) {
+            if (isYangModeledGetter(method)) {
+                ret.add(method.getName());
+            }
+        }
+        return ret;
+    }
+
+    /**
+     *
+     * Returns true if supplied method represent getter for YANG modeled value
+     *
+     * @param method
+     *            Method to be tested
+     * @return true if method represent getter for YANG Modeled value.
+     */
+    private static final boolean isYangModeledGetter(final Method method) {
+        return !method.getName().equals("getClass") && !method.getName().equals("getImplementedInterface")
+                && method.getName().startsWith("get") && method.getParameterTypes().length == 0;
+    }
+
+    private org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier shortenToLastAugmentation(
+            final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier normalized,
+            final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier parentPath) {
+        int parentSize = Iterables.size(parentPath.getPathArguments());
+        int position = 0;
+        int foundPosition = -1;
+        for (PathArgument arg : normalized.getPathArguments()) {
+            position++;
+            if (arg instanceof AugmentationIdentifier) {
+                foundPosition = position;
+            }
+        }
+        if (foundPosition > 0 && foundPosition > parentSize) {
+            Iterable<PathArgument> shortened = Iterables.limit(normalized.getPathArguments(), foundPosition);
+            return org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.create(shortened);
+        }
+        return null;
+    }
+
+    private InstanceIdentifier<? extends DataObject> shortenToLastAugment(
+            final InstanceIdentifier<? extends DataObject> binding) {
+        int position = 0;
+        int foundPosition = -1;
+        for (org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument arg : binding.getPathArguments()) {
+            position++;
+            if (isAugmentation(arg.getType())) {
+                foundPosition = position;
+            }
+        }
+        return InstanceIdentifier.create(Iterables.limit(binding.getPathArguments(), foundPosition));
+    }
+
+    private org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier toNormalizedImpl(
+            final InstanceIdentifier<? extends DataObject> binding) {
+        final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier legacyPath = bindingToLegacy
+                .toDataDom(binding);
+        final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier normalized = legacyToNormalized
+                .toNormalized(legacyPath);
+        return normalized;
+    }
+
+    private static boolean isAugmentation(final Class<? extends DataObject> type) {
+        return Augmentation.class.isAssignableFrom(type);
+    }
+
+    private static boolean isAugmentationIdentifier(final InstanceIdentifier<?> potential) {
+        return Augmentation.class.isAssignableFrom(potential.getTargetType());
+    }
+
+    private boolean isAugmentationIdentifier(final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier processed) {
+        return Iterables.getLast(processed.getPathArguments()) instanceof AugmentationIdentifier;
+    }
+
+    private static int getAugmentationCount(final InstanceIdentifier<?> potential) {
+        int count = 0;
+        for (org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument arg : potential.getPathArguments()) {
+            if (isAugmentation(arg.getType())) {
+                count++;
+            }
+
+        }
+        return count;
+    }
+
+    private static int getAugmentationCount(final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier potential) {
+        int count = 0;
+        for (PathArgument arg : potential.getPathArguments()) {
+            if (arg instanceof AugmentationIdentifier) {
+                count++;
+            }
+        }
+        return count;
+    }
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
     public <T extends DataObject> Function<Optional<NormalizedNode<?, ?>>, Optional<T>>  deserializeFunction(final InstanceIdentifier<T> path) {
-        return codecRegistry.deserializeFunction(path);
+        return new DeserializeFunction(this, path);
+    }
+
+    private static class DeserializeFunction<T extends DataObject> implements Function<Optional<NormalizedNode<?, ?>>, Optional<T>> {
+
+        private final BindingToNormalizedNodeCodec codec;
+        private final InstanceIdentifier<?> path;
+
+        public DeserializeFunction(final BindingToNormalizedNodeCodec codec, final InstanceIdentifier<?> path) {
+            super();
+            this.codec = Preconditions.checkNotNull(codec, "Codec must not be null");
+            this.path = Preconditions.checkNotNull(path, "Path must not be null");
+        }
+
+        @SuppressWarnings("rawtypes")
+        @Nullable
+        @Override
+        public Optional apply(@Nullable final Optional<NormalizedNode<?, ?>> normalizedNode) {
+            if (normalizedNode.isPresent()) {
+                final DataObject dataObject;
+                try {
+                    dataObject = codec.toBinding(path, normalizedNode.get());
+                } catch (DeserializationException e) {
+                    LOG.warn("Failed to create dataobject from node {}", normalizedNode.get(), e);
+                    throw new IllegalStateException("Failed to create dataobject", e);
+                }
+
+                if (dataObject != null) {
+                    return Optional.of(dataObject);
+                }
+            }
+            return Optional.absent();
+        }
     }
 
     /**
@@ -136,13 +566,4 @@ public class BindingToNormalizedNodeCodec implements SchemaContextListener,AutoC
         }
         return currentOp.createDefault(path.getLastPathArgument());
     }
-
-    public BindingIndependentMappingService getLegacy() {
-        return bindingToLegacy;
-    }
-
-    @Override
-    public void close() throws Exception {
-        // NOOP Intentionally
-    }
 }