BUG-1092: rename data.api.InstanceIdentifier to YangInstanceIdentifier
[yangtools.git] / code-generator / binding-generator-impl / src / main / java / org / opendaylight / yangtools / sal / binding / generator / impl / InstanceIdentifierCodecImpl.java
1 /**
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.yangtools.sal.binding.generator.impl;
9
10 import com.google.common.collect.ImmutableList;
11
12 import java.util.ArrayList;
13 import java.util.Arrays;
14 import java.util.Collections;
15 import java.util.HashMap;
16 import java.util.HashSet;
17 import java.util.List;
18 import java.util.Map;
19 import java.util.Set;
20 import java.util.WeakHashMap;
21 import java.util.concurrent.ConcurrentHashMap;
22
23 import org.opendaylight.yangtools.concepts.Identifiable;
24 import org.opendaylight.yangtools.yang.binding.Augmentation;
25 import org.opendaylight.yangtools.yang.binding.DataObject;
26 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
27 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem;
28 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item;
29 import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
30 import org.opendaylight.yangtools.yang.common.QName;
31 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
32 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
33 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
34 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
35 import org.opendaylight.yangtools.yang.data.api.Node;
36 import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl;
37 import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl;
38 import org.opendaylight.yangtools.yang.data.impl.codec.CodecRegistry;
39 import org.opendaylight.yangtools.yang.data.impl.codec.IdentifierCodec;
40 import org.opendaylight.yangtools.yang.data.impl.codec.InstanceIdentifierCodec;
41 import org.opendaylight.yangtools.yang.data.impl.codec.ValueWithQName;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
44
45 public class InstanceIdentifierCodecImpl implements InstanceIdentifierCodec {
46     private static final Logger LOG = LoggerFactory.getLogger(InstanceIdentifierCodecImpl.class);
47
48     private final CodecRegistry codecRegistry;
49
50     private final Map<Class<?>,Set<List<QName>>> augmentationAdapted = new WeakHashMap<>();
51
52     private final Map<Class<?>, Map<List<QName>, Class<?>>> classToPreviousAugment = Collections
53             .synchronizedMap(new WeakHashMap<Class<?>, Map<List<QName>, Class<?>>>());
54
55     public InstanceIdentifierCodecImpl(final CodecRegistry registry) {
56         this.codecRegistry = registry;
57     }
58
59     @Override
60     public InstanceIdentifier<? extends Object> deserialize(
61             final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier input) {
62         Class<?> baType = null;
63         List<org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument> biArgs = input.getPath();
64         List<QName> scannedPath = new ArrayList<>(biArgs.size());
65         List<InstanceIdentifier.PathArgument> baArgs = new ArrayList<InstanceIdentifier.PathArgument>(biArgs.size());
66         for (org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument biArg : biArgs) {
67
68             scannedPath.add(biArg.getNodeType());
69             org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument baArg = deserializePathArgument(
70                     biArg, scannedPath);
71             if (baArg != null) {
72                 baType = baArg.getType();
73             }
74             Map<List<QName>, Class<?>> injectAugment = classToPreviousAugment.get(baType);
75             if (injectAugment != null) {
76                 @SuppressWarnings("unchecked")
77                 Class<? extends DataObject> augment = (Class<? extends DataObject>) injectAugment.get(scannedPath);
78                 if (augment != null) {
79                     baArgs.add(new Item(augment));
80                 }
81             }
82             baArgs.add(baArg);
83         }
84         InstanceIdentifier<?> ret = InstanceIdentifier.create(baArgs);
85         LOG.debug("DOM Instance Identifier {} deserialized to {}", input, ret);
86         return ret;
87     }
88
89     @Override
90     public InstanceIdentifier<? extends Object> deserialize(
91             final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier input,
92             final InstanceIdentifier<?> bindingIdentifier) {
93         return deserialize(input);
94     }
95
96     private InstanceIdentifier.PathArgument deserializeNodeIdentifier(
97             final NodeIdentifier argument, final List<QName> processedPath) {
98         @SuppressWarnings("rawtypes")
99         final Class cls = codecRegistry.getClassForPath(processedPath);
100         @SuppressWarnings("unchecked")
101         Item<DataObject> item = new Item<>(cls);
102         return item;
103     }
104
105     private InstanceIdentifier.PathArgument deserializeNodeIdentifierWithPrecicates(
106             final NodeIdentifierWithPredicates argument, final List<QName> processedPath) {
107         @SuppressWarnings("rawtypes")
108         final Class type = codecRegistry.getClassForPath(processedPath);
109         @SuppressWarnings({ "unchecked", "rawtypes" })
110         final IdentifierCodec codec = codecRegistry
111                 .<Identifiable<? extends Object>> getIdentifierCodecForIdentifiable(type);
112         CompositeNode _compositeNode = this.toCompositeNode(argument);
113         @SuppressWarnings("unchecked")
114         ValueWithQName<CompositeNode> deserialize = codec.deserialize(_compositeNode);
115         Object value = null;
116         if (deserialize != null) {
117             value = deserialize.getValue();
118         }
119         return CodecTypeUtils.newIdentifiableItem(type, value);
120     }
121
122     public CompositeNode toCompositeNode(final NodeIdentifierWithPredicates predicates) {
123         Set<Map.Entry<QName, Object>> keyValues = predicates.getKeyValues().entrySet();
124         List<Node<?>> values = new ArrayList<>(keyValues.size());
125         for (Map.Entry<QName, Object> keyValue : keyValues) {
126             values.add(new SimpleNodeTOImpl<Object>(keyValue.getKey(), null, keyValue.getValue()));
127         }
128         return new CompositeNodeTOImpl(predicates.getNodeType(), null, values);
129     }
130
131     @Override
132     public org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier serialize(final InstanceIdentifier<?> input) {
133         Class<?> previousAugmentation = null;
134         Iterable<InstanceIdentifier.PathArgument> pathArgs = input.getPathArguments();
135         QName previousQName = null;
136         List<PathArgument> components = new ArrayList<>();
137         List<QName> qnamePath = new ArrayList<>();
138         for (InstanceIdentifier.PathArgument baArg : pathArgs) {
139             if (!Augmentation.class.isAssignableFrom(baArg.getType())) {
140                 PathArgument biArg = serializePathArgumentAndUpdateMapping(qnamePath, baArg, previousQName,previousAugmentation);
141                 components.add(biArg);
142                 qnamePath.add(biArg.getNodeType());
143                 previousQName = biArg.getNodeType();
144                 previousAugmentation = null;
145             } else {
146                 previousQName = codecRegistry.getQNameForAugmentation(baArg.getType());
147                 previousAugmentation = baArg.getType();
148                 ensureAugmentation(qnamePath,previousQName,baArg.getType());
149             }
150         }
151         org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier ret =
152                 org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.create(components);
153         LOG.debug("Binding Instance Identifier {} serialized to DOM InstanceIdentifier {}", input, ret);
154         return ret;
155     }
156
157     private synchronized void ensureAugmentation(final List<QName> augPath, final QName augQName, final Class<? extends DataObject> type) {
158         Set<List<QName>> augPotential = augmentationAdapted.get(type);
159         if(augPotential == null) {
160             augPotential = new HashSet<>();
161             augmentationAdapted.put(type, augPotential);
162         }
163         ImmutableList<QName> augTargetPath = ImmutableList.copyOf(augPath);
164         if(augPotential.contains(augPath)) {
165             return;
166         }
167
168         for(Class<? extends DataObject> child : BindingReflections.getChildrenClasses(type)) {
169             Item<? extends DataObject> baArg = new Item<>(child);
170             PathArgument biArg = serializePathArgumentAndUpdateMapping(augPath, baArg, augQName,type);
171         }
172         augPotential.add(augTargetPath);
173     }
174
175
176     public Class<? extends Object> updateAugmentationInjection(final Class<? extends DataObject> class1,
177             final List<QName> list, final Class<?> augmentation) {
178         if (classToPreviousAugment.get(class1) == null) {
179             classToPreviousAugment.put(class1, new ConcurrentHashMap<List<QName>, Class<?>>());
180         }
181         return classToPreviousAugment.get(class1).put(list, augmentation);
182     }
183
184     private PathArgument serializeItem(final Item<?> argument, final QName previousQname) {
185         Class<?> type = argument.getType();
186         QName qname = BindingReflections.findQName(type);
187         if (previousQname == null || (BindingReflections.isAugmentationChild(argument.getType()))) {
188             return new NodeIdentifier(qname);
189         }
190         return new NodeIdentifier(QName.create(previousQname, qname.getLocalName()));
191     }
192
193     private PathArgument serializeIdentifiableItem(final IdentifiableItem<?,?> argument, final QName previousQname) {
194         Map<QName, Object> predicates = new HashMap<>();
195         @SuppressWarnings("rawtypes")
196         Class type = argument.getType();
197         @SuppressWarnings("unchecked")
198         IdentifierCodec<? extends Object> keyCodec = codecRegistry.getIdentifierCodecForIdentifiable(type);
199         QName qname = BindingReflections.findQName(type);
200         if (previousQname != null && !(BindingReflections.isAugmentationChild(argument.getType()))) {
201             qname = QName.create(previousQname, qname.getLocalName());
202         }
203         @SuppressWarnings({ "rawtypes", "unchecked" })
204         ValueWithQName combinedInput = new ValueWithQName(previousQname, argument.getKey());
205         @SuppressWarnings("unchecked")
206         CompositeNode compositeOutput = keyCodec.serialize(combinedInput);
207         for (Node<?> outputValue : compositeOutput.getValue()) {
208             predicates.put(outputValue.getNodeType(), outputValue.getValue());
209         }
210         if (previousQname == null) {
211             return new NodeIdentifierWithPredicates(qname, predicates);
212         }
213         return new NodeIdentifierWithPredicates(qname, predicates);
214     }
215
216     private org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument deserializePathArgument(
217             final PathArgument argument, final List<QName> processedPath) {
218         if (argument instanceof NodeIdentifier) {
219             return deserializeNodeIdentifier((NodeIdentifier) argument, processedPath);
220         } else if (argument instanceof NodeIdentifierWithPredicates) {
221             return deserializeNodeIdentifierWithPrecicates((NodeIdentifierWithPredicates) argument, processedPath);
222         } else {
223             throw new IllegalArgumentException("Unhandled parameter types: "
224                     + Arrays.<Object> asList(argument, processedPath).toString());
225         }
226     }
227
228     private PathArgument serializePathArgumentAndUpdateMapping(final List<QName> parentPath, final InstanceIdentifier.PathArgument baArg, final QName previousQName, final Class<?> previousAugmentation) {
229         org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument biArg = serializePathArgument(baArg, previousQName);
230         List<QName> qnamePath = new ArrayList<>(parentPath);
231         qnamePath.add(biArg.getNodeType());
232         ImmutableList<QName> currentPath = ImmutableList.copyOf(qnamePath);
233         codecRegistry.putPathToClass(currentPath, baArg.getType());
234         if (previousAugmentation != null) {
235             updateAugmentationInjection(baArg.getType(), currentPath, previousAugmentation);
236         }
237         return biArg;
238     }
239
240     private PathArgument serializePathArgument(
241             final InstanceIdentifier.PathArgument argument,
242             final QName previousQname) {
243         if (argument instanceof IdentifiableItem) {
244             return serializeIdentifiableItem((IdentifiableItem<?,?>) argument, previousQname);
245         } else if (argument instanceof Item) {
246             return serializeItem((Item<?>) argument, previousQname);
247         } else {
248             throw new IllegalArgumentException("Unhandled parameter types: "
249                     + Arrays.<Object> asList(argument, previousQname).toString());
250         }
251     }
252
253
254
255 }