2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * Copyright (C) 2017 Huawei Technologies Co., Ltd. All rights reserved.
7 * ================================================================================
8 * Modifications Copyright (C) 2018 IBM.
9 * Modifications Copyright (c) 2019 Samsung
10 * ================================================================================
11 * Licensed under the Apache License, Version 2.0 (the "License");
12 * you may not use this file except in compliance with the License.
13 * You may obtain a copy of the License at
15 * http://www.apache.org/licenses/LICENSE-2.0
17 * Unless required by applicable law or agreed to in writing, software
18 * distributed under the License is distributed on an "AS IS" BASIS,
19 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 * See the License for the specific language governing permissions and
21 * limitations under the License.
22 * ============LICENSE_END=========================================================
25 package org.onap.so.adapters.sdnc.sdncrest;
27 import java.io.IOException;
28 import java.io.StringReader;
29 import java.net.HttpURLConnection;
30 import java.text.ParseException;
31 import java.util.ArrayList;
32 import java.util.List;
34 import javax.xml.XMLConstants;
35 import javax.xml.parsers.DocumentBuilderFactory;
36 import javax.xml.parsers.ParserConfigurationException;
38 import org.onap.so.adapters.sdncrest.SDNCErrorCommon;
39 import org.onap.so.adapters.sdncrest.SDNCResponseCommon;
40 import org.onap.so.adapters.sdncrest.SDNCServiceError;
41 import org.onap.so.adapters.sdncrest.SDNCServiceResponse;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
44 import org.springframework.stereotype.Component;
45 import org.w3c.dom.Document;
46 import org.w3c.dom.Element;
47 import org.xml.sax.InputSource;
48 import org.xml.sax.SAXException;
51 * SDNCConnector for "agnostic" API services.
55 public class SDNCServiceRequestConnector extends SDNCConnector {
57 private static final Logger logger = LoggerFactory.getLogger(SDNCServiceRequestConnector.class);
59 protected SDNCResponseCommon createResponseFromContent(int statusCode, String statusMessage,
60 String responseContent, TypedRequestTunables rt) {
62 return parseResponseContent(responseContent);
63 } catch (ParseException e) {
64 logger.error("Error occured:", e);
65 return createErrorResponse(HttpURLConnection.HTTP_INTERNAL_ERROR, e.getMessage(), rt);
66 }catch (Exception e) {
67 logger.error("Error occured:", e);
68 return createErrorResponse(HttpURLConnection.HTTP_INTERNAL_ERROR, e.getMessage(), rt);
73 protected SDNCErrorCommon createErrorResponse(int statusCode, String errMsg,
74 TypedRequestTunables rt) {
75 return new SDNCServiceError(rt.getReqId(), String.valueOf(statusCode), errMsg, "Y");
79 * Parses SDNC synchronous service response content or service notification content.
80 * If the content can be parsed and contains all required elements, then an object
81 * is returned. The type of the returned object depends on the response code
82 * contained in the content. For 2XX response codes, an SDNCServiceResponse is
83 * returned. Otherwise, an SDNCServiceError is returned. If the content cannot
84 * be parsed, or if the content does not contain all required elements, a parse
85 * exception is thrown. This method performs no logging or alarming.
86 * @throws ParseException on error
88 public static SDNCResponseCommon parseResponseContent(String responseContent)
89 throws ParseException,ParserConfigurationException, SAXException, IOException{
91 // Note: this document builder is not namespace-aware, so namespaces are ignored.
92 DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
93 documentBuilderFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
94 documentBuilderFactory.setFeature("http://xml.org/sax/features/external-general-entities", false);
95 documentBuilderFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
96 InputSource source = new InputSource(new StringReader(responseContent));
97 Document doc = documentBuilderFactory.newDocumentBuilder().parse(source);
99 // Find the configuration-response-common child under the root element.
100 // The root element is expected to be an "output" element, but we don't really care.
102 Element root = doc.getDocumentElement();
103 Element configurationResponseCommon = null;
105 for (Element child : SDNCAdapterUtils.childElements(root)) {
106 if ("configuration-response-common".equals(child.getNodeName())) {
107 configurationResponseCommon = child;
112 if (configurationResponseCommon == null) {
113 throw new ParseException("No configuration-response-common element in SDNC response", 0);
116 // Process the children of configuration-response-common.
118 String responseCode = null;
119 String responseMessage = null;
120 String svcRequestId = null;
121 String ackFinalIndicator = null;
122 List<Element> responseParameters = new ArrayList<>();
124 for (Element child : SDNCAdapterUtils.childElements(configurationResponseCommon)) {
125 if ("response-code".equals(child.getNodeName())) {
126 responseCode = child.getTextContent();
127 } else if ("response-message".equals(child.getNodeName())) {
128 responseMessage = child.getTextContent();
129 } else if ("svc-request-id".equals(child.getNodeName())) {
130 svcRequestId = child.getTextContent();
131 } else if ("ack-final-indicator".equals(child.getNodeName())) {
132 ackFinalIndicator = child.getTextContent();
133 } else if ("response-parameters".equals(child.getNodeName())) {
134 responseParameters.add(child);
138 // svc-request-id is mandatory.
140 if (svcRequestId == null || svcRequestId.isEmpty()) {
141 throw new ParseException("No svc-request-id in SDNC response", 0);
144 // response-code is mandatory.
146 if (responseCode == null || responseCode.isEmpty()) {
147 throw new ParseException("No response-code in SDNC response", 0);
150 // ack-final-indicator is optional: default to "Y".
152 if (ackFinalIndicator == null || ackFinalIndicator.trim().isEmpty()) {
153 ackFinalIndicator = "Y";
156 if (!"Y".equals(ackFinalIndicator) && !"N".equals(ackFinalIndicator)) {
157 throw new ParseException("Invalid ack-final-indicator in SDNC response: '" + ackFinalIndicator + "'", 0);
160 // response-message is optional. If the value is empty, omit it from the response object.
162 if (responseMessage != null && responseMessage.isEmpty()) {
163 responseMessage = null;
166 // If the response code in the message from SDNC was not 2XX, return SDNCServiceError.
168 if (!responseCode.matches("2[0-9][0-9]") && !("0").equals(responseCode)) {
169 // Not a 2XX response. Return SDNCServiceError.
170 return new SDNCServiceError(svcRequestId, responseCode, responseMessage, ackFinalIndicator);
173 // Create a success response object.
175 SDNCServiceResponse response = new SDNCServiceResponse(svcRequestId,
176 responseCode, responseMessage, ackFinalIndicator);
178 // Process any response-parameters that might be present.
180 for (Element element : responseParameters) {
181 String tagName = null;
182 String tagValue = null;
184 for (Element child : SDNCAdapterUtils.childElements(element)) {
185 if ("tag-name".equals(child.getNodeName())) {
186 tagName = child.getTextContent();
187 } else if ("tag-value".equals(child.getNodeName())) {
188 tagValue = child.getTextContent();
192 // tag-name is mandatory
194 if (tagName == null) {
195 throw new ParseException("Missing tag-name in SDNC response parameter", 0);
198 // tag-value is optional. If absent, make it an empty string so we don't
199 // end up with null values in the parameter map.
201 if (tagValue == null) {
205 response.addParam(tagName, tagValue);