Bump MRI upstreams
[netconf.git] / restconf / restconf-common / src / main / java / org / opendaylight / restconf / common / serializer / AbstractWebsocketSerializer.java
1 /*
2  * Copyright (c) 2020 PANTHEON.tech, s.r.o. 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.restconf.common.serializer;
9
10 import java.util.ArrayDeque;
11 import java.util.Collection;
12 import java.util.Deque;
13 import java.util.Map;
14 import java.util.Set;
15 import org.opendaylight.yangtools.yang.common.QName;
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.LeafNode;
19 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
20 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
21 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
22 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNode;
23 import org.opendaylight.yangtools.yang.data.api.schema.tree.ModificationType;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
26
27 public abstract class AbstractWebsocketSerializer<T extends Exception> {
28
29     private static final Logger LOG = LoggerFactory.getLogger(AbstractWebsocketSerializer.class);
30
31     public void serialize(final DataTreeCandidate candidate, final boolean leafNodesOnly, final boolean skipData)
32             throws T {
33         final Deque<PathArgument> path = new ArrayDeque<>();
34         path.addAll(candidate.getRootPath().getPathArguments());
35         if (leafNodesOnly) {
36             serializeLeafNodesOnly(path, candidate.getRootNode(), skipData);
37             return;
38         }
39
40         serializeData(path, candidate.getRootNode(), skipData);
41     }
42
43     void serializeLeafNodesOnly(final Deque<PathArgument> path, final DataTreeCandidateNode candidate,
44             final boolean skipData) throws T {
45         NormalizedNode node = null;
46         switch (candidate.getModificationType()) {
47             case UNMODIFIED:
48                 // no reason to do anything with an unmodified node
49                 LOG.debug("DataTreeCandidate for a notification is unmodified, not serializing leaves. Candidate: {}",
50                         candidate);
51                 break;
52             case SUBTREE_MODIFIED:
53             case WRITE:
54             case APPEARED:
55                 node = candidate.getDataAfter().get();
56                 break;
57             case DELETE:
58             case DISAPPEARED:
59                 node = candidate.getDataBefore().get();
60                 break;
61             default:
62                 LOG.error("DataTreeCandidate modification has unknown type: {}", candidate.getModificationType());
63         }
64
65         if (node == null) {
66             return;
67         }
68
69         if (node instanceof LeafNode<?> || node instanceof LeafSetNode) {
70             serializeData(path, candidate, skipData);
71             return;
72         }
73
74         for (DataTreeCandidateNode childNode : candidate.getChildNodes()) {
75             path.add(childNode.getIdentifier());
76             serializeLeafNodesOnly(path, childNode, skipData);
77             path.removeLast();
78         }
79     }
80
81     abstract void serializeData(Collection<PathArgument> path, DataTreeCandidateNode candidate, boolean skipData)
82             throws T;
83
84     abstract void serializePath(Collection<PathArgument> pathArguments) throws T;
85
86     abstract void serializeOperation(DataTreeCandidateNode candidate) throws T;
87
88     String convertPath(final Collection<PathArgument> path) {
89         final StringBuilder pathBuilder = new StringBuilder();
90
91         for (PathArgument pathArgument : path) {
92             pathBuilder.append("/");
93             pathBuilder.append(pathArgument.getNodeType().getNamespace().toString().replaceAll(":", "-"));
94             pathBuilder.append(":");
95             pathBuilder.append(pathArgument.getNodeType().getLocalName());
96
97             if (pathArgument instanceof YangInstanceIdentifier.NodeIdentifierWithPredicates) {
98                 pathBuilder.append("[");
99                 final Set<Map.Entry<QName, Object>> keys =
100                         ((YangInstanceIdentifier.NodeIdentifierWithPredicates) pathArgument).entrySet();
101                 for (Map.Entry<QName, Object> key : keys) {
102                     pathBuilder.append(key.getKey().getNamespace().toString().replaceAll(":", "-"));
103                     pathBuilder.append(":");
104                     pathBuilder.append(key.getKey().getLocalName());
105                     pathBuilder.append("='");
106                     pathBuilder.append(key.getValue().toString());
107                     pathBuilder.append("'");
108                 }
109                 pathBuilder.append("]");
110             }
111         }
112
113         return pathBuilder.toString();
114     }
115
116     String modificationTypeToOperation(final DataTreeCandidateNode candidate, final ModificationType modificationType) {
117         switch (modificationType) {
118             case UNMODIFIED:
119                 // shouldn't ever happen since the root of a modification is only triggered by some event
120                 LOG.warn("DataTreeCandidate for a notification is unmodified. Candidate: {}", candidate);
121                 return "none";
122             case SUBTREE_MODIFIED:
123             case WRITE:
124             case APPEARED:
125                 if (candidate.getDataBefore().isPresent()) {
126                     return "updated";
127                 } else {
128                     return "created";
129                 }
130             case DELETE:
131             case DISAPPEARED:
132                 return "deleted";
133             default:
134                 LOG.error("DataTreeCandidate modification has unknown type: {}",
135                         candidate.getModificationType());
136                 throw new IllegalStateException("Unknown modification type");
137         }
138     }
139 }