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