2 * Copyright (c) 2014 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.netconf.sal.restconf.impl;
10 import com.google.common.collect.ImmutableMap;
11 import com.google.common.collect.ImmutableSet;
12 import com.google.common.collect.Iterables;
13 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
14 import java.util.Collections;
15 import java.util.HashSet;
18 import java.util.concurrent.ConcurrentHashMap;
19 import org.eclipse.jdt.annotation.Nullable;
20 import org.opendaylight.yangtools.concepts.Identifiable;
21 import org.opendaylight.yangtools.yang.common.Empty;
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.model.api.AnyxmlSchemaNode;
29 import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode;
30 import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
31 import org.opendaylight.yangtools.yang.model.api.CaseSchemaNode;
32 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
33 import org.opendaylight.yangtools.yang.model.api.ContainerLike;
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.EffectiveModelContext;
38 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
39 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
40 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
41 import org.opendaylight.yangtools.yang.model.util.EffectiveAugmentationSchema;
43 abstract class DataNormalizationOperation<T extends PathArgument> implements Identifiable<T> {
44 private final T identifier;
47 public T getIdentifier() {
51 DataNormalizationOperation(final T identifier) {
52 this.identifier = identifier;
55 static DataNormalizationOperation<?> from(final EffectiveModelContext ctx) {
56 return new ContainerNormalization(ctx);
63 Set<QName> getQNameIdentifiers() {
64 return Collections.singleton(identifier.getNodeType());
67 abstract DataNormalizationOperation<?> getChild(PathArgument child) throws DataNormalizationException;
69 abstract DataNormalizationOperation<?> getChild(QName child) throws DataNormalizationException;
71 private abstract static class SimpleTypeNormalization<T extends PathArgument>
72 extends DataNormalizationOperation<T> {
73 SimpleTypeNormalization(final T identifier) {
78 final DataNormalizationOperation<?> getChild(final PathArgument child) {
83 final DataNormalizationOperation<?> getChild(final QName child) {
88 private static final class LeafNormalization extends SimpleTypeNormalization<NodeIdentifier> {
89 LeafNormalization(final LeafSchemaNode potential) {
90 super(new NodeIdentifier(potential.getQName()));
94 private static final class LeafListEntryNormalization extends SimpleTypeNormalization<NodeWithValue> {
95 LeafListEntryNormalization(final LeafListSchemaNode potential) {
96 super(new NodeWithValue<>(potential.getQName(), Empty.value()));
100 private abstract static class DataContainerNormalizationOperation<T extends PathArgument>
101 extends DataNormalizationOperation<T> {
102 private final DataNodeContainer schema;
103 private final Map<QName, DataNormalizationOperation<?>> byQName;
104 private final Map<PathArgument, DataNormalizationOperation<?>> byArg;
106 DataContainerNormalizationOperation(final T identifier, final DataNodeContainer schema) {
108 this.schema = schema;
109 this.byArg = new ConcurrentHashMap<>();
110 this.byQName = new ConcurrentHashMap<>();
114 DataNormalizationOperation<?> getChild(final PathArgument child) throws DataNormalizationException {
115 DataNormalizationOperation<?> potential = byArg.get(child);
116 if (potential != null) {
119 potential = fromLocalSchema(child);
120 return register(potential);
124 DataNormalizationOperation<?> getChild(final QName child) throws DataNormalizationException {
125 DataNormalizationOperation<?> potential = byQName.get(child);
126 if (potential != null) {
129 potential = fromLocalSchemaAndQName(schema, child);
130 return register(potential);
133 private DataNormalizationOperation<?> fromLocalSchema(final PathArgument child)
134 throws DataNormalizationException {
135 if (child instanceof AugmentationIdentifier) {
136 return fromSchemaAndQNameChecked(schema, ((AugmentationIdentifier) child).getPossibleChildNames()
139 return fromSchemaAndQNameChecked(schema, child.getNodeType());
142 DataNormalizationOperation<?> fromLocalSchemaAndQName(final DataNodeContainer schema2,
143 final QName child) throws DataNormalizationException {
144 return fromSchemaAndQNameChecked(schema2, child);
147 private DataNormalizationOperation<?> register(final DataNormalizationOperation<?> potential) {
148 if (potential != null) {
149 byArg.put(potential.getIdentifier(), potential);
150 for (final QName qname : potential.getQNameIdentifiers()) {
151 byQName.put(qname, potential);
157 private static DataNormalizationOperation<?> fromSchemaAndQNameChecked(final DataNodeContainer schema,
158 final QName child) throws DataNormalizationException {
160 final DataSchemaNode result = findChildSchemaNode(schema, child);
161 if (result == null) {
162 throw new DataNormalizationException(String.format(
163 "Supplied QName %s is not valid according to schema %s, potential children nodes: %s", child,
164 schema,schema.getChildNodes()));
167 // We try to look up if this node was added by augmentation
168 if (schema instanceof DataSchemaNode && result.isAugmenting()) {
169 return fromAugmentation(schema, (AugmentationTarget) schema, result);
171 return fromDataSchemaNode(result);
175 private static final class ListItemNormalization extends
176 DataContainerNormalizationOperation<NodeIdentifierWithPredicates> {
177 ListItemNormalization(final NodeIdentifierWithPredicates identifier, final ListSchemaNode schema) {
178 super(identifier, schema);
182 private static final class UnkeyedListItemNormalization
183 extends DataContainerNormalizationOperation<NodeIdentifier> {
184 UnkeyedListItemNormalization(final ListSchemaNode schema) {
185 super(new NodeIdentifier(schema.getQName()), schema);
189 private static final class ContainerNormalization extends DataContainerNormalizationOperation<NodeIdentifier> {
190 ContainerNormalization(final ContainerLike schema) {
191 super(new NodeIdentifier(schema.getQName()), schema);
195 private abstract static class MixinNormalizationOp<T extends PathArgument> extends DataNormalizationOperation<T> {
196 MixinNormalizationOp(final T identifier) {
201 final boolean isMixin() {
206 private static final class LeafListMixinNormalization extends MixinNormalizationOp<NodeIdentifier> {
207 private final DataNormalizationOperation<?> innerOp;
209 LeafListMixinNormalization(final LeafListSchemaNode potential) {
210 super(new NodeIdentifier(potential.getQName()));
211 innerOp = new LeafListEntryNormalization(potential);
215 DataNormalizationOperation<?> getChild(final PathArgument child) {
216 if (child instanceof NodeWithValue) {
223 DataNormalizationOperation<?> getChild(final QName child) {
224 if (getIdentifier().getNodeType().equals(child)) {
231 private static final class AugmentationNormalization
232 extends DataContainerNormalizationOperation<AugmentationIdentifier> {
234 AugmentationNormalization(final AugmentationSchemaNode augmentation, final DataNodeContainer schema) {
235 super(augmentationIdentifierFrom(augmentation), augmentationProxy(augmentation,schema));
238 private static DataNodeContainer augmentationProxy(final AugmentationSchemaNode augmentation,
239 final DataNodeContainer schema) {
240 final Set<DataSchemaNode> children = new HashSet<>();
241 for (final DataSchemaNode augNode : augmentation.getChildNodes()) {
242 children.add(schema.getDataChildByName(augNode.getQName()));
244 return new EffectiveAugmentationSchema(augmentation, children);
253 DataNormalizationOperation<?> fromLocalSchemaAndQName(final DataNodeContainer schema, final QName child) {
254 final DataSchemaNode result = findChildSchemaNode(schema, child);
255 if (result == null) {
259 // We try to look up if this node was added by augmentation
260 if (schema instanceof DataSchemaNode && result.isAugmenting()) {
261 return fromAugmentation(schema, (AugmentationTarget) schema, result);
263 return fromDataSchemaNode(result);
267 Set<QName> getQNameIdentifiers() {
268 return getIdentifier().getPossibleChildNames();
271 private static AugmentationIdentifier augmentationIdentifierFrom(final AugmentationSchemaNode augmentation) {
272 final ImmutableSet.Builder<QName> potentialChildren = ImmutableSet.builder();
273 for (final DataSchemaNode child : augmentation.getChildNodes()) {
274 potentialChildren.add(child.getQName());
276 return new AugmentationIdentifier(potentialChildren.build());
280 private static final class MapMixinNormalization extends MixinNormalizationOp<NodeIdentifier> {
281 private final ListItemNormalization innerNode;
283 MapMixinNormalization(final ListSchemaNode list) {
284 super(new NodeIdentifier(list.getQName()));
285 this.innerNode = new ListItemNormalization(NodeIdentifierWithPredicates.of(list.getQName(),
286 Collections.<QName, Object>emptyMap()), list);
290 DataNormalizationOperation<?> getChild(final PathArgument child) {
291 if (child.getNodeType().equals(getIdentifier().getNodeType())) {
298 DataNormalizationOperation<?> getChild(final QName child) {
299 if (getIdentifier().getNodeType().equals(child)) {
306 private static final class UnkeyedListMixinNormalization extends MixinNormalizationOp<NodeIdentifier> {
307 private final UnkeyedListItemNormalization innerNode;
309 UnkeyedListMixinNormalization(final ListSchemaNode list) {
310 super(new NodeIdentifier(list.getQName()));
311 this.innerNode = new UnkeyedListItemNormalization(list);
315 DataNormalizationOperation<?> getChild(final PathArgument child) {
316 if (child.getNodeType().equals(getIdentifier().getNodeType())) {
323 DataNormalizationOperation<?> getChild(final QName child) {
324 if (getIdentifier().getNodeType().equals(child)) {
331 private static final class ChoiceNodeNormalization extends MixinNormalizationOp<NodeIdentifier> {
332 private final ImmutableMap<QName, DataNormalizationOperation<?>> byQName;
333 private final ImmutableMap<PathArgument, DataNormalizationOperation<?>> byArg;
335 ChoiceNodeNormalization(final ChoiceSchemaNode schema) {
336 super(new NodeIdentifier(schema.getQName()));
337 final ImmutableMap.Builder<QName, DataNormalizationOperation<?>> byQNameBuilder = ImmutableMap.builder();
338 final ImmutableMap.Builder<PathArgument, DataNormalizationOperation<?>> byArgBuilder =
339 ImmutableMap.builder();
341 for (final CaseSchemaNode caze : schema.getCases()) {
342 for (final DataSchemaNode cazeChild : caze.getChildNodes()) {
343 final DataNormalizationOperation<?> childOp = fromDataSchemaNode(cazeChild);
344 byArgBuilder.put(childOp.getIdentifier(), childOp);
345 for (final QName qname : childOp.getQNameIdentifiers()) {
346 byQNameBuilder.put(qname, childOp);
350 byQName = byQNameBuilder.build();
351 byArg = byArgBuilder.build();
355 DataNormalizationOperation<?> getChild(final PathArgument child) {
356 return byArg.get(child);
360 DataNormalizationOperation<?> getChild(final QName child) {
361 return byQName.get(child);
365 private static final class AnyxmlNormalization extends SimpleTypeNormalization<NodeIdentifier> {
366 AnyxmlNormalization(final AnyxmlSchemaNode schema) {
367 super(new NodeIdentifier(schema.getQName()));
371 private static @Nullable DataSchemaNode findChildSchemaNode(final DataNodeContainer parent, final QName child) {
372 final DataSchemaNode potential = parent.dataChildByName(child);
373 return potential != null ? potential : findChoice(parent, child);
376 private static @Nullable ChoiceSchemaNode findChoice(final DataNodeContainer parent, final QName child) {
377 for (final ChoiceSchemaNode choice : Iterables.filter(parent.getChildNodes(), ChoiceSchemaNode.class)) {
378 for (final CaseSchemaNode caze : choice.getCases()) {
379 if (findChildSchemaNode(caze, child) != null) {
388 * Returns a DataNormalizationOperation for provided child node.
391 * If supplied child is added by Augmentation this operation returns
392 * a DataNormalizationOperation for augmentation,
393 * otherwise returns a DataNormalizationOperation for child as
394 * call for {@link #fromDataSchemaNode(DataSchemaNode)}.
396 @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
397 justification = "https://github.com/spotbugs/spotbugs/issues/811")
398 private static DataNormalizationOperation<?> fromAugmentation(final DataNodeContainer parent,
399 final AugmentationTarget parentAug, final DataSchemaNode child) {
400 for (final AugmentationSchemaNode aug : parentAug.getAvailableAugmentations()) {
401 if (aug.dataChildByName(child.getQName()) != null) {
402 return new AugmentationNormalization(aug, parent);
405 return fromDataSchemaNode(child);
408 static DataNormalizationOperation<?> fromDataSchemaNode(final DataSchemaNode potential) {
409 if (potential instanceof ContainerSchemaNode) {
410 return new ContainerNormalization((ContainerSchemaNode) potential);
411 } else if (potential instanceof ListSchemaNode) {
412 return fromListSchemaNode((ListSchemaNode) potential);
413 } else if (potential instanceof LeafSchemaNode) {
414 return new LeafNormalization((LeafSchemaNode) potential);
415 } else if (potential instanceof ChoiceSchemaNode) {
416 return new ChoiceNodeNormalization((ChoiceSchemaNode) potential);
417 } else if (potential instanceof LeafListSchemaNode) {
418 return new LeafListMixinNormalization((LeafListSchemaNode) potential);
419 } else if (potential instanceof AnyxmlSchemaNode) {
420 return new AnyxmlNormalization((AnyxmlSchemaNode) potential);
425 private static DataNormalizationOperation<?> fromListSchemaNode(final ListSchemaNode potential) {
426 if (potential.getKeyDefinition().isEmpty()) {
427 return new UnkeyedListMixinNormalization(potential);
429 return new MapMixinNormalization(potential);