Initial commit for AAI-UI(sparky-backend)
[aai/sparky-be.git] / src / main / java / org / openecomp / sparky / dal / aai / ActiveInventoryAdapter.java
diff --git a/src/main/java/org/openecomp/sparky/dal/aai/ActiveInventoryAdapter.java b/src/main/java/org/openecomp/sparky/dal/aai/ActiveInventoryAdapter.java
new file mode 100644 (file)
index 0000000..de2085c
--- /dev/null
@@ -0,0 +1,418 @@
+/**
+ * ============LICENSE_START===================================================
+ * SPARKY (AAI UI service)
+ * ============================================================================
+ * Copyright © 2017 AT&T Intellectual Property.
+ * Copyright © 2017 Amdocs
+ * All rights reserved.
+ * ============================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=====================================================
+ *
+ * ECOMP and OpenECOMP are trademarks
+ * and service marks of AT&T Intellectual Property.
+ */
+
+package org.openecomp.sparky.dal.aai;
+
+import java.io.IOException;
+import java.net.URLEncoder;
+import java.nio.ByteBuffer;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+import org.apache.http.client.utils.URIBuilder;
+import org.openecomp.cl.api.Logger;
+import org.openecomp.cl.eelf.LoggerFactory;
+import org.openecomp.sparky.config.oxm.OxmEntityDescriptor;
+import org.openecomp.sparky.config.oxm.OxmModelLoader;
+import org.openecomp.sparky.dal.aai.config.ActiveInventoryConfig;
+import org.openecomp.sparky.dal.aai.config.ActiveInventoryRestConfig;
+import org.openecomp.sparky.dal.aai.enums.RestAuthenticationMode;
+import org.openecomp.sparky.dal.exception.ElasticSearchOperationException;
+import org.openecomp.sparky.dal.rest.OperationResult;
+import org.openecomp.sparky.dal.rest.RestClientBuilder;
+import org.openecomp.sparky.dal.rest.RestfulDataAccessor;
+import org.openecomp.sparky.logging.AaiUiMsgs;
+import org.openecomp.sparky.security.SecurityContextFactory;
+import org.openecomp.sparky.util.NodeUtils;
+
+import com.sun.jersey.api.client.Client;
+import com.sun.jersey.api.client.WebResource.Builder;
+
+
+/**
+ * The Class ActiveInventoryAdapter.
+ */
+
+/**
+ * @author davea
+ *
+ */
+public class ActiveInventoryAdapter extends RestfulDataAccessor
+    implements ActiveInventoryDataProvider {
+
+  private static final Logger LOG =
+      LoggerFactory.getInstance().getLogger(ActiveInventoryAdapter.class);
+  
+  private static final String HEADER_TRANS_ID = "X-TransactionId";
+  private static final String HEADER_FROM_APP_ID = "X-FromAppId";
+  private static final String HEADER_AUTHORIZATION = "Authorization";
+
+  private static final String TRANSACTION_ID_PREFIX = "txnId-";
+  private static final String UI_APP_NAME = "AAI-UI";
+  
+  
+  private ActiveInventoryConfig config;
+
+  /**
+   * Instantiates a new active inventory adapter.
+   *
+   * @param restClientBuilder the rest client builder
+   * @throws ElasticSearchOperationException the elastic search operation exception
+   * @throws IOException Signals that an I/O exception has occurred.
+   */
+  public ActiveInventoryAdapter(RestClientBuilder restClientBuilder)
+      throws ElasticSearchOperationException, IOException {
+    super(restClientBuilder);
+
+    try {
+      this.config = ActiveInventoryConfig.getConfig();
+    } catch (Exception exc) {
+      throw new ElasticSearchOperationException("Error getting active inventory configuration",
+          exc);
+    }
+
+    clientBuilder.setUseHttps(true);
+
+    clientBuilder.setValidateServerHostname(config.getAaiSslConfig().isValidateServerHostName());
+
+    SecurityContextFactory sslContextFactory = clientBuilder.getSslContextFactory();
+
+    sslContextFactory.setServerCertificationChainValidationEnabled(
+        config.getAaiSslConfig().isValidateServerCertificateChain());
+    
+    if (config.getAaiRestConfig().getAuthenticationMode() == RestAuthenticationMode.SSL_CERT) {
+      sslContextFactory.setClientCertFileName(config.getAaiSslConfig().getKeystoreFilename());
+      sslContextFactory.setClientCertPassword(config.getAaiSslConfig().getKeystorePassword());
+      sslContextFactory.setTrustStoreFileName(config.getAaiSslConfig().getTruststoreFilename());
+    }
+
+    clientBuilder.setConnectTimeoutInMs(config.getAaiRestConfig().getConnectTimeoutInMs());
+    clientBuilder.setReadTimeoutInMs(config.getAaiRestConfig().getReadTimeoutInMs());
+
+  }
+
+  /* (non-Javadoc)
+   * @see org.openecomp.sparky.dal.rest.RestfulDataAccessor#setClientDefaults(com.sun.jersey.api.client.Client, java.lang.String, java.lang.String, java.lang.String)
+   */
+  @Override
+  protected Builder setClientDefaults(Client client, String url, String payloadContentType,
+      String acceptContentType) {
+    Builder builder = super.setClientDefaults(client, url, payloadContentType, acceptContentType);
+
+    builder = builder.header(HEADER_FROM_APP_ID, UI_APP_NAME);
+    byte bytes[] = new byte[6];
+    txnIdGenerator.nextBytes(bytes);
+    builder =
+        builder.header(HEADER_TRANS_ID, TRANSACTION_ID_PREFIX + ByteBuffer.wrap(bytes).getInt());
+
+    if (config.getAaiRestConfig().getAuthenticationMode() == RestAuthenticationMode.SSL_BASIC) {
+      builder = builder.header(HEADER_AUTHORIZATION,
+          config.getAaiSslConfig().getBasicAuthenticationCredentials());
+    }
+
+    return builder;
+  }
+
+  /**
+   * The main method.
+   *
+   * @param args the arguments
+   */
+  public static void main(String[] args) {
+
+    // TODO Auto-generated method stub
+    RestClientBuilder builder = new RestClientBuilder();
+    RestfulDataAccessor accessor;
+    try {
+      accessor = new ActiveInventoryAdapter(builder);
+      OperationResult or =
+          accessor.doGet("/cloud-infrastructure/pservers/pserver/SQLTEST006", "application/json");
+      String jsonPatch = "{ \"hostname\" : \"SQLTEST006\", \"prov-status\" : \"PREPROV\","
+          + " \"in-maint\" : \"false\", \"is-closed-loop\" : \"false\" }";
+      or = accessor.doPatch("/cloud-infrastructure/pservers/pserver/SQLTEST006", jsonPatch,
+          "application/json");
+      // System.out.println("PATCH or = " + or.getResultCode() + " : " + or.toString());
+    } catch (ElasticSearchOperationException | IOException exc) {
+      // TODO Auto-generated catch block
+      exc.printStackTrace();
+    }
+
+  }
+
+  /**
+   * Gets the full url.
+   *
+   * @param resourceUrl the resource url
+   * @return the full url
+   * @throws Exception the exception
+   */
+  private String getFullUrl(String resourceUrl) throws Exception {
+    ActiveInventoryRestConfig aaiRestConfig = ActiveInventoryConfig.getConfig().getAaiRestConfig();
+    final String host = aaiRestConfig.getHost();
+    final String port = aaiRestConfig.getPort();
+    final String basePath = aaiRestConfig.getResourceBasePath();
+    return String.format("https://%s:%s%s%s", host, port, basePath, resourceUrl);
+  }
+  
+  public String getGenericQueryForSelfLink(String startNodeType, List<String> queryParams) throws Exception {
+    
+    URIBuilder urlBuilder = new URIBuilder(getFullUrl("/search/generic-query"));
+    
+    for( String queryParam : queryParams) {
+      urlBuilder.addParameter("key", queryParam);
+    }
+    
+    urlBuilder.addParameter("start-node-type", startNodeType);
+    urlBuilder.addParameter("include", startNodeType);
+    
+    final String constructedLink = urlBuilder.toString();
+    
+    // TODO: debug log for constructed link
+
+    return constructedLink;
+
+}
+
+
+  /* (non-Javadoc)
+   * @see org.openecomp.sparky.dal.aai.ActiveInventoryDataProvider#getSelfLinksByEntityType(java.lang.String)
+   */
+  @Override
+  public OperationResult getSelfLinksByEntityType(String entityType) throws Exception {
+
+    /*
+     * For this one, I want to dynamically construct the nodes-query for self-link discovery as a
+     * utility method that will use the OXM model entity data to drive the query as well.
+     */
+    
+    if (entityType == null) {
+      throw new NullPointerException(
+          "Failed to getSelfLinksByEntityType() because entityType is null");
+    }
+
+    OxmEntityDescriptor entityDescriptor =
+        OxmModelLoader.getInstance().getEntityDescriptor(entityType);
+
+    if (entityDescriptor == null) {
+      throw new NoSuchElementException("Failed to getSelfLinksByEntityType() because could"
+          + " not find entity descriptor from OXM with type = " + entityType);
+    }
+
+    String link = null;
+    final String primaryKeyStr =
+        NodeUtils.concatArray(entityDescriptor.getPrimaryKeyAttributeName(), "/");
+
+    link = getFullUrl("/search/nodes-query?search-node-type=" + entityType + "&filter="
+        + primaryKeyStr + ":EXISTS");
+
+
+
+    return doGet(link, "application/json");
+
+  }
+
+  /* (non-Javadoc)
+   * @see org.openecomp.sparky.dal.aai.ActiveInventoryDataProvider#getSelfLinkForEntity(java.lang.String, java.lang.String, java.lang.String)
+   */
+  @Override
+  public OperationResult getSelfLinkForEntity(String entityType, String primaryKeyName,
+      String primaryKeyValue) throws Exception {
+
+    if (entityType == null) {
+      throw new NullPointerException("Failed to getSelfLinkForEntity() because entityType is null");
+    }
+
+    if (primaryKeyName == null) {
+      throw new NullPointerException(
+          "Failed to getSelfLinkForEntity() because primaryKeyName is null");
+    }
+
+    if (primaryKeyValue == null) {
+      throw new NullPointerException(
+          "Failed to getSelfLinkForEntity() because primaryKeyValue is null");
+    }
+
+    // https://aai-int1.test.att.com:8443/aai/v8/search/generic-query?key=complex.physical-location-id:atlngade&start-node-type=complex
+
+    /*
+     * Try to protect ourselves from illegal URI formatting exceptions caused by characters that
+     * aren't natively supported in a URI, but can be escaped to make them legal.
+     */
+
+    String encodedEntityType = URLEncoder.encode(entityType, "UTF-8");
+    String encodedPrimaryKeyName = URLEncoder.encode(primaryKeyName, "UTF-8");
+    String encodedPrimaryKeyValue = URLEncoder.encode(primaryKeyValue, "UTF-8");
+
+    String link = null;
+
+    if ("service-instance".equals(entityType)) {
+
+      link = getFullUrl("/search/generic-query?key=" + encodedEntityType + "."
+          + encodedPrimaryKeyName + ":" + encodedPrimaryKeyValue + "&start-node-type="
+          + encodedEntityType + "&include=customer&depth=2");
+
+    } else {
+
+      link =
+          getFullUrl("/search/generic-query?key=" + encodedEntityType + "." + encodedPrimaryKeyName
+              + ":" + encodedPrimaryKeyValue + "&start-node-type=" + encodedEntityType);
+
+    }
+
+    return queryActiveInventoryWithRetries(link, "application/json",
+        this.config.getAaiRestConfig().getNumRequestRetries());
+
+  }
+
+
+  /**
+   * Our retry conditions should be very specific.
+   *
+   * @param r the r
+   * @return true, if successful
+   */
+  private boolean shouldRetryRequest(OperationResult r) {
+
+    if (r == null) {
+      return true;
+    }
+
+    int rc = r.getResultCode();
+
+    if (rc == 200) {
+      return false;
+    }
+
+    if (rc == 404) {
+      return false;
+    }
+
+    return true;
+
+  }
+
+  /**
+   * Query active inventory.
+   *
+   * @param url the url
+   * @param acceptContentType the accept content type
+   * @return the operation result
+   */
+  // package protected for test classes instead of private
+  OperationResult queryActiveInventory(String url, String acceptContentType) {
+    return doGet(url, acceptContentType);
+  }
+
+  /* (non-Javadoc)
+   * @see org.openecomp.sparky.dal.aai.ActiveInventoryDataProvider#queryActiveInventoryWithRetries(java.lang.String, java.lang.String, int)
+   */
+  @Override
+  public OperationResult queryActiveInventoryWithRetries(String url, String responseType,
+      int numRetries) {
+
+    OperationResult result = null;
+
+    for (int x = 0; x < numRetries; x++) {
+
+      LOG.debug(AaiUiMsgs.QUERY_AAI_RETRY_SEQ, url, String.valueOf(x + 1));
+
+      result = queryActiveInventory(url, responseType);
+
+      /**
+       * Record number of times we have attempted the request to later summarize how many times we
+       * are generally retrying over thousands of messages in a sync.
+       * 
+       * If the number of retries is surprisingly high, then we need to understand why that is as
+       * the number of retries is also causing a heavier load on AAI beyond the throttling controls
+       * we already have in place in term of the transaction rate controller and number of
+       * parallelized threads per task processor.
+       */
+
+      result.setNumRequestRetries(x);
+
+      if (!shouldRetryRequest(result)) {
+
+        /*
+         * if (myConfig.getAaiRestConfig().isCacheEnabled()) {
+         * 
+         * CachedHttpRequest cachedRequest = new CachedHttpRequest();
+         * cachedRequest.setHttpRequestMethod("GET"); cachedRequest.setPayload("");
+         * cachedRequest.setPayloadMimeType(""); cachedRequest.setUrl(url);
+         * cachedRequest.setOperationType( TransactionStorageType.ACTIVE_INVENTORY_QUERY.getIndex()
+         * );
+         * 
+         * CachedHttpResponse cachedResponse = new CachedHttpResponse();
+         * cachedResponse.setPayload(result.getResult());
+         * cachedResponse.setPayloadMimeType("application/json");
+         * cachedResponse.setStatusCode(result.getResultCode());
+         * 
+         * CachedHttpTransaction txn = new CachedHttpTransaction(cachedRequest, cachedResponse);
+         * storageProvider.persistTransaction(txn);
+         * 
+         * }
+         */
+
+
+        result.setResolvedLinkFromServer(true);
+        LOG.debug(AaiUiMsgs.QUERY_AAI_RETRY_DONE_SEQ, url, String.valueOf(x + 1));
+
+        return result;
+      }
+
+      try {
+        /*
+         * Sleep between re-tries to be nice to the target system.
+         */
+        Thread.sleep(50);
+      } catch (InterruptedException exc) {
+        LOG.error(AaiUiMsgs.QUERY_AAI_WAIT_INTERRUPTION, exc.getLocalizedMessage());
+        break;
+      }
+      LOG.error(AaiUiMsgs.QUERY_AAI_RETRY_FAILURE_WITH_SEQ, url, String.valueOf(x + 1));
+    }
+
+
+    result.setResolvedLinkFailure(true);
+    LOG.info(AaiUiMsgs.QUERY_AAI_RETRY_MAXED_OUT, url);
+
+    return result;
+
+  }
+
+  /* (non-Javadoc)
+   * @see org.openecomp.sparky.dal.rest.RestfulDataAccessor#shutdown()
+   */
+  @Override
+  public void shutdown() {
+    // TODO Auto-generated method stub
+
+    if (entityCache != null) {
+      entityCache.shutdown();
+    }
+
+  }
+
+
+}