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.yangtools.sal.binding.generator.impl;
10 import com.google.common.collect.ImmutableList;
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;
20 import java.util.WeakHashMap;
21 import java.util.concurrent.ConcurrentHashMap;
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;
45 public class InstanceIdentifierCodecImpl implements InstanceIdentifierCodec {
46 private static final Logger LOG = LoggerFactory.getLogger(InstanceIdentifierCodecImpl.class);
48 private final CodecRegistry codecRegistry;
50 private final Map<Class<?>,Set<List<QName>>> augmentationAdapted = new WeakHashMap<>();
52 private final Map<Class<?>, Map<List<QName>, Class<?>>> classToPreviousAugment = Collections
53 .synchronizedMap(new WeakHashMap<Class<?>, Map<List<QName>, Class<?>>>());
55 public InstanceIdentifierCodecImpl(final CodecRegistry registry) {
56 this.codecRegistry = registry;
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) {
68 scannedPath.add(biArg.getNodeType());
69 org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument baArg = deserializePathArgument(
72 baType = baArg.getType();
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));
84 InstanceIdentifier<?> ret = InstanceIdentifier.create(baArgs);
85 LOG.debug("DOM Instance Identifier {} deserialized to {}", input, ret);
90 public InstanceIdentifier<? extends Object> deserialize(
91 final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier input,
92 final InstanceIdentifier<?> bindingIdentifier) {
93 return deserialize(input);
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);
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);
116 if (deserialize != null) {
117 value = deserialize.getValue();
119 return CodecTypeUtils.newIdentifiableItem(type, value);
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()));
128 return new CompositeNodeTOImpl(predicates.getNodeType(), null, values);
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;
146 previousQName = codecRegistry.getQNameForAugmentation(baArg.getType());
147 previousAugmentation = baArg.getType();
148 ensureAugmentation(qnamePath,previousQName,baArg.getType());
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);
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);
163 ImmutableList<QName> augTargetPath = ImmutableList.copyOf(augPath);
164 if(augPotential.contains(augPath)) {
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);
172 augPotential.add(augTargetPath);
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<?>>());
181 return classToPreviousAugment.get(class1).put(list, augmentation);
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);
190 return new NodeIdentifier(QName.create(previousQname, qname.getLocalName()));
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());
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());
210 if (previousQname == null) {
211 return new NodeIdentifierWithPredicates(qname, predicates);
213 return new NodeIdentifierWithPredicates(qname, predicates);
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);
223 throw new IllegalArgumentException("Unhandled parameter types: "
224 + Arrays.<Object> asList(argument, processedPath).toString());
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);
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);
248 throw new IllegalArgumentException("Unhandled parameter types: "
249 + Arrays.<Object> asList(argument, previousQname).toString());