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.base.Preconditions;
11 import org.opendaylight.yangtools.binding.generator.util.ReferencedTypeImpl;
12 import org.opendaylight.yangtools.binding.generator.util.Types;
13 import org.opendaylight.yangtools.concepts.Delegator;
14 import org.opendaylight.yangtools.concepts.Identifiable;
15 import org.opendaylight.yangtools.sal.binding.generator.api.ClassLoadingStrategy;
16 import org.opendaylight.yangtools.sal.binding.generator.util.ClassLoaderUtils;
17 import org.opendaylight.yangtools.sal.binding.generator.util.CodeGenerationException;
18 import org.opendaylight.yangtools.sal.binding.model.api.ConcreteType;
19 import org.opendaylight.yangtools.sal.binding.model.api.Type;
20 import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTOBuilder;
21 import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTypeBuilder;
22 import org.opendaylight.yangtools.yang.binding.Augmentable;
23 import org.opendaylight.yangtools.yang.binding.Augmentation;
24 import org.opendaylight.yangtools.yang.binding.BaseIdentity;
25 import org.opendaylight.yangtools.yang.binding.BindingCodec;
26 import org.opendaylight.yangtools.yang.binding.DataContainer;
27 import org.opendaylight.yangtools.yang.binding.DataObject;
28 import org.opendaylight.yangtools.yang.binding.Identifier;
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.Node;
33 import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl;
34 import org.opendaylight.yangtools.yang.data.impl.codec.AugmentationCodec;
35 import org.opendaylight.yangtools.yang.data.impl.codec.ChoiceCaseCodec;
36 import org.opendaylight.yangtools.yang.data.impl.codec.ChoiceCodec;
37 import org.opendaylight.yangtools.yang.data.impl.codec.CodecRegistry;
38 import org.opendaylight.yangtools.yang.data.impl.codec.DataContainerCodec;
39 import org.opendaylight.yangtools.yang.data.impl.codec.DomCodec;
40 import org.opendaylight.yangtools.yang.data.impl.codec.IdentifierCodec;
41 import org.opendaylight.yangtools.yang.data.impl.codec.IdentityCodec;
42 import org.opendaylight.yangtools.yang.data.impl.codec.InstanceIdentifierCodec;
43 import org.opendaylight.yangtools.yang.data.impl.codec.ValueWithQName;
44 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
45 import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
46 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
47 import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
48 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
49 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
50 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
51 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
52 import org.opendaylight.yangtools.yang.model.api.Module;
53 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
54 import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
55 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
56 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
57 import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
58 import org.slf4j.Logger;
59 import org.slf4j.LoggerFactory;
61 import java.lang.ref.WeakReference;
62 import java.lang.reflect.Field;
63 import java.lang.reflect.ParameterizedType;
64 import java.util.ArrayList;
65 import java.util.Collection;
66 import java.util.Collections;
67 import java.util.HashMap;
68 import java.util.HashSet;
69 import java.util.Iterator;
70 import java.util.List;
72 import java.util.Map.Entry;
73 import java.util.Objects;
75 import java.util.WeakHashMap;
76 import java.util.concurrent.Callable;
77 import java.util.concurrent.ConcurrentHashMap;
78 import java.util.concurrent.ConcurrentMap;
80 public class LazyGeneratedCodecRegistry implements //
82 SchemaContextListener, //
85 private final static Logger LOG = LoggerFactory.getLogger(LazyGeneratedCodecRegistry.class);
86 private final static LateMixinCodec NOT_READY_CODEC = new LateMixinCodec();
88 private final InstanceIdentifierCodec instanceIdentifierCodec = new InstanceIdentifierCodecImpl(this);
89 private final IdentityCompositeCodec identityRefCodec = new IdentityCompositeCodec();
91 private TransformerGenerator generator;
93 // Concrete class to codecs
94 private static final Map<Class<?>, DataContainerCodec<?>> containerCodecs = Collections
95 .synchronizedMap(new WeakHashMap<Class<?>, DataContainerCodec<?>>());
96 private static final Map<Class<?>, IdentifierCodec<?>> identifierCodecs = Collections
97 .synchronizedMap(new WeakHashMap<Class<?>, IdentifierCodec<?>>());
98 private static final Map<Class<?>, ChoiceCodecImpl<?>> choiceCodecs = Collections
99 .synchronizedMap(new WeakHashMap<Class<?>, ChoiceCodecImpl<?>>());
100 private static final Map<Class<?>, ChoiceCaseCodecImpl<?>> caseCodecs = Collections
101 .synchronizedMap(new WeakHashMap<Class<?>, ChoiceCaseCodecImpl<?>>());
102 private static final Map<Class<?>, AugmentableCompositeCodec> augmentableCodecs = Collections
103 .synchronizedMap(new WeakHashMap<Class<?>, AugmentableCompositeCodec>());
104 private static final Map<Class<?>, AugmentationCodec<?>> augmentationCodecs = Collections
105 .synchronizedMap(new WeakHashMap<Class<?>, AugmentationCodec<?>>());
106 private static final Map<Class<?>, QName> identityQNames = Collections
107 .synchronizedMap(new WeakHashMap<Class<?>, QName>());
108 private static final Map<QName, Type> qnamesToIdentityMap = new ConcurrentHashMap<>();
109 /** Binding type to encountered classes mapping **/
110 @SuppressWarnings("rawtypes")
111 private static final Map<Type, WeakReference<Class>> typeToClass = new ConcurrentHashMap<>();
113 @SuppressWarnings("rawtypes")
114 private static final ConcurrentMap<Type, ChoiceCaseCodecImpl> typeToCaseCodecs = new ConcurrentHashMap<>();
116 private final CaseClassMapFacade classToCaseRawCodec = new CaseClassMapFacade();
118 private static final Map<SchemaPath, GeneratedTypeBuilder> pathToType = new ConcurrentHashMap<>();
119 private static final Map<List<QName>, Type> pathToInstantiatedType = new ConcurrentHashMap<>();
120 private static final Map<Type, QName> typeToQname = new ConcurrentHashMap<>();
121 private static final Map<AugmentationSchema, Type> augmentToType = new ConcurrentHashMap<>();
123 private final SchemaLock lock;
125 private SchemaContext currentSchema;
127 private final ClassLoadingStrategy classLoadingStrategy;
129 LazyGeneratedCodecRegistry(SchemaLock lock, ClassLoadingStrategy identityClassLoadingStrategy) {
130 this.lock = Preconditions.checkNotNull(lock);
131 this.classLoadingStrategy = identityClassLoadingStrategy;
134 public SchemaLock getLock() {
138 public TransformerGenerator getGenerator() {
142 public void setGenerator(TransformerGenerator generator) {
143 this.generator = generator;
147 public InstanceIdentifierCodec getInstanceIdentifierCodec() {
148 return instanceIdentifierCodec;
152 public <T extends Augmentation<?>> AugmentationCodec<T> getCodecForAugmentation(Class<T> object) {
153 AugmentationCodec<T> codec = null;
154 @SuppressWarnings("rawtypes")
155 AugmentationCodec potentialCodec = augmentationCodecs.get(object);
156 if (potentialCodec != null) {
157 codec = potentialCodec;
160 lock.waitForSchema(object);
161 Class<? extends BindingCodec<Map<QName, Object>, Object>> augmentRawCodec = generator
162 .augmentationTransformerFor(object);
163 BindingCodec<Map<QName, Object>, Object> rawCodec = augmentRawCodec.newInstance();
164 codec = new AugmentationCodecWrapper<T>(rawCodec);
165 augmentationCodecs.put(object, codec);
166 } catch (InstantiationException e) {
167 LOG.error("Can not instantiate raw augmentation codec {}", object.getSimpleName(), e);
168 } catch (IllegalAccessException e) {
170 "Run-time consistency issue: constructor {} is not available. This indicates either a code generation bug or a misconfiguration of JVM.",
171 object.getSimpleName(), e);
173 Class<? extends Augmentable<?>> objectSupertype = getAugmentableArgumentFrom(object);
174 if (objectSupertype != null) {
175 getAugmentableCodec(objectSupertype).addAugmentationCodec(object, codec);
177 LOG.warn("Could not find augmentation target for augmentation {}", object);
183 public QName getQNameForAugmentation(Class<?> cls) {
184 Preconditions.checkArgument(Augmentation.class.isAssignableFrom(cls));
185 return getCodecForAugmentation((Class<? extends Augmentation>) cls).getAugmentationQName();
188 private static Class<? extends Augmentable<?>> getAugmentableArgumentFrom(
189 final Class<? extends Augmentation<?>> augmentation) {
191 Class<? extends Augmentable<?>> ret = ClassLoaderUtils.withClassLoader(augmentation.getClassLoader(),
192 new Callable<Class<? extends Augmentable<?>>>() {
194 @SuppressWarnings("unchecked")
195 public Class<? extends Augmentable<?>> call() throws Exception {
196 for (java.lang.reflect.Type supertype : augmentation.getGenericInterfaces()) {
197 if (supertype instanceof ParameterizedType
198 && Augmentation.class.equals(((ParameterizedType) supertype).getRawType())) {
199 ParameterizedType augmentationGeneric = (ParameterizedType) supertype;
200 return (Class<? extends Augmentable<?>>) augmentationGeneric
201 .getActualTypeArguments()[0];
208 } catch (Exception e) {
209 LOG.debug("Could not find augmentable for {} using {}", augmentation, augmentation.getClassLoader(), e);
215 public Class<?> getClassForPath(List<QName> names) {
216 DataSchemaNode node = getSchemaNode(names);
217 SchemaPath path = node.getPath();
218 Type type = pathToType.get(path);
220 type = new ReferencedTypeImpl(type.getPackageName(), type.getName());
222 type = pathToInstantiatedType.get(names);
224 @SuppressWarnings("rawtypes")
225 WeakReference<Class> weakRef = typeToClass.get(type);
226 if (weakRef == null) {
227 LOG.error("Could not find loaded class for path: {} and type: {}", path, type.getFullyQualifiedName());
229 return weakRef.get();
233 public void putPathToClass(List<QName> names, Class<?> cls) {
234 Type reference = Types.typeForClass(cls);
235 pathToInstantiatedType.put(names, reference);
236 bindingClassEncountered(cls);
240 public IdentifierCodec<?> getKeyCodecForPath(List<QName> names) {
241 @SuppressWarnings("unchecked")
242 Class<? extends Identifiable<?>> cls = (Class<? extends Identifiable<?>>) getClassForPath(names);
243 return getIdentifierCodecForIdentifiable(cls);
247 public <T extends DataContainer> DataContainerCodec<T> getCodecForDataObject(Class<T> type) {
248 @SuppressWarnings("unchecked")
249 DataContainerCodec<T> ret = (DataContainerCodec<T>) containerCodecs.get(type);
253 Class<? extends BindingCodec<Map<QName, Object>, Object>> newType = generator.transformerFor(type);
254 BindingCodec<Map<QName, Object>, Object> rawCodec = newInstanceOf(newType);
255 DataContainerCodecImpl<T> newWrapper = new DataContainerCodecImpl<>(rawCodec);
256 containerCodecs.put(type, newWrapper);
261 @SuppressWarnings("rawtypes")
262 public void bindingClassEncountered(Class cls) {
264 ConcreteType typeRef = Types.typeForClass(cls);
265 if (typeToClass.containsKey(typeRef)) {
268 LOG.trace("Binding Class {} encountered.", cls);
269 WeakReference<Class> weakRef = new WeakReference<>(cls);
270 typeToClass.put(typeRef, weakRef);
271 if (Augmentation.class.isAssignableFrom(cls)) {
273 } else if (DataObject.class.isAssignableFrom(cls)) {
274 @SuppressWarnings({ "unchecked", "unused" })
275 Object cdc = getCodecForDataObject((Class<? extends DataObject>) cls);
280 public void onClassProcessed(Class<?> cls) {
281 ConcreteType typeRef = Types.typeForClass(cls);
282 if (typeToClass.containsKey(typeRef)) {
285 LOG.trace("Binding Class {} encountered.", cls);
286 @SuppressWarnings("rawtypes")
287 WeakReference<Class> weakRef = new WeakReference<Class>(cls);
288 typeToClass.put(typeRef, weakRef);
291 private DataSchemaNode getSchemaNode(List<QName> path) {
292 QName firstNode = path.get(0);
293 DataNodeContainer previous = currentSchema.findModuleByNamespaceAndRevision(firstNode.getNamespace(),
294 firstNode.getRevision());
295 Iterator<QName> iterator = path.iterator();
296 while (iterator.hasNext()) {
297 QName arg = iterator.next();
298 DataSchemaNode currentNode = previous.getDataChildByName(arg);
299 if (currentNode == null && previous instanceof DataNodeContainer) {
300 currentNode = searchInChoices(previous, arg);
302 if (currentNode instanceof DataNodeContainer) {
303 previous = (DataNodeContainer) currentNode;
304 } else if (currentNode instanceof LeafSchemaNode || currentNode instanceof LeafListSchemaNode) {
305 Preconditions.checkState(!iterator.hasNext(), "Path tries to nest inside leaf node.");
309 return (DataSchemaNode) previous;
312 private DataSchemaNode searchInChoices(DataNodeContainer node, QName arg) {
313 Set<DataSchemaNode> children = node.getChildNodes();
314 for (DataSchemaNode child : children) {
315 if (child instanceof ChoiceNode) {
316 ChoiceNode choiceNode = (ChoiceNode) child;
317 DataSchemaNode potential = searchInCases(choiceNode, arg);
318 if (potential != null) {
326 private DataSchemaNode searchInCases(ChoiceNode choiceNode, QName arg) {
327 Set<ChoiceCaseNode> cases = choiceNode.getCases();
328 for (ChoiceCaseNode caseNode : cases) {
329 DataSchemaNode node = caseNode.getDataChildByName(arg);
337 private <T> T newInstanceOf(Class<?> newType) {
339 @SuppressWarnings("unchecked")
340 T ret = (T) newType.newInstance();
342 } catch (InstantiationException e) {
343 throw new IllegalStateException(e);
344 } catch (IllegalAccessException e) {
345 throw new IllegalStateException(e);
350 public <T extends Identifiable<?>> IdentifierCodec<?> getIdentifierCodecForIdentifiable(Class<T> type) {
351 IdentifierCodec<?> obj = identifierCodecs.get(type);
355 Class<? extends BindingCodec<Map<QName, Object>, Object>> newCodec = generator
356 .keyTransformerForIdentifiable(type);
357 BindingCodec<Map<QName, Object>, Object> newInstance;
358 newInstance = newInstanceOf(newCodec);
359 IdentifierCodecImpl<?> newWrapper = new IdentifierCodecImpl<>(newInstance);
360 identifierCodecs.put(type, newWrapper);
365 public IdentityCodec<?> getIdentityCodec() {
366 return identityRefCodec;
370 public <T extends BaseIdentity> IdentityCodec<T> getCodecForIdentity(Class<T> codec) {
371 bindingClassEncountered(codec);
372 return identityRefCodec;
376 public void onCodecCreated(Class<?> cls) {
377 CodecMapping.setIdentifierCodec(cls, instanceIdentifierCodec);
378 CodecMapping.setIdentityRefCodec(cls, identityRefCodec);
382 public <T extends Identifier<?>> IdentifierCodec<T> getCodecForIdentifier(Class<T> object) {
383 @SuppressWarnings("unchecked")
384 IdentifierCodec<T> obj = (IdentifierCodec<T>) identifierCodecs.get(object);
388 Class<? extends BindingCodec<Map<QName, Object>, Object>> newCodec = generator
389 .keyTransformerForIdentifier(object);
390 BindingCodec<Map<QName, Object>, Object> newInstance;
391 newInstance = newInstanceOf(newCodec);
392 IdentifierCodecImpl<T> newWrapper = new IdentifierCodecImpl<>(newInstance);
393 identifierCodecs.put(object, newWrapper);
397 @SuppressWarnings("rawtypes")
398 public ChoiceCaseCodecImpl getCaseCodecFor(Class caseClass) {
399 ChoiceCaseCodecImpl<?> potential = caseCodecs.get(caseClass);
400 if (potential != null) {
403 ConcreteType typeref = Types.typeForClass(caseClass);
404 ChoiceCaseCodecImpl caseCodec = typeToCaseCodecs.get(typeref);
406 Preconditions.checkState(caseCodec != null, "Case Codec was not created proactivelly for %s",
407 caseClass.getName());
408 Preconditions.checkState(caseCodec.getSchema() != null, "Case schema is not available for %s",
409 caseClass.getName());
410 @SuppressWarnings("unchecked")
411 Class<? extends BindingCodec> newCodec = generator.caseCodecFor(caseClass, caseCodec.getSchema());
412 BindingCodec newInstance = newInstanceOf(newCodec);
413 caseCodec.setDelegate(newInstance);
414 caseCodecs.put(caseClass, caseCodec);
416 for (Entry<Class<?>, ChoiceCodecImpl<?>> choice : choiceCodecs.entrySet()) {
417 if (choice.getKey().isAssignableFrom(caseClass)) {
418 choice.getValue().cases.put(caseClass, caseCodec);
424 public void onModuleContextAdded(SchemaContext schemaContext, Module module, ModuleContext context) {
425 pathToType.putAll(context.getChildNodes());
426 augmentToType.putAll(context.getTypeToAugmentation().inverse());
427 qnamesToIdentityMap.putAll(context.getIdentities());
428 for (Entry<QName, GeneratedTOBuilder> identity : context.getIdentities().entrySet()) {
430 new ReferencedTypeImpl(identity.getValue().getPackageName(), identity.getValue().getName()),
433 captureCases(context.getCases(), schemaContext);
436 private void captureCases(Map<SchemaPath, GeneratedTypeBuilder> cases, SchemaContext module) {
437 for (Entry<SchemaPath, GeneratedTypeBuilder> caseNode : cases.entrySet()) {
438 ReferencedTypeImpl typeref = new ReferencedTypeImpl(caseNode.getValue().getPackageName(), caseNode
439 .getValue().getName());
441 pathToType.put(caseNode.getKey(), caseNode.getValue());
443 ChoiceCaseNode node = (ChoiceCaseNode) SchemaContextUtil.findDataSchemaNode(module, caseNode.getKey());
446 LOG.warn("Failed to find YANG SchemaNode for {}, with path {} was not found in context.",
447 typeref.getFullyQualifiedName(), caseNode.getKey());
448 @SuppressWarnings("rawtypes")
449 ChoiceCaseCodecImpl value = new ChoiceCaseCodecImpl();
450 typeToCaseCodecs.putIfAbsent(typeref, value);
453 @SuppressWarnings("rawtypes")
454 ChoiceCaseCodecImpl value = new ChoiceCaseCodecImpl(node);
455 typeToCaseCodecs.putIfAbsent(typeref, value);
460 public void onGlobalContextUpdated(SchemaContext context) {
461 currentSchema = context;
464 @SuppressWarnings({ "unchecked", "rawtypes" })
466 public void onChoiceCodecCreated(Class<?> choiceClass,
467 Class<? extends BindingCodec<Map<QName, Object>, Object>> choiceCodec, ChoiceNode schema) {
468 ChoiceCodec<?> oldCodec = choiceCodecs.get(choiceClass);
469 Preconditions.checkState(oldCodec == null);
470 BindingCodec<Map<QName, Object>, Object> delegate = newInstanceOf(choiceCodec);
471 ChoiceCodecImpl<?> newCodec = new ChoiceCodecImpl(delegate);
472 choiceCodecs.put(choiceClass, newCodec);
473 CodecMapping.setClassToCaseMap(choiceCodec, classToCaseRawCodec);
474 CodecMapping.setCompositeNodeToCaseMap(choiceCodec, newCodec.getCompositeToCase());
476 tryToCreateCasesCodecs(schema);
480 private void tryToCreateCasesCodecs(ChoiceNode schema) {
481 for (ChoiceCaseNode choiceCase : schema.getCases()) {
482 ChoiceCaseNode caseNode = choiceCase;
483 if (caseNode.isAddedByUses()) {
484 DataSchemaNode origCaseNode = SchemaContextUtil.findOriginal(caseNode, currentSchema);
485 if (origCaseNode instanceof ChoiceCaseNode) {
486 caseNode = (ChoiceCaseNode) origCaseNode;
489 SchemaPath path = caseNode.getPath();
491 GeneratedTypeBuilder type;
492 if (path != null && (type = pathToType.get(path)) != null) {
493 ReferencedTypeImpl typeref = new ReferencedTypeImpl(type.getPackageName(), type.getName());
494 ChoiceCaseCodecImpl partialCodec = typeToCaseCodecs.get(typeref);
495 if (partialCodec.getSchema() == null) {
496 partialCodec.setSchema(caseNode);
499 Class<?> caseClass = classLoadingStrategy.loadClass(type.getFullyQualifiedName());
500 getCaseCodecFor(caseClass);
501 } catch (ClassNotFoundException e) {
502 LOG.trace("Could not proactivelly create case codec for {}", type, e);
510 public void onValueCodecCreated(Class<?> valueClass, Class<?> valueCodec) {
514 public void onCaseCodecCreated(Class<?> choiceClass,
515 Class<? extends BindingCodec<Map<QName, Object>, Object>> choiceCodec) {
519 public void onDataContainerCodecCreated(Class<?> dataClass, Class<? extends BindingCodec<?, ?>> dataCodec) {
520 if (Augmentable.class.isAssignableFrom(dataClass)) {
521 AugmentableCompositeCodec augmentableCodec = getAugmentableCodec(dataClass);
522 CodecMapping.setAugmentationCodec(dataCodec, augmentableCodec);
527 public AugmentableCompositeCodec getAugmentableCodec(Class<?> dataClass) {
528 AugmentableCompositeCodec ret = augmentableCodecs.get(dataClass);
532 ret = new AugmentableCompositeCodec(dataClass);
533 augmentableCodecs.put(dataClass, ret);
535 Map<Type, SchemaNode> typeToSchemaNode = generator.getTypeToSchemaNode();
536 Type refType = new ReferencedTypeImpl(dataClass.getPackage().getName(), dataClass.getSimpleName());
537 SchemaNode node = typeToSchemaNode.get(refType);
538 tryToLoadAugmentations(node);
543 private void tryToLoadAugmentations(SchemaNode schemaNode) {
544 if (schemaNode instanceof AugmentationTarget) {
545 AugmentationTarget augmentationTarget = (AugmentationTarget) schemaNode;
546 Set<AugmentationSchema> augments = augmentationTarget.getAvailableAugmentations();
547 Set<Type> augmentTypes = new HashSet<>();
548 if (augments != null) {
549 for (AugmentationSchema augment : augments) {
550 Type augmentType = augmentToType.get(augment);
551 if (augmentType == null) {
552 LOG.warn("Failed to find type for augmentation of {}", augment);
554 augmentTypes.add(augmentType);
557 for (Type augmentType : augmentTypes) {
558 Class<? extends Augmentation<?>> clazz = null;
560 clazz = (Class<? extends Augmentation<?>>) classLoadingStrategy.loadClass(augmentType);
561 getCodecForAugmentation(clazz);
562 } catch (ClassNotFoundException e) {
563 LOG.warn("Failed to find class for augmentation of {}, reason: {}", augmentType, e.toString());
564 } catch (CodeGenerationException e) {
565 LOG.warn("Failed to proactively generate augment coded for {}, reason: {}", augmentType, e.toString());
571 if (schemaNode instanceof DataNodeContainer) {
572 Set<DataSchemaNode> childNodes = ((DataNodeContainer) schemaNode).getChildNodes();
573 for (DataSchemaNode child : childNodes) {
574 tryToLoadAugmentations(child);
579 private static abstract class IntermediateCodec<T> implements //
580 DomCodec<T>, Delegator<BindingCodec<Map<QName, Object>, Object>> {
582 private final BindingCodec<Map<QName, Object>, Object> delegate;
585 public BindingCodec<Map<QName, Object>, Object> getDelegate() {
589 public IntermediateCodec(BindingCodec<Map<QName, Object>, Object> delegate) {
590 this.delegate = delegate;
594 public Node<?> serialize(ValueWithQName<T> input) {
595 Map<QName, Object> intermediateOutput = delegate.serialize(input);
596 return IntermediateMapping.toNode(intermediateOutput);
600 private static class IdentifierCodecImpl<T extends Identifier<?>> //
601 extends IntermediateCodec<T> //
602 implements IdentifierCodec<T> {
604 public IdentifierCodecImpl(BindingCodec<Map<QName, Object>, Object> delegate) {
609 public ValueWithQName<T> deserialize(Node<?> input) {
610 QName qname = input.getNodeType();
611 @SuppressWarnings("unchecked")
612 T value = (T) getDelegate().deserialize((Map<QName, Object>) input);
613 return new ValueWithQName<T>(qname, value);
617 public CompositeNode serialize(ValueWithQName<T> input) {
618 return (CompositeNode) super.serialize(input);
622 private static class DataContainerCodecImpl<T extends DataContainer> //
623 extends IntermediateCodec<T> //
624 implements DataContainerCodec<T> {
626 public DataContainerCodecImpl(BindingCodec<Map<QName, Object>, Object> delegate) {
631 public ValueWithQName<T> deserialize(Node<?> input) {
635 QName qname = input.getNodeType();
636 @SuppressWarnings("unchecked")
637 T value = (T) getDelegate().deserialize((Map<QName, Object>) input);
638 return new ValueWithQName<T>(qname, value);
642 public CompositeNode serialize(ValueWithQName<T> input) {
643 return (CompositeNode) super.serialize(input);
647 @SuppressWarnings("rawtypes")
648 private static class ChoiceCaseCodecImpl<T extends DataContainer> implements ChoiceCaseCodec<T>, //
649 Delegator<BindingCodec> {
650 private boolean augmenting;
651 private boolean uses;
652 private BindingCodec delegate;
654 private Set<String> validNames;
655 private Set<QName> validQNames;
656 private ChoiceCaseNode schema;
658 public void setSchema(ChoiceCaseNode caseNode) {
659 this.schema = caseNode;
660 validNames = new HashSet<>();
661 validQNames = new HashSet<>();
662 for (DataSchemaNode node : caseNode.getChildNodes()) {
663 QName qname = node.getQName();
664 validQNames.add(qname);
665 validNames.add(qname.getLocalName());
667 augmenting = caseNode.isAugmenting();
668 uses = caseNode.isAddedByUses();
671 public ChoiceCaseCodecImpl() {
672 this.delegate = NOT_READY_CODEC;
675 public ChoiceCaseCodecImpl(ChoiceCaseNode caseNode) {
676 this.delegate = NOT_READY_CODEC;
681 public ValueWithQName<T> deserialize(Node<?> input) {
682 throw new UnsupportedOperationException("Direct invocation of this codec is not allowed.");
686 public CompositeNode serialize(ValueWithQName<T> input) {
687 throw new UnsupportedOperationException("Direct invocation of this codec is not allowed.");
691 public BindingCodec getDelegate() {
695 public void setDelegate(BindingCodec delegate) {
696 this.delegate = delegate;
699 public ChoiceCaseNode getSchema() {
704 public boolean isAcceptable(Node<?> input) {
705 if (input instanceof CompositeNode) {
706 if (augmenting && !uses) {
707 return checkAugmenting((CompositeNode) input);
709 return checkLocal((CompositeNode) input);
715 private boolean checkLocal(CompositeNode input) {
716 QName parent = input.getNodeType();
717 for (Node<?> childNode : input.getChildren()) {
718 QName child = childNode.getNodeType();
719 if (!Objects.equals(parent.getNamespace(), child.getNamespace())
720 || !Objects.equals(parent.getRevision(), child.getRevision())) {
723 if (validNames.contains(child.getLocalName())) {
730 private boolean checkAugmenting(CompositeNode input) {
731 for (Node<?> child : input.getChildren()) {
732 if (validQNames.contains(child.getNodeType())) {
740 private static class ChoiceCodecImpl<T> implements ChoiceCodec<T> {
742 private final BindingCodec<Map<QName, Object>, Object> delegate;
744 @SuppressWarnings("rawtypes")
745 private final Map<Class, ChoiceCaseCodecImpl<?>> cases = Collections
746 .synchronizedMap(new WeakHashMap<Class, ChoiceCaseCodecImpl<?>>());
748 private final CaseCompositeNodeMapFacade CompositeToCase;
750 public ChoiceCodecImpl(BindingCodec<Map<QName, Object>, Object> delegate) {
751 this.delegate = delegate;
752 this.CompositeToCase = new CaseCompositeNodeMapFacade(cases);
756 public ValueWithQName<T> deserialize(Node<?> input) {
757 throw new UnsupportedOperationException("Direct invocation of this codec is not allowed.");
761 public Node<?> serialize(ValueWithQName<T> input) {
762 throw new UnsupportedOperationException("Direct invocation of this codec is not allowed.");
765 public CaseCompositeNodeMapFacade getCompositeToCase() {
766 return CompositeToCase;
769 public Map<Class, ChoiceCaseCodecImpl<?>> getCases() {
773 public BindingCodec<Map<QName, Object>, Object> getDelegate() {
779 @SuppressWarnings("rawtypes")
780 private class CaseClassMapFacade extends MapFacadeBase {
783 public Set<Entry<Class, BindingCodec<Object, Object>>> entrySet() {
784 return Collections.emptySet();
788 public BindingCodec get(Object key) {
789 if (key instanceof Class) {
790 Class cls = (Class) key;
791 // bindingClassEncountered(cls);
792 ChoiceCaseCodecImpl caseCodec = getCaseCodecFor(cls);
793 return caseCodec.getDelegate();
799 @SuppressWarnings("rawtypes")
800 private static class CaseCompositeNodeMapFacade extends MapFacadeBase<CompositeNode> {
802 final Map<Class, ChoiceCaseCodecImpl<?>> choiceCases;
804 public CaseCompositeNodeMapFacade(Map<Class, ChoiceCaseCodecImpl<?>> choiceCases) {
805 this.choiceCases = choiceCases;
809 public BindingCodec get(Object key) {
810 if (!(key instanceof CompositeNode)) {
813 for (Entry<Class, ChoiceCaseCodecImpl<?>> entry : choiceCases.entrySet()) {
814 ChoiceCaseCodecImpl<?> codec = entry.getValue();
815 if (codec.isAcceptable((CompositeNode) key)) {
816 return codec.getDelegate();
825 * This map is used as only facade for
826 * {@link org.opendaylight.yangtools.yang.binding.BindingCodec} in different
827 * classloaders to retrieve codec dynamicly based on provided key.
832 @SuppressWarnings("rawtypes")
833 private static abstract class MapFacadeBase<T> implements Map<T, BindingCodec<?, ?>> {
836 public boolean containsKey(Object key) {
837 return get(key) != null;
841 public void clear() {
842 throw notModifiable();
846 public boolean equals(Object obj) {
847 return super.equals(obj);
851 public BindingCodec remove(Object key) {
861 public Collection<BindingCodec<?, ?>> values() {
862 return Collections.emptySet();
865 private UnsupportedOperationException notModifiable() {
866 return new UnsupportedOperationException("Not externally modifiable.");
870 public BindingCodec<Map<QName, Object>, Object> put(T key, BindingCodec<?, ?> value) {
871 throw notModifiable();
875 public void putAll(Map<? extends T, ? extends BindingCodec<?, ?>> m) {
876 throw notModifiable();
880 public int hashCode() {
881 return super.hashCode();
885 public boolean isEmpty() {
890 public Set<T> keySet() {
891 return Collections.emptySet();
895 public Set<Entry<T, BindingCodec<?, ?>>> entrySet() {
896 return Collections.emptySet();
900 public boolean containsValue(Object value) {
905 @SuppressWarnings({ "rawtypes", "unchecked" })
906 private class AugmentableCompositeCodec implements BindingCodec {
908 private final Class augmentableType;
910 Map<Class, AugmentationCodec<?>> localAugmentationCodecs = Collections
911 .synchronizedMap(new WeakHashMap<Class, AugmentationCodec<?>>());
913 public AugmentableCompositeCodec(Class type) {
914 Preconditions.checkArgument(Augmentable.class.isAssignableFrom(type));
915 augmentableType = type;
919 public Object serialize(Object input) {
920 if (input instanceof Augmentable<?>) {
922 Map<Class, Augmentation> augmentations = getAugmentations(input);
923 return serializeImpl(augmentations);
928 private Map<Class, Augmentation> getAugmentations(Object input) {
929 Field augmentationField;
931 augmentationField = input.getClass().getDeclaredField("augmentation");
932 augmentationField.setAccessible(true);
933 Map<Class, Augmentation> augMap = (Map<Class, Augmentation>) augmentationField.get(input);
935 } catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) {
936 LOG.debug("Could not read augmentations for {}", input, e);
938 return Collections.emptyMap();
941 private List serializeImpl(Map<Class, Augmentation> input) {
942 List ret = new ArrayList<>();
943 for (Entry<Class, Augmentation> entry : input.entrySet()) {
944 AugmentationCodec codec = getCodecForAugmentation(entry.getKey());
945 CompositeNode node = codec.serialize(new ValueWithQName(null, entry.getValue()));
946 ret.addAll(node.getChildren());
951 public synchronized <T extends Augmentation<?>> void addAugmentationCodec(Class<T> augmentationClass,
952 AugmentationCodec<T> value) {
953 localAugmentationCodecs.put(augmentationClass, value);
957 public Map<Class, Augmentation> deserialize(Object input) {
958 Map<Class, Augmentation> ret = new HashMap<>();
959 if (input instanceof CompositeNode) {
960 List<Entry<Class, AugmentationCodec<?>>> codecs = new ArrayList<>(localAugmentationCodecs.entrySet());
961 for (Entry<Class, AugmentationCodec<?>> codec : codecs) {
962 ValueWithQName<?> value = codec.getValue().deserialize((CompositeNode) input);
963 if (value != null && value.getValue() != null) {
964 ret.put(codec.getKey(), (Augmentation) value.getValue());
971 public Class getAugmentableType() {
972 return augmentableType;
976 @SuppressWarnings({ "rawtypes", "unchecked" })
977 private static class LateMixinCodec implements BindingCodec, Delegator<BindingCodec> {
979 private BindingCodec delegate;
982 public BindingCodec getDelegate() {
983 if (delegate == null) {
984 throw new IllegalStateException("Codec not initialized yet.");
990 public Object deserialize(Object input) {
991 return getDelegate().deserialize(input);
995 public Object serialize(Object input) {
996 return getDelegate().serialize(input);
1000 private static class AugmentationCodecWrapper<T extends Augmentation<?>> implements AugmentationCodec<T>,
1001 Delegator<BindingCodec> {
1003 private final BindingCodec delegate;
1004 private final QName augmentationQName;
1006 public AugmentationCodecWrapper(BindingCodec<Map<QName, Object>, Object> rawCodec) {
1007 this.delegate = rawCodec;
1008 this.augmentationQName = BindingReflections.findQName(rawCodec.getClass());
1012 public BindingCodec getDelegate() {
1017 public CompositeNode serialize(ValueWithQName<T> input) {
1018 @SuppressWarnings("unchecked")
1019 List<Map<QName, Object>> rawValues = (List<Map<QName, Object>>) getDelegate().serialize(input);
1020 List<Node<?>> serialized = new ArrayList<>(rawValues.size());
1021 for (Map<QName, Object> val : rawValues) {
1022 serialized.add(IntermediateMapping.toNode(val));
1024 return new CompositeNodeTOImpl(input.getQname(), null, serialized);
1028 @SuppressWarnings("unchecked")
1029 public ValueWithQName<T> deserialize(Node<?> input) {
1030 Object rawCodecValue = getDelegate().deserialize(input);
1031 return new ValueWithQName<T>(input.getNodeType(), (T) rawCodecValue);
1035 public QName getAugmentationQName() {
1036 return augmentationQName;
1040 private class IdentityCompositeCodec implements IdentityCodec {
1043 public Object deserialize(Object input) {
1044 Preconditions.checkArgument(input instanceof QName);
1045 return deserialize((QName) input);
1049 public Class<?> deserialize(QName input) {
1050 Type type = qnamesToIdentityMap.get(input);
1054 ReferencedTypeImpl typeref = new ReferencedTypeImpl(type.getPackageName(), type.getName());
1055 WeakReference<Class> softref = typeToClass.get(typeref);
1056 if (softref == null) {
1059 Class<?> cls = classLoadingStrategy.loadClass(typeref.getFullyQualifiedName());
1064 } catch (Exception e) {
1065 LOG.warn("Identity {} was not deserialized, because of missing class {}", input,
1066 typeref.getFullyQualifiedName());
1070 return softref.get();
1074 public QName serialize(Class input) {
1075 Preconditions.checkArgument(BaseIdentity.class.isAssignableFrom(input));
1076 bindingClassEncountered(input);
1077 QName qname = identityQNames.get(input);
1078 if (qname != null) {
1081 ConcreteType typeref = Types.typeForClass(input);
1082 qname = typeToQname.get(typeref);
1083 if (qname != null) {
1084 identityQNames.put(input, qname);
1090 public Object serialize(Object input) {
1091 Preconditions.checkArgument(input instanceof Class);
1092 return serialize((Class) input);
1096 public boolean isCodecAvailable(Class<? extends DataContainer> cls) {
1097 if (containerCodecs.containsKey(cls)) {
1100 if (identifierCodecs.containsKey(cls)) {
1103 if (choiceCodecs.containsKey(cls)) {
1106 if (caseCodecs.containsKey(cls)) {
1109 if (augmentableCodecs.containsKey(cls)) {
1112 if (augmentationCodecs.containsKey(cls)) {