blob: c027dd180807e2f43f5906189452ff6feaa6e660 [file] [log] [blame]
Shankara-Huaweid5823ab2016-11-22 10:14:52 +05301/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Shankara-Huaweid5823ab2016-11-22 10:14:52 +05303 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.onosproject.yms.app.ych.defaultcodecs.utils;
18
19import com.google.common.base.Splitter;
20import com.google.common.collect.Lists;
21import org.onosproject.yms.app.ych.YchException;
22import org.onosproject.yms.ydt.YdtBuilder;
23import org.onosproject.yms.ydt.YdtContextOperationType;
24
25import java.io.UnsupportedEncodingException;
26import java.net.URLDecoder;
27import java.util.ArrayList;
28import java.util.List;
29
30import static com.google.common.base.Preconditions.checkNotNull;
31import static org.onosproject.yms.ydt.YdtContextOperationType.NONE;
32import static org.onosproject.yms.ydt.YdtType.SINGLE_INSTANCE_NODE;
33
34/**
35 * Utils to complete the conversion between JSON and YDT(YANG DATA MODEL).
36 */
37public final class DefaultCodecUtils {
38
39 private static final Splitter SLASH_SPLITTER = Splitter.on('/');
40 private static final Splitter COMMA_SPLITTER = Splitter.on(',');
41 private static final String EQUAL = "=";
42 private static final String COMMA = ",";
43 private static final String COLON = ":";
44 private static final String URI_ENCODING_CHAR_SET = "ISO-8859-1";
45 private static final String URI_NULL_CHECK_ERROR = "uri identifier " +
46 "should not be null";
47 private static final String URI_MODULE_FORMAT = "Illegal URI, First " +
48 "node should be in format \"moduleName:nodeName\"";
49
50 private static final String URI_LEAF_FORMAT = "Illegal URI, List or " +
51 "Leaf-list node should be in format \"nodeName=key\"or " +
52 "\"nodeName=instance-value\"";
53
54 // no instantiation
55 private DefaultCodecUtils() {
56 }
57
58 /**
59 * Converts URI identifier to YDT builder.
60 *
61 * @param identifier the uri identifier from web request
62 * @param builder the base YDT builder
63 * @param ydtOpType the YDT context operation type
64 * @return the YDT builder with the tree info of identifier
65 */
66 public static YdtBuilder convertUriToYdt(
67 String identifier,
68 YdtBuilder builder,
69 YdtContextOperationType ydtOpType) {
70 checkNotNull(identifier, URI_NULL_CHECK_ERROR);
71 List<String> segmentPaths =
72 urlPathArgsDecode(SLASH_SPLITTER.split(identifier));
73 if (segmentPaths.isEmpty()) {
74 return null;
75 }
76 processPathSegments(segmentPaths, builder, ydtOpType);
77 return builder;
78 }
79
80 /**
Shankara-Huaweid5823ab2016-11-22 10:14:52 +053081 * Converts a list of path segments to a YDT builder tree.
82 *
83 * @param paths the list of path segments split from URI
84 * @param builder the base YDT builder
85 * @param ydtOpType the YDT context operation type
86 * @return the YDT builder with the tree info of paths
87 */
88 private static YdtBuilder processPathSegments(
89 List<String> paths,
90 YdtBuilder builder,
91 YdtContextOperationType ydtOpType) {
92 if (paths.isEmpty()) {
93 return builder;
94 }
95 boolean isLastNode = paths.size() == 1;
96 YdtContextOperationType thisOpType = isLastNode ? ydtOpType : NONE;
97
98 final String path = paths.iterator().next();
99 if (path.contains(COLON)) {
100 addModule(builder, path);
101 addNode(path, builder, thisOpType);
102 } else if (path.contains(EQUAL)) {
103 addListOrLeafList(path, builder, thisOpType);
104 } else {
105 addLeaf(path, builder, thisOpType);
106 }
107
108 if (isLastNode) {
109 return builder;
110 }
111 List<String> remainPaths = paths.subList(1, paths.size());
112 processPathSegments(remainPaths, builder, ydtOpType);
113
114 return builder;
115 }
116
117 /**
118 * Returns YDT builder after adding module node.
119 *
120 * @param builder YDT builder
121 * @param path path segment
122 * @return the YDT builder
123 */
124 private static YdtBuilder addModule(YdtBuilder builder, String path) {
125 String moduleName = getPreSegment(path, COLON);
126 if (moduleName == null) {
127 throw new YchException(URI_MODULE_FORMAT);
128 }
129 builder.addChild(moduleName, null, SINGLE_INSTANCE_NODE);
130 return builder;
131 }
132
133 /**
134 * Returns YDT builder after adding single instance node.
135 *
136 * @param path path segments
137 * @param builder YDT builder
138 * @param ydtOpType YDT context operation type
139 * @return the YDT builder
140 */
141 private static YdtBuilder addNode(String path, YdtBuilder builder,
142 YdtContextOperationType ydtOpType) {
143 String nodeName = getPostSegment(path, COLON);
144 builder.addChild(nodeName, null, SINGLE_INSTANCE_NODE, ydtOpType);
145 return builder;
146 }
147
148 /**
149 * Returns YDT builder after adding multi instance node.
150 *
151 * @param path path segments
152 * @param builder YDT builder
153 * @param opType the YDT context operation type
154 * @return the YDT builder
155 */
156 private static YdtBuilder addListOrLeafList(
157 String path,
158 YdtBuilder builder,
159 YdtContextOperationType opType) {
160 String nodeName = getPreSegment(path, EQUAL);
161 String keyStr = getPostSegment(path, EQUAL);
162 if (keyStr == null) {
163 throw new YchException(URI_LEAF_FORMAT);
164 }
165 builder.setDefaultEditOperationType(opType);
166 if (keyStr.contains(COMMA)) {
167 List<String> keys = Lists.newArrayList(
168 COMMA_SPLITTER.split(keyStr));
169 builder.addMultiInstanceChild(nodeName, null, keys, null);
170 } else {
171 builder.addMultiInstanceChild(nodeName, null,
172 Lists.newArrayList(keyStr), null);
173 }
174 return builder;
175 }
176
177 /**
178 * Returns YDT builder after adding leaf.
179 *
180 * @param path path segments
181 * @param builder YDT builder
182 * @param ydtOpType YDT context operation type
183 * @return the YDT builder
184 */
185 private static YdtBuilder addLeaf(String path, YdtBuilder builder,
186 YdtContextOperationType ydtOpType) {
187 checkNotNull(path);
188 builder.addChild(path, null, ydtOpType);
189 return builder;
190 }
191
192 /**
193 * Returns the node name before the specified character in the string.
194 *
195 * @param path path segment
196 * @param splitChar character in the string
197 * @return the node name string
198 */
199 private static String getPreSegment(String path, String splitChar) {
200 int idx = path.indexOf(splitChar);
201 if (idx == -1) {
202 return null;
203 }
204
205 if (path.indexOf(':', idx + 1) != -1) {
206 return null;
207 }
208
209 return path.substring(0, idx);
210 }
211
212 /**
213 * Returns the string after the specified character in the string.
214 *
215 * @param path path segment
216 * @param splitChar character in the string
217 * @return the substring after specified character
218 */
219 private static String getPostSegment(String path, String splitChar) {
220 int idx = path.indexOf(splitChar);
221 if (idx == -1) {
222 return path;
223 }
224
225 if (path.indexOf(splitChar, idx + 1) != -1) {
226 return null;
227 }
228
229 return path.substring(idx + 1);
230 }
231
232 /**
233 * Converts a list of path from the original format to ISO-8859-1 code.
234 *
235 * @param paths the original paths
236 * @return list of decoded paths
237 */
238 private static List<String> urlPathArgsDecode(Iterable<String> paths) {
239 try {
240 List<String> decodedPathArgs = new ArrayList<>();
241 for (String pathArg : paths) {
242 String decode = URLDecoder.decode(pathArg,
243 URI_ENCODING_CHAR_SET);
244 decodedPathArgs.add(decode);
245 }
246 return decodedPathArgs;
247 } catch (UnsupportedEncodingException e) {
248 throw new YchException("Invalid URL path arg '" + paths + "': ", e);
249 }
250 }
251}