134868c151b5996a1c134092984ce01fdac41705
[ccsdk/sli.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP - CCSDK
4  * ================================================================================
5  * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved.
6  *
7  * Modifications Copyright © 2018 IBM.
8  * Modifications Copyright (c) 2021 AT&T
9  * ================================================================================
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  *      http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  * ============LICENSE_END=========================================================
22  */
23
24 package org.onap.ccsdk.sli.plugins.restconfapicall;
25
26 import static org.onap.ccsdk.sli.plugins.restapicall.RestapiCallNode.getParameters;
27 import static org.onap.ccsdk.sli.plugins.restapicall.RestapiCallNode.parseParam;
28 import static org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource.forFile;
29 import java.io.File;
30 import java.io.IOException;
31 import java.net.URI;
32 import java.net.URISyntaxException;
33 import java.nio.file.Path;
34 import java.nio.file.Paths;
35 import java.util.LinkedList;
36 import java.util.List;
37 import java.util.Map;
38 import org.onap.ccsdk.sli.core.sli.SvcLogicException;
39 import org.onap.ccsdk.sli.plugins.restapicall.HttpMethod;
40 import org.onap.ccsdk.sli.plugins.yangserializers.dfserializer.YangParameters;
41 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
42 import org.opendaylight.yangtools.yang.model.parser.api.YangParser;
43 import org.opendaylight.yangtools.yang.model.parser.api.YangParserException;
44 import org.opendaylight.yangtools.yang.model.parser.api.YangParserFactory;
45 import org.opendaylight.yangtools.yang.model.parser.api.YangSyntaxErrorException;
46
47 /**
48  * Utilities for restconf api call node.
49  */
50 public final class RestconfApiUtils {
51
52     static final String RES_CODE = "response-code";
53
54     static final String HTTP_REQ ="httpRequest";
55
56     static final String RES_PRE = "responsePrefix";
57
58     static final String RES_MSG = "response-message";
59
60     static final String HEADER = "header.";
61
62     static final String COMMA = ",";
63
64     static final String COLON = ":";
65
66     static final String HTTP_RES = "httpResponse";
67
68     static final String REST_API_URL = "restapiUrl";
69
70     static final String UPDATED_URL = "URL was set to";
71
72     static final String COMM_FAIL = "Failed to communicate with host %s." +
73             "Request will be re-attempted using the host %s.";
74
75     static final String RETRY_COUNT = "This is retry attempt %d out of %d";
76
77     static final String RETRY_FAIL = "Retry attempt has failed. No further " +
78             "retry shall be attempted, calling setFailureResponseStatus";
79
80     static final String NO_MORE_RETRY = "Could not attempt retry";
81
82     static final String MAX_RETRY_ERR = "Maximum retries reached, calling " +
83             "setFailureResponseStatus";
84
85     static final String ATTEMPTS_MSG = "%d attempts were made out of %d " +
86             "maximum retries";
87
88     static final String REQ_ERR = "Error sending the request: ";
89
90     private static final String SLASH = "/";
91
92     private static final String DIR_PATH = "dirPath";
93
94     private static final String URL_SYNTAX = "The following URL cannot be " +
95             "parsed into URI : ";
96
97     private static final String YANG = ".yang";
98
99     private static final String YANG_FILE_ERR = "Unable to parse the YANG " +
100             "file provided";
101
102     //No instantiation.
103     private RestconfApiUtils() {
104     }
105
106     /**
107      * Returns the YANG parameters after parsing it from the map.
108      *
109      * @param paramMap parameters map
110      * @return YANG parameters
111      * @throws SvcLogicException when parsing of parameters map fail
112      */
113     static YangParameters getYangParameters(Map<String, String> paramMap)
114             throws SvcLogicException {
115         YangParameters param = (YangParameters) getParameters(
116                 paramMap, new YangParameters());
117         param.dirPath = parseParam(paramMap, DIR_PATH, false, null);
118         return param;
119     }
120
121     /**
122      * Parses the restconf URL and gives the YANG path from it, which can be
123      * used to get schema node. If it is a PUT operation, then a node must be
124      * reduced from the url to make it always point to the parent.
125      *
126      * @param url    restconf URL
127      * @param method HTTP operation
128      * @return YANG path pointing to parent
129      * @throws SvcLogicException when parsing the URL fails
130      */
131     public static String parseUrl(String url, HttpMethod method)
132             throws SvcLogicException {
133         URI uri;
134         try {
135             uri = new URI(url);
136         } catch (URISyntaxException e) {
137             throw new SvcLogicException(URL_SYNTAX + url, e);
138         }
139
140         String path = uri.getPath();
141         path = getParsedPath(path);
142         return path;
143     }
144
145     /**
146      * Returns the path which contains only the schema nodes.
147      *
148      * @param path path
149      * @return path representing schema
150      */
151     private static String getParsedPath(String path) {
152         String firstHalf;
153         String secondHalf;
154         if (path.contains(COLON)) {
155             String[] p = path.split(COLON);
156             if (p[0].contains(SLASH)) {
157                 int slash = p[0].lastIndexOf(SLASH);
158                 firstHalf = p[0].substring(slash + 1);
159             } else {
160                 firstHalf = p[0];
161             }
162             secondHalf = path.substring(p[0].length() + 1);
163             return firstHalf + COLON + secondHalf;
164         } else if (path.contains(SLASH)) {
165             String[] p = path.split(SLASH);
166             if (p.length > 4) {
167                 String actual = p[3] + COLON + p[4];
168                 if (p.length > 5) {
169                     secondHalf = path.substring(
170                            p[1].length() + p[2].length() + actual.length() + 3);
171                     path = actual + secondHalf;
172                 } else {
173                     path = actual;
174                 }
175             }
176         }
177         return path;
178     }
179
180     /**
181      * Returns the schema context of the YANG files present in a directory.
182      *
183      * @param di directory path
184      * @return YANG schema context
185      * @throws SvcLogicException when YANG file reading fails
186      */
187     static EffectiveModelContext getSchemaCtxFromDir(YangParserFactory parserFactory, String di)
188             throws SvcLogicException {
189         Path d = Paths.get(di);
190         File dir = d.toFile();
191         List<File> yangFiles = new LinkedList<>();
192         getYangFiles(dir, yangFiles);
193         YangParser parser = parserFactory.createParser();
194         for (File file : yangFiles) {
195             try {
196                 parser.addSource(forFile(file));
197             } catch (IOException | YangSyntaxErrorException e) {
198                 throw new SvcLogicException(YANG_FILE_ERR + e.getMessage(), e);
199             }
200         }
201
202         try {
203             return parser.buildEffectiveModel();
204         } catch (YangParserException e) {
205             throw new SvcLogicException(YANG_FILE_ERR + e.getMessage(), e);
206         }
207     }
208
209     /**
210      * Returns all the YANG files present in a directory recursively.
211      *
212      * @param dir       path of the directory
213      * @param yangFiles list of YANG files
214      */
215     private static void getYangFiles(File dir, List<File> yangFiles) {
216         if (dir.exists()) {
217             File[] files = dir.listFiles();
218             if (files != null) {
219                 processFiles(files, yangFiles);
220             }
221         }
222     }
223
224     /**
225      * Processes all the obtained files by isolating all the YANG files from
226      * all the directory of the given path recursively.
227      *
228      * @param files     files in the given path
229      * @param yangFiles YANG files list
230      */
231     private static void processFiles(File[] files, List<File> yangFiles) {
232         for (File file : files) {
233             if (file.isFile() && file.getName().endsWith(YANG)) {
234                 yangFiles.add(file);
235             } else if (file.isDirectory()) {
236                 getYangFiles(file, yangFiles);
237             }
238         }
239     }
240
241     /**
242      * Returns the updated XML request message by adding root node to it.
243      *
244      * @param req      XML request
245      * @param nodeName root node name
246      * @param modNs    module namespace of the root node
247      * @return updated XML request message
248      */
249     static String getUpdatedXmlReq(String req, String nodeName, String modNs) {
250         String rootNode = "\n<" + nodeName + " xmlns=\"" + modNs +
251                 "\">\n";
252         req = req.replaceFirst("\n", rootNode);
253         req = req + "</" + nodeName + ">";
254         return req.replaceAll(">\\s+<", "><");
255     }
256 }