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.QName;
22 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
23 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
24 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
25 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
26 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
27 import org.opendaylight.yangtools.yang.model.api.AnyxmlSchemaNode;
28 import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode;
29 import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
30 import org.opendaylight.yangtools.yang.model.api.CaseSchemaNode;
31 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
32 import org.opendaylight.yangtools.yang.model.api.ContainerLike;
33 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
34 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
35 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
36 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
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.util.EffectiveAugmentationSchema;
42 abstract class DataNormalizationOperation<T extends PathArgument> implements Identifiable<T> {
43 private final T identifier;
46 public T getIdentifier() {
50 DataNormalizationOperation(final T identifier) {
51 this.identifier = identifier;
54 static DataNormalizationOperation<?> from(final EffectiveModelContext ctx) {
55 return new ContainerNormalization(ctx);
62 Set<QName> getQNameIdentifiers() {
63 return Collections.singleton(identifier.getNodeType());
66 abstract DataNormalizationOperation<?> getChild(PathArgument child) throws DataNormalizationException;
68 abstract DataNormalizationOperation<?> getChild(QName child) throws DataNormalizationException;
70 private abstract static class SimpleTypeNormalization<T extends PathArgument>
71 extends DataNormalizationOperation<T> {
72 SimpleTypeNormalization(final T identifier) {
77 final DataNormalizationOperation<?> getChild(final PathArgument child) {
82 final DataNormalizationOperation<?> getChild(final QName child) {
87 private static final class LeafNormalization extends SimpleTypeNormalization<NodeIdentifier> {
88 LeafNormalization(final LeafSchemaNode potential) {
89 super(new NodeIdentifier(potential.getQName()));
93 private static final class LeafListEntryNormalization extends SimpleTypeNormalization<NodeWithValue> {
94 LeafListEntryNormalization(final LeafListSchemaNode potential) {
95 super(new NodeWithValue(potential.getQName(), null));
99 private abstract static class DataContainerNormalizationOperation<T extends PathArgument>
100 extends DataNormalizationOperation<T> {
101 private final DataNodeContainer schema;
102 private final Map<QName, DataNormalizationOperation<?>> byQName;
103 private final Map<PathArgument, DataNormalizationOperation<?>> byArg;
105 DataContainerNormalizationOperation(final T identifier, final DataNodeContainer schema) {
107 this.schema = schema;
108 this.byArg = new ConcurrentHashMap<>();
109 this.byQName = new ConcurrentHashMap<>();
113 DataNormalizationOperation<?> getChild(final PathArgument child) throws DataNormalizationException {
114 DataNormalizationOperation<?> potential = byArg.get(child);
115 if (potential != null) {
118 potential = fromLocalSchema(child);
119 return register(potential);
123 DataNormalizationOperation<?> getChild(final QName child) throws DataNormalizationException {
124 DataNormalizationOperation<?> potential = byQName.get(child);
125 if (potential != null) {
128 potential = fromLocalSchemaAndQName(schema, child);
129 return register(potential);
132 private DataNormalizationOperation<?> fromLocalSchema(final PathArgument child)
133 throws DataNormalizationException {
134 if (child instanceof AugmentationIdentifier) {
135 return fromSchemaAndQNameChecked(schema, ((AugmentationIdentifier) child).getPossibleChildNames()
138 return fromSchemaAndQNameChecked(schema, child.getNodeType());
141 DataNormalizationOperation<?> fromLocalSchemaAndQName(final DataNodeContainer schema2,
142 final QName child) throws DataNormalizationException {
143 return fromSchemaAndQNameChecked(schema2, child);
146 private DataNormalizationOperation<?> register(final DataNormalizationOperation<?> potential) {
147 if (potential != null) {
148 byArg.put(potential.getIdentifier(), potential);
149 for (final QName qname : potential.getQNameIdentifiers()) {
150 byQName.put(qname, potential);
156 private static DataNormalizationOperation<?> fromSchemaAndQNameChecked(final DataNodeContainer schema,
157 final QName child) throws DataNormalizationException {
159 final DataSchemaNode result = findChildSchemaNode(schema, child);
160 if (result == null) {
161 throw new DataNormalizationException(String.format(
162 "Supplied QName %s is not valid according to schema %s, potential children nodes: %s", child,
163 schema,schema.getChildNodes()));
166 // We try to look up if this node was added by augmentation
167 if (schema instanceof DataSchemaNode && result.isAugmenting()) {
168 return fromAugmentation(schema, (AugmentationTarget) schema, result);
170 return fromDataSchemaNode(result);
174 private static final class ListItemNormalization extends
175 DataContainerNormalizationOperation<NodeIdentifierWithPredicates> {
176 ListItemNormalization(final NodeIdentifierWithPredicates identifier, final ListSchemaNode schema) {
177 super(identifier, schema);
181 private static final class UnkeyedListItemNormalization
182 extends DataContainerNormalizationOperation<NodeIdentifier> {
183 UnkeyedListItemNormalization(final ListSchemaNode schema) {
184 super(new NodeIdentifier(schema.getQName()), schema);
188 private static final class ContainerNormalization extends DataContainerNormalizationOperation<NodeIdentifier> {
189 ContainerNormalization(final ContainerLike schema) {
190 super(new NodeIdentifier(schema.getQName()), schema);
194 private abstract static class MixinNormalizationOp<T extends PathArgument> extends DataNormalizationOperation<T> {
195 MixinNormalizationOp(final T identifier) {
200 final boolean isMixin() {
205 private static final class LeafListMixinNormalization extends MixinNormalizationOp<NodeIdentifier> {
206 private final DataNormalizationOperation<?> innerOp;
208 LeafListMixinNormalization(final LeafListSchemaNode potential) {
209 super(new NodeIdentifier(potential.getQName()));
210 innerOp = new LeafListEntryNormalization(potential);
214 DataNormalizationOperation<?> getChild(final PathArgument child) {
215 if (child instanceof NodeWithValue) {
222 DataNormalizationOperation<?> getChild(final QName child) {
223 if (getIdentifier().getNodeType().equals(child)) {
230 private static final class AugmentationNormalization
231 extends DataContainerNormalizationOperation<AugmentationIdentifier> {
233 AugmentationNormalization(final AugmentationSchemaNode augmentation, final DataNodeContainer schema) {
234 super(augmentationIdentifierFrom(augmentation), augmentationProxy(augmentation,schema));
237 private static DataNodeContainer augmentationProxy(final AugmentationSchemaNode augmentation,
238 final DataNodeContainer schema) {
239 final Set<DataSchemaNode> children = new HashSet<>();
240 for (final DataSchemaNode augNode : augmentation.getChildNodes()) {
241 children.add(schema.getDataChildByName(augNode.getQName()));
243 return new EffectiveAugmentationSchema(augmentation, children);
252 DataNormalizationOperation<?> fromLocalSchemaAndQName(final DataNodeContainer schema, final QName child) {
253 final DataSchemaNode result = findChildSchemaNode(schema, child);
254 if (result == null) {
258 // We try to look up if this node was added by augmentation
259 if (schema instanceof DataSchemaNode && result.isAugmenting()) {
260 return fromAugmentation(schema, (AugmentationTarget) schema, result);
262 return fromDataSchemaNode(result);
266 Set<QName> getQNameIdentifiers() {
267 return getIdentifier().getPossibleChildNames();
270 private static AugmentationIdentifier augmentationIdentifierFrom(final AugmentationSchemaNode augmentation) {
271 final ImmutableSet.Builder<QName> potentialChildren = ImmutableSet.builder();
272 for (final DataSchemaNode child : augmentation.getChildNodes()) {
273 potentialChildren.add(child.getQName());
275 return new AugmentationIdentifier(potentialChildren.build());
279 private static final class MapMixinNormalization extends MixinNormalizationOp<NodeIdentifier> {
280 private final ListItemNormalization innerNode;
282 MapMixinNormalization(final ListSchemaNode list) {
283 super(new NodeIdentifier(list.getQName()));
284 this.innerNode = new ListItemNormalization(NodeIdentifierWithPredicates.of(list.getQName(),
285 Collections.<QName, Object>emptyMap()), list);
289 DataNormalizationOperation<?> getChild(final PathArgument child) {
290 if (child.getNodeType().equals(getIdentifier().getNodeType())) {
297 DataNormalizationOperation<?> getChild(final QName child) {
298 if (getIdentifier().getNodeType().equals(child)) {
305 private static final class UnkeyedListMixinNormalization extends MixinNormalizationOp<NodeIdentifier> {
306 private final UnkeyedListItemNormalization innerNode;
308 UnkeyedListMixinNormalization(final ListSchemaNode list) {
309 super(new NodeIdentifier(list.getQName()));
310 this.innerNode = new UnkeyedListItemNormalization(list);
314 DataNormalizationOperation<?> getChild(final PathArgument child) {
315 if (child.getNodeType().equals(getIdentifier().getNodeType())) {
322 DataNormalizationOperation<?> getChild(final QName child) {
323 if (getIdentifier().getNodeType().equals(child)) {
330 private static final class ChoiceNodeNormalization extends MixinNormalizationOp<NodeIdentifier> {
331 private final ImmutableMap<QName, DataNormalizationOperation<?>> byQName;
332 private final ImmutableMap<PathArgument, DataNormalizationOperation<?>> byArg;
334 ChoiceNodeNormalization(final ChoiceSchemaNode schema) {
335 super(new NodeIdentifier(schema.getQName()));
336 final ImmutableMap.Builder<QName, DataNormalizationOperation<?>> byQNameBuilder = ImmutableMap.builder();
337 final ImmutableMap.Builder<PathArgument, DataNormalizationOperation<?>> byArgBuilder =
338 ImmutableMap.builder();
340 for (final CaseSchemaNode caze : schema.getCases()) {
341 for (final DataSchemaNode cazeChild : caze.getChildNodes()) {
342 final DataNormalizationOperation<?> childOp = fromDataSchemaNode(cazeChild);
343 byArgBuilder.put(childOp.getIdentifier(), childOp);
344 for (final QName qname : childOp.getQNameIdentifiers()) {
345 byQNameBuilder.put(qname, childOp);
349 byQName = byQNameBuilder.build();
350 byArg = byArgBuilder.build();
354 DataNormalizationOperation<?> getChild(final PathArgument child) {
355 return byArg.get(child);
359 DataNormalizationOperation<?> getChild(final QName child) {
360 return byQName.get(child);
364 private static final class AnyxmlNormalization extends SimpleTypeNormalization<NodeIdentifier> {
365 AnyxmlNormalization(final AnyxmlSchemaNode schema) {
366 super(new NodeIdentifier(schema.getQName()));
370 private static @Nullable DataSchemaNode findChildSchemaNode(final DataNodeContainer parent, final QName child) {
371 final DataSchemaNode potential = parent.getDataChildByName(child);
372 return potential != null ? potential : findChoice(parent, child);
375 private static @Nullable ChoiceSchemaNode findChoice(final DataNodeContainer parent, final QName child) {
376 for (final ChoiceSchemaNode choice : Iterables.filter(parent.getChildNodes(), ChoiceSchemaNode.class)) {
377 for (final CaseSchemaNode caze : choice.getCases()) {
378 if (findChildSchemaNode(caze, child) != null) {
387 * Returns a DataNormalizationOperation for provided child node.
390 * If supplied child is added by Augmentation this operation returns
391 * a DataNormalizationOperation for augmentation,
392 * otherwise returns a DataNormalizationOperation for child as
393 * call for {@link #fromDataSchemaNode(DataSchemaNode)}.
395 @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
396 justification = "https://github.com/spotbugs/spotbugs/issues/811")
397 private static DataNormalizationOperation<?> fromAugmentation(final DataNodeContainer parent,
398 final AugmentationTarget parentAug, final DataSchemaNode child) {
399 AugmentationSchemaNode augmentation = null;
400 for (final AugmentationSchemaNode aug : parentAug.getAvailableAugmentations()) {
401 final DataSchemaNode potential = aug.getDataChildByName(child.getQName());
402 if (potential != null) {
408 if (augmentation != null) {
409 return new AugmentationNormalization(augmentation, parent);
411 return fromDataSchemaNode(child);
415 static DataNormalizationOperation<?> fromDataSchemaNode(final DataSchemaNode potential) {
416 if (potential instanceof ContainerSchemaNode) {
417 return new ContainerNormalization((ContainerSchemaNode) potential);
418 } else if (potential instanceof ListSchemaNode) {
419 return fromListSchemaNode((ListSchemaNode) potential);
420 } else if (potential instanceof LeafSchemaNode) {
421 return new LeafNormalization((LeafSchemaNode) potential);
422 } else if (potential instanceof ChoiceSchemaNode) {
423 return new ChoiceNodeNormalization((ChoiceSchemaNode) potential);
424 } else if (potential instanceof LeafListSchemaNode) {
425 return new LeafListMixinNormalization((LeafListSchemaNode) potential);
426 } else if (potential instanceof AnyxmlSchemaNode) {
427 return new AnyxmlNormalization((AnyxmlSchemaNode) potential);
432 private static DataNormalizationOperation<?> fromListSchemaNode(final ListSchemaNode potential) {
433 if (potential.getKeyDefinition().isEmpty()) {
434 return new UnkeyedListMixinNormalization(potential);
436 return new MapMixinNormalization(potential);