Update license and poms
[aai/sparky-be.git] / sparkybe-onap-service / src / main / java / org / onap / aai / sparky / dal / GizmoAdapter.java
1 /**
2  * ============LICENSE_START=======================================================
3  * org.onap.aai
4  * ================================================================================
5  * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
6  * Copyright © 2017-2018 Amdocs
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
11  *
12  *       http://www.apache.org/licenses/LICENSE-2.0
13  *
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=========================================================
20  */
21 package org.onap.aai.sparky.dal;
22
23 import java.io.IOException;
24 import java.net.URI;
25 import java.net.URISyntaxException;
26 import java.util.ArrayList;
27 import java.util.HashMap;
28 import java.util.List;
29 import java.util.Map;
30
31 import javax.ws.rs.core.MediaType;
32 import javax.ws.rs.core.UriBuilder;
33
34 import org.onap.aai.cl.api.Logger;
35 import org.onap.aai.cl.eelf.LoggerFactory;
36 import org.onap.aai.restclient.client.OperationResult;
37 import org.onap.aai.restclient.client.RestClient;
38 import org.onap.aai.restclient.enums.RestAuthenticationMode;
39 import org.onap.aai.sparky.config.oxm.OxmModelLoader;
40 import org.onap.aai.sparky.dal.exception.ElasticSearchOperationException;
41 import org.onap.aai.sparky.dal.rest.RestClientConstructionException;
42 import org.onap.aai.sparky.dal.rest.RestClientFactory;
43 import org.onap.aai.sparky.dal.rest.config.RestEndpointConfig;
44 import org.onap.aai.sparky.logging.AaiUiMsgs;
45 import org.onap.aai.sparky.util.NodeUtils;
46
47 /**
48  * The Class GizmoAdapter.
49  */
50
51 public class GizmoAdapter {
52
53         private static final Logger LOG = LoggerFactory.getInstance().getLogger(GizmoAdapter.class);
54
55         private static final String HEADER_TRANS_ID = "X-TransactionId";
56         private static final String HEADER_FROM_APP_ID = "X-FromAppId";
57         private static final String HEADER_AUTHORIZATION = "Authorization";
58
59         private static final String HTTP_SCHEME = "http";
60         private static final String HTTPS_SCHEME = "https";
61
62         private static final String TRANSACTION_ID_PREFIX = "txnId-";
63         private static final String UI_APP_NAME = "AAI-UI";
64
65         private OxmModelLoader oxmModelLoader;
66
67         private RestEndpointConfig endpointConfig;
68
69         private RestClient restClient;
70
71         private String inventoryBasePath;
72         private String relationshipsBasePath;
73
74         /**
75          * Instantiates a new active inventory adapter.
76          * 
77          * @throws RestClientConstructionException
78          *
79          */
80
81         public GizmoAdapter(OxmModelLoader oxmModelLoader, RestEndpointConfig endpointConfig)
82                         throws ElasticSearchOperationException, IOException, RestClientConstructionException {
83
84                 this.oxmModelLoader = oxmModelLoader;
85                 this.endpointConfig = endpointConfig;
86                 this.restClient = RestClientFactory.buildClient(endpointConfig);
87
88         }
89
90         public String getRelationshipsBasePath() {
91                 return relationshipsBasePath;
92         }
93
94         public void setRelationshipsBasePath(String relationshipsBasePath) {
95                 this.relationshipsBasePath = relationshipsBasePath;
96         }
97
98         public String getInventoryBasePath() {
99                 return inventoryBasePath;
100         }
101
102         public void setInventoryBasePath(String inventoryBasePath) {
103                 this.inventoryBasePath = inventoryBasePath;
104         }
105
106         public String getFullInventoryUrl(String resourceUrl) throws Exception {
107                 final String host = endpointConfig.getEndpointIpAddress();
108                 final String port = endpointConfig.getEndpointServerPort();
109                 final String basePath = getInventoryBasePath();
110                 return String.format("https://%s:%s%s%s", host, port, basePath, resourceUrl);
111         }
112
113         public String addServerDetailsToUrl(String resourceUrl) throws Exception {
114                 final String host = endpointConfig.getEndpointIpAddress();
115                 final String port = endpointConfig.getEndpointServerPort();
116                 return String.format("https://%s:%s/%s", host, port, resourceUrl);
117         }
118
119         public String getFullRelationshipUrl(String resourceUrl) throws Exception {
120                 final String host = endpointConfig.getEndpointIpAddress();
121                 final String port = endpointConfig.getEndpointServerPort();
122                 final String basePath = getRelationshipsBasePath();
123                 return String.format("https://%s:%s%s%s", host, port, basePath, resourceUrl);
124         }
125
126         protected Map<String, List<String>> getMessageHeaders() {
127
128                 Map<String, List<String>> headers = new HashMap<String, List<String>>();
129
130                 headers.putIfAbsent(HEADER_FROM_APP_ID, new ArrayList<String>());
131                 headers.get(HEADER_FROM_APP_ID).add(UI_APP_NAME);
132
133                 headers.putIfAbsent(HEADER_TRANS_ID, new ArrayList<String>());
134                 headers.get(HEADER_TRANS_ID).add(TRANSACTION_ID_PREFIX + NodeUtils.getRandomTxnId());
135
136                 if (endpointConfig.getRestAuthenticationMode() == RestAuthenticationMode.SSL_BASIC) {
137
138                         headers.putIfAbsent(HEADER_AUTHORIZATION, new ArrayList<String>());
139                         headers.get(HEADER_AUTHORIZATION).add(getBasicAuthenticationCredentials());
140
141                 }
142
143                 return headers;
144         }
145
146         protected String getBasicAuthenticationCredentials() {
147                 String usernameAndPassword = String.join(":", endpointConfig.getBasicAuthUserName(),
148                                 endpointConfig.getBasicAuthPassword());
149                 return "Basic " + java.util.Base64.getEncoder().encodeToString(usernameAndPassword.getBytes());
150         }
151
152         /**
153          * Our retry conditions should be very specific.
154          *
155          * @param r
156          *            the r
157          * @return true, if successful
158          */
159         private boolean shouldRetryRequest(OperationResult r) {
160
161                 if (r == null) {
162                         return true;
163                 }
164
165                 int rc = r.getResultCode();
166
167                 if (rc == 200) {
168                         return false;
169                 }
170
171                 if (rc == 404) {
172                         return false;
173                 }
174
175                 return true;
176
177         }
178
179         /**
180          * Query active inventory.
181          *
182          * @param url
183          *            the url
184          * @param acceptContentType
185          *            the accept content type
186          * @return the operation result
187          */
188         OperationResult queryGizmo(String url, String acceptContentType) {
189
190                 return restClient.get(url, getMessageHeaders(), MediaType.APPLICATION_JSON_TYPE);
191
192         }
193
194         public RestEndpointConfig getEndpointConfig() {
195                 return endpointConfig;
196         }
197
198         public void setEndpointConfig(RestEndpointConfig endpointConfig) {
199                 this.endpointConfig = endpointConfig;
200         }
201
202         public OperationResult queryGizmoWithRetries(String url, String responseType, int numRetries) {
203
204                 OperationResult result = null;
205
206                 for (int retryCount = 0; retryCount < numRetries; retryCount++) {
207
208                         LOG.debug(AaiUiMsgs.QUERY_AAI_RETRY_SEQ, url, String.valueOf(retryCount + 1));
209
210                         result = queryGizmo(url, responseType);
211
212                         /**
213                          * Record number of times we have attempted the request to later
214                          * summarize how many times we are generally retrying over thousands
215                          * of messages in a sync.
216                          * 
217                          * If the number of retries is surprisingly high, then we need to
218                          * understand why that is as the number of retries is also causing a
219                          * heavier load on AAI beyond the throttling controls we already
220                          * have in place in term of the transaction rate controller and
221                          * number of parallelized threads per task processor.
222                          */
223
224                         result.setNumRetries(retryCount);
225
226                         if (!shouldRetryRequest(result)) {
227
228                                 result.setFromCache(false);
229                                 LOG.debug(AaiUiMsgs.QUERY_AAI_RETRY_DONE_SEQ, url, String.valueOf(retryCount + 1));
230
231                                 return result;
232                         }
233
234                         try {
235                                 /*
236                                  * Sleep between re-tries to be nice to the target system.
237                                  */
238                                 Thread.sleep(50);
239                         } catch (InterruptedException exc) {
240                                 LOG.error(AaiUiMsgs.QUERY_AAI_WAIT_INTERRUPTION, exc.getLocalizedMessage());
241                                 break;
242                         }
243                         LOG.error(AaiUiMsgs.QUERY_AAI_RETRY_FAILURE_WITH_SEQ, url, String.valueOf(retryCount + 1));
244
245                 }
246
247                 LOG.info(AaiUiMsgs.QUERY_AAI_RETRY_MAXED_OUT, url);
248
249                 return result;
250
251         }
252
253         /**
254          * This method adds a scheme, host and port (if missing) to the passed-in
255          * URI. If these parts of the URI are already present, they will not be
256          * duplicated.
257          * 
258          * @param selflink
259          *            The URI to repair
260          * @param queryParams
261          *            The query parameters as a single string
262          * @return The corrected URI (i.e. includes a scheme/host/port)
263          */
264
265   private String repairGizmoSelfLink(String baseUrlPath, String selfLink, String queryParams) {
266
267     if (selfLink == null) {
268       return selfLink;
269     }
270     
271     if (selfLink.startsWith("http") || selfLink.startsWith("https")) {
272       return selfLink;
273     }
274     
275     UriBuilder builder = UriBuilder.fromPath(baseUrlPath + "/" + selfLink)
276         .host(endpointConfig.getEndpointIpAddress())
277         .port(Integer.parseInt(endpointConfig.getEndpointServerPort()));
278
279     switch (endpointConfig.getRestAuthenticationMode()) {
280
281       case SSL_BASIC:
282       case SSL_CERT: {
283         builder.scheme(HTTPS_SCHEME);
284         break;
285       }
286
287       default: {
288         builder.scheme(HTTP_SCHEME);
289       }
290     }
291
292     boolean includeQueryParams = ((null != queryParams) && (!"".equals(queryParams)));
293
294     /*
295      * builder.build().toString() will encode special characters to hexadecimal pairs prefixed with
296      * a '%' so we're adding the query parameters separately, in their UTF-8 representations, so
297      * that characters such as '?', '&', etc. remain intact as needed by the synchronizer
298      */
299     return (builder.build().toString() + (includeQueryParams ? queryParams : ""));
300
301   }
302         
303   public String repairRelationshipSelfLink(String selflink, String queryParams) {
304     return repairGizmoSelfLink(relationshipsBasePath, selflink, queryParams);
305   }
306
307   public String repairInventorySelfLink(String selflink, String queryParams) {
308     return repairGizmoSelfLink(inventoryBasePath, selflink, queryParams);
309   }
310
311         public OperationResult getSelfLinksByEntityType(String entityType) throws Exception {
312                 
313                 if (entityType == null) {
314                         throw new NullPointerException("Failed to getSelfLinksByEntityType() because entityType is null");
315                 }
316
317                 String link = getFullInventoryUrl(entityType);
318
319                 return queryGizmoWithRetries(link, "application/json", endpointConfig.getNumRequestRetries());
320
321         }
322         
323         public static String extractResourcePath(String selflink) {
324                 try {
325                         return new URI(selflink).getRawPath();
326                 } catch (URISyntaxException uriSyntaxException) {
327                         LOG.error(AaiUiMsgs.ERROR_EXTRACTING_RESOURCE_PATH_FROM_LINK, uriSyntaxException.getMessage());
328                         return selflink;
329                 }
330         }
331
332 }