2 * ============LICENSE_START===================================================
3 * SPARKY (AAI UI service)
4 * ============================================================================
5 * Copyright © 2017 AT&T Intellectual Property.
6 * Copyright © 2017 Amdocs
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
13 * http://www.apache.org/licenses/LICENSE-2.0
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=====================================================
22 * ECOMP and OpenECOMP are trademarks
23 * and service marks of AT&T Intellectual Property.
25 package org.onap.aai.sparky.dal;
27 import java.io.IOException;
29 import java.net.URISyntaxException;
30 import java.util.ArrayList;
31 import java.util.HashMap;
32 import java.util.List;
35 import javax.ws.rs.core.MediaType;
36 import javax.ws.rs.core.UriBuilder;
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;
52 * The Class GizmoAdapter.
55 public class GizmoAdapter {
57 private static final Logger LOG = LoggerFactory.getInstance().getLogger(GizmoAdapter.class);
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";
63 private static final String HTTP_SCHEME = "http";
64 private static final String HTTPS_SCHEME = "https";
66 private static final String TRANSACTION_ID_PREFIX = "txnId-";
67 private static final String UI_APP_NAME = "AAI-UI";
69 private OxmModelLoader oxmModelLoader;
71 private RestEndpointConfig endpointConfig;
73 private RestClient restClient;
75 private String inventoryBasePath;
76 private String relationshipsBasePath;
79 * Instantiates a new active inventory adapter.
81 * @throws RestClientConstructionException
85 public GizmoAdapter(OxmModelLoader oxmModelLoader, RestEndpointConfig endpointConfig)
86 throws ElasticSearchOperationException, IOException, RestClientConstructionException {
88 this.oxmModelLoader = oxmModelLoader;
89 this.endpointConfig = endpointConfig;
90 this.restClient = RestClientFactory.buildClient(endpointConfig);
94 public String getRelationshipsBasePath() {
95 return relationshipsBasePath;
98 public void setRelationshipsBasePath(String relationshipsBasePath) {
99 this.relationshipsBasePath = relationshipsBasePath;
102 public String getInventoryBasePath() {
103 return inventoryBasePath;
106 public void setInventoryBasePath(String inventoryBasePath) {
107 this.inventoryBasePath = inventoryBasePath;
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);
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);
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);
130 protected Map<String, List<String>> getMessageHeaders() {
132 Map<String, List<String>> headers = new HashMap<String, List<String>>();
134 headers.putIfAbsent(HEADER_FROM_APP_ID, new ArrayList<String>());
135 headers.get(HEADER_FROM_APP_ID).add(UI_APP_NAME);
137 headers.putIfAbsent(HEADER_TRANS_ID, new ArrayList<String>());
138 headers.get(HEADER_TRANS_ID).add(TRANSACTION_ID_PREFIX + NodeUtils.getRandomTxnId());
140 if (endpointConfig.getRestAuthenticationMode() == RestAuthenticationMode.SSL_BASIC) {
142 headers.putIfAbsent(HEADER_AUTHORIZATION, new ArrayList<String>());
143 headers.get(HEADER_AUTHORIZATION).add(getBasicAuthenticationCredentials());
150 protected String getBasicAuthenticationCredentials() {
151 String usernameAndPassword = String.join(":", endpointConfig.getBasicAuthUserName(),
152 endpointConfig.getBasicAuthPassword());
153 return "Basic " + java.util.Base64.getEncoder().encodeToString(usernameAndPassword.getBytes());
157 * Our retry conditions should be very specific.
161 * @return true, if successful
163 private boolean shouldRetryRequest(OperationResult r) {
169 int rc = r.getResultCode();
184 * Query active inventory.
188 * @param acceptContentType
189 * the accept content type
190 * @return the operation result
192 OperationResult queryGizmo(String url, String acceptContentType) {
194 return restClient.get(url, getMessageHeaders(), MediaType.APPLICATION_JSON_TYPE);
198 public RestEndpointConfig getEndpointConfig() {
199 return endpointConfig;
202 public void setEndpointConfig(RestEndpointConfig endpointConfig) {
203 this.endpointConfig = endpointConfig;
206 public OperationResult queryGizmoWithRetries(String url, String responseType, int numRetries) {
208 OperationResult result = null;
210 for (int retryCount = 0; retryCount < numRetries; retryCount++) {
212 LOG.debug(AaiUiMsgs.QUERY_AAI_RETRY_SEQ, url, String.valueOf(retryCount + 1));
214 result = queryGizmo(url, responseType);
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.
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.
228 result.setNumRetries(retryCount);
230 if (!shouldRetryRequest(result)) {
232 result.setFromCache(false);
233 LOG.debug(AaiUiMsgs.QUERY_AAI_RETRY_DONE_SEQ, url, String.valueOf(retryCount + 1));
240 * Sleep between re-tries to be nice to the target system.
243 } catch (InterruptedException exc) {
244 LOG.error(AaiUiMsgs.QUERY_AAI_WAIT_INTERRUPTION, exc.getLocalizedMessage());
247 LOG.error(AaiUiMsgs.QUERY_AAI_RETRY_FAILURE_WITH_SEQ, url, String.valueOf(retryCount + 1));
251 LOG.info(AaiUiMsgs.QUERY_AAI_RETRY_MAXED_OUT, url);
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
265 * The query parameters as a single string
266 * @return The corrected URI (i.e. includes a scheme/host/port)
269 private String repairGizmoSelfLink(String baseUrlPath, String selfLink, String queryParams) {
271 if (selfLink == null) {
275 if (selfLink.startsWith("http") || selfLink.startsWith("https")) {
279 UriBuilder builder = UriBuilder.fromPath(baseUrlPath + "/" + selfLink)
280 .host(endpointConfig.getEndpointIpAddress())
281 .port(Integer.parseInt(endpointConfig.getEndpointServerPort()));
283 switch (endpointConfig.getRestAuthenticationMode()) {
287 builder.scheme(HTTPS_SCHEME);
292 builder.scheme(HTTP_SCHEME);
296 boolean includeQueryParams = ((null != queryParams) && (!"".equals(queryParams)));
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
303 return (builder.build().toString() + (includeQueryParams ? queryParams : ""));
307 public String repairRelationshipSelfLink(String selflink, String queryParams) {
308 return repairGizmoSelfLink(relationshipsBasePath, selflink, queryParams);
311 public String repairInventorySelfLink(String selflink, String queryParams) {
312 return repairGizmoSelfLink(inventoryBasePath, selflink, queryParams);
315 public OperationResult getSelfLinksByEntityType(String entityType) throws Exception {
317 if (entityType == null) {
318 throw new NullPointerException("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, uriSyntaxException.getMessage());