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();
88 return switch (type) {
89 case APPEARED -> readModifiedNode(ModificationType.APPEARED, in, receiver);
90 case DELETE -> DeletedDataTreeCandidateNode.create(in.readPathArgument());
91 case DISAPPEARED -> readModifiedNode(ModificationType.DISAPPEARED, in, receiver);
92 case SUBTREE_MODIFIED -> readModifiedNode(ModificationType.SUBTREE_MODIFIED, in, receiver);
93 case UNMODIFIED -> null;
94 case WRITE -> DataTreeCandidateNodes.written(in.readNormalizedNode(receiver));
95 default -> throw new IllegalArgumentException("Unhandled node type " + type);
100 public static final class DataTreeCandidateWithVersion implements Immutable {
101 private final DataTreeCandidate candidate;
102 private final NormalizedNodeStreamVersion version;
104 public DataTreeCandidateWithVersion(final DataTreeCandidate candidate,
105 final NormalizedNodeStreamVersion version) {
106 this.candidate = requireNonNull(candidate);
107 this.version = requireNonNull(version);
110 public DataTreeCandidate getCandidate() {
114 public NormalizedNodeStreamVersion getVersion() {
119 public static DataTreeCandidateWithVersion readDataTreeCandidate(final DataInput in,
120 final ReusableStreamReceiver receiver) throws IOException {
121 final NormalizedNodeDataInput reader = NormalizedNodeDataInput.newDataInput(in);
122 final YangInstanceIdentifier rootPath = reader.readYangInstanceIdentifier();
123 final byte type = reader.readByte();
125 final DataTreeCandidateNode rootNode = switch (type) {
126 case APPEARED -> ModifiedDataTreeCandidateNode.create(ModificationType.APPEARED,
127 readChildren(reader, receiver));
128 case DELETE -> DeletedDataTreeCandidateNode.create();
129 case DISAPPEARED -> ModifiedDataTreeCandidateNode.create(ModificationType.DISAPPEARED,
130 readChildren(reader, receiver));
131 case SUBTREE_MODIFIED -> ModifiedDataTreeCandidateNode.create(ModificationType.SUBTREE_MODIFIED,
132 readChildren(reader, receiver));
133 case WRITE -> DataTreeCandidateNodes.written(reader.readNormalizedNode(receiver));
134 case UNMODIFIED -> AbstractDataTreeCandidateNode.createUnmodified();
135 default -> throw new IllegalArgumentException("Unhandled node type " + type);
137 return new DataTreeCandidateWithVersion(DataTreeCandidates.newDataTreeCandidate(rootPath, rootNode),
138 reader.getVersion());
141 private static void writeChildren(final NormalizedNodeDataOutput out,
142 final Collection<DataTreeCandidateNode> children) throws IOException {
143 out.writeInt(children.size());
144 for (DataTreeCandidateNode child : children) {
145 writeNode(out, child);
149 private static void writeNode(final NormalizedNodeDataOutput out, final DataTreeCandidateNode node)
151 switch (node.getModificationType()) {
153 out.writeByte(APPEARED);
154 out.writePathArgument(node.getIdentifier());
155 writeChildren(out, node.getChildNodes());
158 out.writeByte(DELETE);
159 out.writePathArgument(node.getIdentifier());
162 out.writeByte(DISAPPEARED);
163 out.writePathArgument(node.getIdentifier());
164 writeChildren(out, node.getChildNodes());
166 case SUBTREE_MODIFIED:
167 out.writeByte(SUBTREE_MODIFIED);
168 out.writePathArgument(node.getIdentifier());
169 writeChildren(out, node.getChildNodes());
172 out.writeByte(WRITE);
173 out.writeNormalizedNode(node.getDataAfter().orElseThrow());
176 out.writeByte(UNMODIFIED);
179 throwUnhandledNodeType(node);
184 public static void writeDataTreeCandidate(final DataOutput out, final PayloadVersion version,
185 final DataTreeCandidate candidate) throws IOException {
186 try (NormalizedNodeDataOutput writer = version.getStreamVersion().newDataOutput(out)) {
187 writer.writeYangInstanceIdentifier(candidate.getRootPath());
189 final DataTreeCandidateNode node = candidate.getRootNode();
190 switch (node.getModificationType()) {
192 writer.writeByte(APPEARED);
193 writeChildren(writer, node.getChildNodes());
196 writer.writeByte(DELETE);
199 writer.writeByte(DISAPPEARED);
200 writeChildren(writer, node.getChildNodes());
202 case SUBTREE_MODIFIED:
203 writer.writeByte(SUBTREE_MODIFIED);
204 writeChildren(writer, node.getChildNodes());
207 writer.writeByte(UNMODIFIED);
210 writer.writeByte(WRITE);
211 writer.writeNormalizedNode(node.getDataAfter().orElseThrow());
214 throwUnhandledNodeType(node);
219 public static void writeDataTreeCandidate(final DataOutput out, final DataTreeCandidate candidate)
221 writeDataTreeCandidate(out, PayloadVersion.current(), candidate);
224 private static void throwUnhandledNodeType(final DataTreeCandidateNode node) {
225 throw new IllegalArgumentException("Unhandled node type " + node.getModificationType());