2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. 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
11 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
20 package org.openecomp.mso.adapters.sdnc.sdncrest;
22 import org.openecomp.mso.adapters.sdnc.impl.Constants;
23 import org.openecomp.mso.adapters.sdncrest.SDNCErrorCommon;
24 import org.openecomp.mso.adapters.sdncrest.SDNCResponseCommon;
25 import org.openecomp.mso.logger.MessageEnum;
26 import org.openecomp.mso.logger.MsoAlarmLogger;
27 import org.openecomp.mso.logger.MsoLogger;
28 import org.apache.http.HttpResponse;
29 import org.apache.http.client.HttpClient;
30 import org.apache.http.client.config.RequestConfig;
31 import org.apache.http.client.methods.*;
32 import org.apache.http.conn.ConnectTimeoutException;
33 import org.apache.http.entity.ContentType;
34 import org.apache.http.entity.StringEntity;
35 import org.apache.http.impl.client.HttpClientBuilder;
36 import org.apache.http.util.EntityUtils;
37 import org.w3c.dom.Document;
38 import org.w3c.dom.Element;
39 import org.w3c.dom.NodeList;
40 import org.xml.sax.InputSource;
42 import javax.xml.XMLConstants;
43 import javax.xml.bind.DatatypeConverter;
44 import javax.xml.parsers.DocumentBuilderFactory;
45 import javax.xml.xpath.XPath;
46 import javax.xml.xpath.XPathConstants;
47 import javax.xml.xpath.XPathExpressionException;
48 import javax.xml.xpath.XPathFactory;
49 import java.io.StringReader;
50 import java.net.HttpURLConnection;
51 import java.net.SocketTimeoutException;
54 * Sends requests to SDNC and processes the responses.
56 public abstract class SDNCConnector {
57 private static final MsoLogger LOGGER = MsoLogger.getMsoLogger(MsoLogger.Catalog.RA);
58 private static final MsoAlarmLogger ALARMLOGGER = new MsoAlarmLogger();
60 public SDNCResponseCommon send(String content, TypedRequestTunables rt) {
61 LOGGER.info(MessageEnum.RA_SEND_REQUEST_SDNC, rt.toString(), "SDNC", "");
62 LOGGER.debug("SDNC Request Body:\n" + content);
64 HttpRequestBase method = null;
65 HttpResponse httpResponse = null;
68 int timeout = Integer.parseInt(rt.getTimeout());
70 RequestConfig requestConfig = RequestConfig.custom()
71 .setSocketTimeout(timeout)
72 .setConnectTimeout(timeout)
73 .setConnectionRequestTimeout(timeout)
76 HttpClient client = HttpClientBuilder.create().build();
78 if ("POST".equals(rt.getReqMethod())) {
79 HttpPost httpPost = new HttpPost(rt.getSdncUrl());
80 httpPost.setConfig(requestConfig);
81 httpPost.setEntity(new StringEntity(content, ContentType.APPLICATION_XML));
83 } else if ("PUT".equals(rt.getReqMethod())) {
84 HttpPut httpPut = new HttpPut(rt.getSdncUrl());
85 httpPut.setConfig(requestConfig);
86 httpPut.setEntity(new StringEntity(content, ContentType.APPLICATION_XML));
88 } else if ("GET".equals(rt.getReqMethod())) {
89 HttpGet httpGet = new HttpGet(rt.getSdncUrl());
90 httpGet.setConfig(requestConfig);
92 } else if ("DELETE".equals(rt.getReqMethod())) {
93 HttpDelete httpDelete = new HttpDelete(rt.getSdncUrl());
94 httpDelete.setConfig(requestConfig);
98 // AAF Integration, disabled for now due to the constrains from other party
99 // String userCredentials = CredentialConstants.getSecurityProperties().getEncryptedProperty(CredentialConstants.DEFAULT_AUTH, "", CredentialConstants.getEncryptionKey());
100 // if (userCredentials == null) {
101 // userCredentials = "";
103 String userCredentials = SDNCAdapterProperties.getEncryptedProperty(Constants.SDNC_AUTH_PROP,
104 Constants.DEFAULT_SDNC_AUTH, Constants.ENCRYPTION_KEY);
105 String authorization = "Basic " + DatatypeConverter.printBase64Binary(userCredentials.getBytes());
106 method.setHeader("Authorization", authorization);
108 method.setHeader("Accept", "application/yang.data+xml");
110 httpResponse = client.execute(method);
112 String responseContent = null;
113 if (httpResponse.getEntity() != null) {
114 responseContent = EntityUtils.toString(httpResponse.getEntity(), "UTF-8");
117 int statusCode = httpResponse.getStatusLine().getStatusCode();
118 String statusMessage = httpResponse.getStatusLine().getReasonPhrase();
120 LOGGER.debug("SDNC Response: " + statusCode + " " + statusMessage
121 + (responseContent == null ? "" : System.lineSeparator() + responseContent));
123 if (httpResponse.getStatusLine().getStatusCode() >= 300) {
124 String errMsg = "SDNC returned " + statusCode + " " + statusMessage;
126 String errors = analyzeErrors(responseContent);
127 if (errors != null) {
128 errMsg += " " + errors;
132 ALARMLOGGER.sendAlarm("MsoInternalError", MsoAlarmLogger.CRITICAL, errMsg);
133 return createErrorResponse(statusCode, errMsg, rt);
141 LOGGER.info(MessageEnum.RA_RESPONSE_FROM_SDNC, responseContent, "SDNC", "");
142 return createResponseFromContent(statusCode, statusMessage, responseContent, rt);
144 } catch (SocketTimeoutException e) {
145 String errMsg = "Request to SDNC timed out";
147 return createErrorResponse(HttpURLConnection.HTTP_CLIENT_TIMEOUT, errMsg, rt);
149 } catch (ConnectTimeoutException e) {
150 String errMsg = "Request to SDNC timed out";
152 return createErrorResponse(HttpURLConnection.HTTP_CLIENT_TIMEOUT, errMsg, rt);
154 } catch (Exception e) {
155 String errMsg = "Error processing request to SDNC";
157 return createErrorResponse(HttpURLConnection.HTTP_INTERNAL_ERROR, errMsg, rt);
160 if (httpResponse != null) {
162 EntityUtils.consume(httpResponse.getEntity());
163 } catch (Exception e) {
168 if (method != null) {
171 } catch (Exception e) {
178 protected void logError(String errMsg) {
179 LOGGER.error(MessageEnum.RA_EXCEPTION_COMMUNICATE_SDNC, "SDNC", "",
180 MsoLogger.ErrorCode.AvailabilityError, errMsg);
181 ALARMLOGGER.sendAlarm("MsoInternalError", MsoAlarmLogger.CRITICAL, errMsg);
184 protected void logError(String errMsg, Throwable t) {
185 LOGGER.error(MessageEnum.RA_EXCEPTION_COMMUNICATE_SDNC, "SDNC", "",
186 MsoLogger.ErrorCode.AvailabilityError, errMsg, t);
187 ALARMLOGGER.sendAlarm("MsoInternalError", MsoAlarmLogger.CRITICAL, errMsg);
191 * Generates a response object from content received from SDNC. The response
192 * object may be a success response object or an error response object. This
193 * method must be overridden by the subclass to return the correct object type.
194 * @param statusCode the response status code from SDNC (e.g. 200)
195 * @param statusMessage the response status message from SDNC (e.g. "OK")
196 * @param responseContent the body of the response from SDNC (possibly null)
197 * @param rt request tunables
198 * @return a response object
200 protected abstract SDNCResponseCommon createResponseFromContent(int statusCode,
201 String statusMessage, String responseContent, TypedRequestTunables rt);
204 * Generates an error response object. This method must be overridden by the
205 * subclass to return the correct object type.
206 * @param statusCode the response status code (from SDNC, or internally generated)
207 * @param errMsg the error message (normally a verbose explanation of the error)
208 * @param rt request tunables
209 * @return an error response object
211 protected abstract SDNCErrorCommon createErrorResponse(int statusCode,
212 String errMsg, TypedRequestTunables rt);
215 * Called by the send() method to analyze errors that may be encoded in the
216 * content of non-2XX responses. By default, this method tries to parse the
217 * content as a restconf error.
219 * xmlns="urn:ietf:params:xml:ns:yang:ietf-restconf"
221 * If an error (or errors) can be obtained from the content, then the result
222 * is a string in this format:
224 * [error-type:TYPE, error-tag:TAG, error-message:MESSAGE] ...
226 * If no error could be obtained from the content, then the result is null.
228 * The subclass can override this method to provide another implementation.
230 protected String analyzeErrors(String content) {
231 if (content == null || content.isEmpty()) {
235 // Confirmed with Andrew Shen on 11/1/16 that SDNC will send content like
236 // this in error responses (non-2XX response codes) to "agnostic" service
239 // <errors xmlns="urn:ietf:params:xml:ns:yang:ietf-restconf">
241 // <error-type>protocol</error-type>
242 // <error-tag>malformed-message</error-tag>
243 // <error-message>Error parsing input: The element type "input" must be terminated by the matching end-tag "</input>".</error-message>
247 String output = null;
250 XPathFactory xpathFactory = XPathFactory.newInstance();
251 XPath xpath = xpathFactory.newXPath();
252 DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
253 documentBuilderFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
254 InputSource source = new InputSource(new StringReader(content));
255 Document doc = documentBuilderFactory.newDocumentBuilder().parse(source);
256 NodeList errors = (NodeList) xpath.evaluate("errors/error", doc, XPathConstants.NODESET);
258 for (int i = 0; i < errors.getLength(); i++)
260 Element error = (Element) errors.item(i);
265 String errorType = xpath.evaluate("error-type", error);
266 info += "error-type:" + errorType;
267 } catch (XPathExpressionException e) {
268 LOGGER.error(MessageEnum.RA_EVALUATE_XPATH_ERROR, "error-type", error.toString(), "SDNC", "",
269 MsoLogger.ErrorCode.DataError, "XPath Exception", e);
273 String errorTag = xpath.evaluate( "error-tag", error);
274 if (!info.isEmpty()) {
277 info += "error-tag:" + errorTag;
278 } catch (XPathExpressionException e) {
279 LOGGER.error(MessageEnum.RA_EVALUATE_XPATH_ERROR, "error-tag", error.toString(), "SDNC", "",
280 MsoLogger.ErrorCode.DataError, "XPath Exception", e);
284 String errorMessage = xpath.evaluate("error-message", error);
285 if (!info.isEmpty()) {
288 info += "error-message:" + errorMessage;
289 } catch (Exception e) {
290 LOGGER.error(MessageEnum.RA_EVALUATE_XPATH_ERROR, "error-message", error.toString(), "SDNC", "",
291 MsoLogger.ErrorCode.DataError, "XPath Exception", e);
294 if (!info.isEmpty()) {
295 if (output == null) {
296 output = "[" + info + "]";
298 output += " [" + info + "]";
302 } catch (Exception e) {
303 LOGGER.error (MessageEnum.RA_ANALYZE_ERROR_EXC, "SDNC", "",
304 MsoLogger.ErrorCode.DataError, "Exception while analyzing errors", e);