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.HashSet;
17 import java.util.concurrent.ConcurrentHashMap;
18 import org.eclipse.jdt.annotation.Nullable;
19 import org.opendaylight.yangtools.concepts.Identifiable;
20 import org.opendaylight.yangtools.yang.common.Empty;
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 ImmutableSet.of(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(), Empty.value()));
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 = new ConcurrentHashMap<>();
103 private final Map<PathArgument, DataNormalizationOperation<?>> byArg = new ConcurrentHashMap<>();
105 DataContainerNormalizationOperation(final T identifier, final DataNodeContainer schema) {
107 this.schema = schema;
111 DataNormalizationOperation<?> getChild(final PathArgument child) throws DataNormalizationException {
112 DataNormalizationOperation<?> potential = byArg.get(child);
113 if (potential != null) {
116 potential = fromLocalSchema(child);
117 return register(potential);
121 DataNormalizationOperation<?> getChild(final QName child) throws DataNormalizationException {
122 DataNormalizationOperation<?> potential = byQName.get(child);
123 if (potential != null) {
126 potential = fromLocalSchemaAndQName(schema, child);
127 return register(potential);
130 private DataNormalizationOperation<?> fromLocalSchema(final PathArgument child)
131 throws DataNormalizationException {
132 if (child instanceof AugmentationIdentifier) {
133 return fromSchemaAndQNameChecked(schema, ((AugmentationIdentifier) child).getPossibleChildNames()
136 return fromSchemaAndQNameChecked(schema, child.getNodeType());
139 DataNormalizationOperation<?> fromLocalSchemaAndQName(final DataNodeContainer schema2,
140 final QName child) throws DataNormalizationException {
141 return fromSchemaAndQNameChecked(schema2, child);
144 private DataNormalizationOperation<?> register(final DataNormalizationOperation<?> potential) {
145 if (potential != null) {
146 byArg.put(potential.getIdentifier(), potential);
147 for (final QName qname : potential.getQNameIdentifiers()) {
148 byQName.put(qname, potential);
154 private static DataNormalizationOperation<?> fromSchemaAndQNameChecked(final DataNodeContainer schema,
155 final QName child) throws DataNormalizationException {
157 final DataSchemaNode result = findChildSchemaNode(schema, child);
158 if (result == null) {
159 throw new DataNormalizationException(String.format(
160 "Supplied QName %s is not valid according to schema %s, potential children nodes: %s", child,
161 schema,schema.getChildNodes()));
164 // We try to look up if this node was added by augmentation
165 if (schema instanceof DataSchemaNode && result.isAugmenting()) {
166 return fromAugmentation(schema, (AugmentationTarget) schema, result);
168 return fromDataSchemaNode(result);
172 private static final class ListItemNormalization extends
173 DataContainerNormalizationOperation<NodeIdentifierWithPredicates> {
174 ListItemNormalization(final NodeIdentifierWithPredicates identifier, final ListSchemaNode schema) {
175 super(identifier, schema);
179 private static final class UnkeyedListItemNormalization
180 extends DataContainerNormalizationOperation<NodeIdentifier> {
181 UnkeyedListItemNormalization(final ListSchemaNode schema) {
182 super(new NodeIdentifier(schema.getQName()), schema);
186 private static final class ContainerNormalization extends DataContainerNormalizationOperation<NodeIdentifier> {
187 ContainerNormalization(final ContainerLike schema) {
188 super(new NodeIdentifier(schema.getQName()), schema);
192 private abstract static class MixinNormalizationOp<T extends PathArgument> extends DataNormalizationOperation<T> {
193 MixinNormalizationOp(final T identifier) {
198 final boolean isMixin() {
203 private static final class LeafListMixinNormalization extends MixinNormalizationOp<NodeIdentifier> {
204 private final DataNormalizationOperation<?> innerOp;
206 LeafListMixinNormalization(final LeafListSchemaNode potential) {
207 super(new NodeIdentifier(potential.getQName()));
208 innerOp = new LeafListEntryNormalization(potential);
212 DataNormalizationOperation<?> getChild(final PathArgument child) {
213 if (child instanceof NodeWithValue) {
220 DataNormalizationOperation<?> getChild(final QName child) {
221 if (getIdentifier().getNodeType().equals(child)) {
228 private static final class AugmentationNormalization
229 extends DataContainerNormalizationOperation<AugmentationIdentifier> {
231 AugmentationNormalization(final AugmentationSchemaNode augmentation, final DataNodeContainer schema) {
232 super(augmentationIdentifierFrom(augmentation), augmentationProxy(augmentation,schema));
235 private static DataNodeContainer augmentationProxy(final AugmentationSchemaNode augmentation,
236 final DataNodeContainer schema) {
237 final Set<DataSchemaNode> children = new HashSet<>();
238 for (final DataSchemaNode augNode : augmentation.getChildNodes()) {
239 children.add(schema.getDataChildByName(augNode.getQName()));
241 return new EffectiveAugmentationSchema(augmentation, children);
250 DataNormalizationOperation<?> fromLocalSchemaAndQName(final DataNodeContainer schema, final QName child) {
251 final DataSchemaNode result = findChildSchemaNode(schema, child);
252 if (result == null) {
256 // We try to look up if this node was added by augmentation
257 if (schema instanceof DataSchemaNode && result.isAugmenting()) {
258 return fromAugmentation(schema, (AugmentationTarget) schema, result);
260 return fromDataSchemaNode(result);
264 Set<QName> getQNameIdentifiers() {
265 return getIdentifier().getPossibleChildNames();
268 private static AugmentationIdentifier augmentationIdentifierFrom(final AugmentationSchemaNode augmentation) {
269 final ImmutableSet.Builder<QName> potentialChildren = ImmutableSet.builder();
270 for (final DataSchemaNode child : augmentation.getChildNodes()) {
271 potentialChildren.add(child.getQName());
273 return new AugmentationIdentifier(potentialChildren.build());
277 private static final class MapMixinNormalization extends MixinNormalizationOp<NodeIdentifier> {
278 private final ListItemNormalization innerNode;
280 MapMixinNormalization(final ListSchemaNode list) {
281 super(new NodeIdentifier(list.getQName()));
282 innerNode = new ListItemNormalization(NodeIdentifierWithPredicates.of(list.getQName()), list);
286 DataNormalizationOperation<?> getChild(final PathArgument child) {
287 if (child.getNodeType().equals(getIdentifier().getNodeType())) {
294 DataNormalizationOperation<?> getChild(final QName child) {
295 if (getIdentifier().getNodeType().equals(child)) {
302 private static final class UnkeyedListMixinNormalization extends MixinNormalizationOp<NodeIdentifier> {
303 private final UnkeyedListItemNormalization innerNode;
305 UnkeyedListMixinNormalization(final ListSchemaNode list) {
306 super(new NodeIdentifier(list.getQName()));
307 innerNode = new UnkeyedListItemNormalization(list);
311 DataNormalizationOperation<?> getChild(final PathArgument child) {
312 if (child.getNodeType().equals(getIdentifier().getNodeType())) {
319 DataNormalizationOperation<?> getChild(final QName child) {
320 if (getIdentifier().getNodeType().equals(child)) {
327 private static final class ChoiceNodeNormalization extends MixinNormalizationOp<NodeIdentifier> {
328 private final ImmutableMap<QName, DataNormalizationOperation<?>> byQName;
329 private final ImmutableMap<PathArgument, DataNormalizationOperation<?>> byArg;
331 ChoiceNodeNormalization(final ChoiceSchemaNode schema) {
332 super(new NodeIdentifier(schema.getQName()));
333 final ImmutableMap.Builder<QName, DataNormalizationOperation<?>> byQNameBuilder = ImmutableMap.builder();
334 final ImmutableMap.Builder<PathArgument, DataNormalizationOperation<?>> byArgBuilder =
335 ImmutableMap.builder();
337 for (final CaseSchemaNode caze : schema.getCases()) {
338 for (final DataSchemaNode cazeChild : caze.getChildNodes()) {
339 final DataNormalizationOperation<?> childOp = fromDataSchemaNode(cazeChild);
340 byArgBuilder.put(childOp.getIdentifier(), childOp);
341 for (final QName qname : childOp.getQNameIdentifiers()) {
342 byQNameBuilder.put(qname, childOp);
346 byQName = byQNameBuilder.build();
347 byArg = byArgBuilder.build();
351 DataNormalizationOperation<?> getChild(final PathArgument child) {
352 return byArg.get(child);
356 DataNormalizationOperation<?> getChild(final QName child) {
357 return byQName.get(child);
361 Set<QName> getQNameIdentifiers() {
362 return byQName.keySet();
366 private static final class AnyxmlNormalization extends SimpleTypeNormalization<NodeIdentifier> {
367 AnyxmlNormalization(final AnyxmlSchemaNode schema) {
368 super(new NodeIdentifier(schema.getQName()));
372 private static @Nullable DataSchemaNode findChildSchemaNode(final DataNodeContainer parent, final QName child) {
373 final DataSchemaNode potential = parent.dataChildByName(child);
374 return potential != null ? potential : findChoice(parent, child);
377 private static @Nullable ChoiceSchemaNode findChoice(final DataNodeContainer parent, final QName child) {
378 for (final ChoiceSchemaNode choice : Iterables.filter(parent.getChildNodes(), ChoiceSchemaNode.class)) {
379 for (final CaseSchemaNode caze : choice.getCases()) {
380 if (findChildSchemaNode(caze, child) != null) {
389 * Returns a DataNormalizationOperation for provided child node.
392 * If supplied child is added by Augmentation this operation returns
393 * a DataNormalizationOperation for augmentation,
394 * otherwise returns a DataNormalizationOperation for child as
395 * call for {@link #fromDataSchemaNode(DataSchemaNode)}.
397 @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
398 justification = "https://github.com/spotbugs/spotbugs/issues/811")
399 private static DataNormalizationOperation<?> fromAugmentation(final DataNodeContainer parent,
400 final AugmentationTarget parentAug, final DataSchemaNode child) {
401 for (final AugmentationSchemaNode aug : parentAug.getAvailableAugmentations()) {
402 if (aug.dataChildByName(child.getQName()) != null) {
403 return new AugmentationNormalization(aug, parent);
406 return fromDataSchemaNode(child);
409 static DataNormalizationOperation<?> fromDataSchemaNode(final DataSchemaNode potential) {
410 if (potential instanceof ContainerSchemaNode) {
411 return new ContainerNormalization((ContainerSchemaNode) potential);
412 } else if (potential instanceof ListSchemaNode) {
413 return fromListSchemaNode((ListSchemaNode) potential);
414 } else if (potential instanceof LeafSchemaNode) {
415 return new LeafNormalization((LeafSchemaNode) potential);
416 } else if (potential instanceof ChoiceSchemaNode) {
417 return new ChoiceNodeNormalization((ChoiceSchemaNode) potential);
418 } else if (potential instanceof LeafListSchemaNode) {
419 return new LeafListMixinNormalization((LeafListSchemaNode) potential);
420 } else if (potential instanceof AnyxmlSchemaNode) {
421 return new AnyxmlNormalization((AnyxmlSchemaNode) potential);
426 private static DataNormalizationOperation<?> fromListSchemaNode(final ListSchemaNode potential) {
427 if (potential.getKeyDefinition().isEmpty()) {
428 return new UnkeyedListMixinNormalization(potential);
430 return new MapMixinNormalization(potential);