2 * Copyright (c) 2017 Pantheon Technologies 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.javav2.dom.codec.impl.context.base;
10 import com.google.common.annotations.Beta;
11 import com.google.common.collect.ImmutableCollection;
12 import com.google.common.collect.ImmutableSet;
13 import java.io.IOException;
14 import java.util.List;
15 import java.util.Optional;
16 import javax.annotation.Nonnull;
17 import javax.annotation.Nullable;
18 import org.opendaylight.mdsal.binding.javav2.dom.codec.api.BindingNormalizedNodeCachingCodec;
19 import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.MissingSchemaException;
20 import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.NonCachingCodec;
21 import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.cache.CachingNormalizedNodeCodec;
22 import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.serializer.BindingToNormalizedStreamWriter;
23 import org.opendaylight.mdsal.binding.javav2.spec.base.TreeArgument;
24 import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode;
25 import org.opendaylight.mdsal.binding.javav2.spec.runtime.BindingStreamEventWriter;
26 import org.opendaylight.mdsal.binding.javav2.spec.runtime.TreeNodeSerializer;
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.YangInstanceIdentifier.PathArgument;
31 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
32 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
33 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter;
34 import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult;
37 public abstract class DataContainerCodecContext<D extends TreeNode, T> extends NodeCodecContext<D> {
39 private final DataContainerCodecPrototype<T> prototype;
40 private volatile TreeNodeSerializer eventStreamSerializer;
42 protected DataContainerCodecContext(final DataContainerCodecPrototype<T> prototype) {
43 this.prototype = prototype;
48 public final T getSchema() {
49 return prototype.getSchema();
52 protected final QNameModule namespace() {
53 return prototype.getNamespace();
56 protected final CodecContextFactory factory() {
57 return prototype.getFactory();
61 public YangInstanceIdentifier.PathArgument getDomPathArgument() {
62 return prototype.getYangArg();
66 * Returns nested node context using supplied YANG Instance Identifier.
68 * @param arg Yang Instance Identifier Argument
69 * @return Context of child
70 * @throws IllegalArgumentException If supplied argument does not represent valid child.
74 public abstract NodeCodecContext<?> yangPathArgumentChild(YangInstanceIdentifier.PathArgument arg);
77 * Returns nested node context using supplied Binding Instance Identifier
78 * and adds YANG instance identifiers to supplied list.
80 * @param arg Binding Instance Identifier Argument
81 * @return Context of child or null if supplied {@code arg} does not represent valid child.
82 * @throws IllegalArgumentException If supplied argument does not represent valid child.
84 @SuppressWarnings("unchecked")
87 public DataContainerCodecContext<?,?> bindingPathArgumentChild(@Nonnull final TreeArgument<?> arg,
88 final List<PathArgument> builder) {
89 final DataContainerCodecContext<?,?> child = streamChild((Class<? extends TreeNode>) arg.getType());
90 if (builder != null) {
91 child.addYangPathArgument(arg,builder);
97 * Returns de-serialized Binding Path Argument from YANG instance identifier.
99 * @param domArg input path argument
100 * @return returns binding path argument
102 @SuppressWarnings("rawtypes")
103 protected TreeArgument getBindingPathArgument(final YangInstanceIdentifier.PathArgument domArg) {
107 @SuppressWarnings("rawtypes")
108 protected final TreeArgument bindingArg() {
109 return prototype.getBindingArg();
113 @SuppressWarnings("unchecked")
115 public final Class<D> getBindingClass() {
116 return Class.class.cast(prototype.getBindingClass());
120 * Returns child context as if it was walked by
121 * {@link BindingStreamEventWriter}. This means that to enter case, one
122 * must issue getChild(ChoiceClass).getChild(CaseClass).
124 * @param childClass input child class
125 * @return Context of child node or null, if supplied class is not subtree child
126 * @throws IllegalArgumentException
127 * If supplied child class is not valid in specified context.
131 public abstract <C extends TreeNode> DataContainerCodecContext<C,?> streamChild(@Nonnull Class<C> childClass)
132 throws IllegalArgumentException;
135 * Returns child context as if it was walked by {@link BindingStreamEventWriter}. This means that to enter
136 * case, one must issue getChild(ChoiceClass).getChild(CaseClass).
138 * @param childClass input child class
139 * @return Context of child or Optional.empty is supplied class is not applicable in context.
142 public abstract <C extends TreeNode> Optional<DataContainerCodecContext<C, ?>> possibleStreamChild(@Nonnull
143 Class<C> childClass);
146 public String toString() {
147 return getClass().getSimpleName() + " [" + prototype.getBindingClass() + "]";
152 public BindingNormalizedNodeCachingCodec<D> createCachingCodec(
153 @Nonnull final ImmutableCollection<Class<? extends TreeNode>> cacheSpecifier) {
154 if (cacheSpecifier.isEmpty()) {
155 return new NonCachingCodec<D>(this);
157 return new CachingNormalizedNodeCodec<D>(this, ImmutableSet.copyOf(cacheSpecifier));
160 public BindingStreamEventWriter createWriter(final NormalizedNodeStreamWriter domWriter) {
161 return BindingToNormalizedStreamWriter.create(this, domWriter);
165 protected final <V> V childNonNull(@Nullable final V nullable, final YangInstanceIdentifier.PathArgument child,
166 final String message, final Object... args) {
167 if (nullable != null) {
170 MissingSchemaException.checkModulePresent(factory().getRuntimeContext().getSchemaContext(), child);
171 throw IncorrectNestingException.create(message, args);
175 protected final <V> V childNonNull(@Nullable final V nullable, final QName child, final String message,
176 final Object... args) {
177 if (nullable != null) {
180 MissingSchemaException.checkModulePresent(factory().getRuntimeContext().getSchemaContext(), child);
181 throw IncorrectNestingException.create(message, args);
185 protected final <V> V childNonNull(@Nullable final V nullable, final Class<?> childClass, final String message,
186 final Object... args) {
187 if (nullable != null) {
190 MissingSchemaForClassException.check(factory().getRuntimeContext(), childClass);
191 MissingClassInLoadingStrategyException.check(factory().getRuntimeContext().getStrategy(), childClass);
192 throw IncorrectNestingException.create(message, args);
195 public TreeNodeSerializer eventStreamSerializer() {
196 if (eventStreamSerializer == null) {
197 eventStreamSerializer = factory().getEventStreamSerializer(getBindingClass());
199 return eventStreamSerializer;
204 public NormalizedNode<?, ?> serialize(@Nonnull final D data) {
205 final NormalizedNodeResult result = new NormalizedNodeResult();
206 // We create DOM stream writer which produces normalized nodes
207 final NormalizedNodeStreamWriter domWriter = ImmutableNormalizedNodeStreamWriter.from(result);
208 writeAsNormalizedNode(data, domWriter);
209 return result.getResult();
213 public void writeAsNormalizedNode(final D data, final NormalizedNodeStreamWriter writer) {
215 eventStreamSerializer().serialize(data, createWriter(writer));
216 } catch (final IOException e) {
217 throw new IllegalStateException("Failed to serialize Binding DTO",e);