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