2  * ============LICENSE_START=======================================================
 
   4  * ================================================================================
 
   5  * Copyright (C) 2018 Huawei Technologies Co., Ltd. All rights reserved.
 
   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
 
  13  *      http://www.apache.org/licenses/LICENSE-2.0
 
  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=========================================================
 
  23 package org.onap.ccsdk.sli.plugins.restconfapicall;
 
  26 import java.io.IOException;
 
  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;
 
  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;
 
  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;
 
  54  * Utilities for restconf api call node.
 
  56 public final class RestconfApiUtils {
 
  58     static final String RES_CODE = "response-code";
 
  60     static final String HTTP_REQ ="httpRequest";
 
  62     static final String RES_PRE = "responsePrefix";
 
  64     static final String RES_MSG = "response-message";
 
  66     static final String HEADER = "header.";
 
  68     static final String COMMA = ",";
 
  70     static final String COLON = ":";
 
  72     static final String HTTP_RES = "httpResponse";
 
  74     static final String REST_API_URL = "restapiUrl";
 
  76     static final String UPDATED_URL = "URL was set to";
 
  78     static final String COMM_FAIL = "Failed to communicate with host %s." +
 
  79             "Request will be re-attempted using the host %s.";
 
  81     static final String RETRY_COUNT = "This is retry attempt %d out of %d";
 
  83     static final String RETRY_FAIL = "Retry attempt has failed. No further " +
 
  84             "retry shall be attempted, calling setFailureResponseStatus";
 
  86     static final String NO_MORE_RETRY = "Could not attempt retry";
 
  88     static final String MAX_RETRY_ERR = "Maximum retries reached, calling " +
 
  89             "setFailureResponseStatus";
 
  91     static final String ATTEMPTS_MSG = "%d attempts were made out of %d " +
 
  94     static final String REQ_ERR = "Error sending the request: ";
 
  96     private static final String SLASH = "/";
 
  98     private static final String DIR_PATH = "dirPath";
 
 100     private static final String URL_SYNTAX = "The following URL cannot be " +
 
 101             "parsed into URI : ";
 
 103     private static final String YANG = ".yang";
 
 105     private static final String YANG_FILE_ERR = "Unable to parse the YANG " +
 
 109     private RestconfApiUtils() {
 
 113      * Returns the YANG parameters after parsing it from the map.
 
 115      * @param paramMap parameters map
 
 116      * @return YANG parameters
 
 117      * @throws SvcLogicException when parsing of parameters map fail
 
 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);
 
 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.
 
 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
 
 137     public static String parseUrl(String url, HttpMethod method)
 
 138             throws SvcLogicException {
 
 142         } catch (URISyntaxException e) {
 
 143             throw new SvcLogicException(URL_SYNTAX + url, e);
 
 146         String path = uri.getPath();
 
 147         path = getParsedPath(path);
 
 152      * Returns the path which contains only the schema nodes.
 
 155      * @return path representing schema
 
 157     private static String getParsedPath(String path) {
 
 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);
 
 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);
 
 173                 String actual = p[3] + COLON + p[4];
 
 175                     secondHalf = path.substring(
 
 176                            p[1].length() + p[2].length() + actual.length() + 3);
 
 177                     path = actual + secondHalf;
 
 187      * Returns the schema context of the YANG files present in a directory.
 
 189      * @param di directory path
 
 190      * @return YANG schema context
 
 191      * @throws SvcLogicException when YANG file reading fails
 
 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) {
 
 203                 sources.add(create(forFile(file)));
 
 204             } catch (IOException | YangSyntaxErrorException e) {
 
 205                 throw new SvcLogicException(YANG_FILE_ERR + e.getMessage(), e);
 
 209         final CrossSourceStatementReactor.BuildAction reactor = defaultReactor()
 
 210                 .newBuild(DEFAULT_MODE).addSources(sources);
 
 212             return reactor.buildEffective();
 
 213         } catch (ReactorException e) {
 
 214             throw new SvcLogicException(YANG_FILE_ERR + e.getMessage(), e);
 
 219      * Returns all the YANG files present in a directory recursively.
 
 221      * @param dir       path of the directory
 
 222      * @param yangFiles list of YANG files
 
 224     private static void getYangFiles(File dir, List<File> yangFiles) {
 
 226             File[] files = dir.listFiles();
 
 228                 processFiles(files, yangFiles);
 
 234      * Processes all the obtained files by isolating all the YANG files from
 
 235      * all the directory of the given path recursively.
 
 237      * @param files     files in the given path
 
 238      * @param yangFiles YANG files list
 
 240     private static void processFiles(File[] files, List<File> yangFiles) {
 
 241         for (File file : files) {
 
 242             if (file.isFile() && file.getName().endsWith(YANG)) {
 
 244             } else if (file.isDirectory()) {
 
 245                 getYangFiles(file, yangFiles);
 
 251      * Returns the updated XML request message by adding root node to it.
 
 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
 
 258     static String getUpdatedXmlReq(String req, String nodeName, String modNs) {
 
 259         String rootNode = "\n<" + nodeName + " xmlns=\"" + modNs +
 
 261         req = req.replaceFirst("\n", rootNode);
 
 262         req = req + "</" + nodeName + ">";
 
 263         return req.replaceAll(">\\s+<", "><");