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;
11 import java.util.ArrayList;
12 import java.util.Arrays;
13 import java.util.Collections;
14 import java.util.HashSet;
15 import java.util.LinkedHashMap;
16 import java.util.List;
19 import java.util.WeakHashMap;
20 import java.util.concurrent.ConcurrentHashMap;
21 import org.opendaylight.yangtools.concepts.Identifiable;
22 import org.opendaylight.yangtools.yang.binding.Augmentation;
23 import org.opendaylight.yangtools.yang.binding.DataObject;
24 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
25 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem;
26 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.Item;
27 import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
28 import org.opendaylight.yangtools.yang.common.QName;
29 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
30 import org.opendaylight.yangtools.yang.data.api.Node;
31 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
32 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
33 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
34 import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl;
35 import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl;
36 import org.opendaylight.yangtools.yang.data.impl.codec.CodecRegistry;
37 import org.opendaylight.yangtools.yang.data.impl.codec.IdentifierCodec;
38 import org.opendaylight.yangtools.yang.data.impl.codec.InstanceIdentifierCodec;
39 import org.opendaylight.yangtools.yang.data.impl.codec.ValueWithQName;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
43 public class InstanceIdentifierCodecImpl implements InstanceIdentifierCodec {
44 private static final Logger LOG = LoggerFactory.getLogger(InstanceIdentifierCodecImpl.class);
46 private final CodecRegistry codecRegistry;
48 private final Map<Class<?>,Set<List<QName>>> augmentationAdapted = new WeakHashMap<>();
50 private final Map<Class<?>, Map<List<QName>, Class<?>>> classToPreviousAugment = Collections
51 .synchronizedMap(new WeakHashMap<Class<?>, Map<List<QName>, Class<?>>>());
53 public InstanceIdentifierCodecImpl(final CodecRegistry registry) {
54 this.codecRegistry = registry;
58 public InstanceIdentifier<? extends Object> deserialize(
59 final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier input) {
60 Class<?> baType = null;
61 Iterable<org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument> biArgs = input.getPathArguments();
62 List<QName> scannedPath = new ArrayList<>();
63 List<InstanceIdentifier.PathArgument> baArgs = new ArrayList<InstanceIdentifier.PathArgument>();
64 for (org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument biArg : biArgs) {
66 scannedPath.add(biArg.getNodeType());
67 org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument baArg = deserializePathArgument(
70 baType = baArg.getType();
72 Map<List<QName>, Class<?>> injectAugment = classToPreviousAugment.get(baType);
73 if (injectAugment != null) {
74 @SuppressWarnings("unchecked")
75 Class<? extends DataObject> augment = (Class<? extends DataObject>) injectAugment.get(scannedPath);
76 if (augment != null) {
77 baArgs.add(new Item(augment));
82 InstanceIdentifier<?> ret = InstanceIdentifier.create(baArgs);
83 LOG.debug("DOM Instance Identifier {} deserialized to {}", input, ret);
88 public InstanceIdentifier<? extends Object> deserialize(
89 final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier input,
90 final InstanceIdentifier<?> bindingIdentifier) {
91 return deserialize(input);
94 private InstanceIdentifier.PathArgument deserializeNodeIdentifier(
95 final NodeIdentifier argument, final List<QName> processedPath) {
96 @SuppressWarnings("rawtypes")
97 final Class cls = codecRegistry.getClassForPath(processedPath);
98 @SuppressWarnings("unchecked")
99 Item<DataObject> item = new Item<>(cls);
103 private InstanceIdentifier.PathArgument deserializeNodeIdentifierWithPrecicates(
104 final NodeIdentifierWithPredicates argument, final List<QName> processedPath) {
105 @SuppressWarnings("rawtypes")
106 final Class type = codecRegistry.getClassForPath(processedPath);
107 @SuppressWarnings({ "unchecked", "rawtypes" })
108 final IdentifierCodec codec = codecRegistry
109 .<Identifiable<? extends Object>> getIdentifierCodecForIdentifiable(type);
110 CompositeNode _compositeNode = this.toCompositeNode(argument);
111 @SuppressWarnings("unchecked")
112 ValueWithQName<CompositeNode> deserialize = codec.deserialize(_compositeNode);
114 if (deserialize != null) {
115 value = deserialize.getValue();
117 return CodecTypeUtils.newIdentifiableItem(type, value);
120 public CompositeNode toCompositeNode(final NodeIdentifierWithPredicates predicates) {
121 Set<Map.Entry<QName, Object>> keyValues = predicates.getKeyValues().entrySet();
122 List<Node<?>> values = new ArrayList<>(keyValues.size());
123 for (Map.Entry<QName, Object> keyValue : keyValues) {
124 values.add(new SimpleNodeTOImpl<Object>(keyValue.getKey(), null, keyValue.getValue()));
126 return new CompositeNodeTOImpl(predicates.getNodeType(), null, values);
130 public org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier serialize(final InstanceIdentifier<?> input) {
131 Class<?> previousAugmentation = null;
132 Iterable<InstanceIdentifier.PathArgument> pathArgs = input.getPathArguments();
133 QName previousQName = null;
134 List<PathArgument> components = new ArrayList<>();
135 List<QName> qnamePath = new ArrayList<>();
136 for (InstanceIdentifier.PathArgument baArg : pathArgs) {
137 if (!Augmentation.class.isAssignableFrom(baArg.getType())) {
138 PathArgument biArg = serializePathArgumentAndUpdateMapping(qnamePath, baArg, previousQName,previousAugmentation);
139 components.add(biArg);
140 qnamePath.add(biArg.getNodeType());
141 previousQName = biArg.getNodeType();
142 previousAugmentation = null;
144 previousQName = codecRegistry.getQNameForAugmentation(baArg.getType());
145 previousAugmentation = baArg.getType();
146 ensureAugmentation(qnamePath,previousQName,baArg.getType());
149 org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier ret =
150 org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.create(components);
151 LOG.debug("Binding Instance Identifier {} serialized to DOM InstanceIdentifier {}", input, ret);
155 private synchronized void ensureAugmentation(final List<QName> augPath, final QName augQName, final Class<? extends DataObject> type) {
156 Set<List<QName>> augPotential = augmentationAdapted.get(type);
157 if(augPotential == null) {
158 augPotential = new HashSet<>();
159 augmentationAdapted.put(type, augPotential);
161 ImmutableList<QName> augTargetPath = ImmutableList.copyOf(augPath);
162 if(augPotential.contains(augPath)) {
166 for(Class<? extends DataObject> child : BindingReflections.getChildrenClasses(type)) {
167 Item<? extends DataObject> baArg = new Item<>(child);
168 PathArgument biArg = serializePathArgumentAndUpdateMapping(augPath, baArg, augQName,type);
170 augPotential.add(augTargetPath);
174 public Class<? extends Object> updateAugmentationInjection(final Class<? extends DataObject> class1,
175 final List<QName> list, final Class<?> augmentation) {
176 if (classToPreviousAugment.get(class1) == null) {
177 classToPreviousAugment.put(class1, new ConcurrentHashMap<List<QName>, Class<?>>());
179 return classToPreviousAugment.get(class1).put(list, augmentation);
182 private PathArgument serializeItem(final Item<?> argument, final QName previousQname) {
183 Class<?> type = argument.getType();
184 QName qname = BindingReflections.findQName(type);
185 if (previousQname == null || (BindingReflections.isAugmentationChild(argument.getType()))) {
186 return new NodeIdentifier(qname);
188 return new NodeIdentifier(QName.create(previousQname, qname.getLocalName()));
191 private PathArgument serializeIdentifiableItem(final IdentifiableItem<?,?> argument, final QName previousQname) {
192 @SuppressWarnings("rawtypes")
193 Class type = argument.getType();
194 @SuppressWarnings("unchecked")
195 IdentifierCodec<? extends Object> keyCodec = codecRegistry.getIdentifierCodecForIdentifiable(type);
196 QName qname = BindingReflections.findQName(type);
197 if (previousQname != null && !(BindingReflections.isAugmentationChild(argument.getType()))) {
198 qname = QName.create(previousQname, qname.getLocalName());
200 @SuppressWarnings({ "rawtypes", "unchecked" })
201 ValueWithQName combinedInput = new ValueWithQName(previousQname, argument.getKey());
202 @SuppressWarnings("unchecked")
203 CompositeNode compositeOutput = keyCodec.serialize(combinedInput);
205 final Map<QName, Object> predicates = new LinkedHashMap<>();
206 for (Node<?> outputValue : compositeOutput.getValue()) {
207 predicates.put(outputValue.getNodeType(), outputValue.getValue());
209 if (previousQname == null) {
210 return new NodeIdentifierWithPredicates(qname, predicates);
212 return new NodeIdentifierWithPredicates(qname, predicates);
215 private org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument deserializePathArgument(
216 final PathArgument argument, final List<QName> processedPath) {
217 if (argument instanceof NodeIdentifier) {
218 return deserializeNodeIdentifier((NodeIdentifier) argument, processedPath);
219 } else if (argument instanceof NodeIdentifierWithPredicates) {
220 return deserializeNodeIdentifierWithPrecicates((NodeIdentifierWithPredicates) argument, processedPath);
222 throw new IllegalArgumentException("Unhandled parameter types: "
223 + Arrays.<Object> asList(argument, processedPath).toString());
227 private PathArgument serializePathArgumentAndUpdateMapping(final List<QName> parentPath, final InstanceIdentifier.PathArgument baArg, final QName previousQName, final Class<?> previousAugmentation) {
228 org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument biArg = serializePathArgument(baArg, previousQName);
229 List<QName> qnamePath = new ArrayList<>(parentPath);
230 qnamePath.add(biArg.getNodeType());
231 ImmutableList<QName> currentPath = ImmutableList.copyOf(qnamePath);
232 codecRegistry.putPathToClass(currentPath, baArg.getType());
233 if (previousAugmentation != null) {
234 updateAugmentationInjection(baArg.getType(), currentPath, previousAugmentation);
239 private PathArgument serializePathArgument(
240 final InstanceIdentifier.PathArgument argument,
241 final QName previousQname) {
242 if (argument instanceof IdentifiableItem) {
243 return serializeIdentifiableItem((IdentifiableItem<?,?>) argument, previousQname);
244 } else if (argument instanceof Item) {
245 return serializeItem((Item<?>) argument, previousQname);
247 throw new IllegalArgumentException("Unhandled parameter types: "
248 + Arrays.<Object> asList(argument, previousQname).toString());