*/
package org.opendaylight.yangtools.yang.data.impl.schema.transform.base.parser;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.LinkedListMultimap;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
-
+import javax.annotation.Nullable;
import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.AttributesBuilder;
import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
-import org.opendaylight.yangtools.yang.data.impl.schema.transform.ToNormalizedNodeParser;
-import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.AugmentationSchemaProxy;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeBuilder;
import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
-import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
+import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
-
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.LinkedListMultimap;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.util.EffectiveAugmentationSchema;
/**
* Abstract(base) Parser for DataContainerNodes e.g. ContainerNode, AugmentationNode.
*/
-public abstract class BaseDispatcherParser<E, N extends DataContainerNode<?>, S>
- implements ToNormalizedNodeParser<E, N, S> {
+public abstract class BaseDispatcherParser<E, P extends YangInstanceIdentifier.PathArgument, N extends DataContainerNode<P>, S>
+ implements ExtensibleParser<P, E, N, S> {
+
+ private final BuildingStrategy<P, N> buildingStrategy;
+
+ public BaseDispatcherParser(final BuildingStrategy<P, N> buildingStrategy) {
+ this.buildingStrategy = buildingStrategy;
+ }
+
+ public BaseDispatcherParser() {
+ this.buildingStrategy = new SimpleBuildingStrategy<>();
+ }
/**
*
* @param schema
* @return New(empty) instance of a builder to build node identified by schema.
*/
- protected abstract DataContainerNodeBuilder<?, N> getBuilder(S schema);
+ protected abstract DataContainerNodeBuilder<P, N> getBuilder(S schema);
/**
*
* @return map from QName to ChoiceNode schema of child nodes that are
* contained within a choice statement under current schema.
*/
- protected abstract Map<QName, ChoiceNode> mapChildElementsFromChoices(S schema);
+ protected abstract Map<QName, ChoiceSchemaNode> mapChildElementsFromChoices(S schema);
/**
*
*/
protected abstract NodeParserDispatcher<E> getDispatcher();
+ /**
+ * can return null only if you override ParsingStrategy and explicitely return null
+ * @param elements
+ * @param schema
+ * @return
+ */
+ @Nullable
@Override
- public N parse(Iterable<E> elements, S schema) {
+ public N parse(final Iterable<E> elements, final S schema) {
checkAtLeastOneNode(schema, elements);
- DataContainerNodeBuilder<?, N> containerBuilder = getBuilder(schema);
+ DataContainerNodeBuilder<P, N> containerBuilder = getBuilder(schema);
// Map child nodes to QName
LinkedListMultimap<QName, E> mappedChildElements = mapChildElements(elements);
LinkedListMultimap<AugmentationSchema, E> augmentsToElements = LinkedListMultimap.create();
// Map child nodes from choices
- Map<QName, ChoiceNode> mappedChoiceChildNodes = mapChildElementsFromChoices(schema);
- LinkedListMultimap<ChoiceNode, E> choicesToElements = LinkedListMultimap.create();
+ Map<QName, ChoiceSchemaNode> mappedChoiceChildNodes = mapChildElementsFromChoices(schema);
+ LinkedListMultimap<ChoiceSchemaNode, E> choicesToElements = LinkedListMultimap.create();
+
+ Map<QName, String> attributes = getAttributes(elements.iterator().next());
+ if (containerBuilder instanceof AttributesBuilder) {
+ final int size = Iterables.size(elements);
+ Preconditions.checkArgument(size == 1, "Unexpected number of elements: %s, should be 1 for: %s",
+ size, schema);
+ ((AttributesBuilder<?>) containerBuilder).withAttributes(attributes);
+ }
+
+ //parse keys first
+ if (schema instanceof ListSchemaNode) {
+ for (QName qname : ((ListSchemaNode) schema).getKeyDefinition()) {
+ if(mappedChildElements.get(qname.withoutRevision()).isEmpty()) {
+ continue;
+ }
+
+ DataSchemaNode childSchema = getSchemaForChild(schema, qname);
+ List<E> childrenForQName = mappedChildElements.removeAll(qname.withoutRevision());
+
+
+ DataContainerChild<? extends YangInstanceIdentifier.PathArgument, ?> optionalChildNode = getDispatcher()
+ .dispatchChildElement(childSchema, childrenForQName);
+ if (optionalChildNode != null) {
+ containerBuilder.withChild(optionalChildNode);
+ }
+ }
+ }
+
+ //stage attribues for strategy before going deeper in the recursion
+ buildingStrategy.prepareAttributes(attributes, containerBuilder);
// process Child nodes
for (QName childPartialQName : mappedChildElements.keySet()) {
DataSchemaNode childSchema = getSchemaForChild(schema, childPartialQName);
+ //with strict parsing an exception would be already thrown, with nonstrict we want to ignore this node
+ if (childSchema == null) {
+ continue;
+ }
List<E> childrenForQName = mappedChildElements.get(childPartialQName);
// Augment
augmentsToElements.putAll(augmentationSchema, childrenForQName);
// Choices
} else if (isMarkedAs(mappedChoiceChildNodes, childSchema.getQName())) {
- ChoiceNode choiceSchema = mappedChoiceChildNodes.get(childSchema.getQName());
+ ChoiceSchemaNode choiceSchema = mappedChoiceChildNodes.get(childSchema.getQName());
choicesToElements.putAll(choiceSchema, childrenForQName);
// Regular child nodes
} else {
- DataContainerChild<? extends InstanceIdentifier.PathArgument, ?> builtChildNode = getDispatcher()
+ DataContainerChild<? extends YangInstanceIdentifier.PathArgument, ?> optionalChildNode = getDispatcher()
.dispatchChildElement(childSchema, childrenForQName);
- containerBuilder.withChild(builtChildNode);
+ if (optionalChildNode != null) {
+ containerBuilder.withChild(optionalChildNode);
+ }
}
}
// TODO ordering is not preserved for choice and augment elements
- for (ChoiceNode choiceSchema : choicesToElements.keySet()) {
- containerBuilder.withChild(getDispatcher().dispatchChildElement(choiceSchema,
- choicesToElements.get(choiceSchema)));
+ for (ChoiceSchemaNode choiceSchema : choicesToElements.keySet()) {
+ DataContainerChild<? extends YangInstanceIdentifier.PathArgument, ?> optionalChild = getDispatcher()
+ .dispatchChildElement(choiceSchema, choicesToElements.get(choiceSchema));
+ if (optionalChild != null) {
+ containerBuilder.withChild(optionalChild);
+ }
}
for (AugmentationSchema augmentSchema : augmentsToElements.keySet()) {
Set<DataSchemaNode> realChildSchemas = getRealSchemasForAugment(schema, augmentSchema);
- AugmentationSchemaProxy augSchemaProxy = new AugmentationSchemaProxy(augmentSchema, realChildSchemas);
- containerBuilder.withChild(getDispatcher().dispatchChildElement(augSchemaProxy, augmentsToElements.get(augmentSchema)));
+ EffectiveAugmentationSchema augSchemaProxy = new EffectiveAugmentationSchema(augmentSchema, realChildSchemas);
+ DataContainerChild<? extends YangInstanceIdentifier.PathArgument, ?> optionalChild = getDispatcher()
+ .dispatchChildElement(augSchemaProxy, augmentsToElements.get(augmentSchema));
+ if (optionalChild != null) {
+ containerBuilder.withChild(optionalChild);
+ }
}
- if (containerBuilder instanceof AttributesBuilder) {
- final int size = Iterables.size(elements);
- Preconditions.checkArgument(size == 1, "Unexpected number of elements: %s, should be 1 for: %s",
- size, schema);
- ((AttributesBuilder<?>) containerBuilder).withAttributes(getAttributes(elements.iterator().next()));
- }
+ return buildingStrategy.build(containerBuilder);
+ }
- return containerBuilder.build();
+ @Override
+ public BuildingStrategy<P, N> getBuildingStrategy() {
+ return buildingStrategy;
}
- protected Map<QName, String> getAttributes(E e) {
+ protected Map<QName, String> getAttributes(final E e) {
return Collections.emptyMap();
}
- private boolean isMarkedAs(Map<QName, ?> mappedAugmentChildNodes, QName qName) {
+ protected boolean strictParsing() {
+ return true;
+ }
+
+ private static boolean isMarkedAs(final Map<QName, ?> mappedAugmentChildNodes, final QName qName) {
return mappedAugmentChildNodes.containsKey(qName);
}
- protected void checkOnlyOneNode(S schema, Iterable<E> childNodes) {
+ protected void checkOnlyOneNode(final S schema, final Iterable<E> childNodes) {
final int size = Iterables.size(childNodes);
Preconditions.checkArgument(size == 1,
"Node detected multiple times, should be 1, identified by: %s, found: %s", schema, childNodes);
}
- private void checkAtLeastOneNode(S schema, Iterable<E> childNodes) {
- Preconditions.checkArgument(Iterables.isEmpty(childNodes) == false,
+ private void checkAtLeastOneNode(final S schema, final Iterable<E> childNodes) {
+ Preconditions.checkArgument(!Iterables.isEmpty(childNodes),
"Node detected 0 times, should be at least 1, identified by: %s, found: %s", schema, childNodes);
}
+
+ public static class SimpleBuildingStrategy<P extends YangInstanceIdentifier.PathArgument, N extends DataContainerNode<P>> implements BuildingStrategy<P, N> {
+ @Override
+ public N build(final NormalizedNodeBuilder<P, ?, N> builder) {
+ return builder.build();
+ }
+
+ @Override
+ public void prepareAttributes(final Map<QName, String> attributes, final NormalizedNodeBuilder<P, ?, N> containerBuilder) {
+ // NOOP
+ }
+ }
}