21083618f04f26605a809f68c4277378c64df8f4
[controller.git] / opendaylight / md-sal / sal-distributed-datastore / src / main / java / org / opendaylight / controller / cluster / datastore / DataTreeCandidatePayload.java
1 /*
2  * Copyright (c) 2015 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;
9
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;
35
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;
45
46     private transient byte[] serialized;
47
48     public DataTreeCandidatePayload() {
49         // Required by Externalizable
50     }
51
52     private DataTreeCandidatePayload(final byte[] serialized) {
53         this.serialized = Preconditions.checkNotNull(serialized);
54     }
55
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);
61         }
62     }
63
64     private static void writeNode(final NormalizedNodeDataOutput out, final DataTreeCandidateNode node)
65             throws IOException {
66         switch (node.getModificationType()) {
67         case APPEARED:
68             out.writeByte(APPEARED);
69             out.writePathArgument(node.getIdentifier());
70             writeChildren(out, node.getChildNodes());
71             break;
72         case DELETE:
73             out.writeByte(DELETE);
74             out.writePathArgument(node.getIdentifier());
75             break;
76         case DISAPPEARED:
77             out.writeByte(DISAPPEARED);
78             out.writePathArgument(node.getIdentifier());
79             writeChildren(out, node.getChildNodes());
80             break;
81         case SUBTREE_MODIFIED:
82             out.writeByte(SUBTREE_MODIFIED);
83             out.writePathArgument(node.getIdentifier());
84             writeChildren(out, node.getChildNodes());
85             break;
86         case WRITE:
87             out.writeByte(WRITE);
88             out.writeNormalizedNode(node.getDataAfter().get());
89             break;
90         case UNMODIFIED:
91             out.writeByte(UNMODIFIED);
92             break;
93         default:
94             throw new IllegalArgumentException("Unhandled node type " + node.getModificationType());
95         }
96     }
97
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());
102
103             final DataTreeCandidateNode node = candidate.getRootNode();
104             switch (node.getModificationType()) {
105             case APPEARED:
106                 writer.writeByte(APPEARED);
107                 writeChildren(writer, node.getChildNodes());
108                 break;
109             case DELETE:
110                 writer.writeByte(DELETE);
111                 break;
112             case DISAPPEARED:
113                 writer.writeByte(DISAPPEARED);
114                 writeChildren(writer, node.getChildNodes());
115                 break;
116             case SUBTREE_MODIFIED:
117                 writer.writeByte(SUBTREE_MODIFIED);
118                 writeChildren(writer, node.getChildNodes());
119                 break;
120             case UNMODIFIED:
121                 writer.writeByte(UNMODIFIED);
122                 break;
123             case WRITE:
124                 writer.writeByte(WRITE);
125                 writer.writeNormalizedNode(node.getDataAfter().get());
126                 break;
127             default:
128                 throw new IllegalArgumentException("Unhandled node type " + node.getModificationType());
129             }
130
131         } catch (IOException e) {
132             throw new IllegalArgumentException(String.format("Failed to serialize candidate %s", candidate), e);
133         }
134
135         return new DataTreeCandidatePayload(out.toByteArray());
136     }
137
138     private static Collection<DataTreeCandidateNode> readChildren(final NormalizedNodeDataInput in) throws IOException {
139         final int size = in.readInt();
140         if (size != 0) {
141             final Collection<DataTreeCandidateNode> ret = new ArrayList<>(size);
142             for (int i = 0; i < size; ++i) {
143                 final DataTreeCandidateNode child = readNode(in);
144                 if (child != null) {
145                     ret.add(child);
146                 }
147             }
148             return ret;
149         } else {
150             return Collections.emptyList();
151         }
152     }
153
154     private static DataTreeCandidateNode readModifiedNode(final ModificationType type,
155             final NormalizedNodeDataInput in) throws IOException {
156
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);
161             return null;
162         } else {
163             return ModifiedDataTreeCandidateNode.create(identifier, type, children);
164         }
165     }
166
167     private static DataTreeCandidateNode readNode(final NormalizedNodeDataInput in) throws IOException {
168         final byte type = in.readByte();
169         switch (type) {
170         case APPEARED:
171             return readModifiedNode(ModificationType.APPEARED, in);
172         case DELETE:
173             return DeletedDataTreeCandidateNode.create(in.readPathArgument());
174         case DISAPPEARED:
175             return readModifiedNode(ModificationType.DISAPPEARED, in);
176         case SUBTREE_MODIFIED:
177             return readModifiedNode(ModificationType.SUBTREE_MODIFIED, in);
178         case UNMODIFIED:
179             return null;
180         case WRITE:
181             return DataTreeCandidateNodes.fromNormalizedNode(in.readNormalizedNode());
182         default:
183             throw new IllegalArgumentException("Unhandled node type " + type);
184         }
185     }
186
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();
191
192         final DataTreeCandidateNode rootNode;
193         switch (type) {
194         case DELETE:
195             rootNode = DeletedDataTreeCandidateNode.create();
196             break;
197         case SUBTREE_MODIFIED:
198             rootNode = ModifiedDataTreeCandidateNode.create(readChildren(reader));
199             break;
200         case WRITE:
201             rootNode = DataTreeCandidateNodes.fromNormalizedNode(reader.readNormalizedNode());
202             break;
203         default:
204             throw new IllegalArgumentException("Unhandled node type " + type);
205         }
206
207         return DataTreeCandidates.newDataTreeCandidate(rootPath, rootNode);
208     }
209
210     DataTreeCandidate getCandidate() throws IOException {
211         return parseCandidate(ByteStreams.newDataInput(serialized));
212     }
213
214     @Override
215     public int size() {
216         return serialized.length;
217     }
218
219     @Override
220     public void writeExternal(ObjectOutput out) throws IOException {
221         out.writeByte((byte)serialVersionUID);
222         out.writeInt(serialized.length);
223         out.write(serialized);
224     }
225
226     @Override
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);
230
231         final int length = in.readInt();
232         serialized = new byte[length];
233         in.readFully(serialized);
234     }
235 }

©2013 OpenDaylight, A Linux Foundation Collaborative Project. All Rights Reserved.
OpenDaylight is a registered trademark of The OpenDaylight Project, Inc.
Linux Foundation and OpenDaylight are registered trademarks of the Linux Foundation.
Linux is a registered trademark of Linus Torvalds.