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;
75 * Instantiates a new active inventory adapter.
77 * @throws RestClientConstructionException
81 public GizmoAdapter(OxmModelLoader oxmModelLoader, RestEndpointConfig endpointConfig)
82 throws ElasticSearchOperationException, IOException, RestClientConstructionException {
84 this.oxmModelLoader = oxmModelLoader;
85 this.endpointConfig = endpointConfig;
86 this.restClient = RestClientFactory.buildClient(endpointConfig);
90 public String getRelationshipsBasePath() {
91 return relationshipsBasePath;
94 public void setRelationshipsBasePath(String relationshipsBasePath) {
95 this.relationshipsBasePath = relationshipsBasePath;
98 public String getInventoryBasePath() {
99 return inventoryBasePath;
102 public void setInventoryBasePath(String inventoryBasePath) {
103 this.inventoryBasePath = inventoryBasePath;
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);
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);
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);
126 protected Map<String, List<String>> getMessageHeaders() {
128 Map<String, List<String>> headers = new HashMap<String, List<String>>();
130 headers.putIfAbsent(HEADER_FROM_APP_ID, new ArrayList<String>());
131 headers.get(HEADER_FROM_APP_ID).add(UI_APP_NAME);
133 headers.putIfAbsent(HEADER_TRANS_ID, new ArrayList<String>());
134 headers.get(HEADER_TRANS_ID).add(TRANSACTION_ID_PREFIX + NodeUtils.getRandomTxnId());
136 if (endpointConfig.getRestAuthenticationMode() == RestAuthenticationMode.SSL_BASIC) {
138 headers.putIfAbsent(HEADER_AUTHORIZATION, new ArrayList<String>());
139 headers.get(HEADER_AUTHORIZATION).add(getBasicAuthenticationCredentials());
146 protected String getBasicAuthenticationCredentials() {
147 String usernameAndPassword = String.join(":", endpointConfig.getBasicAuthUserName(),
148 endpointConfig.getBasicAuthPassword());
149 return "Basic " + java.util.Base64.getEncoder().encodeToString(usernameAndPassword.getBytes());
153 * Our retry conditions should be very specific.
157 * @return true, if successful
159 private boolean shouldRetryRequest(OperationResult r) {
165 int rc = r.getResultCode();
180 * Query active inventory.
184 * @param acceptContentType
185 * the accept content type
186 * @return the operation result
188 OperationResult queryGizmo(String url, String acceptContentType) {
190 return restClient.get(url, getMessageHeaders(), MediaType.APPLICATION_JSON_TYPE);
194 public RestEndpointConfig getEndpointConfig() {
195 return endpointConfig;
198 public void setEndpointConfig(RestEndpointConfig endpointConfig) {
199 this.endpointConfig = endpointConfig;
202 public OperationResult queryGizmoWithRetries(String url, String responseType, int numRetries) {
204 OperationResult result = null;
206 for (int retryCount = 0; retryCount < numRetries; retryCount++) {
208 LOG.debug(AaiUiMsgs.QUERY_AAI_RETRY_SEQ, url, String.valueOf(retryCount + 1));
210 result = queryGizmo(url, responseType);
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.
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.
224 result.setNumRetries(retryCount);
226 if (!shouldRetryRequest(result)) {
228 result.setFromCache(false);
229 LOG.debug(AaiUiMsgs.QUERY_AAI_RETRY_DONE_SEQ, url, String.valueOf(retryCount + 1));
236 * Sleep between re-tries to be nice to the target system.
239 } catch (InterruptedException exc) {
240 LOG.error(AaiUiMsgs.QUERY_AAI_WAIT_INTERRUPTION, exc.getLocalizedMessage());
241 Thread.currentThread().interrupt();
244 LOG.error(AaiUiMsgs.QUERY_AAI_RETRY_FAILURE_WITH_SEQ, url, String.valueOf(retryCount + 1));
248 LOG.info(AaiUiMsgs.QUERY_AAI_RETRY_MAXED_OUT, url);
255 * This method adds a scheme, host and port (if missing) to the passed-in
256 * URI. If these parts of the URI are already present, they will not be
262 * The query parameters as a single string
263 * @return The corrected URI (i.e. includes a scheme/host/port)
266 private String repairGizmoSelfLink(String baseUrlPath, String selfLink, String queryParams) {
268 if (selfLink == null) {
272 if (selfLink.startsWith("http") || selfLink.startsWith("https")) {
276 UriBuilder builder = UriBuilder.fromPath(baseUrlPath + "/" + selfLink)
277 .host(endpointConfig.getEndpointIpAddress())
278 .port(Integer.parseInt(endpointConfig.getEndpointServerPort()));
280 switch (endpointConfig.getRestAuthenticationMode()) {
284 builder.scheme(HTTPS_SCHEME);
289 builder.scheme(HTTP_SCHEME);
293 boolean includeQueryParams = ((null != queryParams) && (!"".equals(queryParams)));
296 * builder.build().toString() will encode special characters to hexadecimal pairs prefixed with
297 * a '%' so we're adding the query parameters separately, in their UTF-8 representations, so
298 * that characters such as '?', '&', etc. remain intact as needed by the synchronizer
300 return (builder.build().toString() + (includeQueryParams ? queryParams : ""));
304 public String repairRelationshipSelfLink(String selflink, String queryParams) {
305 return repairGizmoSelfLink(relationshipsBasePath, selflink, queryParams);
308 public String repairInventorySelfLink(String selflink, String queryParams) {
309 return repairGizmoSelfLink(inventoryBasePath, selflink, queryParams);
312 public OperationResult getSelfLinksByEntityType(String entityType) throws Exception {
314 if (entityType == null) {
315 throw new NullPointerException("Failed to getSelfLinksByEntityType() because entityType is null");
318 String link = getFullInventoryUrl(entityType);
320 return queryGizmoWithRetries(link, "application/json", endpointConfig.getNumRequestRetries());
324 public static String extractResourcePath(String selflink) {
326 return new URI(selflink).getRawPath();
327 } catch (URISyntaxException uriSyntaxException) {
328 LOG.error(AaiUiMsgs.ERROR_EXTRACTING_RESOURCE_PATH_FROM_LINK, uriSyntaxException.getMessage());