2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Modifications Copyright (c) 2019 Samsung
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.so.adapters.vnf;
26 import java.security.GeneralSecurityException;
28 import java.util.TreeSet;
29 import javax.annotation.PostConstruct;
30 import javax.xml.bind.DatatypeConverter;
31 import org.apache.http.HttpEntity;
32 import org.apache.http.client.config.RequestConfig;
33 import org.apache.http.client.methods.CloseableHttpResponse;
34 import org.apache.http.client.methods.HttpPost;
35 import org.apache.http.entity.ContentType;
36 import org.apache.http.entity.StringEntity;
37 import org.apache.http.impl.client.CloseableHttpClient;
38 import org.apache.http.impl.client.HttpClients;
39 import org.apache.http.util.EntityUtils;
40 import org.onap.so.logger.ErrorCode;
41 import org.onap.so.logger.MessageEnum;
42 import org.onap.so.utils.CryptoUtils;
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
45 import org.springframework.beans.factory.annotation.Autowired;
46 import org.springframework.context.annotation.Scope;
47 import org.springframework.core.env.Environment;
48 import org.springframework.stereotype.Component;
51 * This is the class that is used to POST replies from the MSO adapters to the BPEL engine. It can be configured via
52 * property file, or modified using the member methods. The properties to use are: org.onap.so.adapters.vnf.bpelauth
53 * encrypted authorization string to send to BEPL engine org.onap.so.adapters.vnf.sockettimeout socket timeout value
54 * org.onap.so.adapters.vnf.connecttimeout connect timeout value org.onap.so.adapters.vnf.retrycount number of times to
55 * retry failed connections org.onap.so.adapters.vnf.retryinterval interval (in seconds) between retries
56 * org.onap.so.adapters.vnf.retrylist list of response codes that will trigger a retry (the special code 900 means
57 * "connection was not established")
61 public class BpelRestClient {
62 public static final String MSO_PROP_VNF_ADAPTER = "MSO_PROP_VNF_ADAPTER";
63 private static final String PROPERTY_DOMAIN = "org.onap.so.adapters.vnf";
64 private static final String BPEL_AUTH_PROPERTY = PROPERTY_DOMAIN + ".bpelauth";
65 private static final String SOCKET_TIMEOUT_PROPERTY = PROPERTY_DOMAIN + ".sockettimeout";
66 private static final String CONN_TIMEOUT_PROPERTY = PROPERTY_DOMAIN + ".connecttimeout";
67 private static final String RETRY_COUNT_PROPERTY = PROPERTY_DOMAIN + ".retrycount";
68 private static final String RETRY_INTERVAL_PROPERTY = PROPERTY_DOMAIN + ".retryinterval";
69 private static final String RETRY_LIST_PROPERTY = PROPERTY_DOMAIN + ".retrylist";
70 private static final String ENCRYPTION_KEY_PROP = "org.onap.so.adapters.network.encryptionKey";
71 private static final Logger logger = LoggerFactory.getLogger(BpelRestClient.class);
73 /** Default socket timeout (in seconds) */
74 public static final int DEFAULT_SOCKET_TIMEOUT = 5;
75 /** Default connect timeout (in seconds) */
76 public static final int DEFAULT_CONNECT_TIMEOUT = 5;
77 /** By default, retry up to five times */
78 public static final int DEFAULT_RETRY_COUNT = 5;
79 /** Default interval to wait between retries (in seconds), negative means use backoff algorithm */
80 public static final int DEFAULT_RETRY_INTERVAL = -15;
81 /** Default list of response codes to trigger a retry */
82 public static final String DEFAULT_RETRY_LIST = "408,429,500,502,503,504,900"; // 900 is "connection failed"
83 /** Default credentials */
84 public static final String DEFAULT_CREDENTIALS = "";
87 private Environment env;
88 // Properties of the BPEL client -- all are configurable
89 private int socketTimeout;
90 private int connectTimeout;
91 private int retryCount;
92 private int retryInterval;
93 private Set<Integer> retryList;
94 private String credentials;
96 // last response from BPEL engine
97 private int lastResponseCode;
98 private String lastResponse;
101 * Create a client to send results to the BPEL engine, using configuration from the MSO_PROP_VNF_ADAPTER properties.
103 public BpelRestClient() {
104 socketTimeout = DEFAULT_SOCKET_TIMEOUT;
105 connectTimeout = DEFAULT_CONNECT_TIMEOUT;
106 retryCount = DEFAULT_RETRY_COUNT;
107 retryInterval = DEFAULT_RETRY_INTERVAL;
108 setRetryList(DEFAULT_RETRY_LIST);
109 credentials = DEFAULT_CREDENTIALS;
110 lastResponseCode = 0;
116 protected void init() {
118 socketTimeout = env.getProperty(SOCKET_TIMEOUT_PROPERTY, Integer.class, DEFAULT_SOCKET_TIMEOUT);
119 connectTimeout = env.getProperty(CONN_TIMEOUT_PROPERTY, Integer.class, DEFAULT_CONNECT_TIMEOUT);
120 retryCount = env.getProperty(RETRY_COUNT_PROPERTY, Integer.class, DEFAULT_RETRY_COUNT);
121 retryInterval = env.getProperty(RETRY_INTERVAL_PROPERTY, Integer.class, DEFAULT_RETRY_INTERVAL);
122 setRetryList(env.getProperty(RETRY_LIST_PROPERTY, DEFAULT_RETRY_LIST));
123 credentials = getEncryptedProperty(BPEL_AUTH_PROPERTY, DEFAULT_CREDENTIALS, ENCRYPTION_KEY_PROP);
126 public int getSocketTimeout() {
127 return socketTimeout;
130 public void setSocketTimeout(int socketTimeout) {
131 this.socketTimeout = socketTimeout;
134 public int getConnectTimeout() {
135 return connectTimeout;
138 public void setConnectTimeout(int connectTimeout) {
139 this.connectTimeout = connectTimeout;
142 public int getRetryCount() {
146 public void setRetryCount(int retryCount) {
147 int newRetryCount = retryCount;
148 if (newRetryCount < 0)
149 newRetryCount = DEFAULT_RETRY_COUNT;
150 this.retryCount = newRetryCount;
153 public int getRetryInterval() {
154 return retryInterval;
157 public void setRetryInterval(int retryInterval) {
158 this.retryInterval = retryInterval;
161 public String getCredentials() {
165 public void setCredentials(String credentials) {
166 this.credentials = credentials;
169 public String getRetryList() {
170 if (retryList.isEmpty())
172 String t = retryList.toString();
173 return t.substring(1, t.length() - 1);
176 public void setRetryList(String retryList) {
177 Set<Integer> s = new TreeSet<>();
178 for (String t : retryList.split("[, ]")) {
180 s.add(Integer.parseInt(t));
181 } catch (NumberFormatException x) {
188 public int getLastResponseCode() {
189 return lastResponseCode;
192 public String getLastResponse() {
197 * Post a response to the URL of the BPEL engine. As long as the response code is one of those in the retryList, the
198 * post will be retried up to "retrycount" times with an interval (in seconds) of "retryInterval". If retryInterval
199 * is negative, then each successive retry interval will be double the previous one.
201 * @param toBpelStr the content (XML or JSON) to post
202 * @param bpelUrl the URL to post to
203 * @param isxml true if the content is XML, otherwise assumed to be JSON
204 * @return true if the post succeeded, false if all retries failed
206 public boolean bpelPost(final String toBpelStr, final String bpelUrl, final boolean isxml) {
207 debug("Sending response to BPEL: " + toBpelStr);
208 int totalretries = 0;
209 int retryint = retryInterval;
211 sendOne(toBpelStr, bpelUrl, isxml);
212 // Note: really should handle response code 415 by switching between content types if needed
213 if (!retryList.contains(lastResponseCode)) {
214 debug("Got response code: " + lastResponseCode + ": returning.");
217 if (totalretries >= retryCount) {
218 debug("Retried " + totalretries + " times, giving up.");
219 logger.error("{} {} Could not deliver response to BPEL after {} tries: {}",
220 MessageEnum.RA_SEND_VNF_NOTIF_ERR, ErrorCode.BusinessProcesssError.getValue(), totalretries,
225 int sleepinterval = retryint;
227 // if retry interval is negative double the retry on each pass
228 sleepinterval = -retryint;
231 debug("Sleeping for " + sleepinterval + " seconds.");
233 Thread.sleep(sleepinterval * 1000L);
234 } catch (InterruptedException e) {
235 logger.debug("Exception while Thread sleep", e);
236 Thread.currentThread().interrupt();
241 private void debug(String m) {
245 private void sendOne(final String toBpelStr, final String bpelUrl, final boolean isxml) {
246 logger.debug("Sending to BPEL server: {}", bpelUrl);
247 logger.debug("Content is: {}", toBpelStr);
250 HttpPost post = new HttpPost(bpelUrl);
251 if (credentials != null && !credentials.isEmpty())
252 post.addHeader("Authorization", "Basic " + DatatypeConverter.printBase64Binary(credentials.getBytes()));
254 logger.debug("HTTPPost Headers: {}", post.getAllHeaders());
257 ContentType ctype = isxml ? ContentType.APPLICATION_XML : ContentType.APPLICATION_JSON;
258 post.setEntity(new StringEntity(toBpelStr, ctype));
261 RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout * 1000)
262 .setConnectTimeout(connectTimeout * 1000).build();
263 post.setConfig(requestConfig);
265 try (CloseableHttpClient client = HttpClients.createDefault()) {
266 CloseableHttpResponse response = client.execute(post);
267 if (response != null) {
268 lastResponseCode = response.getStatusLine().getStatusCode();
269 HttpEntity entity = response.getEntity();
270 lastResponse = (entity != null) ? EntityUtils.toString(entity) : "";
272 lastResponseCode = 900;
275 } catch (Exception e) {
276 logger.error("{} {} Exception - Error sending Bpel notification: {} ", MessageEnum.RA_SEND_VNF_NOTIF_ERR,
277 ErrorCode.BusinessProcesssError.getValue(), toBpelStr, e);
278 lastResponseCode = 900;
282 logger.debug("Response code from BPEL server: {}", lastResponseCode);
283 logger.debug("Response body is: {}", lastResponse);
286 private String getEncryptedProperty(String key, String defaultValue, String encryptionKey) {
287 if (env.getProperty(key) != null) {
289 return CryptoUtils.decrypt(env.getProperty(key), env.getProperty(encryptionKey));
290 } catch (GeneralSecurityException e) {
291 logger.debug("Exception while decrypting property: {} ", env.getProperty(key), e);