2 * ============LICENSE_START=======================================================
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
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=========================================================
21 package org.onap.aai.sparky.dal;
23 import java.io.IOException;
25 import java.net.URISyntaxException;
26 import java.util.ArrayList;
27 import java.util.HashMap;
28 import java.util.List;
31 import javax.ws.rs.core.MediaType;
32 import javax.ws.rs.core.UriBuilder;
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;
48 * The Class GizmoAdapter.
51 public class GizmoAdapter {
53 private static final Logger LOG = LoggerFactory.getInstance().getLogger(GizmoAdapter.class);
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";
59 private static final String HTTP_SCHEME = "http";
60 private static final String HTTPS_SCHEME = "https";
62 private static final String TRANSACTION_ID_PREFIX = "txnId-";
63 private static final String UI_APP_NAME = "AAI-UI";
65 private OxmModelLoader oxmModelLoader;
67 private RestEndpointConfig endpointConfig;
69 private RestClient restClient;
71 private String inventoryBasePath;
72 private String relationshipsBasePath;
73 private String appPartnerName = "";
76 * Instantiates a new active inventory adapter.
78 * @throws RestClientConstructionException
82 public GizmoAdapter(OxmModelLoader oxmModelLoader, RestEndpointConfig endpointConfig)
83 throws ElasticSearchOperationException, IOException, RestClientConstructionException {
85 this.oxmModelLoader = oxmModelLoader;
86 this.endpointConfig = endpointConfig;
87 this.restClient = RestClientFactory.buildClient(endpointConfig);
91 public String getAppPartnerName() {
92 return appPartnerName;
95 public void setAppPartnerName(String appPartnerName) {
96 this.appPartnerName = appPartnerName;
100 public String getRelationshipsBasePath() {
101 return relationshipsBasePath;
104 public void setRelationshipsBasePath(String relationshipsBasePath) {
105 this.relationshipsBasePath = relationshipsBasePath;
108 public String getInventoryBasePath() {
109 return inventoryBasePath;
112 public void setInventoryBasePath(String inventoryBasePath) {
113 this.inventoryBasePath = inventoryBasePath;
116 public String getFullInventoryUrl(String resourceUrl) throws Exception {
117 final String host = endpointConfig.getEndpointIpAddress();
118 final String port = endpointConfig.getEndpointServerPort();
119 final String basePath = getInventoryBasePath();
120 return String.format("https://%s:%s%s%s", host, port, basePath, resourceUrl);
123 public String addServerDetailsToUrl(String resourceUrl) throws Exception {
124 final String host = endpointConfig.getEndpointIpAddress();
125 final String port = endpointConfig.getEndpointServerPort();
126 return String.format("https://%s:%s/%s", host, port, resourceUrl);
129 public String getFullRelationshipUrl(String resourceUrl) throws Exception {
130 final String host = endpointConfig.getEndpointIpAddress();
131 final String port = endpointConfig.getEndpointServerPort();
132 final String basePath = getRelationshipsBasePath();
133 return String.format("https://%s:%s%s%s", host, port, basePath, resourceUrl);
136 protected Map<String, List<String>> getMessageHeaders() {
138 Map<String, List<String>> headers = new HashMap<String, List<String>>();
140 headers.putIfAbsent(HEADER_FROM_APP_ID, new ArrayList<String>());
141 headers.get(HEADER_FROM_APP_ID).add(appPartnerName);
143 headers.putIfAbsent(HEADER_TRANS_ID, new ArrayList<String>());
144 headers.get(HEADER_TRANS_ID).add(TRANSACTION_ID_PREFIX + NodeUtils.getRandomTxnId());
146 if (endpointConfig.getRestAuthenticationMode() == RestAuthenticationMode.SSL_BASIC) {
148 headers.putIfAbsent(HEADER_AUTHORIZATION, new ArrayList<String>());
149 headers.get(HEADER_AUTHORIZATION).add(getBasicAuthenticationCredentials());
156 protected String getBasicAuthenticationCredentials() {
157 String usernameAndPassword = String.join(":", endpointConfig.getBasicAuthUserName(),
158 endpointConfig.getBasicAuthPassword());
159 return "Basic " + java.util.Base64.getEncoder().encodeToString(usernameAndPassword.getBytes());
163 * Our retry conditions should be very specific.
166 * @return true, if successful
168 private boolean shouldRetryRequest(OperationResult r) {
174 int rc = r.getResultCode();
189 * Query active inventory.
192 * @param acceptContentType the accept content type
193 * @return the operation result
195 OperationResult queryGizmo(String url, String acceptContentType) {
197 return restClient.get(url, getMessageHeaders(), MediaType.APPLICATION_JSON_TYPE);
201 public RestEndpointConfig getEndpointConfig() {
202 return endpointConfig;
205 public void setEndpointConfig(RestEndpointConfig endpointConfig) {
206 this.endpointConfig = endpointConfig;
209 public OperationResult queryGizmoWithRetries(String url, String responseType, int numRetries) {
211 OperationResult result = null;
213 for (int retryCount = 0; retryCount < numRetries; retryCount++) {
215 LOG.debug(AaiUiMsgs.QUERY_AAI_RETRY_SEQ, url, String.valueOf(retryCount + 1));
217 result = queryGizmo(url, responseType);
220 * Record number of times we have attempted the request to later summarize how many times we
221 * are generally retrying over thousands of messages in a sync.
223 * If the number of retries is surprisingly high, then we need to understand why that is as
224 * the number of retries is also causing a heavier load on AAI beyond the throttling controls
225 * we already have in place in term of the transaction rate controller and number of
226 * parallelized threads per task processor.
229 result.setNumRetries(retryCount);
231 if (!shouldRetryRequest(result)) {
233 result.setFromCache(false);
234 LOG.debug(AaiUiMsgs.QUERY_AAI_RETRY_DONE_SEQ, url, String.valueOf(retryCount + 1));
241 * Sleep between re-tries to be nice to the target system.
244 } catch (InterruptedException exc) {
245 LOG.error(AaiUiMsgs.QUERY_AAI_WAIT_INTERRUPTION, exc.getLocalizedMessage());
246 Thread.currentThread().interrupt();
249 LOG.error(AaiUiMsgs.QUERY_AAI_RETRY_FAILURE_WITH_SEQ, url, String.valueOf(retryCount + 1));
253 LOG.info(AaiUiMsgs.QUERY_AAI_RETRY_MAXED_OUT, url);
260 * This method adds a scheme, host and port (if missing) to the passed-in URI. If these parts of
261 * the URI are already present, they will not be duplicated.
263 * @param selflink The URI to repair
264 * @param queryParams The query parameters as a single string
265 * @return The corrected URI (i.e. includes a scheme/host/port)
268 private String repairGizmoSelfLink(String baseUrlPath, String selfLink, String queryParams) {
270 if (selfLink == null) {
274 if (selfLink.startsWith("http") || selfLink.startsWith("https")) {
278 UriBuilder builder = UriBuilder.fromPath(baseUrlPath + "/" + selfLink)
279 .host(endpointConfig.getEndpointIpAddress())
280 .port(Integer.parseInt(endpointConfig.getEndpointServerPort()));
282 switch (endpointConfig.getRestAuthenticationMode()) {
286 builder.scheme(HTTPS_SCHEME);
291 builder.scheme(HTTP_SCHEME);
295 boolean includeQueryParams = ((null != queryParams) && (!"".equals(queryParams)));
298 * builder.build().toString() will encode special characters to hexadecimal pairs prefixed with
299 * a '%' so we're adding the query parameters separately, in their UTF-8 representations, so
300 * that characters such as '?', '&', etc. remain intact as needed by the synchronizer
302 return (builder.build().toString() + (includeQueryParams ? queryParams : ""));
306 public String repairRelationshipSelfLink(String selflink, String queryParams) {
307 return repairGizmoSelfLink(relationshipsBasePath, selflink, queryParams);
310 public String repairInventorySelfLink(String selflink, String queryParams) {
311 return repairGizmoSelfLink(inventoryBasePath, selflink, queryParams);
314 public OperationResult getSelfLinksByEntityType(String entityType) throws Exception {
316 if (entityType == null) {
317 throw new NullPointerException(
318 "Failed to getSelfLinksByEntityType() because entityType is null");
321 String link = getFullInventoryUrl(entityType);
323 return queryGizmoWithRetries(link, "application/json", endpointConfig.getNumRequestRetries());
327 public static String extractResourcePath(String selflink) {
329 return new URI(selflink).getRawPath();
330 } catch (URISyntaxException uriSyntaxException) {
331 LOG.error(AaiUiMsgs.ERROR_EXTRACTING_RESOURCE_PATH_FROM_LINK,
332 uriSyntaxException.getMessage());