BUG-5280: move DataTreeCandidate serialization to its own class
[controller.git] / opendaylight / md-sal / sal-distributed-datastore / src / main / java / org / opendaylight / controller / cluster / datastore / persisted / DataTreeCandidateInputOutput.java
1 /*
2  * Copyright (c) 2016 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.persisted;
9
10 import com.google.common.annotations.Beta;
11 import java.io.DataInput;
12 import java.io.DataOutput;
13 import java.io.IOException;
14 import java.util.ArrayList;
15 import java.util.Collection;
16 import java.util.Collections;
17 import org.opendaylight.controller.cluster.datastore.node.utils.stream.NormalizedNodeDataInput;
18 import org.opendaylight.controller.cluster.datastore.node.utils.stream.NormalizedNodeDataOutput;
19 import org.opendaylight.controller.cluster.datastore.node.utils.stream.NormalizedNodeInputOutput;
20 import org.opendaylight.controller.cluster.datastore.node.utils.stream.NormalizedNodeInputStreamReader;
21 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
22 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
23 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
24 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNode;
25 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNodes;
26 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidates;
27 import org.opendaylight.yangtools.yang.data.api.schema.tree.ModificationType;
28 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory;
30
31 /**
32  * Utility serialization/deserialization for {@link DataTreeCandidate}. Note that this utility does not maintain
33  * before-image information across serialization.
34  *
35  * @author Robert Varga
36  */
37 @Beta
38 public final class DataTreeCandidateInputOutput {
39     private static final Logger LOG = LoggerFactory.getLogger(DataTreeCandidateInputOutput.class);
40     private static final byte DELETE = 0;
41     private static final byte SUBTREE_MODIFIED = 1;
42     private static final byte UNMODIFIED = 2;
43     private static final byte WRITE = 3;
44     private static final byte APPEARED = 4;
45     private static final byte DISAPPEARED = 5;
46
47     private DataTreeCandidateInputOutput() {
48         throw new UnsupportedOperationException();
49     }
50
51     private static DataTreeCandidateNode readModifiedNode(final ModificationType type,
52             final NormalizedNodeDataInput in) throws IOException {
53
54         final PathArgument identifier = in.readPathArgument();
55         final Collection<DataTreeCandidateNode> children = readChildren(in);
56         if (children.isEmpty()) {
57             LOG.debug("Modified node {} does not have any children, not instantiating it", identifier);
58             return null;
59         } else {
60             return ModifiedDataTreeCandidateNode.create(identifier, type, children);
61         }
62     }
63
64     private static Collection<DataTreeCandidateNode> readChildren(final NormalizedNodeDataInput in) throws IOException {
65         final int size = in.readInt();
66         if (size != 0) {
67             final Collection<DataTreeCandidateNode> ret = new ArrayList<>(size);
68             for (int i = 0; i < size; ++i) {
69                 final DataTreeCandidateNode child = readNode(in);
70                 if (child != null) {
71                     ret.add(child);
72                 }
73             }
74             return ret;
75         } else {
76             return Collections.emptyList();
77         }
78     }
79
80     private static DataTreeCandidateNode readNode(final NormalizedNodeDataInput in) throws IOException {
81         final byte type = in.readByte();
82         switch (type) {
83         case APPEARED:
84             return readModifiedNode(ModificationType.APPEARED, in);
85         case DELETE:
86             return DeletedDataTreeCandidateNode.create(in.readPathArgument());
87         case DISAPPEARED:
88             return readModifiedNode(ModificationType.DISAPPEARED, in);
89         case SUBTREE_MODIFIED:
90             return readModifiedNode(ModificationType.SUBTREE_MODIFIED, in);
91         case UNMODIFIED:
92             return null;
93         case WRITE:
94             return DataTreeCandidateNodes.fromNormalizedNode(in.readNormalizedNode());
95         default:
96             throw new IllegalArgumentException("Unhandled node type " + type);
97         }
98     }
99
100     public static DataTreeCandidate readDataTreeCandidate(final DataInput in) throws IOException {
101         final NormalizedNodeDataInput reader = new NormalizedNodeInputStreamReader(in);
102         final YangInstanceIdentifier rootPath = reader.readYangInstanceIdentifier();
103         final byte type = reader.readByte();
104
105         final DataTreeCandidateNode rootNode;
106         switch (type) {
107         case DELETE:
108             rootNode = DeletedDataTreeCandidateNode.create();
109             break;
110         case SUBTREE_MODIFIED:
111             rootNode = ModifiedDataTreeCandidateNode.create(readChildren(reader));
112             break;
113         case WRITE:
114             rootNode = DataTreeCandidateNodes.fromNormalizedNode(reader.readNormalizedNode());
115             break;
116         default:
117             throw new IllegalArgumentException("Unhandled node type " + type);
118         }
119
120         return DataTreeCandidates.newDataTreeCandidate(rootPath, rootNode);
121     }
122
123
124     private static void writeChildren(final NormalizedNodeDataOutput out,
125             final Collection<DataTreeCandidateNode> children) throws IOException {
126         out.writeInt(children.size());
127         for (DataTreeCandidateNode child : children) {
128             writeNode(out, child);
129         }
130     }
131
132     private static void writeNode(final NormalizedNodeDataOutput out, final DataTreeCandidateNode node)
133             throws IOException {
134         switch (node.getModificationType()) {
135         case APPEARED:
136             out.writeByte(APPEARED);
137             out.writePathArgument(node.getIdentifier());
138             writeChildren(out, node.getChildNodes());
139             break;
140         case DELETE:
141             out.writeByte(DELETE);
142             out.writePathArgument(node.getIdentifier());
143             break;
144         case DISAPPEARED:
145             out.writeByte(DISAPPEARED);
146             out.writePathArgument(node.getIdentifier());
147             writeChildren(out, node.getChildNodes());
148             break;
149         case SUBTREE_MODIFIED:
150             out.writeByte(SUBTREE_MODIFIED);
151             out.writePathArgument(node.getIdentifier());
152             writeChildren(out, node.getChildNodes());
153             break;
154         case WRITE:
155             out.writeByte(WRITE);
156             out.writeNormalizedNode(node.getDataAfter().get());
157             break;
158         case UNMODIFIED:
159             out.writeByte(UNMODIFIED);
160             break;
161         default:
162             throw new IllegalArgumentException("Unhandled node type " + node.getModificationType());
163         }
164     }
165
166     public static void writeDataTreeCandidate(final DataOutput out, DataTreeCandidate candidate) throws IOException {
167         try (final NormalizedNodeDataOutput writer = NormalizedNodeInputOutput.newDataOutput(out)) {
168             writer.writeYangInstanceIdentifier(candidate.getRootPath());
169
170             final DataTreeCandidateNode node = candidate.getRootNode();
171             switch (node.getModificationType()) {
172             case APPEARED:
173                 writer.writeByte(APPEARED);
174                 writeChildren(writer, node.getChildNodes());
175                 break;
176             case DELETE:
177                 writer.writeByte(DELETE);
178                 break;
179             case DISAPPEARED:
180                 writer.writeByte(DISAPPEARED);
181                 writeChildren(writer, node.getChildNodes());
182                 break;
183             case SUBTREE_MODIFIED:
184                 writer.writeByte(SUBTREE_MODIFIED);
185                 writeChildren(writer, node.getChildNodes());
186                 break;
187             case UNMODIFIED:
188                 writer.writeByte(UNMODIFIED);
189                 break;
190             case WRITE:
191                 writer.writeByte(WRITE);
192                 writer.writeNormalizedNode(node.getDataAfter().get());
193                 break;
194             default:
195                 throw new IllegalArgumentException("Unhandled node type " + node.getModificationType());
196             }
197         }
198     }
199 }