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.mdsal.binding.dom.codec.impl;
10 import static java.util.Objects.requireNonNull;
12 import com.google.common.collect.ImmutableCollection;
13 import com.google.common.collect.ImmutableSet;
14 import java.io.IOException;
15 import java.lang.invoke.MethodHandles;
16 import java.lang.invoke.VarHandle;
17 import java.util.List;
18 import java.util.Optional;
19 import org.eclipse.jdt.annotation.NonNull;
20 import org.eclipse.jdt.annotation.Nullable;
21 import org.opendaylight.mdsal.binding.dom.codec.api.BindingDataObjectCodecTreeNode;
22 import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeCachingCodec;
23 import org.opendaylight.mdsal.binding.dom.codec.api.BindingStreamEventWriter;
24 import org.opendaylight.yangtools.yang.binding.BindingObject;
25 import org.opendaylight.yangtools.yang.binding.DataObject;
26 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
27 import org.opendaylight.yangtools.yang.common.QName;
28 import org.opendaylight.yangtools.yang.common.QNameModule;
29 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
30 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
31 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
32 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter;
33 import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult;
34 import org.opendaylight.yangtools.yang.model.api.DocumentedNode.WithStatus;
36 abstract class DataContainerCodecContext<D extends DataObject, T extends WithStatus> extends NodeCodecContext
37 implements BindingDataObjectCodecTreeNode<D> {
38 private static final VarHandle EVENT_STREAM_SERIALIZER;
42 EVENT_STREAM_SERIALIZER = MethodHandles.lookup().findVarHandle(DataContainerCodecContext.class,
43 "eventStreamSerializer", DataObjectSerializer.class);
44 } catch (NoSuchFieldException | IllegalAccessException e) {
45 throw new ExceptionInInitializerError(e);
49 private final @NonNull DataContainerCodecPrototype<T> prototype;
51 // Accessed via a VarHandle
52 @SuppressWarnings("unused")
53 private volatile DataObjectSerializer eventStreamSerializer;
55 DataContainerCodecContext(final DataContainerCodecPrototype<T> prototype) {
56 this.prototype = requireNonNull(prototype);
60 public final T getSchema() {
61 return prototype.getSchema();
65 public final ChildAddressabilitySummary getChildAddressabilitySummary() {
66 return prototype.getChildAddressabilitySummary();
69 protected final QNameModule namespace() {
70 return prototype.getNamespace();
73 protected final CodecContextFactory factory() {
74 return prototype.getFactory();
78 protected YangInstanceIdentifier.PathArgument getDomPathArgument() {
79 return prototype.getYangArg();
83 * Returns nested node context using supplied YANG Instance Identifier.
85 * @param arg Yang Instance Identifier Argument
86 * @return Context of child
87 * @throws IllegalArgumentException If supplied argument does not represent valid child.
90 public abstract NodeCodecContext yangPathArgumentChild(YangInstanceIdentifier.PathArgument arg);
93 * Returns nested node context using supplied Binding Instance Identifier
94 * and adds YANG instance identifiers to supplied list.
96 * @param arg Binding Instance Identifier Argument
97 * @return Context of child or null if supplied {@code arg} does not represent valid child.
98 * @throws IllegalArgumentException If supplied argument does not represent valid child.
101 public DataContainerCodecContext<?, ?> bindingPathArgumentChild(final PathArgument arg,
102 final List<YangInstanceIdentifier.PathArgument> builder) {
103 final DataContainerCodecContext<?,?> child = streamChild(arg.getType());
104 if (builder != null) {
105 child.addYangPathArgument(arg,builder);
111 * Returns deserialized Binding Path Argument from YANG instance identifier.
113 protected PathArgument getBindingPathArgument(final YangInstanceIdentifier.PathArgument domArg) {
117 protected final PathArgument bindingArg() {
118 return prototype.getBindingArg();
121 @SuppressWarnings("unchecked")
123 public final Class<D> getBindingClass() {
124 return Class.class.cast(prototype.getBindingClass());
128 public abstract <C extends DataObject> DataContainerCodecContext<C, ?> streamChild(Class<C> childClass);
131 * Returns child context as if it was walked by {@link BindingStreamEventWriter}. This means that to enter case, one
132 * must issue getChild(ChoiceClass).getChild(CaseClass).
134 * @param childClass child class
135 * @return Context of child or Optional.empty is supplied class is not applicable in context.
138 public abstract <C extends DataObject> Optional<DataContainerCodecContext<C,?>> possibleStreamChild(
139 Class<C> childClass);
142 public String toString() {
143 return getClass().getSimpleName() + " [" + prototype.getBindingClass() + "]";
147 public BindingNormalizedNodeCachingCodec<D> createCachingCodec(
148 final ImmutableCollection<Class<? extends BindingObject>> cacheSpecifier) {
149 if (cacheSpecifier.isEmpty()) {
150 return new NonCachingCodec<>(this);
152 return new CachingNormalizedNodeCodec<>(this, ImmutableSet.copyOf(cacheSpecifier));
155 BindingStreamEventWriter createWriter(final NormalizedNodeStreamWriter domWriter) {
156 return BindingToNormalizedStreamWriter.create(this, domWriter);
159 protected final <V> @NonNull V childNonNull(final @Nullable V nullable,
160 final YangInstanceIdentifier.PathArgument child, final String message, final Object... args) {
161 if (nullable != null) {
164 MissingSchemaException.checkModulePresent(factory().getRuntimeContext().getSchemaContext(), child);
165 throw IncorrectNestingException.create(message, args);
168 protected final <V> @NonNull V childNonNull(final @Nullable V nullable, final QName child, final String message,
169 final Object... args) {
170 if (nullable != null) {
173 MissingSchemaException.checkModulePresent(factory().getRuntimeContext().getSchemaContext(), child);
174 throw IncorrectNestingException.create(message, args);
177 protected final <V> @NonNull V childNonNull(final @Nullable V nullable, final Class<?> childClass,
178 final String message, final Object... args) {
179 if (nullable != null) {
182 MissingSchemaForClassException.check(factory().getRuntimeContext(), childClass);
183 MissingClassInLoadingStrategyException.check(factory().getRuntimeContext().getStrategy(), childClass);
184 throw IncorrectNestingException.create(message, args);
187 final DataObjectSerializer eventStreamSerializer() {
188 final DataObjectSerializer existing = (DataObjectSerializer) EVENT_STREAM_SERIALIZER.getAcquire(this);
189 return existing != null ? existing : loadEventStreamSerializer();
192 // Split out to aid inlining
193 private DataObjectSerializer loadEventStreamSerializer() {
194 final DataObjectSerializer loaded = factory().getEventStreamSerializer(getBindingClass());
195 final Object witness = EVENT_STREAM_SERIALIZER.compareAndExchangeRelease(this, null, loaded);
196 return witness == null ? loaded : (DataObjectSerializer) witness;
200 public NormalizedNode<?, ?> serialize(final D data) {
201 final NormalizedNodeResult result = new NormalizedNodeResult();
202 // We create DOM stream writer which produces normalized nodes
203 final NormalizedNodeStreamWriter domWriter = ImmutableNormalizedNodeStreamWriter.from(result);
204 writeAsNormalizedNode(data, domWriter);
205 return result.getResult();
209 public void writeAsNormalizedNode(final D data, final NormalizedNodeStreamWriter writer) {
211 eventStreamSerializer().serialize(data, createWriter(writer));
212 } catch (final IOException e) {
213 throw new IllegalStateException("Failed to serialize Binding DTO",e);