Removed MsoLogger class
[so.git] / adapters / mso-openstack-adapters / src / main / java / org / onap / so / adapters / vnf / BpelRestClient.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP - SO
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
12  * 
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  * 
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=========================================================
21  */
22
23 package org.onap.so.adapters.vnf;
24
25
26 import java.security.GeneralSecurityException;
27 import java.util.Set;
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;
49
50 /**
51  * This is the class that is used to POST replies from the MSO adapters to the BPEL engine.
52  * It can be configured via property file, or modified using the member methods.
53  * The properties to use are:
54  * org.onap.so.adapters.vnf.bpelauth  encrypted authorization string to send to BEPL engine
55  * org.onap.so.adapters.vnf.sockettimeout socket timeout value
56  * org.onap.so.adapters.vnf.connecttimeout connect timeout value
57  * org.onap.so.adapters.vnf.retrycount number of times to retry failed connections
58  * org.onap.so.adapters.vnf.retryinterval interval (in seconds) between retries
59  * org.onap.so.adapters.vnf.retrylist list of response codes that will trigger a retry (the special code
60  *                      900 means "connection was not established")
61  */
62 @Component
63 @Scope("prototype")
64 public class BpelRestClient {
65         public  static final String MSO_PROP_VNF_ADAPTER     = "MSO_PROP_VNF_ADAPTER";
66         private static final String PROPERTY_DOMAIN          = "org.onap.so.adapters.vnf";
67         private static final String BPEL_AUTH_PROPERTY       = PROPERTY_DOMAIN+".bpelauth";
68         private static final String SOCKET_TIMEOUT_PROPERTY  = PROPERTY_DOMAIN+".sockettimeout";
69         private static final String CONN_TIMEOUT_PROPERTY    = PROPERTY_DOMAIN+".connecttimeout";
70         private static final String RETRY_COUNT_PROPERTY     = PROPERTY_DOMAIN+".retrycount";
71         private static final String RETRY_INTERVAL_PROPERTY  = PROPERTY_DOMAIN+".retryinterval";
72         private static final String RETRY_LIST_PROPERTY      = PROPERTY_DOMAIN+".retrylist";
73         private static final String ENCRYPTION_KEY_PROP      = "org.onap.so.adapters.network.encryptionKey";
74     private static final Logger logger = LoggerFactory.getLogger(BpelRestClient.class);
75
76         /** Default socket timeout (in seconds) */
77         public static final int DEFAULT_SOCKET_TIMEOUT = 5;
78         /** Default connect timeout (in seconds) */
79         public static final int DEFAULT_CONNECT_TIMEOUT = 5;
80         /** By default, retry up to five times */
81         public static final int DEFAULT_RETRY_COUNT = 5;
82         /** Default interval to wait between retries (in seconds), negative means use backoff algorithm */
83         public static final int DEFAULT_RETRY_INTERVAL = -15;
84         /** Default list of response codes to trigger a retry */
85         public static final String DEFAULT_RETRY_LIST = "408,429,500,502,503,504,900";  // 900 is "connection failed"
86         /** Default credentials */
87         public static final String DEFAULT_CREDENTIALS = "";
88
89         @Autowired
90         private Environment env;
91         // Properties of the BPEL client -- all are configurable
92         private int socketTimeout;
93         private int connectTimeout;
94         private int retryCount;
95         private int retryInterval;
96         private Set<Integer> retryList;
97         private String credentials;
98
99         // last response from BPEL engine
100         private int lastResponseCode;
101         private String lastResponse;
102
103         /**
104          * Create a client to send results to the BPEL engine, using configuration from the
105          * MSO_PROP_VNF_ADAPTER properties.
106          */
107         public BpelRestClient() {
108                 socketTimeout  = DEFAULT_SOCKET_TIMEOUT;
109                 connectTimeout = DEFAULT_CONNECT_TIMEOUT;
110                 retryCount     = DEFAULT_RETRY_COUNT;
111                 retryInterval  = DEFAULT_RETRY_INTERVAL;
112                 setRetryList(DEFAULT_RETRY_LIST);
113                 credentials    = DEFAULT_CREDENTIALS;
114                 lastResponseCode = 0;
115                 lastResponse = "";
116                 
117         }
118         
119         @PostConstruct
120         protected void init() {
121
122                 socketTimeout  = env.getProperty(SOCKET_TIMEOUT_PROPERTY, Integer.class, DEFAULT_SOCKET_TIMEOUT);
123                 connectTimeout = env.getProperty(CONN_TIMEOUT_PROPERTY, Integer.class, DEFAULT_CONNECT_TIMEOUT);
124                 retryCount     = env.getProperty(RETRY_COUNT_PROPERTY, Integer.class, DEFAULT_RETRY_COUNT);
125                 retryInterval  = env.getProperty(RETRY_INTERVAL_PROPERTY, Integer.class, DEFAULT_RETRY_INTERVAL);
126                 setRetryList(env.getProperty(RETRY_LIST_PROPERTY, DEFAULT_RETRY_LIST));
127                 credentials    = getEncryptedProperty(BPEL_AUTH_PROPERTY, DEFAULT_CREDENTIALS, ENCRYPTION_KEY_PROP);
128         }
129
130         public int getSocketTimeout() {
131                 return socketTimeout;
132         }
133
134         public void setSocketTimeout(int socketTimeout) {
135                 this.socketTimeout = socketTimeout;
136         }
137
138         public int getConnectTimeout() {
139                 return connectTimeout;
140         }
141
142         public void setConnectTimeout(int connectTimeout) {
143                 this.connectTimeout = connectTimeout;
144         }
145
146         public int getRetryCount() {
147                 return retryCount;
148         }
149
150         public void setRetryCount(int retryCount) {
151                 int newRetryCount = retryCount;
152                 if (newRetryCount < 0)
153                         newRetryCount = DEFAULT_RETRY_COUNT;
154                 this.retryCount = newRetryCount;
155         }
156
157         public int getRetryInterval() {
158                 return retryInterval;
159         }
160
161         public void setRetryInterval(int retryInterval) {
162                 this.retryInterval = retryInterval;
163         }
164
165         public String getCredentials() {
166                 return credentials;
167         }
168
169         public void setCredentials(String credentials) {
170                 this.credentials = credentials;
171         }
172
173         public String getRetryList() {
174                 if (retryList.isEmpty())
175                         return "";
176                 String t = retryList.toString();
177                 return t.substring(1, t.length()-1);
178         }
179
180         public void setRetryList(String retryList) {
181                 Set<Integer> s = new TreeSet<>();
182                 for (String t : retryList.split("[, ]")) {
183                         try {
184                                 s.add(Integer.parseInt(t));
185                         } catch (NumberFormatException x) {
186                                 // ignore
187                         }
188                 }
189                 this.retryList = s;
190         }
191
192         public int getLastResponseCode() {
193                 return lastResponseCode;
194         }
195
196         public String getLastResponse() {
197                 return lastResponse;
198         }
199
200         /**
201          * Post a response to the URL of the BPEL engine.  As long as the response code is one of those in
202          * the retryList, the post will be retried up to "retrycount" times with an interval (in seconds)
203          * of "retryInterval".  If retryInterval is negative, then each successive retry interval will be
204          * double the previous one.
205          * @param toBpelStr the content (XML or JSON) to post
206          * @param bpelUrl the URL to post to
207          * @param isxml true if the content is XML, otherwise assumed to be JSON
208          * @return true if the post succeeded, false if all retries failed
209          */
210         public boolean bpelPost(final String toBpelStr, final String bpelUrl, final boolean isxml)  {
211                 debug("Sending response to BPEL: " + toBpelStr);
212                 int totalretries = 0;
213                 int retryint = retryInterval;
214                 while (true) {
215                         sendOne(toBpelStr, bpelUrl, isxml);
216                         // Note: really should handle response code 415 by switching between content types if needed
217                         if (!retryList.contains(lastResponseCode)) {
218                                 debug("Got response code: " + lastResponseCode + ": returning.");
219                                 return true;
220                         }
221                         if (totalretries >= retryCount) {
222                                 debug("Retried " + totalretries + " times, giving up.");
223           logger.error("{} {} Could not deliver response to BPEL after {} tries: {}", MessageEnum.RA_SEND_VNF_NOTIF_ERR,
224               ErrorCode.BusinessProcesssError.getValue(), totalretries, toBpelStr);
225                                 return false;
226                         }
227                         totalretries++;
228                         int sleepinterval = retryint;
229                         if (retryint < 0) {
230                                 // if retry interval is negative double the retry on each pass
231                                 sleepinterval = -retryint;
232                                 retryint *= 2;
233                         }
234                         debug("Sleeping for " + sleepinterval + " seconds.");
235                         try {
236                                 Thread.sleep(sleepinterval * 1000L);
237                         } catch (InterruptedException e) {
238           logger.debug("Exception while Thread sleep", e);
239                                 Thread.currentThread().interrupt();
240                         }
241                 }
242         }
243         private void debug(String m) {
244                 logger.debug(m);
245         }
246         private void sendOne(final String toBpelStr, final String bpelUrl, final boolean isxml) {
247       logger.debug("Sending to BPEL server: {}", bpelUrl);
248       logger.debug("Content is: {}", toBpelStr);
249
250                 //POST
251                 HttpPost post = new HttpPost(bpelUrl);
252                 if (credentials != null && !credentials.isEmpty())
253                         post.addHeader("Authorization", "Basic " + DatatypeConverter.printBase64Binary(credentials.getBytes()));
254
255       logger.debug("HTTPPost Headers: {}", post.getAllHeaders());
256
257       //ContentType
258         ContentType ctype = isxml ? ContentType.APPLICATION_XML : ContentType.APPLICATION_JSON;
259         post.setEntity(new StringEntity(toBpelStr, ctype));
260
261         //Timeouts
262                 RequestConfig requestConfig = RequestConfig
263                         .custom()
264                         .setSocketTimeout(socketTimeout * 1000)
265                         .setConnectTimeout(connectTimeout * 1000)
266                         .build();
267                 post.setConfig(requestConfig);
268                                 
269         try (CloseableHttpClient client = HttpClients.createDefault()) {
270                         CloseableHttpResponse response = client.execute(post);
271                         if (response != null) {
272                                 lastResponseCode = response.getStatusLine().getStatusCode();
273                                 HttpEntity entity = response.getEntity();
274                                 lastResponse = (entity != null) ? EntityUtils.toString(entity) : "";
275                         } else {
276                                 lastResponseCode = 900;
277                                 lastResponse = "";
278                         }
279                 } catch (Exception e) {
280             logger.error("{} {} Exception - Error sending Bpel notification: {} ", MessageEnum.RA_SEND_VNF_NOTIF_ERR,
281                 ErrorCode.BusinessProcesssError.getValue(), toBpelStr, e);
282                         lastResponseCode = 900;
283                         lastResponse = "";
284                 }
285
286       logger.debug("Response code from BPEL server: {}", lastResponseCode);
287       logger.debug("Response body is: {}", lastResponse);
288         }
289         
290         private String getEncryptedProperty(String key, String defaultValue, String encryptionKey) {
291                 if (env.getProperty(key) != null) {
292                         try {
293                                 return CryptoUtils.decrypt(env.getProperty(key), env.getProperty(encryptionKey));
294                         } catch (GeneralSecurityException e) {
295           logger.debug("Exception while decrypting property: {} ", env.getProperty(key), e);
296                         }
297                 }
298                 return defaultValue;
299         }
300
301 }