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