3ededcc547d3bd3dc40c3dd4916b07944d5dfde5
[ccsdk/sli.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * openECOMP : SDN-C
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights
6  *                         reserved.
7  * ================================================================================
8  * Modifications Copyright (C) 2018 IBM.
9  * ================================================================================
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  *      http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  * ============LICENSE_END=========================================================
22  */
23
24 package org.onap.ccsdk.sli.adaptors.aai;
25
26 import java.io.BufferedReader;
27 import java.io.ByteArrayInputStream;
28 import java.io.File;
29 import java.io.FileInputStream;
30 import java.io.InputStream;
31 import java.io.InputStreamReader;
32 import java.io.OutputStreamWriter;
33 import java.lang.reflect.Field;
34 import java.lang.reflect.InvocationTargetException;
35 import java.lang.reflect.Method;
36 import java.lang.reflect.Modifier;
37 import java.net.HttpURLConnection;
38 import java.net.MalformedURLException;
39 import java.net.URISyntaxException;
40 import java.net.URL;
41 import java.nio.charset.StandardCharsets;
42 import java.security.KeyManagementException;
43 import java.security.KeyStore;
44 import java.security.NoSuchAlgorithmException;
45 import java.text.SimpleDateFormat;
46 import java.util.Properties;
47
48 import javax.net.ssl.HttpsURLConnection;
49 import javax.net.ssl.KeyManagerFactory;
50 import javax.net.ssl.SSLContext;
51 import javax.net.ssl.SSLSession;
52 import javax.net.ssl.SSLSocketFactory;
53
54 import org.apache.commons.codec.binary.Base64;
55 import org.apache.commons.lang3.ObjectUtils;
56 import org.onap.ccsdk.sli.adaptors.aai.AAIService.TransactionIdTracker;
57 import org.onap.ccsdk.sli.adaptors.aai.data.AAIDatum;
58 import org.onap.ccsdk.sli.adaptors.aai.data.ErrorResponse;
59 import org.onap.ccsdk.sli.adaptors.aai.data.RequestError;
60 import org.onap.ccsdk.sli.adaptors.aai.data.ResourceVersion;
61 import org.onap.ccsdk.sli.adaptors.aai.data.ServiceException;
62 import org.onap.ccsdk.sli.adaptors.aai.update.BulkUpdateResponseData;
63 import org.onap.ccsdk.sli.core.sli.MetricLogger;
64 import org.onap.logging.ref.slf4j.ONAPLogConstants;
65 import org.slf4j.Logger;
66 import org.slf4j.LoggerFactory;
67
68 import com.fasterxml.jackson.databind.DeserializationFeature;
69 import com.fasterxml.jackson.databind.ObjectMapper;
70
71 import org.apache.http.client.utils.URIBuilder;
72 import org.apache.http.impl.EnglishReasonPhraseCatalog;
73
74 /**
75  * The AAIClientRESTExecutor class provides CRUD API for AAI Client service.
76  * @author  Rich Tabedzki
77  */
78 public class AAIClientRESTExecutor implements AAIExecutorInterface {
79
80     private final String truststorePath;
81     private final String truststorePassword;
82     private final String keystorePath;
83     private final String keystorePassword;
84     private final Boolean ignoreCertificateHostError;
85     // authentication credentials
86     private String userName;
87     private String userPassword;
88     private final String applicationId;
89     private static final String HTTP_URL_CONNECTION_RESULT="HttpURLConnection result: {} : {}";
90     private static final String ENTRY_DOESNT_EXIST="Entry does not exist.";
91
92     /**
93      * class Constructor
94      * @param props - properties to initialize an instance.
95      */
96     public AAIClientRESTExecutor(Properties props) {
97         super();
98
99         userName            = props.getProperty(AAIService.CLIENT_NAME);
100         userPassword        = props.getProperty(AAIService.CLIENT_PWWD);
101
102         if(userName == null || userName.isEmpty()){
103             LOG.debug("Basic user name is not set");
104         }
105         if(userPassword == null || userPassword.isEmpty()) {
106             LOG.debug("Basic password is not set");
107         }
108
109         truststorePath     = props.getProperty(AAIService.TRUSTSTORE_PATH);
110         truststorePassword = props.getProperty(AAIService.TRUSTSTORE_PSSWD);
111         keystorePath         = props.getProperty(AAIService.KEYSTORE_PATH);
112         keystorePassword     = props.getProperty(AAIService.KEYSTORE_PSSWD);
113
114         String tmpApplicationId =props.getProperty(AAIService.APPLICATION_ID);
115         if(tmpApplicationId == null || tmpApplicationId.isEmpty()) {
116             tmpApplicationId = "SDNC";
117         }
118         applicationId = tmpApplicationId;
119
120         String iche = props.getProperty(AAIService.CERTIFICATE_HOST_ERROR);
121         boolean host_error = false;
122         if(iche != null && !iche.isEmpty()) {
123             host_error = Boolean.valueOf(iche);
124         }
125
126         ignoreCertificateHostError = host_error;
127
128         HttpsURLConnection.setDefaultHostnameVerifier( (String string,SSLSession ssls)  -> {
129              return ignoreCertificateHostError;
130             
131         });
132
133         if(truststorePath != null && truststorePassword != null && (new File(truststorePath)).exists()) {
134             System.setProperty("javax.net.ssl.trustStore", truststorePath);
135             System.setProperty("javax.net.ssl.trustStorePassword", truststorePassword);
136         }
137
138         if(keystorePath != null && keystorePassword != null && (new File(keystorePath)).exists())
139         {
140             //both jersey and HttpURLConnection can use this
141             SSLContext ctx = null;
142             try {
143                 ctx = SSLContext.getInstance("TLS");
144
145                 KeyManagerFactory kmf = null;
146                 try (FileInputStream fin = new FileInputStream(keystorePath)){
147                     String storeType = "PKCS12";
148                     String def = KeyStore.getDefaultType();
149                     kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
150
151                     String extension = keystorePath.substring(keystorePath.lastIndexOf(".") + 1);
152
153                     if(extension != null && !extension.isEmpty() && "JKS".equalsIgnoreCase(extension)) {
154                         storeType = "JKS";
155                     }
156                     KeyStore ks = KeyStore.getInstance(storeType);
157
158                     char[] pwd = keystorePassword.toCharArray();
159                     ks.load(fin, pwd);
160                     kmf.init(ks, pwd);
161                 } catch (Exception ex) {
162                     LOG.error("AAIResource", ex);
163                 }
164                 if (ObjectUtils.anyNotNull(kmf)) {
165                     ctx.init(kmf.getKeyManagers(), null, null);
166                 }
167
168                 CTX = ctx;
169                 LOG.debug("SSLContext created");
170
171             } catch (KeyManagementException | NoSuchAlgorithmException exc) {
172                 LOG.error("AAIResource", exc);
173             }
174         }
175
176         try {
177             Field methodsField = HttpURLConnection.class.getDeclaredField("methods");
178             methodsField.setAccessible(true);
179             // get the methods field modifiers
180             Field modifiersField = Field.class.getDeclaredField("modifiers");
181             // bypass the "private" modifier
182             modifiersField.setAccessible(true);
183
184             // remove the "final" modifier
185             modifiersField.setInt(methodsField, methodsField.getModifiers() & ~Modifier.FINAL);
186
187             /* valid HTTP methods */
188             String[] methods = {
189                        "GET", "POST", "HEAD", "OPTIONS", "PUT", "DELETE", "TRACE", "PATCH"
190             };
191             // set the new methods - including patch
192             methodsField.set(null, methods);
193
194         } catch (SecurityException | IllegalArgumentException | IllegalAccessException | NoSuchFieldException e) {
195             LOG.warn("Adding PATCH method", e);
196         }
197         LOG.info("AAIResource.ctor initialized.");
198
199     }
200
201     private static final Logger LOG = LoggerFactory.getLogger(AAIService.class);
202     private static final String NOT_PROVIDED = "NOT PROVIDED";
203     private final MetricLogger ml = new MetricLogger();
204
205     private SSLContext CTX;
206
207
208     private int connection_timeout = 300000;
209
210     private int read_timeout = 300000;
211
212     /**
213      * Returns an String that contains JSON data returned from the AAI Server.
214      * <p>
215      * This method always returns immediately, whether or not the
216      * data exists.
217      *
218      * @param  request  an instance of AAIRequiest representing
219      *                 the request made by DirectedGraph node.
220      * @return      the JSON based representation of data instance requested.
221      * @see         String
222      */
223     @Override
224     public String get(AAIRequest request) throws AAIServiceException {
225         String response = null;
226         InputStream inputStream = null;
227         HttpURLConnection con = null;
228         URL requestUrl = null;
229
230         StringBuilder errorStringBuilder = new StringBuilder();
231
232         try {
233
234             if(request.getRequestObject() != null) {
235                 requestUrl = request.getRequestUrl(HttpMethod.POST, null);
236                 requestUrl = appendDepth(requestUrl, request);
237                 LOG.info(String.format("%s : %s", HttpMethod.GET, requestUrl.toString()));
238                 con = getConfiguredConnection(requestUrl, HttpMethod.POST);
239                 String json_text = request.toJSONString();
240                 LOGwriteDateTrace("data", json_text);
241                 logMetricRequest("POST "+requestUrl.toString(), json_text, requestUrl.toString());
242                 OutputStreamWriter osw = new OutputStreamWriter(con.getOutputStream());
243                 osw.write(json_text);
244                 osw.flush();
245             } else {
246                 requestUrl = request.getRequestUrl(HttpMethod.GET, null);
247                 requestUrl = appendDepth(requestUrl, request);
248                 LOG.info(String.format("%s : %s", HttpMethod.GET, requestUrl.toString()));
249                 con = getConfiguredConnection(requestUrl, HttpMethod.GET);
250                 logMetricRequest("GET "+requestUrl.toString(), "", requestUrl.toString());
251             }
252
253             // Check for errors
254             int responseCode = con.getResponseCode();
255             if (responseCode == HttpURLConnection.HTTP_OK) {
256                 inputStream = con.getInputStream();
257             } else {
258                 inputStream = con.getErrorStream();
259             }
260             String responseMessage = null;
261             try {
262                 responseMessage = con.getResponseMessage();
263             } catch(Exception exc) {
264                 responseMessage = EnglishReasonPhraseCatalog.INSTANCE.getReason(responseCode,null);
265             } finally {
266                 if(responseMessage == null)
267                         responseMessage = NOT_PROVIDED;
268             }
269
270             // Process the response
271             LOG.info(HTTP_URL_CONNECTION_RESULT, responseCode, responseMessage);
272             logMetricResponse(responseCode, responseMessage);
273
274             if(inputStream == null) inputStream = new ByteArrayInputStream("".getBytes(StandardCharsets.UTF_8));
275             BufferedReader reader = new BufferedReader( new InputStreamReader( inputStream ) );
276
277             ObjectMapper mapper = AAIService.getObjectMapper();
278
279             if (responseCode == HttpURLConnection.HTTP_OK) {
280                 StringBuilder stringBuilder = new StringBuilder();
281                 String line = null;
282                 while( ( line = reader.readLine() ) != null ) {
283                     stringBuilder.append( line );
284                 }
285                 response = stringBuilder.toString();
286                 try {
287                     Object object = mapper.readValue(response, Object.class);
288                     LOGwriteEndingTrace(HttpURLConnection.HTTP_OK, responseMessage, mapper.writeValueAsString(object));
289                 } catch(Exception exc) {
290                     LOGwriteEndingTrace(HttpURLConnection.HTTP_OK, responseMessage, mapper.writeValueAsString(response));
291                 }
292             } else if (responseCode == HttpURLConnection.HTTP_NOT_FOUND) {
293                 LOGwriteEndingTrace(responseCode, responseMessage, ENTRY_DOESNT_EXIST);
294                 ErrorResponse errorresponse = null;
295                 try {
296                     errorresponse = mapper.readValue(reader, ErrorResponse.class);
297                 } catch(Exception exc) {
298                     errorresponse = new ErrorResponse();
299                     RequestError requestError = new RequestError();
300                     ServiceException serviceException = new ServiceException();
301                     serviceException.setText(ENTRY_DOESNT_EXIST);
302                     requestError.setServiceException(serviceException);
303                     errorresponse.setRequestError(requestError );
304                 }
305                 throw new AAIServiceException(responseCode, errorresponse);
306             } else if (responseCode == HttpURLConnection.HTTP_UNAUTHORIZED) {
307                 StringBuilder stringBuilder = new StringBuilder();
308                 String line = null;
309                 while( ( line = reader.readLine() ) != null ) {
310                     stringBuilder.append( line );
311                 }
312                 LOGwriteEndingTrace(responseCode, responseMessage, stringBuilder.toString());
313                 ServiceException serviceException = new ServiceException();
314                 serviceException.setMessageId("HTTP_UNAUTHORIZED");
315                 serviceException.setText(stringBuilder.toString());
316                 RequestError requestError = new RequestError();
317                 requestError.setServiceException(serviceException);
318                 ErrorResponse errorresponse = new ErrorResponse();
319                 errorresponse.setRequestError(requestError);
320                 throw new AAIServiceException(responseCode, errorresponse);
321             } else {
322                 String line = null;
323                 while( ( line = reader.readLine() ) != null ) {
324                     errorStringBuilder.append("\n").append( line );
325                 }
326
327                 ErrorResponse errorresponse = mapper.readValue(errorStringBuilder.toString(), ErrorResponse.class);
328                 LOGwriteEndingTrace(responseCode, responseMessage, mapper.writeValueAsString(errorresponse));
329                 throw new AAIServiceException(responseCode, errorresponse);
330             }
331
332         } catch(AAIServiceException aaiexc) {
333             throw aaiexc;
334         } catch (Exception exc) {
335             LOG.warn(errorStringBuilder.toString(), exc);
336             throw new AAIServiceException(exc);
337         } finally {
338             if(inputStream != null){
339                 try {
340                     inputStream.close();
341                 } catch(Exception exc) {
342                     LOG.warn("", exc);
343                 }
344             }
345         }
346         return response;
347     }
348
349     /**
350      * Returns an String that contains JSON data returned from the AAI Server.
351      * <p>
352      * This method always returns immediately, whether or not the
353      * data exists.
354      *
355      * @param  request  an instance of AAIRequiest representing
356      *                 the request made by DirectedGraph node.
357      * @return      the JSON based representation of data instance requested.
358      * @see         String
359      */
360     @Override
361     public String post(AAIRequest request) throws AAIServiceException {
362         InputStream inputStream = null;
363
364         try {
365             String resourceVersion = null;
366             AAIDatum instance = request.getRequestObject();
367
368             try {
369                 Method getResourceVersionMethod = instance.getClass().getMethod("getResourceVersion");
370                 if(getResourceVersionMethod != null){
371                     try {
372                         Object object = getResourceVersionMethod.invoke(instance);
373                         if(object != null)
374                             resourceVersion = object.toString();
375                     } catch (InvocationTargetException exc) {
376                         LOG.warn("", exc);
377                     }
378                 }
379             } catch(Exception exc) {
380                 LOG.error("", exc);
381             }
382
383             URL requestUrl = request.getRequestUrl(HttpMethod.PUT, resourceVersion);
384             HttpURLConnection con = getConfiguredConnection(requestUrl, HttpMethod.PUT);
385             String jsonText = request.toJSONString();
386             LOGwriteDateTrace("data", jsonText);
387
388             if(jsonText!=null) {
389                     OutputStreamWriter osw = new OutputStreamWriter(con.getOutputStream());
390                     osw.write(jsonText);
391                     osw.flush();
392                     osw.close();
393             }
394             logMetricRequest("PUT "+requestUrl.toString(), jsonText, requestUrl.toString());
395
396
397             // Check for errors
398             int responseCode = con.getResponseCode();
399             if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_CREATED || responseCode == HttpURLConnection.HTTP_ACCEPTED || responseCode == HttpURLConnection.HTTP_NO_CONTENT) {
400                 inputStream = con.getInputStream();
401             } else {
402                 inputStream = con.getErrorStream();
403             }
404             String responseMessage = null;
405             try {
406                 responseMessage = con.getResponseMessage();
407             } catch(Exception exc) {
408                 responseMessage = EnglishReasonPhraseCatalog.INSTANCE.getReason(responseCode,null);
409             } finally {
410                 if(responseMessage == null)
411                         responseMessage = NOT_PROVIDED;
412             }
413
414             LOG.info(HTTP_URL_CONNECTION_RESULT, responseCode, responseMessage);
415             logMetricResponse(responseCode, responseMessage);
416
417             // Process the response
418             ObjectMapper mapper = AAIService.getObjectMapper();
419             BufferedReader reader;
420             String line = null;
421             reader = new BufferedReader( new InputStreamReader( inputStream ) );
422             mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
423
424             if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_CREATED || responseCode == HttpURLConnection.HTTP_ACCEPTED || responseCode == HttpURLConnection.HTTP_NO_CONTENT) {
425                 StringBuilder stringBuilder = new StringBuilder();
426
427                 while( ( line = reader.readLine() ) != null ) {
428                     stringBuilder.append( line );
429                 }
430                 LOGwriteEndingTrace(responseCode, responseMessage, (stringBuilder.length() > 0) ? stringBuilder.toString() : "{no-data}");
431                 return stringBuilder.toString();
432             } else {
433                 ErrorResponse errorresponse = mapper.readValue(reader, ErrorResponse.class);
434                 LOGwriteEndingTrace(responseCode, responseMessage, mapper.writeValueAsString(errorresponse));
435
436                 throw new AAIServiceException(responseCode, errorresponse);
437             }
438         } catch(AAIServiceException aaiexc) {
439             throw aaiexc;
440         } catch (Exception exc) {
441             LOG.warn("AAIRequestExecutor.post", exc);
442             throw new AAIServiceException(exc);
443         } finally {
444             try {
445                 if(inputStream != null)
446                 inputStream.close();
447             } catch (Exception exc) {
448                 LOG.warn("AAIRequestExecutor.post", exc);
449             }
450         }
451     }
452
453     /**
454      * Returns Boolean that contains completion state of the command executed.
455      * <p>
456      * This method always returns immediately, whether or not the
457      * data exists.
458      *
459      * @param  request  an instance of AAIRequiest representing
460      * @param  resourceVersion  a resource version of the data instacne to be deleted.
461      *                 the request made by DirectedGraph node.
462      * @return      completion state of the command.
463      * @see         String
464      */
465     @Override
466     public Boolean delete(AAIRequest request, String resourceVersion) throws AAIServiceException {
467         Boolean response = null;
468         InputStream inputStream = null;
469
470         if(resourceVersion == null) {
471             throw new AAIServiceException("resource-version is required for DELETE request");
472         }
473
474         try {
475             URL requestUrl = request.getRequestUrl(HttpMethod.DELETE, resourceVersion);
476             HttpURLConnection conn = getConfiguredConnection(requestUrl, HttpMethod.DELETE);
477             logMetricRequest("DELETE "+requestUrl.getPath(), "", requestUrl.getPath());
478             conn.setDoOutput(true);
479
480             // Check for errors
481             int responseCode = conn.getResponseCode();
482             if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_NO_CONTENT) {
483                 inputStream = conn.getInputStream();
484             } else {
485                 inputStream = conn.getErrorStream();
486             }
487             String responseMessage = null;
488             try {
489                 responseMessage = conn.getResponseMessage();
490             } catch(Exception exc) {
491                 responseMessage = EnglishReasonPhraseCatalog.INSTANCE.getReason(responseCode,null);
492             } finally {
493                 if(responseMessage == null)
494                         responseMessage = NOT_PROVIDED;
495             }
496
497             // Process the response
498             LOG.info(HTTP_URL_CONNECTION_RESULT, responseCode, responseMessage);
499             logMetricResponse(responseCode, responseMessage);
500
501             if(inputStream == null) inputStream = new ByteArrayInputStream("".getBytes(StandardCharsets.UTF_8));
502             BufferedReader reader = new BufferedReader( new InputStreamReader( inputStream ) );
503             String line = null;
504
505             ObjectMapper mapper = AAIService.getObjectMapper();
506
507             if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_NO_CONTENT) {
508                 StringBuilder stringBuilder = new StringBuilder();
509
510                 while( ( line = reader.readLine() ) != null ) {
511                     stringBuilder.append( line );
512                 }
513                 LOGwriteEndingTrace(responseCode, responseMessage, stringBuilder.toString());
514                 response = true;
515             } else if(responseCode == HttpURLConnection.HTTP_NOT_FOUND ) {
516                 LOGwriteEndingTrace(responseCode, responseMessage, ENTRY_DOESNT_EXIST);
517                 response = false;
518             } else {
519                 ErrorResponse errorresponse = mapper.readValue(reader, ErrorResponse.class);
520                 LOGwriteEndingTrace(responseCode, responseMessage, mapper.writeValueAsString(errorresponse));
521                 throw new AAIServiceException(responseCode, errorresponse);
522             }
523         } catch(AAIServiceException aaiexc) {
524             throw aaiexc;
525         } catch (Exception exc) {
526             LOG.warn("delete", exc);
527             throw new AAIServiceException(exc);
528         } finally {
529             if(inputStream != null){
530                 try {
531                     inputStream.close();
532                 } catch(Exception exc) {
533                     LOG.warn("delete", exc);
534                 }
535             }
536         }
537         return response;
538     }
539
540     /**
541      * Returns an String that contains JSON data returned from the AAI Server.
542      * <p>
543      * This method always returns immediately, whether or not the
544      * data exists.
545      *
546      * @param  request  an instance of AAIRequiest representing
547      *                 the request made by DirectedGraph node.
548      * @param clas   an definition of the class for which data will be returned
549      * @return      the instance of the class with data.
550      * @see         String
551      */
552     @Override
553     public Object query(AAIRequest request, Class clas) throws AAIServiceException {
554         Object response = null;
555         InputStream inputStream = null;
556
557         try {
558             URL requestUrl = request.getRequestQueryUrl(HttpMethod.GET);
559             HttpURLConnection con = getConfiguredConnection(requestUrl, HttpMethod.GET);
560             logMetricRequest("GET "+requestUrl.getPath(), "", requestUrl.getPath());
561
562             // Check for errors
563             int responseCode = con.getResponseCode();
564             if (responseCode == HttpURLConnection.HTTP_OK) {
565                 inputStream = con.getInputStream();
566             } else {
567                 inputStream = con.getErrorStream();
568             }
569             String responseMessage = null;
570             try {
571                 responseMessage = con.getResponseMessage();
572             } catch(Exception exc) {
573                 responseMessage = EnglishReasonPhraseCatalog.INSTANCE.getReason(responseCode,null);
574             } finally {
575                 if(responseMessage == null)
576                         responseMessage = NOT_PROVIDED;
577             }
578
579             LOG.info(HTTP_URL_CONNECTION_RESULT, responseCode, responseMessage);
580             logMetricResponse(responseCode, responseMessage);
581             ObjectMapper mapper = AAIService.getObjectMapper();
582
583             if (responseCode == HttpURLConnection.HTTP_OK) {
584                 // Process the response
585                 BufferedReader reader = new BufferedReader( new InputStreamReader( inputStream ) );
586                 response = mapper.readValue(reader, clas);
587                 LOGwriteEndingTrace(HttpURLConnection.HTTP_OK, "SUCCESS", mapper.writeValueAsString(response));
588             } else if (responseCode == HttpURLConnection.HTTP_NOT_FOUND) {
589                 LOGwriteEndingTrace(responseCode, "HTTP_NOT_FOUND", ENTRY_DOESNT_EXIST);
590                 return response;
591             } else {
592                 BufferedReader reader = new BufferedReader( new InputStreamReader( inputStream ) );
593                 ErrorResponse errorresponse = mapper.readValue(reader, ErrorResponse.class);
594                 LOGwriteEndingTrace(responseCode, "FAILURE", mapper.writeValueAsString(errorresponse));
595                 throw new AAIServiceException(responseCode, errorresponse);
596             }
597
598         } catch(AAIServiceException aaiexc) {
599             throw aaiexc;
600         } catch (Exception exc) {
601             LOG.warn("GET", exc);
602             throw new AAIServiceException(exc);
603         } finally {
604             if(inputStream != null){
605                 try {
606                     inputStream.close();
607                 } catch(Exception exc) {
608                     LOG.warn("GET", exc);
609                 }
610             }
611         }
612         return response;
613     }
614
615     @Override
616     public Boolean patch(AAIRequest request, String resourceVersion) throws AAIServiceException {
617         InputStream inputStream = null;
618
619         try {
620             AAIDatum instance = request.getRequestObject();
621             if(instance instanceof ResourceVersion) {
622                 resourceVersion = ((ResourceVersion)instance).getResourceVersion();
623             }
624
625             URL requestUrl = null;
626             requestUrl = request.getRequestUrl("PATCH", resourceVersion);
627             HttpURLConnection con = getConfiguredConnection(requestUrl, "PATCH");
628             ObjectMapper mapper = AAIService.getObjectMapper();
629             String jsonText = request.toJSONString();
630
631             LOGwriteDateTrace("data", jsonText);
632             logMetricRequest("PATCH "+requestUrl.getPath(), jsonText, requestUrl.getPath());
633
634             OutputStreamWriter osw = new OutputStreamWriter(con.getOutputStream());
635             osw.write(jsonText);
636             osw.flush();
637
638             // Check for errors
639             int responseCode = con.getResponseCode();
640             if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_CREATED || responseCode == HttpURLConnection.HTTP_ACCEPTED || responseCode == HttpURLConnection.HTTP_NO_CONTENT) {
641                 inputStream = con.getInputStream();
642             } else {
643                 inputStream = con.getErrorStream();
644             }
645             String responseMessage = null;
646             try {
647                 responseMessage = con.getResponseMessage();
648             } catch(Exception exc) {
649                 LOG.info("Exception occured", exc.getMessage());
650                 responseMessage = EnglishReasonPhraseCatalog.INSTANCE.getReason(responseCode,null);
651             } finally {
652                 if(responseMessage == null)
653                         responseMessage = NOT_PROVIDED;
654             }
655
656             LOG.info(HTTP_URL_CONNECTION_RESULT, responseCode, responseMessage);
657             logMetricResponse(responseCode, responseMessage);
658
659             // Process the response
660             BufferedReader reader;
661             String line = null;
662             reader = new BufferedReader( new InputStreamReader( inputStream ) );
663             mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
664
665             if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_CREATED || responseCode == HttpURLConnection.HTTP_ACCEPTED || responseCode == HttpURLConnection.HTTP_NO_CONTENT) {
666                 StringBuilder stringBuilder = new StringBuilder();
667
668                 while( ( line = reader.readLine() ) != null ) {
669                     stringBuilder.append( line );
670                 }
671                 LOGwriteEndingTrace(responseCode, responseMessage, (stringBuilder.length() > 0) ? stringBuilder.toString() : "{no-data}");
672                 return true;
673             } else {
674                 StringBuilder stringBuilder = new StringBuilder();
675
676                 while( ( line = reader.readLine() ) != null ) {
677                     stringBuilder.append("\n").append( line );
678                 }
679                 LOG.info(stringBuilder.toString());
680
681
682                 ErrorResponse errorresponse = mapper.readValue(reader, ErrorResponse.class);
683                 LOGwriteEndingTrace(responseCode, responseMessage, mapper.writeValueAsString(errorresponse));
684
685                 throw new AAIServiceException(responseCode, errorresponse);
686             }
687         } catch(AAIServiceException aaiexc) {
688             throw aaiexc;
689         } catch (Exception exc) {
690             LOG.warn("AAIRequestExecutor.patch", exc);
691             throw new AAIServiceException(exc);
692         } finally {
693             try {
694                 if(inputStream != null)
695                 inputStream.close();
696             } catch (Exception exc) {
697                 LOG.warn("AAIRequestExecutor.patch", exc);
698             }
699         }
700     }
701
702        /**
703      * Returns an String that contains JSON data returned from the AAI Server.
704      * <p>
705      * This method always returns immediately, whether or not the
706      * data exists.
707      *
708      * @param  request  an instance of AAIRequiest representing
709      *                 the request made by DirectedGraph node.
710      * @return      the JSON based representation of data instance requested.
711      * @see         String
712      */
713     @Override
714     public String bulkUpdate(BulkUpdateRequest request) throws AAIServiceException {
715         InputStream inputStream = null;
716
717         try {
718             URL requestUrl = request.getRequestUrl(HttpMethod.POST, null);
719             HttpURLConnection con = getConfiguredConnection(requestUrl, HttpMethod.POST);
720             String jsonText = request.toJSONString();
721             LOGwriteDateTrace("data", jsonText);
722
723             if(jsonText!=null) {
724                     OutputStreamWriter osw = new OutputStreamWriter(con.getOutputStream());
725                     osw.write(jsonText);
726                     osw.flush();
727                     osw.close();
728             }
729             logMetricRequest("POST "+requestUrl.toString(), jsonText, requestUrl.toString());
730
731
732             // Check for errors
733             int responseCode = con.getResponseCode();
734             if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_CREATED || responseCode == HttpURLConnection.HTTP_ACCEPTED || responseCode == HttpURLConnection.HTTP_NO_CONTENT) {
735                 inputStream = con.getInputStream();
736             } else {
737                 inputStream = con.getErrorStream();
738             }
739             String responseMessage = null;
740             try {
741                 responseMessage = con.getResponseMessage();
742             } catch(Exception exc) {
743                 responseMessage = EnglishReasonPhraseCatalog.INSTANCE.getReason(responseCode,null);
744             } finally {
745                 if(responseMessage == null)
746                         responseMessage = NOT_PROVIDED;
747             }
748
749             LOG.info(HTTP_URL_CONNECTION_RESULT, responseCode, responseMessage);
750             logMetricResponse(responseCode, responseMessage);
751
752             // Process the response
753             ObjectMapper mapper = AAIService.getObjectMapper();
754             BufferedReader reader;
755             String line = null;
756             reader = new BufferedReader( new InputStreamReader( inputStream ) );
757             mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
758
759             if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_CREATED || responseCode == HttpURLConnection.HTTP_ACCEPTED || responseCode == HttpURLConnection.HTTP_NO_CONTENT) {
760                 StringBuilder stringBuilder = new StringBuilder();
761
762                 while( ( line = reader.readLine() ) != null ) {
763                     stringBuilder.append( line );
764                 }
765                 LOGwriteEndingTrace(responseCode, responseMessage, (stringBuilder.length() > 0) ? stringBuilder.toString() : "{no-data}");
766                 return stringBuilder.toString();
767             } else {
768                 ErrorResponse errorresponse = mapper.readValue(reader, ErrorResponse.class);
769                 LOGwriteEndingTrace(responseCode, responseMessage, mapper.writeValueAsString(errorresponse));
770
771                 throw new AAIServiceException(responseCode, errorresponse);
772             }
773         } catch(AAIServiceException aaiexc) {
774             throw aaiexc;
775         } catch (Exception exc) {
776             LOG.warn("AAIRequestExecutor.post", exc);
777             throw new AAIServiceException(exc);
778         } finally {
779             try {
780                 if(inputStream != null)
781                 inputStream.close();
782             } catch (Exception exc) {
783                 LOG.warn("AAIRequestExecutor.post", exc);
784             }
785         }
786     }
787
788     /**
789      *
790      * @param httpReqUrl
791      * @param method
792      * @return
793      * @throws Exception
794      */
795     protected HttpURLConnection getConfiguredConnection(URL httpReqUrl, String method) throws Exception {
796         HttpURLConnection con = (HttpURLConnection) httpReqUrl.openConnection();
797
798         // Set up the connection properties
799         con.setRequestProperty("Connection", "close");
800         con.setDoInput(true);
801         con.setDoOutput(true);
802         con.setUseCaches(false);
803         con.setConnectTimeout(connection_timeout);
804         con.setReadTimeout(read_timeout);
805         con.setRequestMethod(method);
806         con.setRequestProperty("Accept", "application/json");
807         con.setRequestProperty("Transfer-Encoding","chunked");
808         con.setRequestProperty("Content-Type",
809                 "PATCH".equalsIgnoreCase(method) ? "application/merge-patch+json" : "application/json");
810         con.setRequestProperty("X-FromAppId", applicationId);
811         con.setRequestProperty("X-TransactionId", TransactionIdTracker.getNextTransactionId());
812         con.setRequestProperty("X-DslApiVersion", "V2");
813         String mlId = ml.getRequestID();
814         if (mlId != null && !mlId.isEmpty()) {
815             LOG.debug(String.format("MetricLogger requestId = %s", mlId));
816             con.setRequestProperty(ONAPLogConstants.MDCs.REQUEST_ID, mlId);
817         } else {
818             LOG.debug("MetricLogger requestId is null");
819         }
820
821         if (userName != null && !userName.isEmpty() && userPassword != null && !userPassword.isEmpty()) {
822             String basicAuth = "Basic " + new String(Base64.encodeBase64((userName + ":" + userPassword).getBytes()));
823             con.setRequestProperty("Authorization", basicAuth);
824         }
825
826         if (con instanceof HttpsURLConnection && CTX != null) {
827             SSLSocketFactory sockFact = CTX.getSocketFactory();
828             HttpsURLConnection.class.cast(con).setSSLSocketFactory(sockFact);
829         }
830         return con;
831     }
832
833     private URL appendDepth(URL requestUrl, AAIRequest request) throws MalformedURLException, URISyntaxException {
834         final String NODES_ONLY = "nodes-only";
835         URIBuilder builder = new URIBuilder(requestUrl.toURI());
836         // PROCESS nodes-only option
837         if (request.requestProperties.containsKey(NODES_ONLY)) {
838             if(request.requestProperties.containsKey(NODES_ONLY)) {
839                 String nodesOnly = request.requestProperties.getProperty(NODES_ONLY);
840                 if(nodesOnly != null && !nodesOnly.isEmpty()) {
841                     builder.setParameter(NODES_ONLY, nodesOnly);
842                 }
843             }
844             // do not add depth by default with nodes-only
845             if(!request.requestProperties.containsKey("depth")) {
846                 return builder.build().toURL();
847             }
848         }
849
850         String depth = request.requestProperties.getProperty("depth", "1");
851         
852         builder.setParameter("depth", depth);
853         
854         return builder.build().toURL();
855     }
856
857     public void logMetricRequest(String targetServiceName, String msg, String path){
858         String svcInstanceId = "";
859         String svcName = null;
860         String partnerName = null;
861         String targetEntity = "A&AI";
862         String targetVirtualEntity = null;
863
864         ml.logRequest(svcInstanceId, svcName, partnerName, targetEntity, targetServiceName, targetVirtualEntity, msg);
865     }
866
867     public void logMetricResponse(int responseCode, String responseDescription){
868         ml.logResponse(responseCode < 400 ? "COMPLETE" : "ERROR", Integer.toString(responseCode), responseDescription);
869     }
870
871     protected void LOGwriteFirstTrace(String method, String url) {
872         String time = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'").format(System.currentTimeMillis());
873         LOG.info("A&AI transaction :");
874         LOG.info("Request Time : " + time + ", Method : " + method);
875         LOG.info("Request URL : "+ url);
876     }
877
878     protected void LOGwriteDateTrace(String name, String data) {
879         LOG.info("Input - " + name  + " : " + data);
880     }
881
882     protected void LOGwriteEndingTrace(int response_code, String comment, String data) {
883         LOG.info("Response code : " + response_code +", " + comment);
884         LOG.info(String.format("Response data : %s", data));
885     }
886
887 }