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