Migrate mdsal-binding-dom-codec to JDT annotations
[mdsal.git] / binding / mdsal-binding-dom-codec / src / main / java / org / opendaylight / mdsal / binding / dom / codec / impl / DataContainerCodecContext.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. 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 package org.opendaylight.mdsal.binding.dom.codec.impl;
9
10 import com.google.common.collect.ImmutableCollection;
11 import com.google.common.collect.ImmutableSet;
12 import java.io.IOException;
13 import java.util.List;
14 import java.util.Optional;
15 import org.eclipse.jdt.annotation.NonNull;
16 import org.eclipse.jdt.annotation.Nullable;
17 import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeCachingCodec;
18 import org.opendaylight.yangtools.yang.binding.BindingStreamEventWriter;
19 import org.opendaylight.yangtools.yang.binding.DataObject;
20 import org.opendaylight.yangtools.yang.binding.DataObjectSerializer;
21 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
22 import org.opendaylight.yangtools.yang.common.QName;
23 import org.opendaylight.yangtools.yang.common.QNameModule;
24 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
25 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
26 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
27 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter;
28 import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult;
29 import org.opendaylight.yangtools.yang.model.api.DocumentedNode.WithStatus;
30
31 abstract class DataContainerCodecContext<D extends DataObject, T extends WithStatus> extends NodeCodecContext<D>  {
32
33     private final DataContainerCodecPrototype<T> prototype;
34     private volatile DataObjectSerializer eventStreamSerializer;
35
36     protected DataContainerCodecContext(final DataContainerCodecPrototype<T> prototype) {
37         this.prototype = prototype;
38     }
39
40     @Override
41     public final T getSchema() {
42         return prototype.getSchema();
43     }
44
45     @Override
46     public final ChildAddressabilitySummary getChildAddressabilitySummary() {
47         return prototype.getChildAddressabilitySummary();
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     @Override
71     public abstract NodeCodecContext<?> yangPathArgumentChild(YangInstanceIdentifier.PathArgument arg);
72
73     /**
74      * Returns nested node context using supplied Binding Instance Identifier
75      * and adds YANG instance identifiers to supplied list.
76      *
77      * @param arg Binding Instance Identifier Argument
78      * @return Context of child or null if supplied {@code arg} does not represent valid child.
79      * @throws IllegalArgumentException If supplied argument does not represent valid child.
80      */
81     @Override
82     public DataContainerCodecContext<?,?> bindingPathArgumentChild(final PathArgument arg,
83             final List<YangInstanceIdentifier.PathArgument> builder) {
84         final DataContainerCodecContext<?,?> child = streamChild(arg.getType());
85         if (child != null) {
86             if (builder != null) {
87                 child.addYangPathArgument(arg,builder);
88             }
89             return child;
90         }
91         throw new IllegalArgumentException("Supplied argument is not valid child");
92     }
93
94     /**
95      * Returns deserialized Binding Path Argument from YANG instance identifier.
96      */
97     protected PathArgument getBindingPathArgument(final YangInstanceIdentifier.PathArgument domArg) {
98         return bindingArg();
99     }
100
101     protected final PathArgument bindingArg() {
102         return prototype.getBindingArg();
103     }
104
105     @SuppressWarnings("unchecked")
106     @Override
107     public final Class<D> getBindingClass() {
108         return Class.class.cast(prototype.getBindingClass());
109     }
110
111     /**
112      * Returns child context as if it was walked by {@link BindingStreamEventWriter}. This means that to enter case, one
113      * must issue getChild(ChoiceClass).getChild(CaseClass).
114      *
115      * @param childClass child class
116      * @return Context of child node or null, if supplied class is not subtree child
117      * @throws IllegalArgumentException If supplied child class is not valid in specified context.
118      */
119     @Override
120     public abstract <C extends DataObject> DataContainerCodecContext<C, ?> streamChild(Class<C> childClass);
121
122     /**
123      * Returns child context as if it was walked by {@link BindingStreamEventWriter}. This means that to enter case, one
124      * must issue getChild(ChoiceClass).getChild(CaseClass).
125      *
126      * @param childClass child class
127      * @return Context of child or Optional.empty is supplied class is not applicable in context.
128      */
129     @Override
130     public abstract <C extends DataObject> Optional<DataContainerCodecContext<C,?>> possibleStreamChild(
131             Class<C> childClass);
132
133     @Override
134     public String toString() {
135         return getClass().getSimpleName() + " [" + prototype.getBindingClass() + "]";
136     }
137
138     @Override
139     public BindingNormalizedNodeCachingCodec<D> createCachingCodec(
140             final ImmutableCollection<Class<? extends DataObject>> cacheSpecifier) {
141         if (cacheSpecifier.isEmpty()) {
142             return new NonCachingCodec<>(this);
143         }
144         return new CachingNormalizedNodeCodec<>(this,ImmutableSet.copyOf(cacheSpecifier));
145     }
146
147     BindingStreamEventWriter createWriter(final NormalizedNodeStreamWriter domWriter) {
148         return BindingToNormalizedStreamWriter.create(this, domWriter);
149     }
150
151     protected final <V> @NonNull V childNonNull(final @Nullable V nullable,
152             final YangInstanceIdentifier.PathArgument child, final String message, final Object... args) {
153         if (nullable != null) {
154             return nullable;
155         }
156         MissingSchemaException.checkModulePresent(factory().getRuntimeContext().getSchemaContext(), child);
157         throw IncorrectNestingException.create(message, args);
158     }
159
160     protected final <V> @NonNull V childNonNull(final @Nullable V nullable, final QName child, final String message,
161             final Object... args) {
162         if (nullable != null) {
163             return nullable;
164         }
165         MissingSchemaException.checkModulePresent(factory().getRuntimeContext().getSchemaContext(), child);
166         throw IncorrectNestingException.create(message, args);
167     }
168
169     protected final <V> @NonNull V childNonNull(final @Nullable V nullable, final Class<?> childClass,
170             final String message, final Object... args) {
171         if (nullable != null) {
172             return nullable;
173         }
174         MissingSchemaForClassException.check(factory().getRuntimeContext(), childClass);
175         MissingClassInLoadingStrategyException.check(factory().getRuntimeContext().getStrategy(), childClass);
176         throw IncorrectNestingException.create(message, args);
177     }
178
179     DataObjectSerializer eventStreamSerializer() {
180         if (eventStreamSerializer == null) {
181             eventStreamSerializer = factory().getEventStreamSerializer(getBindingClass());
182         }
183         return eventStreamSerializer;
184     }
185
186     @Override
187     public NormalizedNode<?, ?> serialize(final D data) {
188         final NormalizedNodeResult result = new NormalizedNodeResult();
189         // We create DOM stream writer which produces normalized nodes
190         final NormalizedNodeStreamWriter domWriter = ImmutableNormalizedNodeStreamWriter.from(result);
191         writeAsNormalizedNode(data, domWriter);
192         return result.getResult();
193     }
194
195     @Override
196     public void writeAsNormalizedNode(final D data, final NormalizedNodeStreamWriter writer) {
197         try {
198             eventStreamSerializer().serialize(data, createWriter(writer));
199         } catch (final IOException e) {
200             throw new IllegalStateException("Failed to serialize Binding DTO",e);
201         }
202     }
203
204 }