org.opendaylight.controller.cluster.datastore.node.NodeToNormalizedNodeBuilder.java Source code

Java tutorial

Introduction

Here is the source code for org.opendaylight.controller.cluster.datastore.node.NodeToNormalizedNodeBuilder.java

Source

/*
 *
 *  Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
 *
 *  This program and the accompanying materials are made available under the
 *  terms of the Eclipse Public License v1.0 which accompanies this distribution,
 *  and is available at http://www.eclipse.org/legal/epl-v10.html
 *
 */

package org.opendaylight.controller.cluster.datastore.node;

import com.google.common.base.Preconditions;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import org.opendaylight.controller.cluster.datastore.node.utils.NodeIdentifierFactory;
import org.opendaylight.controller.protobuff.messages.common.NormalizedNodeMessages.Node;
import org.opendaylight.yangtools.concepts.Identifiable;
import org.opendaylight.yangtools.yang.common.QName;
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.NodeIdentifierWithPredicates;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
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.LeafNode;
import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer;
import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeContainerBuilder;
import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import static com.google.common.base.Preconditions.checkArgument;

/**
 * NormalizedNodeBuilder is a builder that walks through a tree like structure and constructs a
 * NormalizedNode from it.
 * <p/>
 * A large part of this code has been copied over from a similar class in sal-common-impl which was
 * originally supposed to convert a CompositeNode to NormalizedNode
 *
 * @param <T>
 */
public abstract class NodeToNormalizedNodeBuilder<T extends PathArgument> implements Identifiable<T> {

    private final T identifier;

    protected static final Logger logger = LoggerFactory.getLogger(NodeToNormalizedNodeBuilder.class);

    @Override
    public T getIdentifier() {
        return identifier;
    }

    ;

    protected NodeToNormalizedNodeBuilder(final T identifier) {
        super();
        this.identifier = identifier;

    }

    /**
     * @return Should return true if the node that this operation corresponds to is a mixin
     */
    public boolean isMixin() {
        return false;
    }

    /**
     * @return Should return true if the node that this operation corresponds to has a 'key'
     * associated with it. This is typically true for a list-item or leaf-list entry in yang
     */
    public boolean isKeyedEntry() {
        return false;
    }

    protected Set<QName> getQNameIdentifiers() {
        return Collections.singleton(identifier.getNodeType());
    }

    public abstract NodeToNormalizedNodeBuilder<?> getChild(final PathArgument child);

    public abstract NodeToNormalizedNodeBuilder<?> getChild(QName child);

    public abstract NormalizedNode<?, ?> normalize(QName nodeType, Node node);

    private static abstract class SimpleTypeNormalization<T extends PathArgument>
            extends NodeToNormalizedNodeBuilder<T> {

        protected SimpleTypeNormalization(final T identifier) {
            super(identifier);
        }

        @Override
        public NormalizedNode<?, ?> normalize(final QName nodeType, final Node node) {
            checkArgument(node != null);
            return normalizeImpl(nodeType, node);
        }

        protected abstract NormalizedNode<?, ?> normalizeImpl(QName nodeType, Node node);

        @Override
        public NodeToNormalizedNodeBuilder<?> getChild(final PathArgument child) {
            return null;
        }

        @Override
        public NodeToNormalizedNodeBuilder<?> getChild(final QName child) {
            return null;
        }

        @Override
        public NormalizedNode<?, ?> createDefault(final PathArgument currentArg) {
            // TODO Auto-generated method stub
            return null;
        }

    }

    private static final class LeafNormalization extends SimpleTypeNormalization<NodeIdentifier> {

        private final LeafSchemaNode schema;

        protected LeafNormalization(final LeafSchemaNode schema, final NodeIdentifier identifier) {
            super(identifier);
            this.schema = schema;
        }

        @Override
        protected NormalizedNode<?, ?> normalizeImpl(final QName nodeType, final Node node) {
            Object value = NodeValueCodec.toTypeSafeValue(this.schema, this.schema.getType(), node);
            return ImmutableNodes.leafNode(nodeType, value);

        }

    }

    private static final class LeafListEntryNormalization extends SimpleTypeNormalization<NodeWithValue> {

        private final LeafListSchemaNode schema;

        public LeafListEntryNormalization(final LeafListSchemaNode potential) {
            super(new NodeWithValue(potential.getQName(), null));
            this.schema = potential;
        }

        @Override
        protected NormalizedNode<?, ?> normalizeImpl(final QName nodeType, final Node node) {
            final Object data = node.getValue();
            if (data == null) {
                Preconditions.checkArgument(false, "No data available in leaf list entry for " + nodeType);
            }

            Object value = NodeValueCodec.toTypeSafeValue(this.schema, this.schema.getType(), node);

            NodeWithValue nodeId = new NodeWithValue(nodeType, value);
            return Builders.leafSetEntryBuilder().withNodeIdentifier(nodeId).withValue(value).build();
        }

        @Override
        public boolean isKeyedEntry() {
            return true;
        }
    }

    private static abstract class NodeToNormalizationNodeOperation<T extends PathArgument>
            extends NodeToNormalizedNodeBuilder<T> {

        protected NodeToNormalizationNodeOperation(final T identifier) {
            super(identifier);
        }

        @SuppressWarnings({ "rawtypes", "unchecked" })
        @Override
        public final NormalizedNodeContainer<?, ?, ?> normalize(final QName nodeType, final Node node) {
            checkArgument(node != null);

            if (!node.getType().equals(AugmentationNode.class.getSimpleName())
                    && !node.getType().equals(ContainerNode.class.getSimpleName())
                    && !node.getType().equals(MapNode.class.getSimpleName())) {
                checkArgument(nodeType != null);
            }

            NormalizedNodeContainerBuilder builder = createBuilder(node);

            Set<NodeToNormalizedNodeBuilder<?>> usedMixins = new HashSet<>();

            logNode(node);

            if (node.getChildCount() == 0 && (node.getType().equals(LeafSetEntryNode.class.getSimpleName())
                    || node.getType().equals(LeafNode.class.getSimpleName()))) {
                PathArgument childPathArgument = NodeIdentifierFactory.getArgument(node.getPath());

                final NormalizedNode child;
                if (childPathArgument instanceof NodeWithValue) {
                    final NodeWithValue nodeWithValue = new NodeWithValue(childPathArgument.getNodeType(),
                            node.getValue());
                    child = Builders.leafSetEntryBuilder().withNodeIdentifier(nodeWithValue)
                            .withValue(node.getValue()).build();
                } else {
                    child = ImmutableNodes.leafNode(childPathArgument.getNodeType(), node.getValue());
                }
                builder.addChild(child);
            }

            final List<Node> children = node.getChildList();
            for (Node nodeChild : children) {

                PathArgument childPathArgument = NodeIdentifierFactory.getArgument(nodeChild.getPath());

                QName childNodeType = null;
                NodeToNormalizedNodeBuilder childOp = null;

                if (childPathArgument instanceof AugmentationIdentifier) {
                    childOp = getChild(childPathArgument);
                    checkArgument(childOp instanceof AugmentationNormalization, childPathArgument);
                } else {
                    childNodeType = childPathArgument.getNodeType();
                    childOp = getChild(childNodeType);
                }
                // We skip unknown nodes if this node is mixin since
                // it's nodes and parent nodes are interleaved
                if (childOp == null && isMixin()) {
                    continue;
                } else if (childOp == null) {
                    logger.error("childOp is null and this operation is not a mixin : this = {}", this.toString());
                }

                checkArgument(childOp != null, "Node %s is not allowed inside %s", childNodeType, getIdentifier());

                if (childOp.isMixin()) {
                    if (usedMixins.contains(childOp)) {
                        // We already run / processed that mixin, so to avoid
                        // duplicate we are
                        // skipping next nodes.
                        continue;
                    }
                    // builder.addChild(childOp.normalize(nodeType, treeCacheNode));
                    final NormalizedNode childNode = childOp.normalize(childNodeType, nodeChild);
                    if (childNode != null)
                        builder.addChild(childNode);
                    usedMixins.add(childOp);
                } else {
                    final NormalizedNode childNode = childOp.normalize(childNodeType, nodeChild);
                    if (childNode != null)
                        builder.addChild(childNode);
                }
            }

            try {
                return (NormalizedNodeContainer<?, ?, ?>) builder.build();
            } catch (Exception e) {
                return null;
            }

        }

        private void logNode(Node node) {
            //let us find out the type of the node
            logger.debug("We got a {} , with identifier {} with {} children", node.getType(), node.getPath(),
                    node.getChildList());
        }

        @SuppressWarnings("rawtypes")
        protected abstract NormalizedNodeContainerBuilder createBuilder(final Node node);

    }

    private static abstract class DataContainerNormalizationOperation<T extends PathArgument>
            extends NodeToNormalizationNodeOperation<T> {

        private final DataNodeContainer schema;
        private final Map<QName, NodeToNormalizedNodeBuilder<?>> byQName;
        private final Map<PathArgument, NodeToNormalizedNodeBuilder<?>> byArg;

        protected DataContainerNormalizationOperation(final T identifier, final DataNodeContainer schema) {
            super(identifier);
            this.schema = schema;
            this.byArg = new ConcurrentHashMap<>();
            this.byQName = new ConcurrentHashMap<>();
        }

        @Override
        public NodeToNormalizedNodeBuilder<?> getChild(final PathArgument child) {
            NodeToNormalizedNodeBuilder<?> potential = byArg.get(child);
            if (potential != null) {
                return potential;
            }
            potential = fromSchema(schema, child);
            return register(potential);
        }

        @Override
        public NodeToNormalizedNodeBuilder<?> getChild(final QName child) {
            if (child == null) {
                return null;
            }

            NodeToNormalizedNodeBuilder<?> potential = byQName.get(child);
            if (potential != null) {
                return potential;
            }
            potential = fromSchemaAndPathArgument(schema, child);
            return register(potential);
        }

        private NodeToNormalizedNodeBuilder<?> register(final NodeToNormalizedNodeBuilder<?> potential) {
            if (potential != null) {
                byArg.put(potential.getIdentifier(), potential);
                for (QName qName : potential.getQNameIdentifiers()) {
                    byQName.put(qName, potential);
                }
            }
            return potential;
        }

    }

    private static final class ListItemNormalization
            extends DataContainerNormalizationOperation<NodeIdentifierWithPredicates> {

        private final List<QName> keyDefinition;
        private final ListSchemaNode schemaNode;

        protected ListItemNormalization(final NodeIdentifierWithPredicates identifier,
                final ListSchemaNode schema) {
            super(identifier, schema);
            this.schemaNode = schema;
            keyDefinition = schema.getKeyDefinition();
        }

        @Override
        protected NormalizedNodeContainerBuilder createBuilder(final Node node) {
            NodeIdentifierWithPredicates nodeIdentifierWithPredicates = (NodeIdentifierWithPredicates) NodeIdentifierFactory
                    .createPathArgument(node.getPath(), schemaNode);
            return Builders.mapEntryBuilder().withNodeIdentifier(nodeIdentifierWithPredicates);
        }

        @Override
        public NormalizedNode<?, ?> createDefault(final PathArgument currentArg) {
            DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> builder = Builders
                    .mapEntryBuilder().withNodeIdentifier((NodeIdentifierWithPredicates) currentArg);
            for (Entry<QName, Object> keyValue : ((NodeIdentifierWithPredicates) currentArg).getKeyValues()
                    .entrySet()) {
                if (keyValue.getValue() == null) {
                    throw new NullPointerException("Null value found for path : " + currentArg);
                }
                builder.addChild(Builders.leafBuilder()
                        //
                        .withNodeIdentifier(new NodeIdentifier(keyValue.getKey())).withValue(keyValue.getValue())
                        .build());
            }
            return builder.build();
        }

        @Override
        public boolean isKeyedEntry() {
            return true;
        }
    }

    private static final class ContainerNormalization extends DataContainerNormalizationOperation<NodeIdentifier> {

        protected ContainerNormalization(final ContainerSchemaNode schema) {
            super(new NodeIdentifier(schema.getQName()), schema);
        }

        @Override
        protected NormalizedNodeContainerBuilder createBuilder(final Node node) {
            return Builders.containerBuilder().withNodeIdentifier(getIdentifier());
        }

        @Override
        public NormalizedNode<?, ?> createDefault(final PathArgument currentArg) {
            return Builders.containerBuilder().withNodeIdentifier((NodeIdentifier) currentArg).build();
        }

    }

    private static abstract class MixinNormalizationOp<T extends PathArgument>
            extends NodeToNormalizationNodeOperation<T> {

        protected MixinNormalizationOp(final T identifier) {
            super(identifier);
        }

        @Override
        public final boolean isMixin() {
            return true;
        }

    }

    private static final class LeafListMixinNormalization extends MixinNormalizationOp<NodeIdentifier> {

        private final NodeToNormalizedNodeBuilder<?> innerOp;

        public LeafListMixinNormalization(final LeafListSchemaNode potential) {
            super(new NodeIdentifier(potential.getQName()));
            innerOp = new LeafListEntryNormalization(potential);
        }

        @Override
        protected NormalizedNodeContainerBuilder createBuilder(final Node node) {
            return Builders.leafSetBuilder().withNodeIdentifier(getIdentifier());
        }

        @Override
        public NormalizedNode<?, ?> createDefault(final PathArgument currentArg) {
            return Builders.leafSetBuilder().withNodeIdentifier(getIdentifier()).build();
        }

        @Override
        public NodeToNormalizedNodeBuilder<?> getChild(final PathArgument child) {
            if (child instanceof NodeWithValue) {
                return innerOp;
            }
            return null;
        }

        @Override
        public NodeToNormalizedNodeBuilder<?> getChild(final QName child) {
            if (getIdentifier().getNodeType().equals(child)) {
                return innerOp;
            }
            return null;
        }

    }

    private static final class AugmentationNormalization extends MixinNormalizationOp<AugmentationIdentifier> {

        private final Map<QName, NodeToNormalizedNodeBuilder<?>> byQName;
        private final Map<PathArgument, NodeToNormalizedNodeBuilder<?>> byArg;

        public AugmentationNormalization(final AugmentationSchema augmentation, final DataNodeContainer schema) {
            super(augmentationIdentifierFrom(augmentation));

            ImmutableMap.Builder<QName, NodeToNormalizedNodeBuilder<?>> byQNameBuilder = ImmutableMap.builder();
            ImmutableMap.Builder<PathArgument, NodeToNormalizedNodeBuilder<?>> byArgBuilder = ImmutableMap
                    .builder();

            for (DataSchemaNode augNode : augmentation.getChildNodes()) {
                DataSchemaNode resolvedNode = schema.getDataChildByName(augNode.getQName());
                NodeToNormalizedNodeBuilder<?> resolvedOp = fromDataSchemaNode(resolvedNode);
                byArgBuilder.put(resolvedOp.getIdentifier(), resolvedOp);
                for (QName resQName : resolvedOp.getQNameIdentifiers()) {
                    byQNameBuilder.put(resQName, resolvedOp);
                }
            }
            byQName = byQNameBuilder.build();
            byArg = byArgBuilder.build();

        }

        @Override
        public NodeToNormalizedNodeBuilder<?> getChild(final PathArgument child) {
            return byArg.get(child);
        }

        @Override
        public NodeToNormalizedNodeBuilder<?> getChild(final QName child) {
            return byQName.get(child);
        }

        @Override
        protected Set<QName> getQNameIdentifiers() {
            return getIdentifier().getPossibleChildNames();
        }

        @SuppressWarnings("rawtypes")
        @Override
        protected NormalizedNodeContainerBuilder createBuilder(final Node node) {
            return Builders.augmentationBuilder().withNodeIdentifier(getIdentifier());
        }

        @Override
        public NormalizedNode<?, ?> createDefault(final PathArgument currentArg) {
            return Builders.augmentationBuilder().withNodeIdentifier(getIdentifier()).build();
        }

    }

    private static final class ListMixinNormalization extends MixinNormalizationOp<NodeIdentifier> {

        private final ListItemNormalization innerNode;

        public ListMixinNormalization(final ListSchemaNode list) {
            super(new NodeIdentifier(list.getQName()));
            this.innerNode = new ListItemNormalization(
                    new NodeIdentifierWithPredicates(list.getQName(), Collections.<QName, Object>emptyMap()), list);
        }

        @SuppressWarnings("rawtypes")
        @Override
        protected NormalizedNodeContainerBuilder createBuilder(final Node node) {
            return Builders.mapBuilder().withNodeIdentifier(getIdentifier());
        }

        @Override
        public NormalizedNode<?, ?> createDefault(final PathArgument currentArg) {
            return Builders.mapBuilder().withNodeIdentifier(getIdentifier()).build();
        }

        @Override
        public NodeToNormalizedNodeBuilder<?> getChild(final PathArgument child) {
            if (child.getNodeType().equals(getIdentifier().getNodeType())) {
                return innerNode;
            }
            return null;
        }

        @Override
        public NodeToNormalizedNodeBuilder<?> getChild(final QName child) {
            if (getIdentifier().getNodeType().equals(child)) {
                return innerNode;
            }
            return null;
        }

    }

    private static class ChoiceNodeNormalization extends MixinNormalizationOp<NodeIdentifier> {

        private final ImmutableMap<QName, NodeToNormalizedNodeBuilder<?>> byQName;
        private final ImmutableMap<PathArgument, NodeToNormalizedNodeBuilder<?>> byArg;

        protected ChoiceNodeNormalization(final org.opendaylight.yangtools.yang.model.api.ChoiceNode schema) {
            super(new NodeIdentifier(schema.getQName()));
            ImmutableMap.Builder<QName, NodeToNormalizedNodeBuilder<?>> byQNameBuilder = ImmutableMap.builder();
            ImmutableMap.Builder<PathArgument, NodeToNormalizedNodeBuilder<?>> byArgBuilder = ImmutableMap
                    .builder();

            for (ChoiceCaseNode caze : schema.getCases()) {
                for (DataSchemaNode cazeChild : caze.getChildNodes()) {
                    NodeToNormalizedNodeBuilder<?> childOp = fromDataSchemaNode(cazeChild);
                    byArgBuilder.put(childOp.getIdentifier(), childOp);
                    for (QName qname : childOp.getQNameIdentifiers()) {
                        byQNameBuilder.put(qname, childOp);
                    }
                }
            }
            byQName = byQNameBuilder.build();
            byArg = byArgBuilder.build();
        }

        @Override
        public NodeToNormalizedNodeBuilder<?> getChild(final PathArgument child) {
            return byArg.get(child);
        }

        @Override
        public NodeToNormalizedNodeBuilder<?> getChild(final QName child) {
            return byQName.get(child);
        }

        @Override
        protected NormalizedNodeContainerBuilder createBuilder(final Node node) {
            return Builders.choiceBuilder().withNodeIdentifier(getIdentifier());
        }

        @Override
        public NormalizedNode<?, ?> createDefault(final PathArgument currentArg) {
            return Builders.choiceBuilder().withNodeIdentifier(getIdentifier()).build();
        }
    }

    /**
     * Find an appropriate NormalizedNodeBuilder using both the schema and the
     * Path Argument
     *
     * @param schema
     * @param child
     * @return
     */
    public static NodeToNormalizedNodeBuilder<?> fromSchemaAndPathArgument(final DataNodeContainer schema,
            final QName child) {
        DataSchemaNode potential = schema.getDataChildByName(child);
        if (potential == null) {
            Iterable<org.opendaylight.yangtools.yang.model.api.ChoiceNode> choices = FluentIterable
                    .from(schema.getChildNodes())
                    .filter(org.opendaylight.yangtools.yang.model.api.ChoiceNode.class);
            potential = findChoice(choices, child);
        }
        if (potential == null) {
            if (logger.isTraceEnabled()) {
                logger.trace("BAD CHILD = {}", child.toString());
            }
        }

        checkArgument(potential != null, "Supplied QName %s is not valid according to schema %s", child, schema);

        // If the schema in an instance of DataSchemaNode and the potential
        // is augmenting something then there is a chance that this may be
        // and augmentation node
        if ((schema instanceof DataSchemaNode) && potential.isAugmenting()) {

            AugmentationNormalization augmentation = fromAugmentation(schema, (AugmentationTarget) schema,
                    potential);

            // If an augmentation normalization (builder) is not found then
            // we fall through to the regular processing
            if (augmentation != null) {
                return augmentation;
            }
        }
        return fromDataSchemaNode(potential);
    }

    /**
     * Given a bunch of choice nodes and a the name of child find a choice node for that child which
     * has a non-null value
     *
     * @param choices
     * @param child
     * @return
     */
    private static org.opendaylight.yangtools.yang.model.api.ChoiceNode findChoice(
            final Iterable<org.opendaylight.yangtools.yang.model.api.ChoiceNode> choices, final QName child) {
        org.opendaylight.yangtools.yang.model.api.ChoiceNode foundChoice = null;
        choiceLoop: for (org.opendaylight.yangtools.yang.model.api.ChoiceNode choice : choices) {
            for (ChoiceCaseNode caze : choice.getCases()) {
                if (caze.getDataChildByName(child) != null) {
                    foundChoice = choice;
                    break choiceLoop;
                }
            }
        }
        return foundChoice;
    }

    /**
     * Create an AugmentationIdentifier based on the AugmentationSchema
     *
     * @param augmentation
     * @return
     */
    public static AugmentationIdentifier augmentationIdentifierFrom(final AugmentationSchema augmentation) {
        ImmutableSet.Builder<QName> potentialChildren = ImmutableSet.builder();
        for (DataSchemaNode child : augmentation.getChildNodes()) {
            potentialChildren.add(child.getQName());
        }
        return new AugmentationIdentifier(potentialChildren.build());
    }

    /**
     * Create an AugmentationNormalization based on the schema of the DataContainer, the
     * AugmentationTarget and the potential schema node
     *
     * @param schema
     * @param augments
     * @param potential
     * @return
     */
    private static AugmentationNormalization fromAugmentation(final DataNodeContainer schema,
            final AugmentationTarget augments, final DataSchemaNode potential) {
        AugmentationSchema augmentation = null;
        for (AugmentationSchema aug : augments.getAvailableAugmentations()) {
            DataSchemaNode child = aug.getDataChildByName(potential.getQName());
            if (child != null) {
                augmentation = aug;
                break;
            }

        }
        if (augmentation != null) {
            return new AugmentationNormalization(augmentation, schema);
        } else {
            return null;
        }
    }

    /**
     * @param schema
     * @param child
     * @return
     */
    private static NodeToNormalizedNodeBuilder<?> fromSchema(final DataNodeContainer schema,
            final PathArgument child) {
        if (child instanceof AugmentationIdentifier) {
            QName childQName = ((AugmentationIdentifier) child).getPossibleChildNames().iterator().next();

            return fromSchemaAndPathArgument(schema, childQName);
        }
        return fromSchemaAndPathArgument(schema, child.getNodeType());
    }

    public static NodeToNormalizedNodeBuilder<?> fromDataSchemaNode(final DataSchemaNode potential) {
        if (potential instanceof ContainerSchemaNode) {
            return new ContainerNormalization((ContainerSchemaNode) potential);
        } else if (potential instanceof ListSchemaNode) {
            return new ListMixinNormalization((ListSchemaNode) potential);
        } else if (potential instanceof LeafSchemaNode) {
            return new LeafNormalization((LeafSchemaNode) potential, new NodeIdentifier(potential.getQName()));
        } else if (potential instanceof org.opendaylight.yangtools.yang.model.api.ChoiceNode) {
            return new ChoiceNodeNormalization((org.opendaylight.yangtools.yang.model.api.ChoiceNode) potential);
        } else if (potential instanceof LeafListSchemaNode) {
            return new LeafListMixinNormalization((LeafListSchemaNode) potential);
        }
        return null;
    }

    public static NodeToNormalizedNodeBuilder<?> from(final SchemaContext ctx) {
        return new ContainerNormalization(ctx);
    }

    public abstract NormalizedNode<?, ?> createDefault(PathArgument currentArg);

}