Rename ChoiceCaseNode to CaseSchemaNode
[yangtools.git] / yang / yang-data-util / src / main / java / org / opendaylight / yangtools / yang / data / util / DataSchemaContextNode.java
1 /*
2  * Copyright (c) 2015 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.yangtools.yang.data.util;
9
10 import com.google.common.collect.FluentIterable;
11 import com.google.common.collect.ImmutableSet;
12 import java.util.Collections;
13 import java.util.HashSet;
14 import java.util.List;
15 import java.util.Set;
16 import javax.annotation.Nullable;
17 import org.opendaylight.yangtools.concepts.Identifiable;
18 import org.opendaylight.yangtools.yang.common.QName;
19 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
20 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
21 import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
22 import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode;
23 import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
24 import org.opendaylight.yangtools.yang.model.api.CaseSchemaNode;
25 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
26 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
27 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
28 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
29 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
30 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
31 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
32 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
33 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
34 import org.opendaylight.yangtools.yang.model.util.EffectiveAugmentationSchema;
35
36 /**
37  * Schema derived data providing necessary information for mapping
38  * between {@link org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode}
39  * and serialization format defined in RFC6020, since the mapping
40  * is not one-to-one.
41  *
42  * @param <T> Path Argument type
43  *
44  */
45 public abstract class DataSchemaContextNode<T extends PathArgument> implements Identifiable<T> {
46
47     private final T identifier;
48     private final DataSchemaNode dataSchemaNode;
49
50     @Override
51     public T getIdentifier() {
52         return identifier;
53     }
54
55     protected DataSchemaContextNode(final T identifier, final SchemaNode schema) {
56         this.identifier = identifier;
57         if (schema instanceof DataSchemaNode) {
58             this.dataSchemaNode = (DataSchemaNode) schema;
59         } else {
60             this.dataSchemaNode = null;
61         }
62     }
63
64     public boolean isMixin() {
65         return false;
66     }
67
68     public boolean isKeyedEntry() {
69         return false;
70     }
71
72     protected Set<QName> getQNameIdentifiers() {
73         return Collections.singleton(identifier.getNodeType());
74     }
75
76     @Nullable public abstract DataSchemaContextNode<?> getChild(PathArgument child);
77
78     @Nullable public abstract DataSchemaContextNode<?> getChild(QName child);
79
80     public abstract boolean isLeaf();
81
82
83     @Nullable public DataSchemaNode getDataSchemaNode() {
84         return dataSchemaNode;
85     }
86
87     static DataSchemaNode findChildSchemaNode(final DataNodeContainer parent, final QName child) {
88         DataSchemaNode potential = parent.getDataChildByName(child);
89         if (potential == null) {
90             Iterable<ChoiceSchemaNode> choices = FluentIterable.from(
91                     parent.getChildNodes()).filter(ChoiceSchemaNode.class);
92             potential = findChoice(choices, child);
93         }
94         return potential;
95     }
96
97     static DataSchemaContextNode<?> fromSchemaAndQNameChecked(final DataNodeContainer schema, final QName child) {
98         DataSchemaNode result = findChildSchemaNode(schema, child);
99         // We try to look up if this node was added by augmentation
100         if (result != null && schema instanceof DataSchemaNode && result.isAugmenting()) {
101             return fromAugmentation(schema, (AugmentationTarget) schema, result);
102         }
103         return fromDataSchemaNode(result);
104     }
105
106     // FIXME: this looks like it should be a Predicate on a stream with findFirst()
107     private static ChoiceSchemaNode findChoice(final Iterable<ChoiceSchemaNode> choices, final QName child) {
108         for (ChoiceSchemaNode choice : choices) {
109             // FIXME: this looks weird: what are we looking for again?
110             for (CaseSchemaNode caze : choice.getCases().values()) {
111                 if (findChildSchemaNode(caze, child) != null) {
112                     return choice;
113                 }
114             }
115         }
116         return null;
117     }
118
119     public static AugmentationIdentifier augmentationIdentifierFrom(final AugmentationSchemaNode augmentation) {
120         ImmutableSet.Builder<QName> potentialChildren = ImmutableSet.builder();
121         for (DataSchemaNode child : augmentation.getChildNodes()) {
122             potentialChildren.add(child.getQName());
123         }
124         return new AugmentationIdentifier(potentialChildren.build());
125     }
126
127     static DataNodeContainer augmentationProxy(final AugmentationSchemaNode augmentation,
128             final DataNodeContainer schema) {
129         Set<DataSchemaNode> children = new HashSet<>();
130         for (DataSchemaNode augNode : augmentation.getChildNodes()) {
131             children.add(schema.getDataChildByName(augNode.getQName()));
132         }
133         return new EffectiveAugmentationSchema(augmentation, children);
134     }
135
136     /**
137      * Returns a DataContextNodeOperation for provided child node
138      *
139      * <p>
140      * If supplied child is added by Augmentation this operation returns a
141      * DataContextNodeOperation for augmentation, otherwise returns a
142      * DataContextNodeOperation for child as call for
143      * {@link #fromDataSchemaNode(DataSchemaNode)}.
144      */
145     @Nullable static DataSchemaContextNode<?> fromAugmentation(final DataNodeContainer parent,
146             final AugmentationTarget parentAug, final DataSchemaNode child) {
147         AugmentationSchemaNode augmentation = null;
148         for (AugmentationSchemaNode aug : parentAug.getAvailableAugmentations()) {
149             DataSchemaNode potential = aug.getDataChildByName(child.getQName());
150             if (potential != null) {
151                 augmentation = aug;
152                 break;
153             }
154         }
155         if (augmentation != null) {
156             return new AugmentationContextNode(augmentation, parent);
157         }
158         return fromDataSchemaNode(child);
159     }
160
161     @Nullable public static DataSchemaContextNode<?> fromDataSchemaNode(final DataSchemaNode potential) {
162         if (potential instanceof ContainerSchemaNode) {
163             return new ContainerContextNode((ContainerSchemaNode) potential);
164         } else if (potential instanceof ListSchemaNode) {
165             return fromListSchemaNode((ListSchemaNode) potential);
166         } else if (potential instanceof LeafSchemaNode) {
167             return new LeafContextNode((LeafSchemaNode) potential);
168         } else if (potential instanceof ChoiceSchemaNode) {
169             return new ChoiceNodeContextNode((ChoiceSchemaNode) potential);
170         } else if (potential instanceof LeafListSchemaNode) {
171             return fromLeafListSchemaNode((LeafListSchemaNode) potential);
172         } else if (potential instanceof AnyXmlSchemaNode) {
173             return new AnyXmlContextNode((AnyXmlSchemaNode) potential);
174         }
175         return null;
176     }
177
178     private static DataSchemaContextNode<?> fromListSchemaNode(final ListSchemaNode potential) {
179         List<QName> keyDefinition = potential.getKeyDefinition();
180         if (keyDefinition == null || keyDefinition.isEmpty()) {
181             return new UnkeyedListMixinContextNode(potential);
182         }
183         if (potential.isUserOrdered()) {
184             return new OrderedMapMixinContextNode(potential);
185         }
186         return new UnorderedMapMixinContextNode(potential);
187     }
188
189     private static DataSchemaContextNode<?> fromLeafListSchemaNode(final LeafListSchemaNode potential) {
190         if (potential.isUserOrdered()) {
191             return new OrderedLeafListMixinContextNode(potential);
192         }
193         return new UnorderedLeafListMixinContextNode(potential);
194     }
195
196     public static DataSchemaContextNode<?> from(final SchemaContext ctx) {
197         return new ContainerContextNode(ctx);
198     }
199 }