2 * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.controller.cluster.datastore.persisted;
10 import static java.util.Objects.requireNonNull;
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;
37 * Utility serialization/deserialization for {@link DataTreeCandidate}. Note that this utility does not maintain
38 * before-image information across serialization.
40 * @author Robert Varga
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;
52 private DataTreeCandidateInputOutput() {
53 throw new UnsupportedOperationException();
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);
65 return ModifiedDataTreeCandidateNode.create(identifier, type, children);
68 private static Collection<DataTreeCandidateNode> readChildren(final NormalizedNodeDataInput in,
69 final ReusableStreamReceiver receiver) throws IOException {
70 final int size = in.readInt();
72 return ImmutableList.of();
75 final Collection<DataTreeCandidateNode> ret = new ArrayList<>(size);
76 for (int i = 0; i < size; ++i) {
77 final DataTreeCandidateNode child = readNode(in, receiver);
85 private static DataTreeCandidateNode readNode(final NormalizedNodeDataInput in,
86 final ReusableStreamReceiver receiver) throws IOException {
87 final byte type = in.readByte();
90 return readModifiedNode(ModificationType.APPEARED, in, receiver);
92 return DeletedDataTreeCandidateNode.create(in.readPathArgument());
94 return readModifiedNode(ModificationType.DISAPPEARED, in, receiver);
95 case SUBTREE_MODIFIED:
96 return readModifiedNode(ModificationType.SUBTREE_MODIFIED, in, receiver);
100 return DataTreeCandidateNodes.written(in.readNormalizedNode(receiver));
102 throw new IllegalArgumentException("Unhandled node type " + type);
107 public static final class DataTreeCandidateWithVersion implements Immutable {
108 private final DataTreeCandidate candidate;
109 private final NormalizedNodeStreamVersion version;
111 public DataTreeCandidateWithVersion(final DataTreeCandidate candidate,
112 final NormalizedNodeStreamVersion version) {
113 this.candidate = requireNonNull(candidate);
114 this.version = requireNonNull(version);
117 public DataTreeCandidate getCandidate() {
121 public NormalizedNodeStreamVersion getVersion() {
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();
132 final DataTreeCandidateNode rootNode;
135 rootNode = ModifiedDataTreeCandidateNode.create(ModificationType.APPEARED,
136 readChildren(reader, receiver));
139 rootNode = DeletedDataTreeCandidateNode.create();
142 rootNode = ModifiedDataTreeCandidateNode.create(ModificationType.DISAPPEARED,
143 readChildren(reader, receiver));
145 case SUBTREE_MODIFIED:
146 rootNode = ModifiedDataTreeCandidateNode.create(ModificationType.SUBTREE_MODIFIED,
147 readChildren(reader, receiver));
150 rootNode = DataTreeCandidateNodes.written(reader.readNormalizedNode(receiver));
153 rootNode = AbstractDataTreeCandidateNode.createUnmodified();
156 throw new IllegalArgumentException("Unhandled node type " + type);
159 return new DataTreeCandidateWithVersion(DataTreeCandidates.newDataTreeCandidate(rootPath, rootNode),
160 reader.getVersion());
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);
171 private static void writeNode(final NormalizedNodeDataOutput out, final DataTreeCandidateNode node)
173 switch (node.getModificationType()) {
175 out.writeByte(APPEARED);
176 out.writePathArgument(node.getIdentifier());
177 writeChildren(out, node.getChildNodes());
180 out.writeByte(DELETE);
181 out.writePathArgument(node.getIdentifier());
184 out.writeByte(DISAPPEARED);
185 out.writePathArgument(node.getIdentifier());
186 writeChildren(out, node.getChildNodes());
188 case SUBTREE_MODIFIED:
189 out.writeByte(SUBTREE_MODIFIED);
190 out.writePathArgument(node.getIdentifier());
191 writeChildren(out, node.getChildNodes());
194 out.writeByte(WRITE);
195 out.writeNormalizedNode(node.getDataAfter().get());
198 out.writeByte(UNMODIFIED);
201 throwUnhandledNodeType(node);
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());
211 final DataTreeCandidateNode node = candidate.getRootNode();
212 switch (node.getModificationType()) {
214 writer.writeByte(APPEARED);
215 writeChildren(writer, node.getChildNodes());
218 writer.writeByte(DELETE);
221 writer.writeByte(DISAPPEARED);
222 writeChildren(writer, node.getChildNodes());
224 case SUBTREE_MODIFIED:
225 writer.writeByte(SUBTREE_MODIFIED);
226 writeChildren(writer, node.getChildNodes());
229 writer.writeByte(UNMODIFIED);
232 writer.writeByte(WRITE);
233 writer.writeNormalizedNode(node.getDataAfter().get());
236 throwUnhandledNodeType(node);
241 public static void writeDataTreeCandidate(final DataOutput out, final DataTreeCandidate candidate)
243 writeDataTreeCandidate(out, PayloadVersion.current(), candidate);
246 private static void throwUnhandledNodeType(final DataTreeCandidateNode node) {
247 throw new IllegalArgumentException("Unhandled node type " + node.getModificationType());