Add support for reusable streaming
[controller.git] / opendaylight / md-sal / sal-distributed-datastore / src / main / java / org / opendaylight / controller / cluster / datastore / persisted / DataTreeCandidateInputOutput.java
1 /*
2  * Copyright (c) 2016 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.controller.cluster.datastore.persisted;
9
10 import com.google.common.annotations.Beta;
11 import com.google.common.collect.ImmutableList;
12 import java.io.DataInput;
13 import java.io.DataOutput;
14 import java.io.IOException;
15 import java.util.ArrayList;
16 import java.util.Collection;
17 import org.opendaylight.controller.cluster.datastore.node.utils.stream.NormalizedNodeDataInput;
18 import org.opendaylight.controller.cluster.datastore.node.utils.stream.NormalizedNodeDataOutput;
19 import org.opendaylight.controller.cluster.datastore.node.utils.stream.NormalizedNodeInputOutput;
20 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
21 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
22 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
23 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNode;
24 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNodes;
25 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidates;
26 import org.opendaylight.yangtools.yang.data.api.schema.tree.ModificationType;
27 import org.opendaylight.yangtools.yang.data.impl.schema.ReusableImmutableNormalizedNodeStreamWriter;
28 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory;
30
31 /**
32  * Utility serialization/deserialization for {@link DataTreeCandidate}. Note that this utility does not maintain
33  * before-image information across serialization.
34  *
35  * @author Robert Varga
36  */
37 @Beta
38 public final class DataTreeCandidateInputOutput {
39     private static final Logger LOG = LoggerFactory.getLogger(DataTreeCandidateInputOutput.class);
40     private static final byte DELETE = 0;
41     private static final byte SUBTREE_MODIFIED = 1;
42     private static final byte UNMODIFIED = 2;
43     private static final byte WRITE = 3;
44     private static final byte APPEARED = 4;
45     private static final byte DISAPPEARED = 5;
46
47     private DataTreeCandidateInputOutput() {
48         throw new UnsupportedOperationException();
49     }
50
51     private static DataTreeCandidateNode readModifiedNode(final ModificationType type,
52             final NormalizedNodeDataInput in, final ReusableImmutableNormalizedNodeStreamWriter writer)
53                     throws IOException {
54
55         final PathArgument identifier = in.readPathArgument();
56         final Collection<DataTreeCandidateNode> children = readChildren(in, writer);
57         if (children.isEmpty()) {
58             LOG.debug("Modified node {} does not have any children, not instantiating it", identifier);
59             return null;
60         }
61
62         return ModifiedDataTreeCandidateNode.create(identifier, type, children);
63     }
64
65     private static Collection<DataTreeCandidateNode> readChildren(final NormalizedNodeDataInput in,
66             final ReusableImmutableNormalizedNodeStreamWriter writer) throws IOException {
67         final int size = in.readInt();
68         if (size == 0) {
69             return ImmutableList.of();
70         }
71
72         final Collection<DataTreeCandidateNode> ret = new ArrayList<>(size);
73         for (int i = 0; i < size; ++i) {
74             final DataTreeCandidateNode child = readNode(in, writer);
75             if (child != null) {
76                 ret.add(child);
77             }
78         }
79         return ret;
80     }
81
82     private static DataTreeCandidateNode readNode(final NormalizedNodeDataInput in,
83             final ReusableImmutableNormalizedNodeStreamWriter writer) throws IOException {
84         final byte type = in.readByte();
85         switch (type) {
86             case APPEARED:
87                 return readModifiedNode(ModificationType.APPEARED, in, writer);
88             case DELETE:
89                 return DeletedDataTreeCandidateNode.create(in.readPathArgument());
90             case DISAPPEARED:
91                 return readModifiedNode(ModificationType.DISAPPEARED, in, writer);
92             case SUBTREE_MODIFIED:
93                 return readModifiedNode(ModificationType.SUBTREE_MODIFIED, in, writer);
94             case UNMODIFIED:
95                 return null;
96             case WRITE:
97                 return DataTreeCandidateNodes.written(in.readNormalizedNode(writer));
98             default:
99                 throw new IllegalArgumentException("Unhandled node type " + type);
100         }
101     }
102
103     public static DataTreeCandidate readDataTreeCandidate(final DataInput in,
104             final ReusableImmutableNormalizedNodeStreamWriter writer) throws IOException {
105         final NormalizedNodeDataInput reader = NormalizedNodeInputOutput.newDataInput(in);
106         final YangInstanceIdentifier rootPath = reader.readYangInstanceIdentifier();
107         final byte type = reader.readByte();
108
109         final DataTreeCandidateNode rootNode;
110         switch (type) {
111             case APPEARED:
112                 rootNode = ModifiedDataTreeCandidateNode.create(ModificationType.APPEARED,
113                     readChildren(reader, writer));
114                 break;
115             case DELETE:
116                 rootNode = DeletedDataTreeCandidateNode.create();
117                 break;
118             case DISAPPEARED:
119                 rootNode = ModifiedDataTreeCandidateNode.create(ModificationType.DISAPPEARED,
120                     readChildren(reader, writer));
121                 break;
122             case SUBTREE_MODIFIED:
123                 rootNode = ModifiedDataTreeCandidateNode.create(ModificationType.SUBTREE_MODIFIED,
124                         readChildren(reader, writer));
125                 break;
126             case WRITE:
127                 rootNode = DataTreeCandidateNodes.written(reader.readNormalizedNode(writer));
128                 break;
129             case UNMODIFIED:
130                 rootNode = AbstractDataTreeCandidateNode.createUnmodified();
131                 break;
132             default:
133                 throw new IllegalArgumentException("Unhandled node type " + type);
134         }
135
136         return DataTreeCandidates.newDataTreeCandidate(rootPath, rootNode);
137     }
138
139     private static void writeChildren(final NormalizedNodeDataOutput out,
140             final Collection<DataTreeCandidateNode> children) throws IOException {
141         out.writeInt(children.size());
142         for (DataTreeCandidateNode child : children) {
143             writeNode(out, child);
144         }
145     }
146
147     private static void writeNode(final NormalizedNodeDataOutput out, final DataTreeCandidateNode node)
148             throws IOException {
149         switch (node.getModificationType()) {
150             case APPEARED:
151                 out.writeByte(APPEARED);
152                 out.writePathArgument(node.getIdentifier());
153                 writeChildren(out, node.getChildNodes());
154                 break;
155             case DELETE:
156                 out.writeByte(DELETE);
157                 out.writePathArgument(node.getIdentifier());
158                 break;
159             case DISAPPEARED:
160                 out.writeByte(DISAPPEARED);
161                 out.writePathArgument(node.getIdentifier());
162                 writeChildren(out, node.getChildNodes());
163                 break;
164             case SUBTREE_MODIFIED:
165                 out.writeByte(SUBTREE_MODIFIED);
166                 out.writePathArgument(node.getIdentifier());
167                 writeChildren(out, node.getChildNodes());
168                 break;
169             case WRITE:
170                 out.writeByte(WRITE);
171                 out.writeNormalizedNode(node.getDataAfter().get());
172                 break;
173             case UNMODIFIED:
174                 out.writeByte(UNMODIFIED);
175                 break;
176             default:
177                 throwUnhandledNodeType(node);
178         }
179     }
180
181     public static void writeDataTreeCandidate(final DataOutput out, final DataTreeCandidate candidate)
182             throws IOException {
183         try (NormalizedNodeDataOutput writer = NormalizedNodeInputOutput.newDataOutput(out,
184                 PayloadVersion.current().getStreamVersion())) {
185             writer.writeYangInstanceIdentifier(candidate.getRootPath());
186
187             final DataTreeCandidateNode node = candidate.getRootNode();
188             switch (node.getModificationType()) {
189                 case APPEARED:
190                     writer.writeByte(APPEARED);
191                     writeChildren(writer, node.getChildNodes());
192                     break;
193                 case DELETE:
194                     writer.writeByte(DELETE);
195                     break;
196                 case DISAPPEARED:
197                     writer.writeByte(DISAPPEARED);
198                     writeChildren(writer, node.getChildNodes());
199                     break;
200                 case SUBTREE_MODIFIED:
201                     writer.writeByte(SUBTREE_MODIFIED);
202                     writeChildren(writer, node.getChildNodes());
203                     break;
204                 case UNMODIFIED:
205                     writer.writeByte(UNMODIFIED);
206                     break;
207                 case WRITE:
208                     writer.writeByte(WRITE);
209                     writer.writeNormalizedNode(node.getDataAfter().get());
210                     break;
211                 default:
212                     throwUnhandledNodeType(node);
213             }
214         }
215     }
216
217     private static void throwUnhandledNodeType(final DataTreeCandidateNode node) {
218         throw new IllegalArgumentException("Unhandled node type " + node.getModificationType());
219     }
220 }