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.List;
14 import org.opendaylight.yangtools.yang.common.QName;
15 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
16 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
17 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
18 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
19 import org.opendaylight.yangtools.yang.data.impl.schema.transform.ToNormalizedNodeParser;
20 import org.opendaylight.yangtools.yang.data.impl.schema.transform.base.AugmentationSchemaProxy;
21 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
22 import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
23 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
25 import com.google.common.base.Preconditions;
26 import com.google.common.collect.Iterables;
27 import com.google.common.collect.LinkedListMultimap;
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> element, S schema) {
94 checkAtLeastOneNode(schema, element);
96 DataContainerNodeBuilder<?, N> containerBuilder = getBuilder(schema);
98 // Map child nodes to QName
99 LinkedListMultimap<QName, E> mappedChildElements = mapChildElements(element);
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 InstanceIdentifier.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 return containerBuilder.build();
145 private boolean isMarkedAs(Map<QName, ?> mappedAugmentChildNodes, QName qName) {
146 return mappedAugmentChildNodes.containsKey(qName);
149 protected void checkOnlyOneNode(S schema, Iterable<E> childNodes) {
150 final int size = Iterables.size(childNodes);
151 Preconditions.checkArgument(size == 1,
152 "Node detected multiple times, should be 1, identified by: %s, found: %s", schema, childNodes);
155 private void checkAtLeastOneNode(S schema, Iterable<E> childNodes) {
156 Preconditions.checkArgument(Iterables.isEmpty(childNodes) == false,
157 "Node detected 0 times, should be at least 1, identified by: %s, found: %s", schema, childNodes);