Fixed Minor Code Smells issues "Deprecated JsonParser"
[cli.git] / profiles / http / src / main / java / org / onap / cli / fw / http / utils / OnapCommandHttpUtils.java
1 /*
2  * Copyright 2017 Huawei Technologies Co., Ltd.
3  *
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
17 package org.onap.cli.fw.http.utils;
18
19 import java.util.ArrayList;
20 import java.util.HashMap;
21 import java.util.Iterator;
22 import java.util.List;
23 import java.util.Map;
24 import java.util.Map.Entry;
25
26 import org.onap.cli.fw.error.OnapCommandException;
27 import org.onap.cli.fw.error.OnapCommandInvalidParameterValue;
28 import org.onap.cli.fw.error.OnapCommandParameterNotFound;
29 import org.onap.cli.fw.error.OnapCommandResultEmpty;
30 import org.onap.cli.fw.error.OnapCommandResultMapProcessingFailed;
31 import org.onap.cli.fw.http.conf.OnapCommandHttpConstants;
32 import org.onap.cli.fw.http.connect.HttpInput;
33 import org.onap.cli.fw.http.connect.HttpResult;
34 import org.onap.cli.fw.http.error.OnapCommandHttpHeaderNotFound;
35 import org.onap.cli.fw.http.error.OnapCommandHttpInvalidRequestBody;
36 import org.onap.cli.fw.http.error.OnapCommandHttpInvalidResponseBody;
37 import org.onap.cli.fw.input.OnapCommandParameter;
38 import org.onap.cli.fw.input.OnapCommandParameterType;
39 import org.onap.cli.fw.utils.OnapCommandUtils;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
42
43 import com.google.gson.Gson;
44 import com.google.gson.GsonBuilder;
45 import com.google.gson.JsonElement;
46 import com.google.gson.JsonParser;
47
48 import com.jayway.jsonpath.JsonPath;
49 import com.jayway.jsonpath.PathNotFoundException;
50
51 import net.minidev.json.JSONArray;
52
53 public class OnapCommandHttpUtils {
54
55     static Logger log = LoggerFactory.getLogger(OnapCommandHttpUtils.class);
56     private static Gson gson = new GsonBuilder().serializeNulls().create();
57     private OnapCommandHttpUtils() {
58         throw new IllegalStateException("Utility class");
59     }
60     /**
61      * Set argument to param value.
62      *
63      * @param params
64      *            map
65      * @param input
66      *            HttpInput
67      * @return HttpInput
68      * @throws OnapCommandParameterNotFound
69      *             exception
70      * @throws OnapCommandInvalidParameterValue
71      *             exception
72      */
73     public static HttpInput populateParameters(Map<String, OnapCommandParameter> params, HttpInput input)
74             throws OnapCommandException {
75
76         HttpInput inp = new HttpInput();
77
78         for (OnapCommandParameter param : params.values()) {
79             if (OnapCommandParameterType.BINARY.equals(param.getParameterType())) {
80                 inp.setBinaryData(true);
81                 break;
82             }
83         }
84
85         inp.setUri(OnapCommandUtils.replaceLineForSpecialValues(input.getUri()));
86         inp.setUri(OnapCommandUtils.replaceLineFromInputParameters(input.getUri(), params));
87
88         inp.setMethod(input.getMethod().toLowerCase());
89
90         boolean isRemoveEmptyNodes = Boolean.parseBoolean(input.getContext().getOrDefault(OnapCommandHttpConstants.CONTEXT_REMOVE_EMPTY_JSON_NODES, "false"));
91
92         //Process for md5
93         Map <String, String> values = new HashMap<>();
94         for (Map.Entry<String, OnapCommandParameter> param: params.entrySet()) {
95             values.put(param.getKey(), param.getValue().getValue().toString());
96         }
97
98         if (!input.getMultiparts().isEmpty()) {
99             for (HttpInput.Part part: input.getMultiparts()) {
100                 part.setContent(OnapCommandUtils.replaceLineForSpecialValues(part.getContent(), values));
101                 part.setContent(OnapCommandUtils.replaceLineFromInputParameters(part.getContent(), params));
102                 if (isRemoveEmptyNodes) {
103                     part.setContent(OnapCommandHttpUtils.normalizeJson(part.getContent()));
104                 }
105             }
106
107             inp.setMultiparts(input.getMultiparts());
108         } else {
109             inp.setMultipartEntityName(input.getMultipartEntityName());
110             inp.setBody(OnapCommandUtils.replaceLineForSpecialValues(input.getBody(), values));
111             inp.setBody(OnapCommandUtils.replaceLineFromInputParameters(inp.getBody(), params));
112             if (isRemoveEmptyNodes) {
113                 inp.setBody(OnapCommandHttpUtils.normalizeJson(inp.getBody()));
114             }
115         }
116
117         //consider __body__ spl entry
118         values.put(OnapCommandHttpConstants.__BODY__, inp.getBody());
119
120         for (String h : input.getReqHeaders().keySet()) {
121             String value = input.getReqHeaders().get(h);
122             value = OnapCommandUtils.replaceLineForSpecialValues(value, values);
123             inp.getReqHeaders().put(h, OnapCommandUtils.replaceLineFromInputParameters(value, params));
124         }
125
126         for (String h : input.getReqQueries().keySet()) {
127             String value = input.getReqQueries().get(h);
128             value = OnapCommandUtils.replaceLineForSpecialValues(value, values);
129             inp.getReqQueries().put(h, OnapCommandUtils.replaceLineFromInputParameters(value, params));
130         }
131
132         return inp;
133     }
134
135     /**
136      * Populate result.
137      *
138      * @param resultMap
139      *            map
140      * @param resultHttp
141      *            HttpResult
142      * @return map
143      * @throws OnapCommandHttpHeaderNotFound
144      *             header not found exception
145      * @throws OnapCommandHttpInvalidResponseBody
146      *             invalid response body exception
147      * @throws OnapCommandResultMapProcessingFailed
148      *             map processing failed exception
149      */
150     public static Map<String, List<String>> populateOutputs(Map<String, String> resultMap, HttpResult resultHttp)
151             throws OnapCommandException {
152         Map<String, List<String>> resultsProcessed = new HashMap<>();
153
154         for (Entry<String, String> entry : resultMap.entrySet()) {
155             String key = entry.getKey();
156             try {
157                 resultsProcessed.put(key, OnapCommandHttpUtils.replaceLineFromOutputResults(resultMap.get(key), resultHttp));
158             } catch(OnapCommandResultEmpty e) {  // NOSONAR
159                 // pass
160             }
161         }
162
163         return resultsProcessed;
164     }
165
166     public static List<String> replaceLineFromOutputResults(String line, HttpResult resultHttp)
167             throws OnapCommandHttpHeaderNotFound, OnapCommandHttpInvalidResponseBody,
168             OnapCommandResultMapProcessingFailed, OnapCommandResultEmpty {
169         StringBuilder headerProcessedLine = new StringBuilder();
170
171         ArrayList<String> result = new ArrayList<>();
172         if (!line.contains("$b{") && !line.contains("$h{")) {
173             result.add(line);
174             return result;
175         }
176
177         /**
178          * In case of empty response body [] or {}
179          **/
180         if (resultHttp.getBody() != null && resultHttp.getBody().length() <= 2) {
181             return result;
182         }
183
184         /**
185          * Process headers macros : line: $h{abc}-$b{$.[*].xyz} , After processing line will be [abc's
186          * value]-$b{$.[*].xyz}
187          **/
188         int currentIdx = 0;
189         while (currentIdx < line.length()) {
190             int idxS = line.indexOf("$h{", currentIdx);
191             if (idxS == -1) {
192                 headerProcessedLine.append(line.substring(currentIdx));
193                 break;
194             }
195             int idxE = line.indexOf('}', idxS);
196             String headerName = line.substring(idxS + 3, idxE);
197             headerName = headerName.trim();
198             if (!resultHttp.getRespHeaders().containsKey(headerName)) {
199                 throw new OnapCommandHttpHeaderNotFound(headerName);
200             }
201             String value = resultHttp.getRespHeaders().get(headerName);
202
203             headerProcessedLine.append(line.substring(currentIdx, idxS) + value);
204             currentIdx = idxE + 1;
205         }
206
207         // Process body jsonpath macros
208         List<Object> values = new ArrayList<>();
209         StringBuilder bodyProcessedPattern = new StringBuilder();
210         currentIdx = 0;
211         int maxRows = 1; // in normal case, only one row will be there
212         while (currentIdx < headerProcessedLine.length()) {
213             int idxS = headerProcessedLine.indexOf("$b{", currentIdx);
214             if (idxS == -1) {
215                 bodyProcessedPattern.append(headerProcessedLine.substring(currentIdx));
216                 break;
217             }
218             int idxE = headerProcessedLine.indexOf("}", idxS);
219             String jsonPath = headerProcessedLine.substring(idxS + 3, idxE);
220             jsonPath = jsonPath.trim();
221             Object value = new Object();
222             try {
223                 // JSONArray or String
224                 value = JsonPath.read(resultHttp.getBody(), jsonPath);
225             } catch (PathNotFoundException e1) { // NOSONAR
226                 //set to blank for those entries which are missing from the output json
227                 value = "";
228             } catch (Exception e) {
229                 throw new OnapCommandHttpInvalidResponseBody(jsonPath, e);
230             }
231
232             if (value instanceof JSONArray) {
233                 JSONArray arr = (JSONArray) value;
234                 if (arr.size() > maxRows) {
235                     maxRows = arr.size();
236                 }
237             }
238             bodyProcessedPattern.append(headerProcessedLine.substring(currentIdx, idxS) + "%s");
239             values.add(value);
240             currentIdx = idxE + 1;
241         }
242
243         if (bodyProcessedPattern.toString().isEmpty()) {
244             result.add(headerProcessedLine.toString());
245             return result;
246         } else {
247             for (int i = 0; i < maxRows; i++) {
248                 currentIdx = 0;
249                 StringBuilder bodyProcessedLine = new StringBuilder();
250                 int positionalIdx = 0; // %s positional idx
251                 while (currentIdx < bodyProcessedPattern.length()) {
252                     int idxS = bodyProcessedPattern.indexOf("%s", currentIdx);
253                     if (idxS == -1) {
254                         bodyProcessedLine.append(bodyProcessedPattern.substring(currentIdx));
255                         break;
256                     }
257                     int idxE = idxS + 2; // %s
258                     try {
259                         Object value = values.get(positionalIdx);
260                         String valueS = String.valueOf(value);
261                         if (value instanceof JSONArray) {
262                             JSONArray arr = (JSONArray) value;
263                             if (!arr.isEmpty()) {
264                                 valueS = arr.get(i).toString();
265                             } else {
266                                 throw new OnapCommandResultEmpty();
267                             }
268                         }
269
270                         bodyProcessedLine.append(bodyProcessedPattern.substring(currentIdx, idxS) + valueS);
271                         currentIdx = idxE;
272                         positionalIdx++;
273                     } catch (OnapCommandResultEmpty e) {
274                         throw e;
275                     } catch (Exception e) {
276                         throw new OnapCommandResultMapProcessingFailed(line, e);
277                     }
278                 }
279                 result.add(bodyProcessedLine.toString());
280             }
281
282             return result;
283         }
284     }
285
286     public static void normalizeJson(JsonElement node) {
287         Iterator<Entry<String, JsonElement>> it = node.getAsJsonObject().entrySet().iterator();
288
289         while (it.hasNext()) {
290             JsonElement child = it.next().getValue();
291             if (child.isJsonPrimitive() && child.getAsJsonPrimitive().isString() && child.getAsJsonPrimitive().getAsString().equals(""))
292                 it.remove();
293             else  if (child.isJsonNull())
294                 it.remove();
295             else if (child.isJsonObject())
296                 normalizeJson(child);
297             else if (child.isJsonArray()) {
298                 for (JsonElement ele:child.getAsJsonArray()) {
299                     if (ele.isJsonObject())
300                         normalizeJson(ele);
301                 }
302             }
303         }
304     }
305
306     public static String normalizeJson(String json) throws OnapCommandHttpInvalidRequestBody {
307         JsonElement node;
308         try {
309             node = JsonParser.parseString(json);
310             normalizeJson(node);
311             return gson.toJson(node);
312         } catch (Exception e) {  //NOSONAR
313             throw new OnapCommandHttpInvalidRequestBody(e);
314         }
315
316     }
317 }
318