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