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 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 * ============LICENSE_END=========================================================
22 package org.onap.so.adapters.network;
25 import java.security.GeneralSecurityException;
27 import java.util.TreeSet;
29 import javax.annotation.PostConstruct;
30 import javax.xml.bind.DatatypeConverter;
32 import org.apache.http.HttpEntity;
33 import org.apache.http.client.config.RequestConfig;
34 import org.apache.http.client.methods.CloseableHttpResponse;
35 import org.apache.http.client.methods.HttpPost;
36 import org.apache.http.entity.ContentType;
37 import org.apache.http.entity.StringEntity;
38 import org.apache.http.impl.client.CloseableHttpClient;
39 import org.apache.http.impl.client.HttpClients;
40 import org.apache.http.util.EntityUtils;
41 import org.onap.so.logger.MessageEnum;
42 import org.onap.so.logger.MsoLogger;
43 import org.onap.so.utils.CryptoUtils;
44 import org.springframework.beans.factory.annotation.Autowired;
45 import org.springframework.context.annotation.Scope;
46 import org.springframework.core.env.Environment;
47 import org.springframework.stereotype.Component;
50 * This is the class that is used to POST replies from the MSO adapters to the BPEL engine.
51 * It can be configured via property file, or modified using the member methods.
52 * The properties to use are:
53 * org.onap.so.adapters.vnf.bpelauth encrypted authorization string to send to BEPL engine
54 * org.onap.so.adapters.vnf.sockettimeout socket timeout value
55 * org.onap.so.adapters.vnf.connecttimeout connect timeout value
56 * org.onap.so.adapters.vnf.retrycount number of times to retry failed connections
57 * org.onap.so.adapters.vnf.retryinterval interval (in seconds) between retries
58 * org.onap.so.adapters.vnf.retrylist list of response codes that will trigger a retry (the special code
59 * 900 means "connection was not established")
61 @Component("NetworkBpel")
63 public class BpelRestClient {
64 public static final String MSO_PROP_NETWORK_ADAPTER = "MSO_PROP_NETWORK_ADAPTER";
65 private static final String PROPERTY_DOMAIN = "org.onap.so.adapters.network";
66 private static final String BPEL_AUTH_PROPERTY = PROPERTY_DOMAIN+".bpelauth";
67 private static final String SOCKET_TIMEOUT_PROPERTY = PROPERTY_DOMAIN+".sockettimeout";
68 private static final String CONN_TIMEOUT_PROPERTY = PROPERTY_DOMAIN+".connecttimeout";
69 private static final String RETRY_COUNT_PROPERTY = PROPERTY_DOMAIN+".retrycount";
70 private static final String RETRY_INTERVAL_PROPERTY = PROPERTY_DOMAIN+".retryinterval";
71 private static final String RETRY_LIST_PROPERTY = PROPERTY_DOMAIN+".retrylist";
72 private static final String ENCRYPTION_KEY_PROP = PROPERTY_DOMAIN + ".encryptionKey";
73 private static final MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA, BpelRestClient.class);
76 private Environment env;
77 /** Default socket timeout (in seconds) */
78 public static final int DEFAULT_SOCKET_TIMEOUT = 5;
79 /** Default connect timeout (in seconds) */
80 public static final int DEFAULT_CONNECT_TIMEOUT = 5;
81 /** By default, retry up to five times */
82 public static final int DEFAULT_RETRY_COUNT = 5;
83 /** Default interval to wait between retries (in seconds), negative means use backoff algorithm */
84 public static final int DEFAULT_RETRY_INTERVAL = -15;
85 /** Default list of response codes to trigger a retry */
86 public static final String DEFAULT_RETRY_LIST = "408,429,500,502,503,504,900"; // 900 is "connection failed"
87 /** Default credentials */
88 public static final String DEFAULT_CREDENTIALS = "";
90 // Properties of the BPEL client -- all are configurable
91 private int socketTimeout;
92 private int connectTimeout;
93 private int retryCount;
94 private int retryInterval;
95 private Set<Integer> retryList;
96 private String credentials;
98 // last response from BPEL engine
99 private int lastResponseCode;
100 private String lastResponse;
103 * Create a client to send results to the BPEL engine, using configuration from the
104 * MSO_PROP_NETWORK_ADAPTER properties.
106 public BpelRestClient() {
107 socketTimeout = DEFAULT_SOCKET_TIMEOUT;
108 connectTimeout = DEFAULT_CONNECT_TIMEOUT;
109 retryCount = DEFAULT_RETRY_COUNT;
110 retryInterval = DEFAULT_RETRY_INTERVAL;
111 setRetryList(DEFAULT_RETRY_LIST);
112 credentials = DEFAULT_CREDENTIALS;
113 lastResponseCode = 0;
119 protected void init() {
121 socketTimeout = env.getProperty(SOCKET_TIMEOUT_PROPERTY, Integer.class, DEFAULT_SOCKET_TIMEOUT);
122 connectTimeout = env.getProperty(CONN_TIMEOUT_PROPERTY, Integer.class, DEFAULT_CONNECT_TIMEOUT);
123 retryCount = env.getProperty(RETRY_COUNT_PROPERTY, Integer.class, DEFAULT_RETRY_COUNT);
124 retryInterval = env.getProperty(RETRY_INTERVAL_PROPERTY, Integer.class, DEFAULT_RETRY_INTERVAL);
125 setRetryList(env.getProperty(RETRY_LIST_PROPERTY, DEFAULT_RETRY_LIST));
126 credentials = getEncryptedProperty(BPEL_AUTH_PROPERTY, DEFAULT_CREDENTIALS, env.getProperty(ENCRYPTION_KEY_PROP));
129 public int getSocketTimeout() {
130 return socketTimeout;
133 public void setSocketTimeout(int socketTimeout) {
134 this.socketTimeout = socketTimeout;
137 public int getConnectTimeout() {
138 return connectTimeout;
141 public void setConnectTimeout(int connectTimeout) {
142 this.connectTimeout = connectTimeout;
145 public int getRetryCount() {
149 public void setRetryCount(int retryCount) {
152 retCnt = DEFAULT_RETRY_COUNT;
153 this.retryCount = retCnt;
156 public int getRetryInterval() {
157 return retryInterval;
160 public void setRetryInterval(int retryInterval) {
161 this.retryInterval = retryInterval;
164 public String getCredentials() {
168 public void setCredentials(String credentials) {
169 this.credentials = credentials;
172 public String getRetryList() {
173 if (retryList.isEmpty())
175 String t = retryList.toString();
176 return t.substring(1, t.length()-1);
179 public void setRetryList(String retryList) {
180 Set<Integer> s = new TreeSet<>();
181 for (String t : retryList.split("[, ]")) {
183 s.add(Integer.parseInt(t));
184 } catch (NumberFormatException x) {
185 LOGGER.debug("Exception while parsing", x);
191 public int getLastResponseCode() {
192 return lastResponseCode;
195 public String getLastResponse() {
200 * Post a response to the URL of the BPEL engine. As long as the response code is one of those in
201 * the retryList, the post will be retried up to "retrycount" times with an interval (in seconds)
202 * of "retryInterval". If retryInterval is negative, then each successive retry interval will be
203 * double the previous one.
204 * @param toBpelStr the content (XML or JSON) to post
205 * @param bpelUrl the URL to post to
206 * @param isxml true if the content is XML, otherwise assumed to be JSON
207 * @return true if the post succeeded, false if all retries failed
209 public boolean bpelPost(final String toBpelStr, final String bpelUrl, final boolean isxml) {
210 debug("Sending response to BPEL: " + toBpelStr);
211 int totalretries = 0;
212 int retryint = retryInterval;
214 sendOne(toBpelStr, bpelUrl, isxml);
215 // Note: really should handle response code 415 by switching between content types if needed
216 if (!retryList.contains(lastResponseCode)) {
217 debug("Got response code: " + lastResponseCode + ": returning.");
220 if (totalretries >= retryCount) {
221 debug("Retried " + totalretries + " times, giving up.");
222 LOGGER.error(MessageEnum.RA_SEND_VNF_NOTIF_ERR, "Could not deliver response to BPEL after "+totalretries+" tries: "+toBpelStr, "Camunda", "", MsoLogger.ErrorCode.DataError, "Could not deliver response to BPEL");
226 int sleepinterval = retryint;
228 // if retry interval is negative double the retry on each pass
229 sleepinterval = -retryint;
232 debug("Sleeping for " + sleepinterval + " seconds.");
234 Thread.sleep(sleepinterval * 1000L);
235 } catch (InterruptedException e) {
236 LOGGER.debug("Exception while Thread sleep", e);
237 Thread.currentThread().interrupt();
241 private void debug(String m) {
244 private void sendOne(final String toBpelStr, final String bpelUrl, final boolean isxml) {
245 LOGGER.debug("Sending to BPEL server: "+bpelUrl);
246 LOGGER.debug("Content is: "+toBpelStr);
249 HttpPost post = new HttpPost(bpelUrl);
250 if (credentials != null && !credentials.isEmpty())
251 post.addHeader("Authorization", "Basic " + DatatypeConverter.printBase64Binary(credentials.getBytes()));
254 ContentType ctype = isxml ? ContentType.APPLICATION_XML : ContentType.APPLICATION_JSON;
255 post.setEntity(new StringEntity(toBpelStr, ctype));
258 RequestConfig requestConfig = RequestConfig
260 .setSocketTimeout(socketTimeout * 1000)
261 .setConnectTimeout(connectTimeout * 1000)
263 post.setConfig(requestConfig);
266 //Execute & GetResponse
267 try (CloseableHttpClient client = HttpClients.createDefault()) {
268 CloseableHttpResponse response = client.execute(post);
269 if (response != null) {
270 lastResponseCode = response.getStatusLine().getStatusCode();
271 HttpEntity entity = response.getEntity();
272 lastResponse = (entity != null) ? EntityUtils.toString(entity) : "";
274 lastResponseCode = 900;
277 } catch (Exception e) {
278 String error = "Error sending Bpel notification:" + toBpelStr;
279 LOGGER.error (MessageEnum.RA_SEND_VNF_NOTIF_ERR, error, "Camunda", "", MsoLogger.ErrorCode.AvailabilityError, "Exception sending Bpel notification", e);
280 lastResponseCode = 900;
283 LOGGER.debug("Response code from BPEL server: "+lastResponseCode);
284 LOGGER.debug("Response body is: "+lastResponse);
287 private String getEncryptedProperty(String key, String defaultValue, String encryptionKey) {
288 if (env.getProperty(key) != null) {
290 return CryptoUtils.decrypt(env.getProperty(key), encryptionKey);
291 } catch (GeneralSecurityException e) {
292 LOGGER.debug("Exception while decrypting property: " + env.getProperty(key), e);