2 * Copyright (c) 2019 PANTHEON.tech, s.r.o. 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.mdsal.binding.dom.codec.impl;
10 import static java.util.Objects.requireNonNull;
12 import com.google.common.base.MoreObjects.ToStringHelper;
13 import com.google.common.collect.ImmutableMap;
15 import java.util.Optional;
16 import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
17 import org.eclipse.jdt.annotation.Nullable;
18 import org.opendaylight.mdsal.binding.dom.codec.util.AugmentationReader;
19 import org.opendaylight.mdsal.binding.spec.reflect.BindingReflections;
20 import org.opendaylight.yangtools.yang.binding.Augmentable;
21 import org.opendaylight.yangtools.yang.binding.Augmentation;
22 import org.opendaylight.yangtools.yang.binding.AugmentationHolder;
23 import org.opendaylight.yangtools.yang.binding.DataObject;
24 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
25 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer;
28 * A base class for {@link DataObject}s which are also {@link Augmentable}, backed by {@link DataObjectCodecContext}.
29 * While this class is public, it not part of API surface and is an implementation detail. The only reason for it being
30 * public is that it needs to be accessible by code generated at runtime.
32 * @param <T> DataObject type
34 public abstract class AugmentableCodecDataObject<T extends DataObject & Augmentable<T>>
35 extends CodecDataObject<T> implements Augmentable<T>, AugmentationHolder<T> {
36 @SuppressWarnings("rawtypes")
37 private static final AtomicReferenceFieldUpdater<AugmentableCodecDataObject, ImmutableMap>
38 CACHED_AUGMENTATIONS_UPDATER = AtomicReferenceFieldUpdater.newUpdater(AugmentableCodecDataObject.class,
39 ImmutableMap.class, "cachedAugmentations");
40 private volatile ImmutableMap<Class<? extends Augmentation<T>>, Augmentation<T>> cachedAugmentations;
42 protected AugmentableCodecDataObject(final DataObjectCodecContext<T, ?> context,
43 final NormalizedNodeContainer<?, ?, ?> data) {
47 @SuppressWarnings("unchecked")
49 public final <A extends Augmentation<T>> @Nullable A augmentation(final Class<A> augmentationType) {
50 requireNonNull(augmentationType, "Supplied augmentation must not be null.");
52 final ImmutableMap<Class<? extends Augmentation<T>>, Augmentation<T>> aug = cachedAugmentations;
54 return (A) aug.get(augmentationType);
57 @SuppressWarnings("rawtypes")
58 final Optional<DataContainerCodecContext<?, ?>> optAugCtx = codecContext().possibleStreamChild(
59 (Class) augmentationType);
60 if (optAugCtx.isPresent()) {
61 final DataContainerCodecContext<?, ?> augCtx = optAugCtx.get();
62 // Due to binding specification not representing grouping instantiations we can end up having the same
63 // augmentation applied to a grouping multiple times. While these augmentations have the same shape, they
64 // are still represented by distinct binding classes and therefore we need to make sure the result matches
65 // the augmentation the user is requesting -- otherwise a strict receiver would end up with a cryptic
66 // ClassCastException.
67 if (augmentationType.isAssignableFrom(augCtx.getBindingClass())) {
68 final Optional<NormalizedNode<?, ?>> augData = codecData().getChild(augCtx.getDomPathArgument());
69 if (augData.isPresent()) {
70 return (A) augCtx.deserialize(augData.get());
78 public final ImmutableMap<Class<? extends Augmentation<T>>, Augmentation<T>> augmentations() {
79 ImmutableMap<Class<? extends Augmentation<T>>, Augmentation<T>> local = cachedAugmentations;
84 local = ImmutableMap.copyOf(codecContext().getAllAugmentationsFrom(codecData()));
85 return CACHED_AUGMENTATIONS_UPDATER.compareAndSet(this, null, local) ? local : cachedAugmentations;
89 final int codecAugmentedHashCode() {
90 return 31 * super.codecAugmentedHashCode() + augmentations().hashCode();
94 final boolean codecAugmentedEquals(final T other) {
95 return super.codecAugmentedEquals(other) && augmentations().equals(getAllAugmentations(other));
99 final ToStringHelper codecAugmentedFillToString(final ToStringHelper helper) {
100 return super.codecAugmentedFillToString(helper).add("augmentation", augmentations().values());
103 private static Map<Class<? extends Augmentation<?>>, Augmentation<?>> getAllAugmentations(
104 final Augmentable<?> dataObject) {
105 if (dataObject instanceof AugmentationReader) {
106 return ((AugmentationReader) dataObject).getAugmentations(dataObject);
108 return BindingReflections.getAugmentations(dataObject);