1 package org.opendaylight.controller.md.sal.common.impl.util.compat;
3 import static com.google.common.base.Preconditions.checkArgument;
4 import static com.google.common.base.Preconditions.checkNotNull;
6 import java.util.Collections;
7 import java.util.HashSet;
10 import java.util.Map.Entry;
12 import java.util.concurrent.ConcurrentHashMap;
14 import org.opendaylight.yangtools.concepts.Identifiable;
15 import org.opendaylight.yangtools.yang.common.QName;
16 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
17 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.AugmentationIdentifier;
18 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier;
19 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates;
20 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeWithValue;
21 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
22 import org.opendaylight.yangtools.yang.data.api.Node;
23 import org.opendaylight.yangtools.yang.data.api.SimpleNode;
24 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
25 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
26 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer;
27 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
28 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
29 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
30 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeContainerBuilder;
31 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
32 import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
33 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
34 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
35 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
36 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
37 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
38 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
39 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
40 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
42 import com.google.common.collect.FluentIterable;
43 import com.google.common.collect.ImmutableMap;
44 import com.google.common.collect.ImmutableSet;
46 public abstract class DataNormalizationOperation<T extends PathArgument> implements Identifiable<T> {
48 private final T identifier;
51 public T getIdentifier() {
55 protected DataNormalizationOperation(final T identifier) {
57 this.identifier = identifier;
60 public boolean isMixin() {
65 public boolean isKeyedEntry() {
69 protected Set<QName> getQNameIdentifiers() {
70 return Collections.singleton(identifier.getNodeType());
73 public abstract DataNormalizationOperation<?> getChild(final PathArgument child);
75 public abstract DataNormalizationOperation<?> getChild(QName child);
77 public abstract NormalizedNode<?, ?> normalize(Node<?> legacyData);
79 private static abstract class SimpleTypeNormalization<T extends PathArgument> extends DataNormalizationOperation<T> {
81 protected SimpleTypeNormalization(final T identifier) {
86 public NormalizedNode<?, ?> normalize(final Node<?> legacyData) {
87 checkArgument(legacyData != null);
88 checkArgument(legacyData instanceof SimpleNode<?>);
89 return normalizeImpl((SimpleNode<?>) legacyData);
92 protected abstract NormalizedNode<?, ?> normalizeImpl(SimpleNode<?> node);
95 public DataNormalizationOperation<?> getChild(final PathArgument child) {
100 public DataNormalizationOperation<?> getChild(final QName child) {
105 public NormalizedNode<?, ?> createDefault(final PathArgument currentArg) {
106 // TODO Auto-generated method stub
112 private static final class LeafNormalization extends SimpleTypeNormalization<NodeIdentifier> {
114 protected LeafNormalization(final NodeIdentifier identifier) {
119 protected NormalizedNode<?, ?> normalizeImpl(final SimpleNode<?> node) {
120 return ImmutableNodes.leafNode(node.getNodeType(), node.getValue());
125 private static final class LeafListEntryNormalization extends SimpleTypeNormalization<NodeWithValue> {
127 public LeafListEntryNormalization(final LeafListSchemaNode potential) {
128 super(new NodeWithValue(potential.getQName(), null));
132 protected NormalizedNode<?, ?> normalizeImpl(final SimpleNode<?> node) {
133 NodeWithValue nodeId = new NodeWithValue(node.getNodeType(), node.getValue());
134 return Builders.leafSetEntryBuilder().withNodeIdentifier(nodeId).withValue(node.getValue()).build();
139 public boolean isKeyedEntry() {
144 private static abstract class CompositeNodeNormalizationOpertation<T extends PathArgument> extends
145 DataNormalizationOperation<T> {
147 protected CompositeNodeNormalizationOpertation(final T identifier) {
151 @SuppressWarnings({ "rawtypes", "unchecked" })
153 public final NormalizedNodeContainer<?, ?, ?> normalize(final Node<?> legacyData) {
154 checkArgument(legacyData != null);
155 if (!isMixin() && getIdentifier().getNodeType() != null) {
156 checkArgument(getIdentifier().getNodeType().equals(legacyData.getNodeType()),
157 "Node QName must be %s was %s", getIdentifier().getNodeType(), legacyData.getNodeType());
159 checkArgument(legacyData instanceof CompositeNode, "Node %s should be composite", legacyData);
160 CompositeNode compositeNode = (CompositeNode) legacyData;
161 NormalizedNodeContainerBuilder builder = createBuilder(compositeNode);
163 Set<DataNormalizationOperation<?>> usedMixins = new HashSet<>();
164 for (Node<?> childLegacy : compositeNode.getValue()) {
165 DataNormalizationOperation childOp = getChild(childLegacy.getNodeType());
167 // We skip unknown nodes if this node is mixin since
168 // it's nodes and parent nodes are interleaved
169 if (childOp == null && isMixin()) {
173 checkArgument(childOp != null, "Node %s is not allowed inside %s", childLegacy.getNodeType(),
175 if (childOp.isMixin()) {
176 if (usedMixins.contains(childOp)) {
177 // We already run / processed that mixin, so to avoid
179 // skiping next nodes.
182 builder.addChild(childOp.normalize(compositeNode));
183 usedMixins.add(childOp);
185 builder.addChild(childOp.normalize(childLegacy));
188 return (NormalizedNodeContainer<?, ?, ?>) builder.build();
191 @SuppressWarnings("rawtypes")
192 protected abstract NormalizedNodeContainerBuilder createBuilder(final CompositeNode compositeNode);
196 private static abstract class DataContainerNormalizationOperation<T extends PathArgument> extends
197 CompositeNodeNormalizationOpertation<T> {
199 private final DataNodeContainer schema;
200 private final Map<QName, DataNormalizationOperation<?>> byQName;
201 private final Map<PathArgument, DataNormalizationOperation<?>> byArg;
203 protected DataContainerNormalizationOperation(final T identifier, final DataNodeContainer schema) {
205 this.schema = schema;
206 this.byArg = new ConcurrentHashMap<>();
207 this.byQName = new ConcurrentHashMap<>();
211 public DataNormalizationOperation<?> getChild(final PathArgument child) {
212 DataNormalizationOperation<?> potential = byArg.get(child);
213 if (potential != null) {
216 potential = fromSchema(schema, child);
217 return register(potential);
221 public DataNormalizationOperation<?> getChild(final QName child) {
222 DataNormalizationOperation<?> potential = byQName.get(child);
223 if (potential != null) {
226 potential = fromSchemaAndPathArgument(schema, child);
227 return register(potential);
230 private DataNormalizationOperation<?> register(final DataNormalizationOperation<?> potential) {
231 if (potential != null) {
232 byArg.put(potential.getIdentifier(), potential);
233 for (QName qName : potential.getQNameIdentifiers()) {
234 byQName.put(qName, potential);
242 private static final class ListItemNormalization extends
243 DataContainerNormalizationOperation<NodeIdentifierWithPredicates> {
245 private final List<QName> keyDefinition;
247 protected ListItemNormalization(final NodeIdentifierWithPredicates identifier, final ListSchemaNode schema) {
248 super(identifier, schema);
249 keyDefinition = schema.getKeyDefinition();
253 protected NormalizedNodeContainerBuilder createBuilder(final CompositeNode compositeNode) {
254 ImmutableMap.Builder<QName, Object> keys = ImmutableMap.builder();
255 for (QName key : keyDefinition) {
257 SimpleNode<?> valueNode = checkNotNull(compositeNode.getFirstSimpleByName(key),
258 "List node %s MUST contain leaf %s with value.", getIdentifier().getNodeType(), key);
259 keys.put(key, valueNode.getValue());
262 return Builders.mapEntryBuilder().withNodeIdentifier(
263 new NodeIdentifierWithPredicates(getIdentifier().getNodeType(), keys.build()));
267 public NormalizedNode<?, ?> createDefault(final PathArgument currentArg) {
268 DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> builder = Builders
269 .mapEntryBuilder().withNodeIdentifier((NodeIdentifierWithPredicates) currentArg);
270 for (Entry<QName, Object> keyValue : ((NodeIdentifierWithPredicates) currentArg).getKeyValues().entrySet()) {
271 builder.addChild(Builders.leafBuilder()
273 .withNodeIdentifier(new NodeIdentifier(keyValue.getKey())).withValue(keyValue.getValue())
276 return builder.build();
281 public boolean isKeyedEntry() {
286 private static final class ContainerNormalization extends DataContainerNormalizationOperation<NodeIdentifier> {
288 protected ContainerNormalization(final ContainerSchemaNode schema) {
289 super(new NodeIdentifier(schema.getQName()), schema);
293 protected NormalizedNodeContainerBuilder createBuilder(final CompositeNode compositeNode) {
294 return Builders.containerBuilder().withNodeIdentifier(getIdentifier());
298 public NormalizedNode<?, ?> createDefault(final PathArgument currentArg) {
299 return Builders.containerBuilder().withNodeIdentifier((NodeIdentifier) currentArg).build();
304 private static abstract class MixinNormalizationOp<T extends PathArgument> extends
305 CompositeNodeNormalizationOpertation<T> {
307 protected MixinNormalizationOp(final T identifier) {
312 public final boolean isMixin() {
318 private static final class LeafListMixinNormalization extends MixinNormalizationOp<NodeIdentifier> {
320 private final DataNormalizationOperation<?> innerOp;
322 public LeafListMixinNormalization(final LeafListSchemaNode potential) {
323 super(new NodeIdentifier(potential.getQName()));
324 innerOp = new LeafListEntryNormalization(potential);
328 protected NormalizedNodeContainerBuilder createBuilder(final CompositeNode compositeNode) {
329 return Builders.leafSetBuilder().withNodeIdentifier(getIdentifier());
333 public NormalizedNode<?, ?> createDefault(final PathArgument currentArg) {
334 return Builders.leafSetBuilder().withNodeIdentifier(getIdentifier()).build();
338 public DataNormalizationOperation<?> getChild(final PathArgument child) {
339 if (child instanceof NodeWithValue) {
346 public DataNormalizationOperation<?> getChild(final QName child) {
347 if (getIdentifier().getNodeType().equals(child)) {
354 private static final class AugmentationNormalization extends MixinNormalizationOp<AugmentationIdentifier> {
356 private final Map<QName, DataNormalizationOperation<?>> byQName;
357 private final Map<PathArgument, DataNormalizationOperation<?>> byArg;
359 public AugmentationNormalization(final AugmentationSchema augmentation, final DataNodeContainer schema) {
360 super(augmentationIdentifierFrom(augmentation));
362 ImmutableMap.Builder<QName, DataNormalizationOperation<?>> byQNameBuilder = ImmutableMap.builder();
363 ImmutableMap.Builder<PathArgument, DataNormalizationOperation<?>> byArgBuilder = ImmutableMap.builder();
365 for (DataSchemaNode augNode : augmentation.getChildNodes()) {
366 DataSchemaNode resolvedNode = schema.getDataChildByName(augNode.getQName());
367 DataNormalizationOperation<?> resolvedOp = fromDataSchemaNode(resolvedNode);
368 byArgBuilder.put(resolvedOp.getIdentifier(), resolvedOp);
369 for (QName resQName : resolvedOp.getQNameIdentifiers()) {
370 byQNameBuilder.put(resQName, resolvedOp);
373 byQName = byQNameBuilder.build();
374 byArg = byArgBuilder.build();
379 public DataNormalizationOperation<?> getChild(final PathArgument child) {
380 return byArg.get(child);
384 public DataNormalizationOperation<?> getChild(final QName child) {
385 return byQName.get(child);
389 protected Set<QName> getQNameIdentifiers() {
390 return getIdentifier().getPossibleChildNames();
393 @SuppressWarnings("rawtypes")
395 protected NormalizedNodeContainerBuilder createBuilder(final CompositeNode compositeNode) {
396 return Builders.augmentationBuilder().withNodeIdentifier(getIdentifier());
400 public NormalizedNode<?, ?> createDefault(final PathArgument currentArg) {
401 return Builders.augmentationBuilder().withNodeIdentifier(getIdentifier()).build();
406 private static final class ListMixinNormalization extends MixinNormalizationOp<NodeIdentifier> {
408 private final ListItemNormalization innerNode;
410 public ListMixinNormalization(final ListSchemaNode list) {
411 super(new NodeIdentifier(list.getQName()));
412 this.innerNode = new ListItemNormalization(new NodeIdentifierWithPredicates(list.getQName(),
413 Collections.<QName, Object> emptyMap()), list);
416 @SuppressWarnings("rawtypes")
418 protected NormalizedNodeContainerBuilder createBuilder(final CompositeNode compositeNode) {
419 return Builders.mapBuilder().withNodeIdentifier(getIdentifier());
423 public NormalizedNode<?, ?> createDefault(final PathArgument currentArg) {
424 return Builders.mapBuilder().withNodeIdentifier(getIdentifier()).build();
428 public DataNormalizationOperation<?> getChild(final PathArgument child) {
429 if (child.getNodeType().equals(getIdentifier().getNodeType())) {
436 public DataNormalizationOperation<?> getChild(final QName child) {
437 if (getIdentifier().getNodeType().equals(child)) {
445 private static class ChoiceNodeNormalization extends MixinNormalizationOp<NodeIdentifier> {
447 private final ImmutableMap<QName, DataNormalizationOperation<?>> byQName;
448 private final ImmutableMap<PathArgument, DataNormalizationOperation<?>> byArg;
450 protected ChoiceNodeNormalization(final org.opendaylight.yangtools.yang.model.api.ChoiceNode schema) {
451 super(new NodeIdentifier(schema.getQName()));
452 ImmutableMap.Builder<QName, DataNormalizationOperation<?>> byQNameBuilder = ImmutableMap.builder();
453 ImmutableMap.Builder<PathArgument, DataNormalizationOperation<?>> byArgBuilder = ImmutableMap.builder();
455 for (ChoiceCaseNode caze : schema.getCases()) {
456 for (DataSchemaNode cazeChild : caze.getChildNodes()) {
457 DataNormalizationOperation<?> childOp = fromDataSchemaNode(cazeChild);
458 byArgBuilder.put(childOp.getIdentifier(), childOp);
459 for (QName qname : childOp.getQNameIdentifiers()) {
460 byQNameBuilder.put(qname, childOp);
464 byQName = byQNameBuilder.build();
465 byArg = byArgBuilder.build();
469 public DataNormalizationOperation<?> getChild(final PathArgument child) {
470 return byArg.get(child);
474 public DataNormalizationOperation<?> getChild(final QName child) {
475 return byQName.get(child);
479 protected NormalizedNodeContainerBuilder createBuilder(final CompositeNode compositeNode) {
480 return Builders.choiceBuilder().withNodeIdentifier(getIdentifier());
484 public NormalizedNode<?, ?> createDefault(final PathArgument currentArg) {
485 return Builders.choiceBuilder().withNodeIdentifier(getIdentifier()).build();
489 public static DataNormalizationOperation<?> fromSchemaAndPathArgument(final DataNodeContainer schema,
491 DataSchemaNode potential = schema.getDataChildByName(child);
492 if (potential == null) {
493 Iterable<org.opendaylight.yangtools.yang.model.api.ChoiceNode> choices = FluentIterable.from(
494 schema.getChildNodes()).filter(org.opendaylight.yangtools.yang.model.api.ChoiceNode.class);
495 potential = findChoice(choices, child);
497 checkArgument(potential != null, "Supplied QName %s is not valid according to schema %s", child, schema);
498 if ((schema instanceof DataSchemaNode) && !((DataSchemaNode) schema).isAugmenting() && potential.isAugmenting()) {
499 return fromAugmentation(schema, (AugmentationTarget) schema, potential);
501 return fromDataSchemaNode(potential);
504 private static org.opendaylight.yangtools.yang.model.api.ChoiceNode findChoice(
505 final Iterable<org.opendaylight.yangtools.yang.model.api.ChoiceNode> choices, final QName child) {
506 org.opendaylight.yangtools.yang.model.api.ChoiceNode foundChoice = null;
507 choiceLoop: for (org.opendaylight.yangtools.yang.model.api.ChoiceNode choice : choices) {
508 for (ChoiceCaseNode caze : choice.getCases()) {
509 if (caze.getDataChildByName(child) != null) {
510 foundChoice = choice;
518 public static AugmentationIdentifier augmentationIdentifierFrom(final AugmentationSchema augmentation) {
519 ImmutableSet.Builder<QName> potentialChildren = ImmutableSet.builder();
520 for (DataSchemaNode child : augmentation.getChildNodes()) {
521 potentialChildren.add(child.getQName());
523 return new AugmentationIdentifier(null, potentialChildren.build());
526 private static AugmentationNormalization fromAugmentation(final DataNodeContainer schema,
527 final AugmentationTarget augments, final DataSchemaNode potential) {
528 AugmentationSchema augmentation = null;
529 for (AugmentationSchema aug : augments.getAvailableAugmentations()) {
530 DataSchemaNode child = aug.getDataChildByName(potential.getQName());
537 if (augmentation != null) {
538 return new AugmentationNormalization(augmentation, schema);
544 private static DataNormalizationOperation<?> fromSchema(final DataNodeContainer schema, final PathArgument child) {
545 if (child instanceof AugmentationIdentifier) {
546 return fromSchemaAndPathArgument(schema, ((AugmentationIdentifier) child).getPossibleChildNames()
549 return fromSchemaAndPathArgument(schema, child.getNodeType());
552 public static DataNormalizationOperation<?> fromDataSchemaNode(final DataSchemaNode potential) {
553 if (potential instanceof ContainerSchemaNode) {
554 return new ContainerNormalization((ContainerSchemaNode) potential);
555 } else if (potential instanceof ListSchemaNode) {
556 return new ListMixinNormalization((ListSchemaNode) potential);
557 } else if (potential instanceof LeafSchemaNode) {
558 return new LeafNormalization(new NodeIdentifier(potential.getQName()));
559 } else if (potential instanceof org.opendaylight.yangtools.yang.model.api.ChoiceNode) {
560 return new ChoiceNodeNormalization((org.opendaylight.yangtools.yang.model.api.ChoiceNode) potential);
561 } else if (potential instanceof LeafListSchemaNode) {
562 return new LeafListMixinNormalization((LeafListSchemaNode) potential);
567 public static DataNormalizationOperation<?> from(final SchemaContext ctx) {
568 return new ContainerNormalization(ctx);
571 public abstract NormalizedNode<?, ?> createDefault(PathArgument currentArg);