ca344aa578794a3033575914916502c5474027fa
[controller.git] / opendaylight / md-sal / sal-common-impl / src / main / java / org / opendaylight / controller / md / sal / common / impl / util / compat / DataNormalizationOperation.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.controller.md.sal.common.impl.util.compat;
9
10 import com.google.common.base.Optional;
11 import com.google.common.collect.FluentIterable;
12 import com.google.common.collect.ImmutableMap;
13 import com.google.common.collect.ImmutableSet;
14 import java.util.Collections;
15 import java.util.HashSet;
16 import java.util.List;
17 import java.util.Map;
18 import java.util.Map.Entry;
19 import java.util.Set;
20 import java.util.concurrent.ConcurrentHashMap;
21 import org.opendaylight.yangtools.concepts.Identifiable;
22 import org.opendaylight.yangtools.yang.common.QName;
23 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
24 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
25 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
26 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
27 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
28 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
29 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
30 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
31 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
32 import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
33 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
34 import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
35 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
36 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
37 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
38 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
39 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
40 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
41 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
42 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
43 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
44 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
45 import org.opendaylight.yangtools.yang.model.util.EffectiveAugmentationSchema;
46
47 @Deprecated
48 public abstract class DataNormalizationOperation<T extends PathArgument> implements Identifiable<T> {
49
50     private final T identifier;
51     private final Optional<DataSchemaNode> dataSchemaNode;
52
53     @Override
54     public T getIdentifier() {
55         return identifier;
56     }
57
58     protected DataNormalizationOperation(final T identifier, final SchemaNode schema) {
59         this.identifier = identifier;
60         if(schema instanceof DataSchemaNode) {
61             this.dataSchemaNode = Optional.of((DataSchemaNode) schema);
62         } else {
63             this.dataSchemaNode = Optional.absent();
64         }
65     }
66
67     public boolean isMixin() {
68         return false;
69     }
70
71
72     public boolean isKeyedEntry() {
73         return false;
74     }
75
76     protected Set<QName> getQNameIdentifiers() {
77         return Collections.singleton(identifier.getNodeType());
78     }
79
80     public abstract DataNormalizationOperation<?> getChild(final PathArgument child) throws DataNormalizationException;
81
82     public abstract DataNormalizationOperation<?> getChild(QName child) throws DataNormalizationException;
83
84
85     public abstract boolean isLeaf();
86
87     public Optional<DataSchemaNode> getDataSchemaNode() {
88         // FIXME
89         return dataSchemaNode;
90     }
91
92     private static abstract class SimpleTypeNormalization<T extends PathArgument> extends DataNormalizationOperation<T> {
93
94         protected SimpleTypeNormalization(final T identifier, final DataSchemaNode potential) {
95             super(identifier,potential);
96         }
97
98         @Override
99         public DataNormalizationOperation<?> getChild(final PathArgument child) {
100             return null;
101         }
102
103         @Override
104         public DataNormalizationOperation<?> getChild(final QName child) {
105             return null;
106         }
107
108         @Override
109         public NormalizedNode<?, ?> createDefault(final PathArgument currentArg) {
110             return null;
111         }
112
113         @Override
114         public boolean isLeaf() {
115             return true;
116         }
117
118     }
119
120     private static final class LeafNormalization extends SimpleTypeNormalization<NodeIdentifier> {
121
122         protected LeafNormalization(final LeafSchemaNode potential) {
123             super(new NodeIdentifier(potential.getQName()),potential);
124         }
125
126     }
127
128     private static final class LeafListEntryNormalization extends SimpleTypeNormalization<NodeWithValue> {
129
130         public LeafListEntryNormalization(final LeafListSchemaNode potential) {
131             super(new NodeWithValue(potential.getQName(), null),potential);
132         }
133
134         @Override
135         public boolean isKeyedEntry() {
136             return true;
137         }
138     }
139
140     private static abstract class CompositeNodeNormalizationOperation<T extends PathArgument> extends
141     DataNormalizationOperation<T> {
142
143         protected CompositeNodeNormalizationOperation(final T identifier, final DataSchemaNode schema) {
144             super(identifier,schema);
145         }
146
147         @Override
148         public boolean isLeaf() {
149             return false;
150         }
151
152
153     }
154
155     private static abstract class DataContainerNormalizationOperation<T extends PathArgument> extends
156     CompositeNodeNormalizationOperation<T> {
157
158         private final DataNodeContainer schema;
159         private final Map<QName, DataNormalizationOperation<?>> byQName;
160         private final Map<PathArgument, DataNormalizationOperation<?>> byArg;
161
162         protected DataContainerNormalizationOperation(final T identifier, final DataNodeContainer schema, final DataSchemaNode node) {
163             super(identifier,node);
164             this.schema = schema;
165             this.byArg = new ConcurrentHashMap<>();
166             this.byQName = new ConcurrentHashMap<>();
167         }
168
169         @Override
170         public DataNormalizationOperation<?> getChild(final PathArgument child) throws DataNormalizationException {
171             DataNormalizationOperation<?> potential = byArg.get(child);
172             if (potential != null) {
173                 return potential;
174             }
175             potential = fromLocalSchema(child);
176             return register(potential);
177         }
178
179         private DataNormalizationOperation<?> fromLocalSchema(final PathArgument child) throws DataNormalizationException {
180             if (child instanceof AugmentationIdentifier) {
181                 return fromSchemaAndQNameChecked(schema, ((AugmentationIdentifier) child).getPossibleChildNames()
182                         .iterator().next());
183             }
184             return fromSchemaAndQNameChecked(schema, child.getNodeType());
185         }
186
187         @Override
188         public DataNormalizationOperation<?> getChild(final QName child) throws DataNormalizationException {
189             DataNormalizationOperation<?> potential = byQName.get(child);
190             if (potential != null) {
191                 return potential;
192             }
193             potential = fromLocalSchemaAndQName(schema, child);
194             return register(potential);
195         }
196
197         protected DataNormalizationOperation<?> fromLocalSchemaAndQName(final DataNodeContainer schema2, final QName child) throws DataNormalizationException {
198             return fromSchemaAndQNameChecked(schema2, child);
199         }
200
201         private DataNormalizationOperation<?> register(final DataNormalizationOperation<?> potential) {
202             if (potential != null) {
203                 byArg.put(potential.getIdentifier(), potential);
204                 for (final QName qName : potential.getQNameIdentifiers()) {
205                     byQName.put(qName, potential);
206                 }
207             }
208             return potential;
209         }
210
211     }
212
213     private static final class ListItemNormalization extends
214     DataContainerNormalizationOperation<NodeIdentifierWithPredicates> {
215
216         private final List<QName> keyDefinition;
217
218         protected ListItemNormalization(final NodeIdentifierWithPredicates identifier, final ListSchemaNode schema) {
219             super(identifier, schema,schema);
220             keyDefinition = schema.getKeyDefinition();
221         }
222
223         @Override
224         public NormalizedNode<?, ?> createDefault(final PathArgument currentArg) {
225             final DataContainerNodeAttrBuilder<NodeIdentifierWithPredicates, MapEntryNode> builder = Builders
226                     .mapEntryBuilder().withNodeIdentifier((NodeIdentifierWithPredicates) currentArg);
227             for (final Entry<QName, Object> keyValue : ((NodeIdentifierWithPredicates) currentArg).getKeyValues().entrySet()) {
228                 builder.addChild(Builders.leafBuilder()
229                         //
230                         .withNodeIdentifier(new NodeIdentifier(keyValue.getKey())).withValue(keyValue.getValue())
231                         .build());
232             }
233             return builder.build();
234         }
235
236
237         @Override
238         public boolean isKeyedEntry() {
239             return true;
240         }
241     }
242
243     private static final class UnkeyedListItemNormalization extends DataContainerNormalizationOperation<NodeIdentifier> {
244
245         protected UnkeyedListItemNormalization(final ListSchemaNode schema) {
246             super(new NodeIdentifier(schema.getQName()), schema,schema);
247         }
248
249         @Override
250         public NormalizedNode<?, ?> createDefault(final PathArgument currentArg) {
251             return Builders.unkeyedListEntryBuilder().withNodeIdentifier((NodeIdentifier) currentArg).build();
252         }
253
254     }
255
256     private static final class ContainerNormalization extends DataContainerNormalizationOperation<NodeIdentifier> {
257
258         protected ContainerNormalization(final ContainerSchemaNode schema) {
259             super(new NodeIdentifier(schema.getQName()),schema, schema);
260         }
261
262         @Override
263         public NormalizedNode<?, ?> createDefault(final PathArgument currentArg) {
264             return Builders.containerBuilder().withNodeIdentifier((NodeIdentifier) currentArg).build();
265         }
266
267     }
268
269     private static abstract class MixinNormalizationOp<T extends PathArgument> extends
270     CompositeNodeNormalizationOperation<T> {
271
272         protected MixinNormalizationOp(final T identifier, final DataSchemaNode schema) {
273             super(identifier,schema);
274         }
275
276         @Override
277         public final boolean isMixin() {
278             return true;
279         }
280
281     }
282
283
284     private static final class OrderedLeafListMixinNormalization extends UnorderedLeafListMixinNormalization {
285
286
287         public OrderedLeafListMixinNormalization(final LeafListSchemaNode potential) {
288             super(potential);
289         }
290
291         @Override
292         public NormalizedNode<?, ?> createDefault(final PathArgument currentArg) {
293             return Builders.orderedLeafSetBuilder().withNodeIdentifier(getIdentifier()).build();
294         }
295     }
296
297     private static class UnorderedLeafListMixinNormalization extends MixinNormalizationOp<NodeIdentifier> {
298
299         private final DataNormalizationOperation<?> innerOp;
300
301         public UnorderedLeafListMixinNormalization(final LeafListSchemaNode potential) {
302             super(new NodeIdentifier(potential.getQName()),potential);
303             innerOp = new LeafListEntryNormalization(potential);
304         }
305         @Override
306         public NormalizedNode<?, ?> createDefault(final PathArgument currentArg) {
307             return Builders.leafSetBuilder().withNodeIdentifier(getIdentifier()).build();
308         }
309
310         @Override
311         public DataNormalizationOperation<?> getChild(final PathArgument child) {
312             if (child instanceof NodeWithValue) {
313                 return innerOp;
314             }
315             return null;
316         }
317
318         @Override
319         public DataNormalizationOperation<?> getChild(final QName child) {
320             if (getIdentifier().getNodeType().equals(child)) {
321                 return innerOp;
322             }
323             return null;
324         }
325     }
326
327     private static final class AugmentationNormalization extends DataContainerNormalizationOperation<AugmentationIdentifier> {
328
329         public AugmentationNormalization(final AugmentationSchema augmentation, final DataNodeContainer schema) {
330             super(augmentationIdentifierFrom(augmentation), augmentationProxy(augmentation,schema),null);
331         }
332
333         @Override
334         public boolean isMixin() {
335             return true;
336         }
337
338
339
340         @Override
341         protected DataNormalizationOperation<?> fromLocalSchemaAndQName(final DataNodeContainer schema, final QName child)
342                 throws DataNormalizationException {
343             final Optional<DataSchemaNode> potential = findChildSchemaNode(schema, child);
344             if (!potential.isPresent()) {
345                 return null;
346             }
347
348             final DataSchemaNode result = potential.get();
349             // We try to look up if this node was added by augmentation
350             if ((schema instanceof DataSchemaNode) && result.isAugmenting()) {
351                 return fromAugmentation(schema, (AugmentationTarget) schema, result);
352             }
353             return fromDataSchemaNode(result);
354         }
355
356         @Override
357         protected Set<QName> getQNameIdentifiers() {
358             return getIdentifier().getPossibleChildNames();
359         }
360
361         @Override
362         public NormalizedNode<?, ?> createDefault(final PathArgument currentArg) {
363             return Builders.augmentationBuilder().withNodeIdentifier(getIdentifier()).build();
364         }
365
366     }
367
368     private static class UnorderedMapMixinNormalization extends MixinNormalizationOp<NodeIdentifier> {
369
370         private final ListItemNormalization innerNode;
371
372         public UnorderedMapMixinNormalization(final ListSchemaNode list) {
373             super(new NodeIdentifier(list.getQName()),list);
374             this.innerNode = new ListItemNormalization(new NodeIdentifierWithPredicates(list.getQName(),
375                     Collections.<QName, Object> emptyMap()), list);
376         }
377
378         @Override
379         public NormalizedNode<?, ?> createDefault(final PathArgument currentArg) {
380             return Builders.mapBuilder().withNodeIdentifier(getIdentifier()).build();
381         }
382
383         @Override
384         public DataNormalizationOperation<?> getChild(final PathArgument child) {
385             if (child.getNodeType().equals(getIdentifier().getNodeType())) {
386                 return innerNode;
387             }
388             return null;
389         }
390
391         @Override
392         public DataNormalizationOperation<?> getChild(final QName child) {
393             if (getIdentifier().getNodeType().equals(child)) {
394                 return innerNode;
395             }
396             return null;
397         }
398
399     }
400
401
402     private static class UnkeyedListMixinNormalization extends MixinNormalizationOp<NodeIdentifier> {
403
404         private final UnkeyedListItemNormalization innerNode;
405
406         public UnkeyedListMixinNormalization(final ListSchemaNode list) {
407             super(new NodeIdentifier(list.getQName()),list);
408             this.innerNode = new UnkeyedListItemNormalization(list);
409         }
410
411         @Override
412         public NormalizedNode<?, ?> createDefault(final PathArgument currentArg) {
413             return Builders.unkeyedListBuilder().withNodeIdentifier(getIdentifier()).build();
414         }
415
416         @Override
417         public DataNormalizationOperation<?> getChild(final PathArgument child) {
418             if (child.getNodeType().equals(getIdentifier().getNodeType())) {
419                 return innerNode;
420             }
421             return null;
422         }
423
424         @Override
425         public DataNormalizationOperation<?> getChild(final QName child) {
426             if (getIdentifier().getNodeType().equals(child)) {
427                 return innerNode;
428             }
429             return null;
430         }
431
432     }
433
434     private static final class OrderedMapMixinNormalization extends UnorderedMapMixinNormalization {
435
436         public OrderedMapMixinNormalization(final ListSchemaNode list) {
437             super(list);
438         }
439
440         @Override
441         public NormalizedNode<?, ?> createDefault(final PathArgument currentArg) {
442             return Builders.orderedMapBuilder().withNodeIdentifier(getIdentifier()).build();
443         }
444
445     }
446
447     private static class ChoiceNodeNormalization extends MixinNormalizationOp<NodeIdentifier> {
448
449         private final ImmutableMap<QName, DataNormalizationOperation<?>> byQName;
450         private final ImmutableMap<PathArgument, DataNormalizationOperation<?>> byArg;
451
452         protected ChoiceNodeNormalization(final ChoiceSchemaNode schema) {
453             super(new NodeIdentifier(schema.getQName()),schema);
454             final ImmutableMap.Builder<QName, DataNormalizationOperation<?>> byQNameBuilder = ImmutableMap.builder();
455             final ImmutableMap.Builder<PathArgument, DataNormalizationOperation<?>> byArgBuilder = ImmutableMap.builder();
456
457             for (final ChoiceCaseNode caze : schema.getCases()) {
458                 for (final DataSchemaNode cazeChild : caze.getChildNodes()) {
459                     final DataNormalizationOperation<?> childOp = fromDataSchemaNode(cazeChild);
460                     byArgBuilder.put(childOp.getIdentifier(), childOp);
461                     for (final QName qname : childOp.getQNameIdentifiers()) {
462                         byQNameBuilder.put(qname, childOp);
463                     }
464                 }
465             }
466             byQName = byQNameBuilder.build();
467             byArg = byArgBuilder.build();
468         }
469
470         @Override
471         public DataNormalizationOperation<?> getChild(final PathArgument child) {
472             return byArg.get(child);
473         }
474
475         @Override
476         public DataNormalizationOperation<?> getChild(final QName child) {
477             return byQName.get(child);
478         }
479
480         @Override
481         public NormalizedNode<?, ?> createDefault(final PathArgument currentArg) {
482             return Builders.choiceBuilder().withNodeIdentifier(getIdentifier()).build();
483         }
484     }
485
486     private static class AnyXmlNormalization extends DataNormalizationOperation<NodeIdentifier> {
487
488         protected AnyXmlNormalization( final AnyXmlSchemaNode schema) {
489             super( new NodeIdentifier(schema.getQName()), schema);
490         }
491
492         @Override
493         public DataNormalizationOperation<?> getChild( final PathArgument child ) throws DataNormalizationException {
494             return null;
495         }
496
497         @Override
498         public DataNormalizationOperation<?> getChild( final QName child ) throws DataNormalizationException {
499             return null;
500         }
501
502         @Override
503         public boolean isLeaf() {
504             return false;
505         }
506
507         @Override
508         public NormalizedNode<?, ?> createDefault( final PathArgument currentArg ) {
509             return null;
510         }
511     }
512
513     private static final Optional<DataSchemaNode> findChildSchemaNode(final DataNodeContainer parent,final QName child) {
514         DataSchemaNode potential = parent.getDataChildByName(child);
515         if (potential == null) {
516             final Iterable<ChoiceSchemaNode> choices = FluentIterable.from(parent.getChildNodes()).filter(ChoiceSchemaNode.class);
517             potential = findChoice(choices, child);
518         }
519         return Optional.fromNullable(potential);
520     }
521
522     private static DataNormalizationOperation<?> fromSchemaAndQNameChecked(final DataNodeContainer schema,
523             final QName child) throws DataNormalizationException {
524
525         final Optional<DataSchemaNode> potential = findChildSchemaNode(schema, child);
526         if (!potential.isPresent()) {
527             throw new DataNormalizationException(String.format("Supplied QName %s is not valid according to schema %s, potential children nodes: %s", child, schema,schema.getChildNodes()));
528         }
529
530         final DataSchemaNode result = potential.get();
531         // We try to look up if this node was added by augmentation
532         if ((schema instanceof DataSchemaNode) && result.isAugmenting()) {
533             return fromAugmentation(schema, (AugmentationTarget) schema, result);
534         }
535         return fromDataSchemaNode(result);
536     }
537
538     private static ChoiceSchemaNode findChoice(final Iterable<ChoiceSchemaNode> choices, final QName child) {
539         ChoiceSchemaNode foundChoice = null;
540         choiceLoop: for (final ChoiceSchemaNode choice : choices) {
541             for (final ChoiceCaseNode caze : choice.getCases()) {
542                 if (findChildSchemaNode(caze, child).isPresent()) {
543                     foundChoice = choice;
544                     break choiceLoop;
545                 }
546             }
547         }
548         return foundChoice;
549     }
550
551     public static AugmentationIdentifier augmentationIdentifierFrom(final AugmentationSchema augmentation) {
552         final ImmutableSet.Builder<QName> potentialChildren = ImmutableSet.builder();
553         for (final DataSchemaNode child : augmentation.getChildNodes()) {
554             potentialChildren.add(child.getQName());
555         }
556         return new AugmentationIdentifier(potentialChildren.build());
557     }
558
559     private static DataNodeContainer augmentationProxy(final AugmentationSchema augmentation, final DataNodeContainer schema) {
560         final Set<DataSchemaNode> children = new HashSet<>();
561         for (final DataSchemaNode augNode : augmentation.getChildNodes()) {
562             children.add(schema.getDataChildByName(augNode.getQName()));
563         }
564         return new EffectiveAugmentationSchema(augmentation, children);
565     }
566
567     /**
568      * Returns a DataNormalizationOperation for provided child node
569      *
570      * If supplied child is added by Augmentation this operation returns
571      * a DataNormalizationOperation for augmentation,
572      * otherwise returns a DataNormalizationOperation for child as
573      * call for {@link #fromDataSchemaNode(DataSchemaNode)}.
574      *
575      *
576      * @param parent
577      * @param parentAug
578      * @param child
579      * @return
580      */
581     private static DataNormalizationOperation<?> fromAugmentation(final DataNodeContainer parent,
582             final AugmentationTarget parentAug, final DataSchemaNode child) {
583         AugmentationSchema augmentation = null;
584         for (final AugmentationSchema aug : parentAug.getAvailableAugmentations()) {
585             final DataSchemaNode potential = aug.getDataChildByName(child.getQName());
586             if (potential != null) {
587                 augmentation = aug;
588                 break;
589             }
590
591         }
592         if (augmentation != null) {
593             return new AugmentationNormalization(augmentation, parent);
594         } else {
595             return fromDataSchemaNode(child);
596         }
597     }
598
599     public static DataNormalizationOperation<?> fromDataSchemaNode(final DataSchemaNode potential) {
600         if (potential instanceof ContainerSchemaNode) {
601             return new ContainerNormalization((ContainerSchemaNode) potential);
602         } else if (potential instanceof ListSchemaNode) {
603
604             return fromListSchemaNode((ListSchemaNode) potential);
605         } else if (potential instanceof LeafSchemaNode) {
606             return new LeafNormalization((LeafSchemaNode) potential);
607         } else if (potential instanceof ChoiceSchemaNode) {
608             return new ChoiceNodeNormalization((ChoiceSchemaNode) potential);
609         } else if (potential instanceof LeafListSchemaNode) {
610             return fromLeafListSchemaNode((LeafListSchemaNode) potential);
611         } else if (potential instanceof AnyXmlSchemaNode) {
612             return new AnyXmlNormalization( (AnyXmlSchemaNode) potential);
613         }
614         return null;
615     }
616
617     private static DataNormalizationOperation<?> fromListSchemaNode(final ListSchemaNode potential) {
618         final List<QName> keyDefinition = potential.getKeyDefinition();
619         if(keyDefinition == null || keyDefinition.isEmpty()) {
620             return new UnkeyedListMixinNormalization(potential);
621         }
622         if(potential.isUserOrdered()) {
623             return new OrderedMapMixinNormalization(potential);
624         }
625         return new UnorderedMapMixinNormalization(potential);
626     }
627
628     private static DataNormalizationOperation<?> fromLeafListSchemaNode(final LeafListSchemaNode potential) {
629         if(potential.isUserOrdered()) {
630             return new OrderedLeafListMixinNormalization(potential);
631         }
632         return new UnorderedLeafListMixinNormalization(potential);
633     }
634
635
636     public static DataNormalizationOperation<?> from(final SchemaContext ctx) {
637         return new ContainerNormalization(ctx);
638     }
639
640     public abstract NormalizedNode<?, ?> createDefault(PathArgument currentArg);
641 }

©2013 OpenDaylight, A Linux Foundation Collaborative Project. All Rights Reserved.
OpenDaylight is a registered trademark of The OpenDaylight Project, Inc.
Linux Foundation and OpenDaylight are registered trademarks of the Linux Foundation.
Linux is a registered trademark of Linus Torvalds.