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