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