2 * Copyright (c) 2015 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;
10 import com.google.common.base.Preconditions;
11 import com.google.common.io.ByteArrayDataInput;
12 import com.google.common.io.ByteArrayDataOutput;
13 import com.google.common.io.ByteStreams;
14 import java.io.Externalizable;
15 import java.io.IOException;
16 import java.io.ObjectInput;
17 import java.io.ObjectOutput;
18 import java.util.ArrayList;
19 import java.util.Collection;
20 import java.util.Collections;
21 import org.opendaylight.controller.cluster.datastore.node.utils.stream.NormalizedNodeDataInput;
22 import org.opendaylight.controller.cluster.datastore.node.utils.stream.NormalizedNodeDataOutput;
23 import org.opendaylight.controller.cluster.datastore.node.utils.stream.NormalizedNodeInputStreamReader;
24 import org.opendaylight.controller.cluster.datastore.node.utils.stream.NormalizedNodeInputOutput;
25 import org.opendaylight.controller.cluster.raft.protobuff.client.messages.Payload;
26 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
27 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
28 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
29 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNode;
30 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNodes;
31 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidates;
32 import org.opendaylight.yangtools.yang.data.api.schema.tree.ModificationType;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
36 final class DataTreeCandidatePayload extends Payload implements Externalizable {
37 private static final Logger LOG = LoggerFactory.getLogger(DataTreeCandidatePayload.class);
38 private static final long serialVersionUID = 1L;
39 private static final byte DELETE = 0;
40 private static final byte SUBTREE_MODIFIED = 1;
41 private static final byte UNMODIFIED = 2;
42 private static final byte WRITE = 3;
43 private static final byte APPEARED = 4;
44 private static final byte DISAPPEARED = 5;
46 private transient byte[] serialized;
48 public DataTreeCandidatePayload() {
49 // Required by Externalizable
52 private DataTreeCandidatePayload(final byte[] serialized) {
53 this.serialized = Preconditions.checkNotNull(serialized);
56 private static void writeChildren(final NormalizedNodeDataOutput out,
57 final Collection<DataTreeCandidateNode> children) throws IOException {
58 out.writeInt(children.size());
59 for (DataTreeCandidateNode child : children) {
60 writeNode(out, child);
64 private static void writeNode(final NormalizedNodeDataOutput out, final DataTreeCandidateNode node)
66 switch (node.getModificationType()) {
68 out.writeByte(APPEARED);
69 out.writePathArgument(node.getIdentifier());
70 writeChildren(out, node.getChildNodes());
73 out.writeByte(DELETE);
74 out.writePathArgument(node.getIdentifier());
77 out.writeByte(DISAPPEARED);
78 out.writePathArgument(node.getIdentifier());
79 writeChildren(out, node.getChildNodes());
81 case SUBTREE_MODIFIED:
82 out.writeByte(SUBTREE_MODIFIED);
83 out.writePathArgument(node.getIdentifier());
84 writeChildren(out, node.getChildNodes());
88 out.writeNormalizedNode(node.getDataAfter().get());
91 out.writeByte(UNMODIFIED);
94 throw new IllegalArgumentException("Unhandled node type " + node.getModificationType());
98 static DataTreeCandidatePayload create(final DataTreeCandidate candidate) {
99 final ByteArrayDataOutput out = ByteStreams.newDataOutput();
100 try (final NormalizedNodeDataOutput writer = NormalizedNodeInputOutput.newDataOutput(out)) {
101 writer.writeYangInstanceIdentifier(candidate.getRootPath());
103 final DataTreeCandidateNode node = candidate.getRootNode();
104 switch (node.getModificationType()) {
106 writer.writeByte(APPEARED);
107 writeChildren(writer, node.getChildNodes());
110 writer.writeByte(DELETE);
113 writer.writeByte(DISAPPEARED);
114 writeChildren(writer, node.getChildNodes());
116 case SUBTREE_MODIFIED:
117 writer.writeByte(SUBTREE_MODIFIED);
118 writeChildren(writer, node.getChildNodes());
121 writer.writeByte(UNMODIFIED);
124 writer.writeByte(WRITE);
125 writer.writeNormalizedNode(node.getDataAfter().get());
128 throw new IllegalArgumentException("Unhandled node type " + node.getModificationType());
131 } catch (IOException e) {
132 throw new IllegalArgumentException(String.format("Failed to serialize candidate %s", candidate), e);
135 return new DataTreeCandidatePayload(out.toByteArray());
138 private static Collection<DataTreeCandidateNode> readChildren(final NormalizedNodeDataInput in) throws IOException {
139 final int size = in.readInt();
141 final Collection<DataTreeCandidateNode> ret = new ArrayList<>(size);
142 for (int i = 0; i < size; ++i) {
143 final DataTreeCandidateNode child = readNode(in);
150 return Collections.emptyList();
154 private static DataTreeCandidateNode readModifiedNode(final ModificationType type,
155 final NormalizedNodeDataInput in) throws IOException {
157 final PathArgument identifier = in.readPathArgument();
158 final Collection<DataTreeCandidateNode> children = readChildren(in);
159 if (children.isEmpty()) {
160 LOG.debug("Modified node {} does not have any children, not instantiating it", identifier);
163 return ModifiedDataTreeCandidateNode.create(identifier, type, children);
167 private static DataTreeCandidateNode readNode(final NormalizedNodeDataInput in) throws IOException {
168 final byte type = in.readByte();
171 return readModifiedNode(ModificationType.APPEARED, in);
173 return DeletedDataTreeCandidateNode.create(in.readPathArgument());
175 return readModifiedNode(ModificationType.DISAPPEARED, in);
176 case SUBTREE_MODIFIED:
177 return readModifiedNode(ModificationType.SUBTREE_MODIFIED, in);
181 return DataTreeCandidateNodes.fromNormalizedNode(in.readNormalizedNode());
183 throw new IllegalArgumentException("Unhandled node type " + type);
187 private static DataTreeCandidate parseCandidate(final ByteArrayDataInput in) throws IOException {
188 final NormalizedNodeDataInput reader = new NormalizedNodeInputStreamReader(in);
189 final YangInstanceIdentifier rootPath = reader.readYangInstanceIdentifier();
190 final byte type = reader.readByte();
192 final DataTreeCandidateNode rootNode;
195 rootNode = DeletedDataTreeCandidateNode.create();
197 case SUBTREE_MODIFIED:
198 rootNode = ModifiedDataTreeCandidateNode.create(readChildren(reader));
201 rootNode = DataTreeCandidateNodes.fromNormalizedNode(reader.readNormalizedNode());
204 throw new IllegalArgumentException("Unhandled node type " + type);
207 return DataTreeCandidates.newDataTreeCandidate(rootPath, rootNode);
210 DataTreeCandidate getCandidate() throws IOException {
211 return parseCandidate(ByteStreams.newDataInput(serialized));
216 return serialized.length;
220 public void writeExternal(ObjectOutput out) throws IOException {
221 out.writeByte((byte)serialVersionUID);
222 out.writeInt(serialized.length);
223 out.write(serialized);
227 public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
228 final long version = in.readByte();
229 Preconditions.checkArgument(version == serialVersionUID, "Unsupported serialization version %s", version);
231 final int length = in.readInt();
232 serialized = new byte[length];
233 in.readFully(serialized);