Binding2 runtime - Codecs impl #2
[mdsal.git] / binding2 / mdsal-binding2-dom-codec / src / main / java / org / opendaylight / mdsal / binding / javav2 / dom / codec / impl / context / base / DataContainerCodecContext.java
1 /*
2  * Copyright (c) 2017 Pantheon Technologies s.r.o. and others.  All rights reserved.
3  *
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
7  */
8
9 package org.opendaylight.mdsal.binding.javav2.dom.codec.impl.context.base;
10
11 import com.google.common.annotations.Beta;
12 import com.google.common.base.Optional;
13 import com.google.common.collect.ImmutableCollection;
14 import java.io.IOException;
15 import java.util.List;
16 import javax.annotation.Nonnull;
17 import javax.annotation.Nullable;
18 import org.opendaylight.mdsal.binding.javav2.dom.codec.api.codecs.BindingNormalizedNodeCachingCodec;
19 import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.MissingSchemaException;
20 import org.opendaylight.mdsal.binding.javav2.spec.base.TreeArgument;
21 import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode;
22 import org.opendaylight.mdsal.binding.javav2.spec.runtime.BindingStreamEventWriter;
23 import org.opendaylight.mdsal.binding.javav2.spec.runtime.TreeNodeSerializer;
24 import org.opendaylight.yangtools.yang.common.QName;
25 import org.opendaylight.yangtools.yang.common.QNameModule;
26 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
27 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
28 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
29 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
30 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter;
31 import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult;
32 import sun.reflect.generics.reflectiveObjects.NotImplementedException;
33
34 @Beta
35 abstract class DataContainerCodecContext<D extends TreeNode, T> extends NodeCodecContext<D> {
36
37     private final DataContainerCodecPrototype<T> prototype;
38     private volatile TreeNodeSerializer eventStreamSerializer;
39
40     protected DataContainerCodecContext(final DataContainerCodecPrototype<T> prototype) {
41         this.prototype = prototype;
42     }
43
44     @Nonnull
45     @Override
46     public final T getSchema() {
47         return prototype.getSchema();
48     }
49
50     protected final QNameModule namespace() {
51         return prototype.getNamespace();
52     }
53
54     protected final CodecContextFactory factory() {
55         return prototype.getFactory();
56     }
57
58     @Override
59     protected YangInstanceIdentifier.PathArgument getDomPathArgument() {
60         return prototype.getYangArg();
61     }
62
63     /**
64      * Returns nested node context using supplied YANG Instance Identifier
65      *
66      * @param arg Yang Instance Identifier Argument
67      * @return Context of child
68      * @throws IllegalArgumentException If supplied argument does not represent valid child.
69      */
70     @Nonnull
71     @Override
72     public abstract NodeCodecContext<?> yangPathArgumentChild(final YangInstanceIdentifier.PathArgument arg);
73
74     /**
75      * Returns nested node context using supplied Binding Instance Identifier
76      * and adds YANG instance identifiers to supplied list.
77      *
78      * @param arg Binding Instance Identifier Argument
79      * @return Context of child or null if supplied {@code arg} does not represent valid child.
80      * @throws IllegalArgumentException If supplied argument does not represent valid child.
81      */
82     @SuppressWarnings("unchecked")
83     @Nonnull
84     @Override
85     public DataContainerCodecContext<?,?> bindingPathArgumentChild(@Nonnull final TreeArgument<?> arg,
86             final List<PathArgument> builder) {
87         final DataContainerCodecContext<?,?> child = streamChild((Class<? extends TreeNode>) arg.getType());
88         if (builder != null) {
89             child.addYangPathArgument(arg,builder);
90         }
91         return child;
92     }
93
94     /**
95      * Returns de-serialized Binding Path Argument from YANG instance identifier.
96      *
97      * @param domArg input path argument
98      * @return returns binding path argument
99      */
100     @SuppressWarnings("rawtypes")
101     protected TreeArgument getBindingPathArgument(final YangInstanceIdentifier.PathArgument domArg) {
102         return bindingArg();
103     }
104
105     @SuppressWarnings("rawtypes")
106     protected final TreeArgument bindingArg() {
107         return prototype.getBindingArg();
108     }
109
110     @Nonnull
111     @SuppressWarnings("unchecked")
112     @Override
113     public final Class<D> getBindingClass() {
114         return Class.class.cast(prototype.getBindingClass());
115     }
116
117     /**
118      * Returns child context as if it was walked by
119      * {@link BindingStreamEventWriter}. This means that to enter case, one
120      * must issue getChild(ChoiceClass).getChild(CaseClass).
121      *
122      * @param childClass input child class
123      * @return Context of child node or null, if supplied class is not subtree child
124      * @throws IllegalArgumentException If supplied child class is not valid in specified context.
125      */
126     @Nonnull
127     @Override
128     public abstract <DV extends TreeNode> DataContainerCodecContext<DV,?> streamChild(@Nonnull final Class<DV> childClass) throws IllegalArgumentException;
129
130     /**
131      * Returns child context as if it was walked by
132      * {@link BindingStreamEventWriter}. This means that to enter case, one
133      * must issue getChild(ChoiceClass).getChild(CaseClass).
134      *
135      * @param childClass input child class
136      * @return Context of child or Optional absent is supplied class is not applicable in context.
137      */
138     @Override
139     public abstract <DV extends TreeNode> Optional<DataContainerCodecContext<DV, ?>> possibleStreamChild(@Nonnull
140         final Class<DV> childClass);
141
142     @Override
143     public String toString() {
144         return getClass().getSimpleName() + " [" + prototype.getBindingClass() + "]";
145     }
146
147     @Nonnull
148     @Override
149     public BindingNormalizedNodeCachingCodec<D> createCachingCodec(
150             @Nonnull final ImmutableCollection<Class<? extends TreeNode>> cacheSpecifier) {
151
152         //TODO: implement in cache-related patches to come
153         throw new NotImplementedException();
154     }
155
156     BindingStreamEventWriter createWriter(final NormalizedNodeStreamWriter domWriter) {
157
158         //TODO: streamWriter to come
159         throw new NotImplementedException();
160     }
161
162     @Nonnull
163     protected final <V> V childNonNull(@Nullable final V nullable, final YangInstanceIdentifier.PathArgument child,
164             final String message, final Object... args) {
165         if (nullable != null) {
166             return nullable;
167         }
168         MissingSchemaException.checkModulePresent(factory().getRuntimeContext().getSchemaContext(), child);
169         throw IncorrectNestingException.create(message, args);
170     }
171
172     @Nonnull
173     protected final <V> V childNonNull(@Nullable final V nullable, final QName child, final String message,
174             final Object... args) {
175         if (nullable != null) {
176             return nullable;
177         }
178         MissingSchemaException.checkModulePresent(factory().getRuntimeContext().getSchemaContext(), child);
179         throw IncorrectNestingException.create(message, args);
180     }
181
182     @Nonnull
183     protected final <V> V childNonNull(@Nullable final V nullable, final Class<?> childClass, final String message,
184             final Object... args) {
185         if (nullable != null) {
186             return nullable;
187         }
188         MissingSchemaForClassException.check(factory().getRuntimeContext(), childClass);
189         MissingClassInLoadingStrategyException.check(factory().getRuntimeContext().getStrategy(), childClass);
190         throw IncorrectNestingException.create(message, args);
191     }
192
193     TreeNodeSerializer eventStreamSerializer() {
194         if(eventStreamSerializer == null) {
195             eventStreamSerializer = factory().getEventStreamSerializer(getBindingClass());
196         }
197         return eventStreamSerializer;
198     }
199
200     @Nonnull
201     @Override
202     public NormalizedNode<?, ?> serialize(@Nonnull final D data) {
203         final NormalizedNodeResult result = new NormalizedNodeResult();
204         // We create DOM stream writer which produces normalized nodes
205         final NormalizedNodeStreamWriter domWriter = ImmutableNormalizedNodeStreamWriter.from(result);
206         writeAsNormalizedNode(data, domWriter);
207         return result.getResult();
208     }
209
210     @Override
211     public void writeAsNormalizedNode(final D data, final NormalizedNodeStreamWriter writer) {
212         try {
213             eventStreamSerializer().serialize(data, createWriter(writer));
214         } catch (final IOException e) {
215             throw new IllegalStateException("Failed to serialize Binding DTO",e);
216         }
217     }
218
219 }