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