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.ContainerSchemaNode;
33 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
34 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
35 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
36 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
37 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
38 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
39 import org.opendaylight.yangtools.yang.model.util.EffectiveAugmentationSchema;
41 abstract class DataNormalizationOperation<T extends PathArgument> implements Identifiable<T> {
42 private final T identifier;
45 public T getIdentifier() {
49 DataNormalizationOperation(final T identifier) {
50 this.identifier = identifier;
53 static DataNormalizationOperation<?> from(final SchemaContext ctx) {
54 return new ContainerNormalization(ctx);
61 Set<QName> getQNameIdentifiers() {
62 return Collections.singleton(identifier.getNodeType());
65 abstract DataNormalizationOperation<?> getChild(PathArgument child) throws DataNormalizationException;
67 abstract DataNormalizationOperation<?> getChild(QName child) throws DataNormalizationException;
69 private abstract static class SimpleTypeNormalization<T extends PathArgument>
70 extends DataNormalizationOperation<T> {
71 SimpleTypeNormalization(final T identifier) {
76 final DataNormalizationOperation<?> getChild(final PathArgument child) {
81 final DataNormalizationOperation<?> getChild(final QName child) {
86 private static final class LeafNormalization extends SimpleTypeNormalization<NodeIdentifier> {
87 LeafNormalization(final LeafSchemaNode potential) {
88 super(new NodeIdentifier(potential.getQName()));
92 private static final class LeafListEntryNormalization extends SimpleTypeNormalization<NodeWithValue> {
93 LeafListEntryNormalization(final LeafListSchemaNode potential) {
94 super(new NodeWithValue(potential.getQName(), null));
98 private abstract static class DataContainerNormalizationOperation<T extends PathArgument>
99 extends DataNormalizationOperation<T> {
100 private final DataNodeContainer schema;
101 private final Map<QName, DataNormalizationOperation<?>> byQName;
102 private final Map<PathArgument, DataNormalizationOperation<?>> byArg;
104 DataContainerNormalizationOperation(final T identifier, final DataNodeContainer schema) {
106 this.schema = schema;
107 this.byArg = new ConcurrentHashMap<>();
108 this.byQName = new ConcurrentHashMap<>();
112 DataNormalizationOperation<?> getChild(final PathArgument child) throws DataNormalizationException {
113 DataNormalizationOperation<?> potential = byArg.get(child);
114 if (potential != null) {
117 potential = fromLocalSchema(child);
118 return register(potential);
122 DataNormalizationOperation<?> getChild(final QName child) throws DataNormalizationException {
123 DataNormalizationOperation<?> potential = byQName.get(child);
124 if (potential != null) {
127 potential = fromLocalSchemaAndQName(schema, child);
128 return register(potential);
131 private DataNormalizationOperation<?> fromLocalSchema(final PathArgument child)
132 throws DataNormalizationException {
133 if (child instanceof AugmentationIdentifier) {
134 return fromSchemaAndQNameChecked(schema, ((AugmentationIdentifier) child).getPossibleChildNames()
137 return fromSchemaAndQNameChecked(schema, child.getNodeType());
140 DataNormalizationOperation<?> fromLocalSchemaAndQName(final DataNodeContainer schema2,
141 final QName child) throws DataNormalizationException {
142 return fromSchemaAndQNameChecked(schema2, child);
145 private DataNormalizationOperation<?> register(final DataNormalizationOperation<?> potential) {
146 if (potential != null) {
147 byArg.put(potential.getIdentifier(), potential);
148 for (final QName qname : potential.getQNameIdentifiers()) {
149 byQName.put(qname, potential);
155 private static DataNormalizationOperation<?> fromSchemaAndQNameChecked(final DataNodeContainer schema,
156 final QName child) throws DataNormalizationException {
158 final DataSchemaNode result = findChildSchemaNode(schema, child);
159 if (result == null) {
160 throw new DataNormalizationException(String.format(
161 "Supplied QName %s is not valid according to schema %s, potential children nodes: %s", child,
162 schema,schema.getChildNodes()));
165 // We try to look up if this node was added by augmentation
166 if (schema instanceof DataSchemaNode && result.isAugmenting()) {
167 return fromAugmentation(schema, (AugmentationTarget) schema, result);
169 return fromDataSchemaNode(result);
173 private static final class ListItemNormalization extends
174 DataContainerNormalizationOperation<NodeIdentifierWithPredicates> {
175 ListItemNormalization(final NodeIdentifierWithPredicates identifier, final ListSchemaNode schema) {
176 super(identifier, schema);
180 private static final class UnkeyedListItemNormalization
181 extends DataContainerNormalizationOperation<NodeIdentifier> {
182 UnkeyedListItemNormalization(final ListSchemaNode schema) {
183 super(new NodeIdentifier(schema.getQName()), schema);
187 private static final class ContainerNormalization extends DataContainerNormalizationOperation<NodeIdentifier> {
188 ContainerNormalization(final ContainerSchemaNode schema) {
189 super(new NodeIdentifier(schema.getQName()), schema);
193 private abstract static class MixinNormalizationOp<T extends PathArgument> extends DataNormalizationOperation<T> {
194 MixinNormalizationOp(final T identifier) {
199 final boolean isMixin() {
204 private static final class LeafListMixinNormalization extends MixinNormalizationOp<NodeIdentifier> {
205 private final DataNormalizationOperation<?> innerOp;
207 LeafListMixinNormalization(final LeafListSchemaNode potential) {
208 super(new NodeIdentifier(potential.getQName()));
209 innerOp = new LeafListEntryNormalization(potential);
213 DataNormalizationOperation<?> getChild(final PathArgument child) {
214 if (child instanceof NodeWithValue) {
221 DataNormalizationOperation<?> getChild(final QName child) {
222 if (getIdentifier().getNodeType().equals(child)) {
229 private static final class AugmentationNormalization
230 extends DataContainerNormalizationOperation<AugmentationIdentifier> {
232 AugmentationNormalization(final AugmentationSchemaNode augmentation, final DataNodeContainer schema) {
233 super(augmentationIdentifierFrom(augmentation), augmentationProxy(augmentation,schema));
236 private static DataNodeContainer augmentationProxy(final AugmentationSchemaNode augmentation,
237 final DataNodeContainer schema) {
238 final Set<DataSchemaNode> children = new HashSet<>();
239 for (final DataSchemaNode augNode : augmentation.getChildNodes()) {
240 children.add(schema.getDataChildByName(augNode.getQName()));
242 return new EffectiveAugmentationSchema(augmentation, children);
251 DataNormalizationOperation<?> fromLocalSchemaAndQName(final DataNodeContainer schema, final QName child) {
252 final DataSchemaNode result = findChildSchemaNode(schema, child);
253 if (result == null) {
257 // We try to look up if this node was added by augmentation
258 if (schema instanceof DataSchemaNode && result.isAugmenting()) {
259 return fromAugmentation(schema, (AugmentationTarget) schema, result);
261 return fromDataSchemaNode(result);
265 Set<QName> getQNameIdentifiers() {
266 return getIdentifier().getPossibleChildNames();
269 private static AugmentationIdentifier augmentationIdentifierFrom(final AugmentationSchemaNode augmentation) {
270 final ImmutableSet.Builder<QName> potentialChildren = ImmutableSet.builder();
271 for (final DataSchemaNode child : augmentation.getChildNodes()) {
272 potentialChildren.add(child.getQName());
274 return new AugmentationIdentifier(potentialChildren.build());
278 private static final class MapMixinNormalization extends MixinNormalizationOp<NodeIdentifier> {
279 private final ListItemNormalization innerNode;
281 MapMixinNormalization(final ListSchemaNode list) {
282 super(new NodeIdentifier(list.getQName()));
283 this.innerNode = new ListItemNormalization(NodeIdentifierWithPredicates.of(list.getQName(),
284 Collections.<QName, Object>emptyMap()), list);
288 DataNormalizationOperation<?> getChild(final PathArgument child) {
289 if (child.getNodeType().equals(getIdentifier().getNodeType())) {
296 DataNormalizationOperation<?> getChild(final QName child) {
297 if (getIdentifier().getNodeType().equals(child)) {
304 private static final class UnkeyedListMixinNormalization extends MixinNormalizationOp<NodeIdentifier> {
305 private final UnkeyedListItemNormalization innerNode;
307 UnkeyedListMixinNormalization(final ListSchemaNode list) {
308 super(new NodeIdentifier(list.getQName()));
309 this.innerNode = new UnkeyedListItemNormalization(list);
313 DataNormalizationOperation<?> getChild(final PathArgument child) {
314 if (child.getNodeType().equals(getIdentifier().getNodeType())) {
321 DataNormalizationOperation<?> getChild(final QName child) {
322 if (getIdentifier().getNodeType().equals(child)) {
329 private static final class ChoiceNodeNormalization extends MixinNormalizationOp<NodeIdentifier> {
330 private final ImmutableMap<QName, DataNormalizationOperation<?>> byQName;
331 private final ImmutableMap<PathArgument, DataNormalizationOperation<?>> byArg;
333 ChoiceNodeNormalization(final ChoiceSchemaNode schema) {
334 super(new NodeIdentifier(schema.getQName()));
335 final ImmutableMap.Builder<QName, DataNormalizationOperation<?>> byQNameBuilder = ImmutableMap.builder();
336 final ImmutableMap.Builder<PathArgument, DataNormalizationOperation<?>> byArgBuilder =
337 ImmutableMap.builder();
339 for (final CaseSchemaNode caze : schema.getCases()) {
340 for (final DataSchemaNode cazeChild : caze.getChildNodes()) {
341 final DataNormalizationOperation<?> childOp = fromDataSchemaNode(cazeChild);
342 byArgBuilder.put(childOp.getIdentifier(), childOp);
343 for (final QName qname : childOp.getQNameIdentifiers()) {
344 byQNameBuilder.put(qname, childOp);
348 byQName = byQNameBuilder.build();
349 byArg = byArgBuilder.build();
353 DataNormalizationOperation<?> getChild(final PathArgument child) {
354 return byArg.get(child);
358 DataNormalizationOperation<?> getChild(final QName child) {
359 return byQName.get(child);
363 private static final class AnyxmlNormalization extends SimpleTypeNormalization<NodeIdentifier> {
364 AnyxmlNormalization(final AnyxmlSchemaNode schema) {
365 super(new NodeIdentifier(schema.getQName()));
369 private static @Nullable DataSchemaNode findChildSchemaNode(final DataNodeContainer parent, final QName child) {
370 final DataSchemaNode potential = parent.getDataChildByName(child);
371 return potential != null ? potential : findChoice(parent, child);
374 private static @Nullable ChoiceSchemaNode findChoice(final DataNodeContainer parent, final QName child) {
375 for (final ChoiceSchemaNode choice : Iterables.filter(parent.getChildNodes(), ChoiceSchemaNode.class)) {
376 for (final CaseSchemaNode caze : choice.getCases()) {
377 if (findChildSchemaNode(caze, child) != null) {
386 * Returns a DataNormalizationOperation for provided child node.
389 * If supplied child is added by Augmentation this operation returns
390 * a DataNormalizationOperation for augmentation,
391 * otherwise returns a DataNormalizationOperation for child as
392 * call for {@link #fromDataSchemaNode(DataSchemaNode)}.
394 @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
395 justification = "https://github.com/spotbugs/spotbugs/issues/811")
396 private static DataNormalizationOperation<?> fromAugmentation(final DataNodeContainer parent,
397 final AugmentationTarget parentAug, final DataSchemaNode child) {
398 AugmentationSchemaNode augmentation = null;
399 for (final AugmentationSchemaNode aug : parentAug.getAvailableAugmentations()) {
400 final DataSchemaNode potential = aug.getDataChildByName(child.getQName());
401 if (potential != null) {
407 if (augmentation != null) {
408 return new AugmentationNormalization(augmentation, parent);
410 return fromDataSchemaNode(child);
414 static DataNormalizationOperation<?> fromDataSchemaNode(final DataSchemaNode potential) {
415 if (potential instanceof ContainerSchemaNode) {
416 return new ContainerNormalization((ContainerSchemaNode) potential);
417 } else if (potential instanceof ListSchemaNode) {
418 return fromListSchemaNode((ListSchemaNode) potential);
419 } else if (potential instanceof LeafSchemaNode) {
420 return new LeafNormalization((LeafSchemaNode) potential);
421 } else if (potential instanceof ChoiceSchemaNode) {
422 return new ChoiceNodeNormalization((ChoiceSchemaNode) potential);
423 } else if (potential instanceof LeafListSchemaNode) {
424 return new LeafListMixinNormalization((LeafListSchemaNode) potential);
425 } else if (potential instanceof AnyxmlSchemaNode) {
426 return new AnyxmlNormalization((AnyxmlSchemaNode) potential);
431 private static DataNormalizationOperation<?> fromListSchemaNode(final ListSchemaNode potential) {
432 if (potential.getKeyDefinition().isEmpty()) {
433 return new UnkeyedListMixinNormalization(potential);
435 return new MapMixinNormalization(potential);