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