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