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