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