Bug 735 - Part 1: Update ietf-restconf and ietf-yangtypes to newer versions
[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 java.util.ArrayList;
11 import java.util.Arrays;
12 import java.util.Collections;
13 import java.util.HashMap;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.Set;
17 import java.util.WeakHashMap;
18 import java.util.concurrent.ConcurrentHashMap;
19
20 import org.opendaylight.yangtools.concepts.Identifiable;
21 import org.opendaylight.yangtools.yang.binding.Augmentation;
22 import org.opendaylight.yangtools.yang.binding.DataObject;
23 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
24 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem;
25 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item;
26 import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
27 import org.opendaylight.yangtools.yang.common.QName;
28 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
29 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifier;
30 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates;
31 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
32 import org.opendaylight.yangtools.yang.data.api.Node;
33 import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl;
34 import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl;
35 import org.opendaylight.yangtools.yang.data.impl.codec.CodecRegistry;
36 import org.opendaylight.yangtools.yang.data.impl.codec.IdentifierCodec;
37 import org.opendaylight.yangtools.yang.data.impl.codec.InstanceIdentifierCodec;
38 import org.opendaylight.yangtools.yang.data.impl.codec.ValueWithQName;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41
42 import com.google.common.collect.ImmutableList;
43
44 public class InstanceIdentifierCodecImpl implements InstanceIdentifierCodec {
45     private static final Logger LOG = LoggerFactory.getLogger(InstanceIdentifierCodecImpl.class);
46
47     private final CodecRegistry codecRegistry;
48
49     private final Map<Class<?>, Map<List<QName>, Class<?>>> classToPreviousAugment = Collections
50             .synchronizedMap(new WeakHashMap<Class<?>, Map<List<QName>, Class<?>>>());
51
52     public InstanceIdentifierCodecImpl(final CodecRegistry registry) {
53         this.codecRegistry = registry;
54     }
55
56     @Override
57     public InstanceIdentifier<? extends Object> deserialize(
58             final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier input) {
59         Class<?> baType = null;
60         List<org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument> biArgs = input.getPath();
61         List<QName> scannedPath = new ArrayList<>(biArgs.size());
62         List<InstanceIdentifier.PathArgument> baArgs = new ArrayList<InstanceIdentifier.PathArgument>(biArgs.size());
63         for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument biArg : biArgs) {
64
65             scannedPath.add(biArg.getNodeType());
66             org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument baArg = deserializePathArgument(
67                     biArg, scannedPath);
68             if (baArg != null) {
69                 baType = baArg.getType();
70             }
71             Map<List<QName>, Class<?>> injectAugment = classToPreviousAugment.get(baType);
72             if (injectAugment != null) {
73                 Class<? extends DataObject> augment = (Class<? extends DataObject>) injectAugment.get(scannedPath);
74                 if (augment != null) {
75                     baArgs.add(new Item(augment));
76                 }
77             }
78             baArgs.add(baArg);
79         }
80         InstanceIdentifier ret = InstanceIdentifier.create(baArgs);
81         LOG.debug("DOM Instance Identifier {} deserialized to {}", input, ret);
82         return ret;
83     }
84
85     @Override
86     public InstanceIdentifier<? extends Object> deserialize(
87             final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier input,
88             InstanceIdentifier<?> bindingIdentifier) {
89         return deserialize(input);
90     }
91
92     private org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument _deserializePathArgument(
93             final NodeIdentifier argument, final List<QName> processedPath) {
94         final Class cls = codecRegistry.getClassForPath(processedPath);
95         Item<DataObject> item = new Item<>(cls);
96         return item;
97     }
98
99     private org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument _deserializePathArgument(
100             final NodeIdentifierWithPredicates argument, final List<QName> processedPath) {
101         final Class type = codecRegistry.getClassForPath(processedPath);
102         final IdentifierCodec codec = codecRegistry
103                 .<Identifiable<? extends Object>> getIdentifierCodecForIdentifiable(type);
104         CompositeNode _compositeNode = this.toCompositeNode(argument);
105         ValueWithQName<CompositeNode> deserialize = codec.deserialize(_compositeNode);
106         Object value = null;
107         if (deserialize != null) {
108             value = deserialize.getValue();
109         }
110         return CodecTypeUtils.newIdentifiableItem(type, value);
111     }
112
113     public CompositeNode toCompositeNode(final NodeIdentifierWithPredicates predicates) {
114         Set<Map.Entry<QName, Object>> keyValues = predicates.getKeyValues().entrySet();
115         List<Node<?>> values = new ArrayList<>(keyValues.size());
116         for (Map.Entry<QName, Object> keyValue : keyValues) {
117             values.add(new SimpleNodeTOImpl<Object>(keyValue.getKey(), null, keyValue.getValue()));
118         }
119         return new CompositeNodeTOImpl(predicates.getNodeType(), null, values);
120     }
121
122     @Override
123     public org.opendaylight.yangtools.yang.data.api.InstanceIdentifier serialize(final InstanceIdentifier<?> input) {
124         Class<?> previousAugmentation = null;
125         List<InstanceIdentifier.PathArgument> pathArgs = input.getPath();
126         QName previousQName = null;
127         List<PathArgument> components = new ArrayList<>(pathArgs.size());
128         List<QName> qnamePath = new ArrayList<>(pathArgs.size());
129         for (InstanceIdentifier.PathArgument baArg : pathArgs) {
130
131             if (!Augmentation.class.isAssignableFrom(baArg.getType())) {
132                 org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument biArg = serializePathArgument(
133                         baArg, previousQName);
134                 previousQName = biArg.getNodeType();
135                 components.add(biArg);
136                 qnamePath.add(biArg.getNodeType());
137                 ImmutableList<QName> immutableList = ImmutableList.copyOf(qnamePath);
138                 codecRegistry.putPathToClass(immutableList, baArg.getType());
139                 if (previousAugmentation != null) {
140                     updateAugmentationInjection(baArg.getType(), immutableList, previousAugmentation);
141                 }
142                 previousAugmentation = null;
143             } else {
144                 previousQName = codecRegistry.getQNameForAugmentation(baArg.getType());
145                 previousAugmentation = baArg.getType();
146             }
147         }
148         org.opendaylight.yangtools.yang.data.api.InstanceIdentifier ret = new org.opendaylight.yangtools.yang.data.api.InstanceIdentifier(
149                 components);
150         LOG.debug("Binding Instance Identifier {} serialized to DOM InstanceIdentifier {}", input, ret);
151         return ret;
152     }
153
154     public Class<? extends Object> updateAugmentationInjection(final Class<? extends DataObject> class1,
155             final ImmutableList<QName> list, final Class<?> augmentation) {
156         if (classToPreviousAugment.get(class1) == null) {
157             classToPreviousAugment.put(class1, new ConcurrentHashMap<List<QName>, Class<?>>());
158         }
159         return classToPreviousAugment.get(class1).put(list, augmentation);
160     }
161
162     private PathArgument _serializePathArgument(final Item<?> argument, final QName previousQname) {
163         Class<?> type = argument.getType();
164         QName qname = BindingReflections.findQName(type);
165         if (previousQname == null || (BindingReflections.isAugmentationChild(argument.getType()))) {
166             return new NodeIdentifier(qname);
167         }
168         return new NodeIdentifier(QName.create(previousQname, qname.getLocalName()));
169     }
170
171     private PathArgument _serializePathArgument(final IdentifiableItem argument, final QName previousQname) {
172         Map<QName, Object> predicates = new HashMap<>();
173         Class type = argument.getType();
174         IdentifierCodec<? extends Object> keyCodec = codecRegistry.getIdentifierCodecForIdentifiable(type);
175         QName qname = BindingReflections.findQName(type);
176         if (previousQname != null && !(BindingReflections.isAugmentationChild(argument.getType()))) {
177             qname = QName.create(previousQname, qname.getLocalName());
178         }
179         ValueWithQName combinedInput = new ValueWithQName(previousQname, argument.getKey());
180         CompositeNode compositeOutput = keyCodec.serialize(combinedInput);
181         for (Node<?> outputValue : compositeOutput.getValue()) {
182             predicates.put(outputValue.getNodeType(), outputValue.getValue());
183         }
184         if (previousQname == null) {
185             return new NodeIdentifierWithPredicates(qname, predicates);
186         }
187         return new NodeIdentifierWithPredicates(qname, predicates);
188     }
189
190     private org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument deserializePathArgument(
191             final PathArgument argument, final List<QName> processedPath) {
192         if (argument instanceof NodeIdentifier) {
193             return _deserializePathArgument((NodeIdentifier) argument, processedPath);
194         } else if (argument instanceof NodeIdentifierWithPredicates) {
195             return _deserializePathArgument((NodeIdentifierWithPredicates) argument, processedPath);
196         } else {
197             throw new IllegalArgumentException("Unhandled parameter types: "
198                     + Arrays.<Object> asList(argument, processedPath).toString());
199         }
200     }
201
202     private PathArgument serializePathArgument(
203             final org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument argument,
204             final QName previousQname) {
205         if (argument instanceof IdentifiableItem) {
206             return _serializePathArgument((IdentifiableItem) argument, previousQname);
207         } else if (argument instanceof Item) {
208             return _serializePathArgument((Item<?>) argument, previousQname);
209         } else {
210             throw new IllegalArgumentException("Unhandled parameter types: "
211                     + Arrays.<Object> asList(argument, previousQname).toString());
212         }
213     }
214
215 }