Add DataPatchPath
[netconf.git] / restconf / restconf-nb / src / main / java / org / opendaylight / restconf / server / api / OperationsGetResult.java
1 /*
2  * Copyright (c) 2021 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.server.api;
9
10 import static java.util.Objects.requireNonNull;
11 import static org.opendaylight.restconf.server.api.OperationsGetResultHelper.appendJSON;
12 import static org.opendaylight.restconf.server.api.OperationsGetResultHelper.appendXML;
13 import static org.opendaylight.restconf.server.api.OperationsGetResultHelper.jsonPrefix;
14
15 import com.google.common.base.MoreObjects;
16 import com.google.common.collect.ImmutableSetMultimap;
17 import java.util.Comparator;
18 import java.util.Map;
19 import java.util.Map.Entry;
20 import org.eclipse.jdt.annotation.NonNull;
21 import org.opendaylight.yangtools.yang.common.QName;
22 import org.opendaylight.yangtools.yang.common.QNameModule;
23 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
24
25 /**
26  * RESTCONF {@code /operations} content for a {@code GET} operation as per
27  * <a href="https://www.rfc-editor.org/rfc/rfc8040#section-3.3.2">RFC8040</a>.
28  */
29 public sealed interface OperationsGetResult {
30     record Leaf(EffectiveModelContext modelContext, QName rpc) implements OperationsGetResult {
31         public Leaf {
32             requireNonNull(modelContext);
33             requireNonNull(rpc);
34         }
35
36         @Override
37         public String toJSON() {
38             // https://www.rfc-editor.org/rfc/rfc8040#page-84:
39             //
40             //            In JSON, the YANG module name identifies the module:
41             //
42             //              { 'ietf-system:system-restart' : [null] }
43             return appendJSON(new StringBuilder("{ "), jsonPrefix(modelContext, rpc.getModule()), rpc).append(" }")
44                 .toString();
45         }
46
47         @Override
48         public String toXML() {
49             // https://www.rfc-editor.org/rfc/rfc8040#page-84:
50             //
51             //            In XML, the YANG module namespace identifies the module:
52             //
53             //              <system-restart
54             //                 xmlns='urn:ietf:params:xml:ns:yang:ietf-system'/>
55             return appendXML(new StringBuilder(), rpc).toString();
56         }
57
58         @Override
59         public String toString() {
60             return MoreObjects.toStringHelper(this).add("rpc", rpc).toString();
61         }
62     }
63
64     record Container(EffectiveModelContext modelContext, ImmutableSetMultimap<QNameModule, QName> rpcs)
65             implements OperationsGetResult {
66         public Container {
67             requireNonNull(modelContext);
68             requireNonNull(rpcs);
69         }
70
71         @Override
72         public String toJSON() {
73             final var sb = new StringBuilder("""
74                 {
75                   "ietf-restconf:operations" : {\
76                 """);
77
78             if (!rpcs.isEmpty()) {
79                 final var entryIt = rpcs.asMap().entrySet().stream()
80                     .map(entry -> Map.entry(jsonPrefix(modelContext, entry.getKey()), entry.getValue()))
81                     .sorted(Comparator.comparing(Entry::getKey))
82                     .iterator();
83                 var entry = entryIt.next();
84                 var nameIt = entry.getValue().iterator();
85                 while (true) {
86                     appendJSON(sb.append("\n    "), entry.getKey(), nameIt.next());
87                     if (nameIt.hasNext()) {
88                         sb.append(',');
89                         continue;
90                     }
91
92                     if (entryIt.hasNext()) {
93                         sb.append(',');
94                         entry = entryIt.next();
95                         nameIt = entry.getValue().iterator();
96                         continue;
97                     }
98
99                     break;
100                 }
101             }
102
103             return sb.append("\n  }\n}").toString();
104         }
105
106         @Override
107         public String toXML() {
108             // Header with namespace declarations for each module
109             final var sb = new StringBuilder("<operations xmlns=\"urn:ietf:params:xml:ns:yang:ietf-restconf\"");
110             if (rpcs.isEmpty()) {
111                 return sb.append("/>").toString();
112             }
113
114             sb.append('>');
115             rpcs.asMap().entrySet().stream()
116                 .sorted(Comparator.comparing(Entry::getKey))
117                 .flatMap(entry -> entry.getValue().stream())
118                 .forEach(rpc -> appendXML(sb.append("\n  "), rpc));
119             return sb.append("\n</operations>").toString();
120         }
121     }
122
123     @NonNull String toJSON();
124
125     @NonNull String toXML();
126 }