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 com.google.protobuf.GeneratedMessage.GeneratedExtension;
15 import java.io.DataInput;
16 import java.io.DataOutput;
17 import java.io.Externalizable;
18 import java.io.IOException;
19 import java.io.ObjectInput;
20 import java.io.ObjectOutput;
21 import java.util.ArrayList;
22 import java.util.Collection;
23 import java.util.Collections;
25 import org.opendaylight.controller.cluster.datastore.node.utils.stream.NormalizedNodeInputStreamReader;
26 import org.opendaylight.controller.cluster.datastore.node.utils.stream.NormalizedNodeOutputStreamWriter;
27 import org.opendaylight.controller.cluster.raft.protobuff.client.messages.Payload;
28 import org.opendaylight.controller.protobuff.messages.cluster.raft.AppendEntriesMessages.AppendEntries;
29 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
30 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
31 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
32 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNode;
33 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNodes;
34 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidates;
35 import org.opendaylight.yangtools.yang.data.api.schema.tree.ModificationType;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
39 final class DataTreeCandidatePayload extends Payload implements Externalizable {
40 private static final Logger LOG = LoggerFactory.getLogger(DataTreeCandidatePayload.class);
41 private static final long serialVersionUID = 1L;
42 private static final byte DELETE = 0;
43 private static final byte SUBTREE_MODIFIED = 1;
44 private static final byte UNMODIFIED = 2;
45 private static final byte WRITE = 3;
46 private static final byte APPEARED = 4;
47 private static final byte DISAPPEARED = 5;
49 private transient byte[] serialized;
51 public DataTreeCandidatePayload() {
52 // Required by Externalizable
55 private DataTreeCandidatePayload(final byte[] serialized) {
56 this.serialized = Preconditions.checkNotNull(serialized);
59 private static void writeChildren(final NormalizedNodeOutputStreamWriter writer, final DataOutput out,
60 final Collection<DataTreeCandidateNode> children) throws IOException {
61 out.writeInt(children.size());
62 for (DataTreeCandidateNode child : children) {
63 writeNode(writer, out, child);
67 private static void writeNode(final NormalizedNodeOutputStreamWriter writer, final DataOutput out,
68 final DataTreeCandidateNode node) throws IOException {
69 switch (node.getModificationType()) {
71 out.writeByte(APPEARED);
72 writer.writePathArgument(node.getIdentifier());
73 writeChildren(writer, out, node.getChildNodes());
76 out.writeByte(DELETE);
77 writer.writePathArgument(node.getIdentifier());
80 out.writeByte(DISAPPEARED);
81 writer.writePathArgument(node.getIdentifier());
82 writeChildren(writer, out, node.getChildNodes());
84 case SUBTREE_MODIFIED:
85 out.writeByte(SUBTREE_MODIFIED);
86 writer.writePathArgument(node.getIdentifier());
87 writeChildren(writer, out, node.getChildNodes());
91 writer.writeNormalizedNode(node.getDataAfter().get());
94 out.writeByte(UNMODIFIED);
97 throw new IllegalArgumentException("Unhandled node type " + node.getModificationType());
101 static DataTreeCandidatePayload create(DataTreeCandidate candidate) {
102 final ByteArrayDataOutput out = ByteStreams.newDataOutput();
103 try (final NormalizedNodeOutputStreamWriter writer = new NormalizedNodeOutputStreamWriter(out)) {
104 writer.writeYangInstanceIdentifier(candidate.getRootPath());
106 final DataTreeCandidateNode node = candidate.getRootNode();
107 switch (node.getModificationType()) {
109 out.writeByte(APPEARED);
110 writeChildren(writer, out, node.getChildNodes());
113 out.writeByte(DELETE);
116 out.writeByte(DISAPPEARED);
117 writeChildren(writer, out, node.getChildNodes());
119 case SUBTREE_MODIFIED:
120 out.writeByte(SUBTREE_MODIFIED);
121 writeChildren(writer, out, node.getChildNodes());
124 out.writeByte(UNMODIFIED);
127 out.writeByte(WRITE);
128 writer.writeNormalizedNode(node.getDataAfter().get());
131 throw new IllegalArgumentException("Unhandled node type " + node.getModificationType());
135 } catch (IOException e) {
136 throw new IllegalArgumentException(String.format("Failed to serialize candidate %s", candidate), e);
139 return new DataTreeCandidatePayload(out.toByteArray());
142 private static Collection<DataTreeCandidateNode> readChildren(final NormalizedNodeInputStreamReader reader,
143 final DataInput in) throws IOException {
144 final int size = in.readInt();
146 final Collection<DataTreeCandidateNode> ret = new ArrayList<>(size);
147 for (int i = 0; i < size; ++i) {
148 final DataTreeCandidateNode child = readNode(reader, in);
155 return Collections.emptyList();
159 private static DataTreeCandidateNode readModifiedNode(final ModificationType type,
160 final NormalizedNodeInputStreamReader reader, final DataInput in) throws IOException {
162 final PathArgument identifier = reader.readPathArgument();
163 final Collection<DataTreeCandidateNode> children = readChildren(reader, in);
164 if (children.isEmpty()) {
165 LOG.debug("Modified node {} does not have any children, not instantiating it", identifier);
168 return ModifiedDataTreeCandidateNode.create(identifier, type, children);
172 private static DataTreeCandidateNode readNode(final NormalizedNodeInputStreamReader reader,
173 final DataInput in) throws IOException {
174 final byte type = in.readByte();
177 return readModifiedNode(ModificationType.APPEARED, reader, in);
179 return DeletedDataTreeCandidateNode.create(reader.readPathArgument());
181 return readModifiedNode(ModificationType.DISAPPEARED, reader, in);
182 case SUBTREE_MODIFIED:
183 return readModifiedNode(ModificationType.SUBTREE_MODIFIED, reader, in);
187 return DataTreeCandidateNodes.fromNormalizedNode(reader.readNormalizedNode());
189 throw new IllegalArgumentException("Unhandled node type " + type);
193 private static DataTreeCandidate parseCandidate(final ByteArrayDataInput in) throws IOException {
194 final NormalizedNodeInputStreamReader reader = new NormalizedNodeInputStreamReader(in);
195 final YangInstanceIdentifier rootPath = reader.readYangInstanceIdentifier();
196 final byte type = in.readByte();
198 final DataTreeCandidateNode rootNode;
201 rootNode = DeletedDataTreeCandidateNode.create();
203 case SUBTREE_MODIFIED:
204 rootNode = ModifiedDataTreeCandidateNode.create(readChildren(reader, in));
207 rootNode = DataTreeCandidateNodes.fromNormalizedNode(reader.readNormalizedNode());
210 throw new IllegalArgumentException("Unhandled node type " + type);
213 return DataTreeCandidates.newDataTreeCandidate(rootPath, rootNode);
216 DataTreeCandidate getCandidate() throws IOException {
217 return parseCandidate(ByteStreams.newDataInput(serialized));
222 @SuppressWarnings("rawtypes")
223 public <T> Map<GeneratedExtension, T> encode() {
229 public Payload decode(final AppendEntries.ReplicatedLogEntry.Payload payload) {
235 return serialized.length;
239 public void writeExternal(ObjectOutput out) throws IOException {
240 out.writeByte((byte)serialVersionUID);
241 out.writeInt(serialized.length);
242 out.write(serialized);
246 public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
247 final long version = in.readByte();
248 Preconditions.checkArgument(version == serialVersionUID, "Unsupported serialization version %s", version);
250 final int length = in.readInt();
251 serialized = new byte[length];
252 in.readFully(serialized);