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