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