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