2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.yangtools.yang.data.impl.schema.transform.base.parser;
10 import com.google.common.base.Preconditions;
11 import com.google.common.collect.Iterables;
12 import com.google.common.collect.LinkedListMultimap;
13 import java.util.Collections;
14 import java.util.List;
17 import org.opendaylight.yangtools.yang.common.QName;
18 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
19 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
20 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
21 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.AttributesBuilder;
22 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
23 import org.opendaylight.yangtools.yang.data.impl.schema.transform.ToNormalizedNodeParser;
24 import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.AugmentationSchemaProxy;
25 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
26 import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
27 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
30 * Abstract(base) Parser for DataContainerNodes e.g. ContainerNode, AugmentationNode.
32 public abstract class BaseDispatcherParser<E, N extends DataContainerNode<?>, S>
33 implements ToNormalizedNodeParser<E, N, S> {
38 * @return New(empty) instance of a builder to build node identified by schema.
40 protected abstract DataContainerNodeBuilder<?, N> getBuilder(S schema);
45 * @param childQName QName of a child being parsed, QName does not continue revision date
46 * @return schema object for child identified by parent schema: schema and QName childQName
48 protected abstract DataSchemaNode getSchemaForChild(S schema, QName childQName);
53 * @return map from QName to child elements. Multiple elements are allowed under QName.
55 protected abstract LinkedListMultimap<QName, E> mapChildElements(Iterable<E> xml);
60 * @return map from QName to ChoiceNode schema of child nodes that are
61 * contained within a choice statement under current schema.
63 protected abstract Map<QName, ChoiceNode> mapChildElementsFromChoices(S schema);
68 * @return map from QName to child elements that are added by augmentation
69 * that targets current schema.
71 protected abstract Map<QName, AugmentationSchema> mapChildElementsFromAugments(S schema);
76 * @param augmentSchema
77 * @return Set of real schema objects that represent child nodes of an
78 * augmentation. Augmentation schema child nodes, if further
79 * augmented, do not contain further augmented, that are crucial for
80 * parsing. The real schema object can be retrieved from parent schema: schema.
82 protected abstract Set<DataSchemaNode> getRealSchemasForAugment(S schema, AugmentationSchema augmentSchema);
86 * @return dispatcher object to dispatch parsing of child elements, might be
87 * the same instance if provided parsers are immutable.
89 protected abstract NodeParserDispatcher<E> getDispatcher();
92 public N parse(Iterable<E> elements, S schema) {
94 checkAtLeastOneNode(schema, elements);
96 DataContainerNodeBuilder<?, N> containerBuilder = getBuilder(schema);
98 // Map child nodes to QName
99 LinkedListMultimap<QName, E> mappedChildElements = mapChildElements(elements);
101 // Map child nodes from Augments
102 Map<QName, AugmentationSchema> mappedAugmentChildNodes = mapChildElementsFromAugments(schema);
103 LinkedListMultimap<AugmentationSchema, E> augmentsToElements = LinkedListMultimap.create();
105 // Map child nodes from choices
106 Map<QName, ChoiceNode> mappedChoiceChildNodes = mapChildElementsFromChoices(schema);
107 LinkedListMultimap<ChoiceNode, E> choicesToElements = LinkedListMultimap.create();
109 // process Child nodes
110 for (QName childPartialQName : mappedChildElements.keySet()) {
111 DataSchemaNode childSchema = getSchemaForChild(schema, childPartialQName);
112 List<E> childrenForQName = mappedChildElements.get(childPartialQName);
115 if (isMarkedAs(mappedAugmentChildNodes, childSchema.getQName())) {
116 AugmentationSchema augmentationSchema = mappedAugmentChildNodes.get(childSchema.getQName());
117 augmentsToElements.putAll(augmentationSchema, childrenForQName);
119 } else if (isMarkedAs(mappedChoiceChildNodes, childSchema.getQName())) {
120 ChoiceNode choiceSchema = mappedChoiceChildNodes.get(childSchema.getQName());
121 choicesToElements.putAll(choiceSchema, childrenForQName);
122 // Regular child nodes
124 DataContainerChild<? extends YangInstanceIdentifier.PathArgument, ?> builtChildNode = getDispatcher()
125 .dispatchChildElement(childSchema, childrenForQName);
126 containerBuilder.withChild(builtChildNode);
130 // TODO ordering is not preserved for choice and augment elements
131 for (ChoiceNode choiceSchema : choicesToElements.keySet()) {
132 containerBuilder.withChild(getDispatcher().dispatchChildElement(choiceSchema,
133 choicesToElements.get(choiceSchema)));
136 for (AugmentationSchema augmentSchema : augmentsToElements.keySet()) {
137 Set<DataSchemaNode> realChildSchemas = getRealSchemasForAugment(schema, augmentSchema);
138 AugmentationSchemaProxy augSchemaProxy = new AugmentationSchemaProxy(augmentSchema, realChildSchemas);
139 containerBuilder.withChild(getDispatcher().dispatchChildElement(augSchemaProxy, augmentsToElements.get(augmentSchema)));
142 if (containerBuilder instanceof AttributesBuilder) {
143 final int size = Iterables.size(elements);
144 Preconditions.checkArgument(size == 1, "Unexpected number of elements: %s, should be 1 for: %s",
146 ((AttributesBuilder<?>) containerBuilder).withAttributes(getAttributes(elements.iterator().next()));
149 return containerBuilder.build();
152 protected Map<QName, String> getAttributes(E e) {
153 return Collections.emptyMap();
156 private boolean isMarkedAs(Map<QName, ?> mappedAugmentChildNodes, QName qName) {
157 return mappedAugmentChildNodes.containsKey(qName);
160 protected void checkOnlyOneNode(S schema, Iterable<E> childNodes) {
161 final int size = Iterables.size(childNodes);
162 Preconditions.checkArgument(size == 1,
163 "Node detected multiple times, should be 1, identified by: %s, found: %s", schema, childNodes);
166 private void checkAtLeastOneNode(S schema, Iterable<E> childNodes) {
167 Preconditions.checkArgument(!Iterables.isEmpty(childNodes),
168 "Node detected 0 times, should be at least 1, identified by: %s, found: %s", schema, childNodes);