Initial commit for AAI-UI(sparky-backend)
[aai/sparky-be.git] / src / main / java / org / openecomp / sparky / dal / aai / ActiveInventoryAdapter.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
26 package org.openecomp.sparky.dal.aai;
27
28 import java.io.IOException;
29 import java.net.URLEncoder;
30 import java.nio.ByteBuffer;
31 import java.util.List;
32 import java.util.NoSuchElementException;
33
34 import org.apache.http.client.utils.URIBuilder;
35 import org.openecomp.cl.api.Logger;
36 import org.openecomp.cl.eelf.LoggerFactory;
37 import org.openecomp.sparky.config.oxm.OxmEntityDescriptor;
38 import org.openecomp.sparky.config.oxm.OxmModelLoader;
39 import org.openecomp.sparky.dal.aai.config.ActiveInventoryConfig;
40 import org.openecomp.sparky.dal.aai.config.ActiveInventoryRestConfig;
41 import org.openecomp.sparky.dal.aai.enums.RestAuthenticationMode;
42 import org.openecomp.sparky.dal.exception.ElasticSearchOperationException;
43 import org.openecomp.sparky.dal.rest.OperationResult;
44 import org.openecomp.sparky.dal.rest.RestClientBuilder;
45 import org.openecomp.sparky.dal.rest.RestfulDataAccessor;
46 import org.openecomp.sparky.logging.AaiUiMsgs;
47 import org.openecomp.sparky.security.SecurityContextFactory;
48 import org.openecomp.sparky.util.NodeUtils;
49
50 import com.sun.jersey.api.client.Client;
51 import com.sun.jersey.api.client.WebResource.Builder;
52
53
54 /**
55  * The Class ActiveInventoryAdapter.
56  */
57
58 /**
59  * @author davea
60  *
61  */
62 public class ActiveInventoryAdapter extends RestfulDataAccessor
63     implements ActiveInventoryDataProvider {
64
65   private static final Logger LOG =
66       LoggerFactory.getInstance().getLogger(ActiveInventoryAdapter.class);
67   
68   private static final String HEADER_TRANS_ID = "X-TransactionId";
69   private static final String HEADER_FROM_APP_ID = "X-FromAppId";
70   private static final String HEADER_AUTHORIZATION = "Authorization";
71
72   private static final String TRANSACTION_ID_PREFIX = "txnId-";
73   private static final String UI_APP_NAME = "AAI-UI";
74   
75   
76   private ActiveInventoryConfig config;
77
78   /**
79    * Instantiates a new active inventory adapter.
80    *
81    * @param restClientBuilder the rest client builder
82    * @throws ElasticSearchOperationException the elastic search operation exception
83    * @throws IOException Signals that an I/O exception has occurred.
84    */
85   public ActiveInventoryAdapter(RestClientBuilder restClientBuilder)
86       throws ElasticSearchOperationException, IOException {
87     super(restClientBuilder);
88
89     try {
90       this.config = ActiveInventoryConfig.getConfig();
91     } catch (Exception exc) {
92       throw new ElasticSearchOperationException("Error getting active inventory configuration",
93           exc);
94     }
95
96     clientBuilder.setUseHttps(true);
97
98     clientBuilder.setValidateServerHostname(config.getAaiSslConfig().isValidateServerHostName());
99
100     SecurityContextFactory sslContextFactory = clientBuilder.getSslContextFactory();
101
102     sslContextFactory.setServerCertificationChainValidationEnabled(
103         config.getAaiSslConfig().isValidateServerCertificateChain());
104     
105     if (config.getAaiRestConfig().getAuthenticationMode() == RestAuthenticationMode.SSL_CERT) {
106       sslContextFactory.setClientCertFileName(config.getAaiSslConfig().getKeystoreFilename());
107       sslContextFactory.setClientCertPassword(config.getAaiSslConfig().getKeystorePassword());
108       sslContextFactory.setTrustStoreFileName(config.getAaiSslConfig().getTruststoreFilename());
109     }
110
111     clientBuilder.setConnectTimeoutInMs(config.getAaiRestConfig().getConnectTimeoutInMs());
112     clientBuilder.setReadTimeoutInMs(config.getAaiRestConfig().getReadTimeoutInMs());
113
114   }
115
116   /* (non-Javadoc)
117    * @see org.openecomp.sparky.dal.rest.RestfulDataAccessor#setClientDefaults(com.sun.jersey.api.client.Client, java.lang.String, java.lang.String, java.lang.String)
118    */
119   @Override
120   protected Builder setClientDefaults(Client client, String url, String payloadContentType,
121       String acceptContentType) {
122     Builder builder = super.setClientDefaults(client, url, payloadContentType, acceptContentType);
123
124     builder = builder.header(HEADER_FROM_APP_ID, UI_APP_NAME);
125     byte bytes[] = new byte[6];
126     txnIdGenerator.nextBytes(bytes);
127     builder =
128         builder.header(HEADER_TRANS_ID, TRANSACTION_ID_PREFIX + ByteBuffer.wrap(bytes).getInt());
129
130     if (config.getAaiRestConfig().getAuthenticationMode() == RestAuthenticationMode.SSL_BASIC) {
131       builder = builder.header(HEADER_AUTHORIZATION,
132           config.getAaiSslConfig().getBasicAuthenticationCredentials());
133     }
134
135     return builder;
136   }
137
138   /**
139    * The main method.
140    *
141    * @param args the arguments
142    */
143   public static void main(String[] args) {
144
145     // TODO Auto-generated method stub
146     RestClientBuilder builder = new RestClientBuilder();
147     RestfulDataAccessor accessor;
148     try {
149       accessor = new ActiveInventoryAdapter(builder);
150       OperationResult or =
151           accessor.doGet("/cloud-infrastructure/pservers/pserver/SQLTEST006", "application/json");
152       String jsonPatch = "{ \"hostname\" : \"SQLTEST006\", \"prov-status\" : \"PREPROV\","
153           + " \"in-maint\" : \"false\", \"is-closed-loop\" : \"false\" }";
154       or = accessor.doPatch("/cloud-infrastructure/pservers/pserver/SQLTEST006", jsonPatch,
155           "application/json");
156       // System.out.println("PATCH or = " + or.getResultCode() + " : " + or.toString());
157     } catch (ElasticSearchOperationException | IOException exc) {
158       // TODO Auto-generated catch block
159       exc.printStackTrace();
160     }
161
162   }
163
164   /**
165    * Gets the full url.
166    *
167    * @param resourceUrl the resource url
168    * @return the full url
169    * @throws Exception the exception
170    */
171   private String getFullUrl(String resourceUrl) throws Exception {
172     ActiveInventoryRestConfig aaiRestConfig = ActiveInventoryConfig.getConfig().getAaiRestConfig();
173     final String host = aaiRestConfig.getHost();
174     final String port = aaiRestConfig.getPort();
175     final String basePath = aaiRestConfig.getResourceBasePath();
176     return String.format("https://%s:%s%s%s", host, port, basePath, resourceUrl);
177   }
178   
179   public String getGenericQueryForSelfLink(String startNodeType, List<String> queryParams) throws Exception {
180     
181     URIBuilder urlBuilder = new URIBuilder(getFullUrl("/search/generic-query"));
182     
183     for( String queryParam : queryParams) {
184       urlBuilder.addParameter("key", queryParam);
185     }
186     
187     urlBuilder.addParameter("start-node-type", startNodeType);
188     urlBuilder.addParameter("include", startNodeType);
189     
190     final String constructedLink = urlBuilder.toString();
191     
192     // TODO: debug log for constructed link
193
194     return constructedLink;
195
196 }
197
198
199   /* (non-Javadoc)
200    * @see org.openecomp.sparky.dal.aai.ActiveInventoryDataProvider#getSelfLinksByEntityType(java.lang.String)
201    */
202   @Override
203   public OperationResult getSelfLinksByEntityType(String entityType) throws Exception {
204
205     /*
206      * For this one, I want to dynamically construct the nodes-query for self-link discovery as a
207      * utility method that will use the OXM model entity data to drive the query as well.
208      */
209     
210     if (entityType == null) {
211       throw new NullPointerException(
212           "Failed to getSelfLinksByEntityType() because entityType is null");
213     }
214
215     OxmEntityDescriptor entityDescriptor =
216         OxmModelLoader.getInstance().getEntityDescriptor(entityType);
217
218     if (entityDescriptor == null) {
219       throw new NoSuchElementException("Failed to getSelfLinksByEntityType() because could"
220           + " not find entity descriptor from OXM with type = " + entityType);
221     }
222
223     String link = null;
224     final String primaryKeyStr =
225         NodeUtils.concatArray(entityDescriptor.getPrimaryKeyAttributeName(), "/");
226
227     link = getFullUrl("/search/nodes-query?search-node-type=" + entityType + "&filter="
228         + primaryKeyStr + ":EXISTS");
229
230
231
232     return doGet(link, "application/json");
233
234   }
235
236   /* (non-Javadoc)
237    * @see org.openecomp.sparky.dal.aai.ActiveInventoryDataProvider#getSelfLinkForEntity(java.lang.String, java.lang.String, java.lang.String)
238    */
239   @Override
240   public OperationResult getSelfLinkForEntity(String entityType, String primaryKeyName,
241       String primaryKeyValue) throws Exception {
242
243     if (entityType == null) {
244       throw new NullPointerException("Failed to getSelfLinkForEntity() because entityType is null");
245     }
246
247     if (primaryKeyName == null) {
248       throw new NullPointerException(
249           "Failed to getSelfLinkForEntity() because primaryKeyName is null");
250     }
251
252     if (primaryKeyValue == null) {
253       throw new NullPointerException(
254           "Failed to getSelfLinkForEntity() because primaryKeyValue is null");
255     }
256
257     // https://aai-int1.test.att.com:8443/aai/v8/search/generic-query?key=complex.physical-location-id:atlngade&start-node-type=complex
258
259     /*
260      * Try to protect ourselves from illegal URI formatting exceptions caused by characters that
261      * aren't natively supported in a URI, but can be escaped to make them legal.
262      */
263
264     String encodedEntityType = URLEncoder.encode(entityType, "UTF-8");
265     String encodedPrimaryKeyName = URLEncoder.encode(primaryKeyName, "UTF-8");
266     String encodedPrimaryKeyValue = URLEncoder.encode(primaryKeyValue, "UTF-8");
267
268     String link = null;
269
270     if ("service-instance".equals(entityType)) {
271
272       link = getFullUrl("/search/generic-query?key=" + encodedEntityType + "."
273           + encodedPrimaryKeyName + ":" + encodedPrimaryKeyValue + "&start-node-type="
274           + encodedEntityType + "&include=customer&depth=2");
275
276     } else {
277
278       link =
279           getFullUrl("/search/generic-query?key=" + encodedEntityType + "." + encodedPrimaryKeyName
280               + ":" + encodedPrimaryKeyValue + "&start-node-type=" + encodedEntityType);
281
282     }
283
284     return queryActiveInventoryWithRetries(link, "application/json",
285         this.config.getAaiRestConfig().getNumRequestRetries());
286
287   }
288
289
290   /**
291    * Our retry conditions should be very specific.
292    *
293    * @param r the r
294    * @return true, if successful
295    */
296   private boolean shouldRetryRequest(OperationResult r) {
297
298     if (r == null) {
299       return true;
300     }
301
302     int rc = r.getResultCode();
303
304     if (rc == 200) {
305       return false;
306     }
307
308     if (rc == 404) {
309       return false;
310     }
311
312     return true;
313
314   }
315
316   /**
317    * Query active inventory.
318    *
319    * @param url the url
320    * @param acceptContentType the accept content type
321    * @return the operation result
322    */
323   // package protected for test classes instead of private
324   OperationResult queryActiveInventory(String url, String acceptContentType) {
325     return doGet(url, acceptContentType);
326   }
327
328   /* (non-Javadoc)
329    * @see org.openecomp.sparky.dal.aai.ActiveInventoryDataProvider#queryActiveInventoryWithRetries(java.lang.String, java.lang.String, int)
330    */
331   @Override
332   public OperationResult queryActiveInventoryWithRetries(String url, String responseType,
333       int numRetries) {
334
335     OperationResult result = null;
336
337     for (int x = 0; x < numRetries; x++) {
338
339       LOG.debug(AaiUiMsgs.QUERY_AAI_RETRY_SEQ, url, String.valueOf(x + 1));
340
341       result = queryActiveInventory(url, responseType);
342
343       /**
344        * Record number of times we have attempted the request to later summarize how many times we
345        * are generally retrying over thousands of messages in a sync.
346        * 
347        * If the number of retries is surprisingly high, then we need to understand why that is as
348        * the number of retries is also causing a heavier load on AAI beyond the throttling controls
349        * we already have in place in term of the transaction rate controller and number of
350        * parallelized threads per task processor.
351        */
352
353       result.setNumRequestRetries(x);
354
355       if (!shouldRetryRequest(result)) {
356
357         /*
358          * if (myConfig.getAaiRestConfig().isCacheEnabled()) {
359          * 
360          * CachedHttpRequest cachedRequest = new CachedHttpRequest();
361          * cachedRequest.setHttpRequestMethod("GET"); cachedRequest.setPayload("");
362          * cachedRequest.setPayloadMimeType(""); cachedRequest.setUrl(url);
363          * cachedRequest.setOperationType( TransactionStorageType.ACTIVE_INVENTORY_QUERY.getIndex()
364          * );
365          * 
366          * CachedHttpResponse cachedResponse = new CachedHttpResponse();
367          * cachedResponse.setPayload(result.getResult());
368          * cachedResponse.setPayloadMimeType("application/json");
369          * cachedResponse.setStatusCode(result.getResultCode());
370          * 
371          * CachedHttpTransaction txn = new CachedHttpTransaction(cachedRequest, cachedResponse);
372          * storageProvider.persistTransaction(txn);
373          * 
374          * }
375          */
376
377
378         result.setResolvedLinkFromServer(true);
379         LOG.debug(AaiUiMsgs.QUERY_AAI_RETRY_DONE_SEQ, url, String.valueOf(x + 1));
380
381         return result;
382       }
383
384       try {
385         /*
386          * Sleep between re-tries to be nice to the target system.
387          */
388         Thread.sleep(50);
389       } catch (InterruptedException exc) {
390         LOG.error(AaiUiMsgs.QUERY_AAI_WAIT_INTERRUPTION, exc.getLocalizedMessage());
391         break;
392       }
393       LOG.error(AaiUiMsgs.QUERY_AAI_RETRY_FAILURE_WITH_SEQ, url, String.valueOf(x + 1));
394     }
395
396
397     result.setResolvedLinkFailure(true);
398     LOG.info(AaiUiMsgs.QUERY_AAI_RETRY_MAXED_OUT, url);
399
400     return result;
401
402   }
403
404   /* (non-Javadoc)
405    * @see org.openecomp.sparky.dal.rest.RestfulDataAccessor#shutdown()
406    */
407   @Override
408   public void shutdown() {
409     // TODO Auto-generated method stub
410
411     if (entityCache != null) {
412       entityCache.shutdown();
413     }
414
415   }
416
417
418 }