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.model.api.AugmentationSchema;
25 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
26 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
27 import org.opendaylight.yangtools.yang.model.util.EffectiveAugmentationSchema;
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, ChoiceSchemaNode> 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(final Iterable<E> elements, final 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, ChoiceSchemaNode> mappedChoiceChildNodes = mapChildElementsFromChoices(schema);
107 LinkedListMultimap<ChoiceSchemaNode, E> choicesToElements = LinkedListMultimap.create();
109 // process Child nodes
110 for (QName childPartialQName : mappedChildElements.keySet()) {
111 DataSchemaNode childSchema = getSchemaForChild(schema, childPartialQName);
112 //with strict parsing an exception would be already thrown, with nonstrict we want to ignore this node
113 if (childSchema == null) {
116 List<E> childrenForQName = mappedChildElements.get(childPartialQName);
119 if (isMarkedAs(mappedAugmentChildNodes, childSchema.getQName())) {
120 AugmentationSchema augmentationSchema = mappedAugmentChildNodes.get(childSchema.getQName());
121 augmentsToElements.putAll(augmentationSchema, childrenForQName);
123 } else if (isMarkedAs(mappedChoiceChildNodes, childSchema.getQName())) {
124 ChoiceSchemaNode choiceSchema = mappedChoiceChildNodes.get(childSchema.getQName());
125 choicesToElements.putAll(choiceSchema, childrenForQName);
126 // Regular child nodes
128 DataContainerChild<? extends YangInstanceIdentifier.PathArgument, ?> builtChildNode = getDispatcher()
129 .dispatchChildElement(childSchema, childrenForQName);
130 containerBuilder.withChild(builtChildNode);
134 // TODO ordering is not preserved for choice and augment elements
135 for (ChoiceSchemaNode choiceSchema : choicesToElements.keySet()) {
136 containerBuilder.withChild(getDispatcher().dispatchChildElement(choiceSchema,
137 choicesToElements.get(choiceSchema)));
140 for (AugmentationSchema augmentSchema : augmentsToElements.keySet()) {
141 Set<DataSchemaNode> realChildSchemas = getRealSchemasForAugment(schema, augmentSchema);
142 EffectiveAugmentationSchema augSchemaProxy = new EffectiveAugmentationSchema(augmentSchema, realChildSchemas);
143 containerBuilder.withChild(getDispatcher().dispatchChildElement(augSchemaProxy, augmentsToElements.get(augmentSchema)));
146 if (containerBuilder instanceof AttributesBuilder) {
147 final int size = Iterables.size(elements);
148 Preconditions.checkArgument(size == 1, "Unexpected number of elements: %s, should be 1 for: %s",
150 ((AttributesBuilder<?>) containerBuilder).withAttributes(getAttributes(elements.iterator().next()));
153 return containerBuilder.build();
156 protected Map<QName, String> getAttributes(final E e) {
157 return Collections.emptyMap();
160 protected boolean strictParsing() {
164 private boolean isMarkedAs(final Map<QName, ?> mappedAugmentChildNodes, final QName qName) {
165 return mappedAugmentChildNodes.containsKey(qName);
168 protected void checkOnlyOneNode(final S schema, final Iterable<E> childNodes) {
169 final int size = Iterables.size(childNodes);
170 Preconditions.checkArgument(size == 1,
171 "Node detected multiple times, should be 1, identified by: %s, found: %s", schema, childNodes);
174 private void checkAtLeastOneNode(final S schema, final Iterable<E> childNodes) {
175 Preconditions.checkArgument(!Iterables.isEmpty(childNodes),
176 "Node detected 0 times, should be at least 1, identified by: %s, found: %s", schema, childNodes);