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