9487f2159011132cd71e935a757b432dd324270a
[controller.git] / opendaylight / md-sal / sal-common-impl / src / main / java / org / opendaylight / controller / md / sal / common / impl / util / compat / DataNormalizer.java
1 package org.opendaylight.controller.md.sal.common.impl.util.compat;
2
3 import static com.google.common.base.Preconditions.checkArgument;
4
5 import java.util.AbstractMap;
6 import java.util.ArrayList;
7 import java.util.Map;
8
9 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
10 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
11 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.AugmentationIdentifier;
12 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier;
13 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates;
14 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
15 import org.opendaylight.yangtools.yang.data.api.Node;
16 import org.opendaylight.yangtools.yang.data.api.SimpleNode;
17 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
18 import org.opendaylight.yangtools.yang.data.api.schema.MixinNode;
19 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
20 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer;
21 import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode;
22 import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl;
23 import org.opendaylight.yangtools.yang.data.impl.util.CompositeNodeBuilder;
24 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
25
26 import com.google.common.base.Preconditions;
27 import com.google.common.base.Predicate;
28 import com.google.common.collect.FluentIterable;
29 import com.google.common.collect.ImmutableList;
30 import com.google.common.collect.Iterables;
31
32 public class DataNormalizer {
33
34     private final SchemaContext schemaContext;
35
36     private final DataNormalizationOperation<?> operation;
37
38     public DataNormalizer(final SchemaContext ctx) {
39         schemaContext = ctx;
40         operation = DataNormalizationOperation.from(ctx);
41     }
42
43     public InstanceIdentifier toNormalized(final InstanceIdentifier legacy) {
44         ImmutableList.Builder<PathArgument> normalizedArgs = ImmutableList.builder();
45
46         DataNormalizationOperation<?> currentOp = operation;
47         for (PathArgument legacyArg : legacy.getPath()) {
48             currentOp = currentOp.getChild(legacyArg);
49             checkArgument(currentOp != null, "Legacy Instance Identifier %s is not correct. Normalized Instance Identifier so far %s",legacy,normalizedArgs.build());
50             while (currentOp.isMixin()) {
51                 normalizedArgs.add(currentOp.getIdentifier());
52                 currentOp = currentOp.getChild(legacyArg.getNodeType());
53             }
54             normalizedArgs.add(legacyArg);
55         }
56         return new InstanceIdentifier(normalizedArgs.build());
57     }
58
59     public Map.Entry<InstanceIdentifier,NormalizedNode<?, ?>> toNormalized(final Map.Entry<InstanceIdentifier,CompositeNode> legacy) {
60         return toNormalized(legacy.getKey(), legacy.getValue());
61     }
62
63     public Map.Entry<InstanceIdentifier,NormalizedNode<?, ?>> toNormalized(final InstanceIdentifier legacyPath, final CompositeNode legacyData) {
64
65         InstanceIdentifier normalizedPath = toNormalized(legacyPath);
66
67         DataNormalizationOperation<?> currentOp = operation;
68         for (PathArgument arg : normalizedPath.getPath()) {
69             currentOp = currentOp.getChild(arg);
70         }
71         // Write Augmentaiton data resolution
72         if (legacyData.getChildren().size() == 1) {
73             DataNormalizationOperation<?> potentialOp = currentOp.getChild(legacyData.getChildren().get(0)
74                     .getNodeType());
75             if(potentialOp.getIdentifier() instanceof AugmentationIdentifier) {
76                 currentOp = potentialOp;
77                 ArrayList<PathArgument> reworkedArgs = new ArrayList<>(normalizedPath.getPath());
78                 reworkedArgs.add(potentialOp.getIdentifier());
79                 normalizedPath = new InstanceIdentifier(reworkedArgs);
80             }
81         }
82
83         Preconditions.checkArgument(currentOp != null,
84                 "Instance Identifier %s does not reference correct schema Node.", normalizedPath);
85         return new AbstractMap.SimpleEntry<InstanceIdentifier,NormalizedNode<?, ?>>(normalizedPath,currentOp.normalize(legacyData));
86     }
87
88     public InstanceIdentifier toLegacy(final InstanceIdentifier normalized) {
89         ImmutableList.Builder<PathArgument> legacyArgs = ImmutableList.builder();
90         PathArgument previous = null;
91         for (PathArgument normalizedArg : normalized.getPath()) {
92             if (normalizedArg instanceof NodeIdentifier) {
93                 if (previous != null) {
94                     legacyArgs.add(previous);
95                 }
96                 previous = normalizedArg;
97             } else if (normalizedArg instanceof NodeIdentifierWithPredicates) {
98                 // We skip previous node, which was mixin.
99                 previous = normalizedArg;
100             } else if (normalizedArg instanceof AugmentationIdentifier) {
101                 // We ignore argument
102             }
103             // FIXME : Add option for reading choice
104         }
105         if (previous != null) {
106             legacyArgs.add(previous);
107         }
108         return new InstanceIdentifier(legacyArgs.build());
109     }
110
111     public CompositeNode toLegacy(final InstanceIdentifier normalizedPath, final NormalizedNode<?, ?> normalizedData) {
112         // Preconditions.checkArgument(normalizedData instanceof
113         // DataContainerNode<?>,"Node object %s, %s should be of type DataContainerNode",normalizedPath,normalizedData);
114         if (normalizedData instanceof DataContainerNode<?>) {
115             return toLegacyFromDataContainer((DataContainerNode<?>) normalizedData);
116         }
117         return null;
118     }
119
120     public static Node<?> toLegacy(final NormalizedNode<?, ?> node) {
121         if (node instanceof MixinNode) {
122             /**
123              * Direct reading of MixinNodes is not supported,
124              * since it is not possible in legacy APIs create pointer
125              * to Mixin Nodes.
126              *
127              */
128             return null;
129         }
130
131         if (node instanceof DataContainerNode<?>) {
132             return toLegacyFromDataContainer((DataContainerNode<?>) node);
133         }
134         return toLegacySimple(node);
135
136     }
137
138     private static SimpleNode<?> toLegacySimple(final NormalizedNode<?, ?> node) {
139         return new SimpleNodeTOImpl<Object>(node.getNodeType(), null, node.getValue());
140     }
141
142     @SuppressWarnings({ "unchecked", "rawtypes" })
143     private static CompositeNode toLegacyFromDataContainer(final DataContainerNode<?> node) {
144         CompositeNodeBuilder<ImmutableCompositeNode> builder = ImmutableCompositeNode.builder();
145         builder.setQName(node.getNodeType());
146         for (NormalizedNode<?, ?> child : node.getValue()) {
147             if (child instanceof MixinNode && child instanceof NormalizedNodeContainer<?, ?, ?>) {
148                 builder.addAll(toLegacyNodesFromMixin((NormalizedNodeContainer) child));
149             } else {
150                 addToBuilder(builder, toLegacy(child));
151             }
152         }
153         return builder.toInstance();
154     }
155
156     private static void addToBuilder(final CompositeNodeBuilder<ImmutableCompositeNode> builder, final Node<?> legacy) {
157         if (legacy != null) {
158             builder.add(legacy);
159         }
160     }
161
162     @SuppressWarnings({ "rawtypes", "unchecked" })
163     private static Iterable<Node<?>> toLegacyNodesFromMixin(
164             final NormalizedNodeContainer<?, ?, NormalizedNode<?, ?>> mixin) {
165         ArrayList<Node<?>> ret = new ArrayList<>();
166         for (NormalizedNode<?, ?> child : mixin.getValue()) {
167             if(child instanceof MixinNode && child instanceof NormalizedNodeContainer<?, ?, ?>) {
168                 Iterables.addAll(ret,toLegacyNodesFromMixin((NormalizedNodeContainer) child));
169             } else {
170                 ret.add(toLegacy(child));
171             }
172         }
173         return FluentIterable.from(ret).filter(new Predicate<Node<?>>() {
174
175             @Override
176             public boolean apply(final Node<?> input) {
177                 return input != null;
178             }
179         });
180     }
181
182     public DataNormalizationOperation<?> getRootOperation() {
183         return operation;
184     }
185
186 }