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 java.util.Collections;
11 import java.util.List;
15 import org.opendaylight.yangtools.yang.common.QName;
16 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
17 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
18 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
19 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.AttributesBuilder;
20 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
21 import org.opendaylight.yangtools.yang.data.impl.schema.transform.ToNormalizedNodeParser;
22 import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.AugmentationSchemaProxy;
23 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
24 import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
25 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
27 import com.google.common.base.Preconditions;
28 import com.google.common.collect.Iterables;
29 import com.google.common.collect.LinkedListMultimap;
32 * Abstract(base) Parser for DataContainerNodes e.g. ContainerNode, AugmentationNode.
34 public abstract class BaseDispatcherParser<E, N extends DataContainerNode<?>, S>
35 implements ToNormalizedNodeParser<E, N, S> {
40 * @return New(empty) instance of a builder to build node identified by schema.
42 protected abstract DataContainerNodeBuilder<?, N> getBuilder(S schema);
47 * @param childQName QName of a child being parsed, QName does not continue revision date
48 * @return schema object for child identified by parent schema: schema and QName childQName
50 protected abstract DataSchemaNode getSchemaForChild(S schema, QName childQName);
55 * @return map from QName to child elements. Multiple elements are allowed under QName.
57 protected abstract LinkedListMultimap<QName, E> mapChildElements(Iterable<E> xml);
62 * @return map from QName to ChoiceNode schema of child nodes that are
63 * contained within a choice statement under current schema.
65 protected abstract Map<QName, ChoiceNode> mapChildElementsFromChoices(S schema);
70 * @return map from QName to child elements that are added by augmentation
71 * that targets current schema.
73 protected abstract Map<QName, AugmentationSchema> mapChildElementsFromAugments(S schema);
78 * @param augmentSchema
79 * @return Set of real schema objects that represent child nodes of an
80 * augmentation. Augmentation schema child nodes, if further
81 * augmented, do not contain further augmented, that are crucial for
82 * parsing. The real schema object can be retrieved from parent schema: schema.
84 protected abstract Set<DataSchemaNode> getRealSchemasForAugment(S schema, AugmentationSchema augmentSchema);
88 * @return dispatcher object to dispatch parsing of child elements, might be
89 * the same instance if provided parsers are immutable.
91 protected abstract NodeParserDispatcher<E> getDispatcher();
94 public N parse(Iterable<E> elements, S schema) {
96 checkAtLeastOneNode(schema, elements);
98 DataContainerNodeBuilder<?, N> containerBuilder = getBuilder(schema);
100 // Map child nodes to QName
101 LinkedListMultimap<QName, E> mappedChildElements = mapChildElements(elements);
103 // Map child nodes from Augments
104 Map<QName, AugmentationSchema> mappedAugmentChildNodes = mapChildElementsFromAugments(schema);
105 LinkedListMultimap<AugmentationSchema, E> augmentsToElements = LinkedListMultimap.create();
107 // Map child nodes from choices
108 Map<QName, ChoiceNode> mappedChoiceChildNodes = mapChildElementsFromChoices(schema);
109 LinkedListMultimap<ChoiceNode, E> choicesToElements = LinkedListMultimap.create();
111 // process Child nodes
112 for (QName childPartialQName : mappedChildElements.keySet()) {
113 DataSchemaNode childSchema = getSchemaForChild(schema, childPartialQName);
114 List<E> childrenForQName = mappedChildElements.get(childPartialQName);
117 if (isMarkedAs(mappedAugmentChildNodes, childSchema.getQName())) {
118 AugmentationSchema augmentationSchema = mappedAugmentChildNodes.get(childSchema.getQName());
119 augmentsToElements.putAll(augmentationSchema, childrenForQName);
121 } else if (isMarkedAs(mappedChoiceChildNodes, childSchema.getQName())) {
122 ChoiceNode choiceSchema = mappedChoiceChildNodes.get(childSchema.getQName());
123 choicesToElements.putAll(choiceSchema, childrenForQName);
124 // Regular child nodes
126 DataContainerChild<? extends YangInstanceIdentifier.PathArgument, ?> builtChildNode = getDispatcher()
127 .dispatchChildElement(childSchema, childrenForQName);
128 containerBuilder.withChild(builtChildNode);
132 // TODO ordering is not preserved for choice and augment elements
133 for (ChoiceNode choiceSchema : choicesToElements.keySet()) {
134 containerBuilder.withChild(getDispatcher().dispatchChildElement(choiceSchema,
135 choicesToElements.get(choiceSchema)));
138 for (AugmentationSchema augmentSchema : augmentsToElements.keySet()) {
139 Set<DataSchemaNode> realChildSchemas = getRealSchemasForAugment(schema, augmentSchema);
140 AugmentationSchemaProxy augSchemaProxy = new AugmentationSchemaProxy(augmentSchema, realChildSchemas);
141 containerBuilder.withChild(getDispatcher().dispatchChildElement(augSchemaProxy, augmentsToElements.get(augmentSchema)));
144 if (containerBuilder instanceof AttributesBuilder) {
145 final int size = Iterables.size(elements);
146 Preconditions.checkArgument(size == 1, "Unexpected number of elements: %s, should be 1 for: %s",
148 ((AttributesBuilder<?>) containerBuilder).withAttributes(getAttributes(elements.iterator().next()));
151 return containerBuilder.build();
154 protected Map<QName, String> getAttributes(E e) {
155 return Collections.emptyMap();
158 private boolean isMarkedAs(Map<QName, ?> mappedAugmentChildNodes, QName qName) {
159 return mappedAugmentChildNodes.containsKey(qName);
162 protected void checkOnlyOneNode(S schema, Iterable<E> childNodes) {
163 final int size = Iterables.size(childNodes);
164 Preconditions.checkArgument(size == 1,
165 "Node detected multiple times, should be 1, identified by: %s, found: %s", schema, childNodes);
168 private void checkAtLeastOneNode(S schema, Iterable<E> childNodes) {
169 Preconditions.checkArgument(Iterables.isEmpty(childNodes) == false,
170 "Node detected 0 times, should be at least 1, identified by: %s, found: %s", schema, childNodes);