Updating aai adapter to v16 model
[ccsdk/sli/adaptors.git] / aai-service / provider / src / main / java / org / onap / ccsdk / sli / adaptors / aai / AAIService.java
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) 2019 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  * @author Rich Tabedzki
25  *
26  */
27 package org.onap.ccsdk.sli.adaptors.aai;
28
29 import java.io.BufferedReader;
30 import java.io.ByteArrayInputStream;
31 import java.io.File;
32 import java.io.FileInputStream;
33 import java.io.IOException;
34 import java.io.InputStream;
35 import java.io.InputStreamReader;
36 import java.io.OutputStreamWriter;
37 import java.io.UnsupportedEncodingException;
38 import java.lang.reflect.Field;
39 import java.lang.reflect.Modifier;
40 import java.net.HttpURLConnection;
41 import java.net.MalformedURLException;
42 import java.net.URI;
43 import java.net.URISyntaxException;
44 import java.net.URL;
45 import java.net.URLEncoder;
46 import java.nio.charset.StandardCharsets;
47 import java.security.KeyManagementException;
48 import java.security.KeyStore;
49 import java.security.NoSuchAlgorithmException;
50 import java.text.SimpleDateFormat;
51 import java.util.Calendar;
52 import java.util.Enumeration;
53 import java.util.HashMap;
54 import java.util.LinkedList;
55 import java.util.List;
56 import java.util.Map;
57 import java.util.Map.Entry;
58 import java.util.Properties;
59 import java.util.Set;
60 import java.util.TimeZone;
61 import java.util.UUID;
62 import java.util.regex.Matcher;
63 import java.util.regex.Pattern;
64
65 import javax.net.ssl.HostnameVerifier;
66 import javax.net.ssl.HttpsURLConnection;
67 import javax.net.ssl.KeyManagerFactory;
68 import javax.net.ssl.SSLContext;
69 import javax.net.ssl.SSLSession;
70 import javax.net.ssl.SSLSocketFactory;
71 import javax.ws.rs.HttpMethod;
72 import javax.xml.bind.annotation.XmlElement;
73
74 import org.apache.commons.codec.binary.Base64;
75 import org.apache.commons.lang3.StringUtils;
76 import org.onap.ccsdk.sli.adaptors.aai.data.AAIDatum;
77 import org.onap.ccsdk.sli.adaptors.aai.data.ErrorResponse;
78 import org.onap.ccsdk.sli.adaptors.aai.data.notify.NotifyEvent;
79 import org.onap.ccsdk.sli.core.sli.ConfigurationException;
80 import org.onap.ccsdk.sli.core.sli.MetricLogger;
81 import org.onap.ccsdk.sli.core.sli.SvcLogicContext;
82 import org.onap.ccsdk.sli.core.sli.SvcLogicException;
83 import org.onap.ccsdk.sli.core.sli.SvcLogicResource;
84 import org.onap.aai.inventory.v16.GenericVnf;
85 import org.onap.aai.inventory.v16.PhysicalLink;
86 import org.onap.aai.inventory.v16.ResultData;
87 import org.onap.aai.inventory.v16.SearchResults;
88 import org.onap.aai.inventory.v16.Vserver;
89 import org.slf4j.Logger;
90 import org.slf4j.LoggerFactory;
91 import org.slf4j.MDC;
92
93 import com.fasterxml.jackson.annotation.JsonInclude.Include;
94 import com.fasterxml.jackson.databind.AnnotationIntrospector;
95 import com.fasterxml.jackson.databind.DeserializationFeature;
96 import com.fasterxml.jackson.databind.ObjectMapper;
97 import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector;
98 import com.fasterxml.jackson.databind.type.TypeFactory;
99 import com.fasterxml.jackson.module.jaxb.JaxbAnnotationIntrospector;
100
101
102 public class AAIService extends AAIDeclarations implements AAIClient, SvcLogicResource {
103
104     public static final String AAICLIENT_PROPERTIES = "/aaiclient.properties";
105     public static final String PATH_PROPERTIES = "/aai-path.properties";
106
107     private static final Logger LOG = LoggerFactory.getLogger(AAIService.class);
108
109     private final String truststorePath;
110     private final String truststorePassword;
111     private final String keystorePath;
112     private final String keystorePassword;
113     private final Boolean ignoreCertificateHostError;
114
115     private final String targetUri;
116     private final String networkVserverPath;
117
118     private final String svc_inst_query_path;
119
120     private final String ubb_notify_path;
121     private final String selflinkAvpn;
122     private final String selflinkFqdn;
123
124     private final int connectionTimeout;
125     private final int readTimeout;
126
127     // 1602
128     private final String queryNodesPath;
129     private final String applicationId;
130
131     // authentication credentials
132     private String userName;
133     private String userPassword;
134
135     // runtime
136     private final boolean runtimeOSGI;
137
138     private SSLContext CTX;
139
140     private final MetricLogger ml = new MetricLogger();
141
142     private AAIExecutorInterface executor;
143
144     public AAIService(final UtilsProvider configuration) {
145         this(configuration.getProperties());
146     }
147
148     public AAIService(final URL url) {
149         this(getProperties(url));
150     }
151
152     public AAIService(Properties props) {
153         LOG.info("Entered AAIService.ctor");
154
155         String runtime = System.getProperty("aaiclient.runtime");
156         if("OSGI".equals(runtime)) {
157             runtimeOSGI = true;
158         } else {
159             runtimeOSGI = false;
160         }
161
162         try {
163             AAIRequest.setProperties(props, this);
164
165         } catch(Exception exc){
166             LOG.error("AicAAIResource.static", exc);
167         }
168
169         executor = new AAIClientRESTExecutor(props);
170
171         userName            = props.getProperty(CLIENT_NAME);
172         userPassword        = props.getProperty(CLIENT_PWWD);
173
174         if(userName == null || userName.isEmpty()){
175             LOG.debug("Basic user name is not set");
176         }
177         if(userPassword == null || userPassword.isEmpty()) {
178             LOG.debug("Basic password is not set");
179         }
180
181         truststorePath     = props.getProperty(TRUSTSTORE_PATH);
182         truststorePassword = props.getProperty(TRUSTSTORE_PSSWD);
183         keystorePath         = props.getProperty(KEYSTORE_PATH);
184         keystorePassword     = props.getProperty(KEYSTORE_PSSWD);
185
186         targetUri             = props.getProperty(TARGET_URI);
187         props.getProperty(QUERY_PATH);
188         props.getProperty(UPDATE_PATH);
189
190         String tmpApplicationId = props.getProperty(APPLICATION_ID);
191         if(tmpApplicationId == null || tmpApplicationId.isEmpty()) {
192             tmpApplicationId = "SDNC";
193         }
194         this.applicationId = tmpApplicationId;
195
196         // connection timeout
197         int tmpConnectionTimeout = 30000;
198         int tmpReadTimeout = 30000;
199
200         try {
201             String tmpValue = null;
202             tmpValue = props.getProperty(CONNECTION_TIMEOUT, "30000");
203             tmpConnectionTimeout = Integer.parseInt(tmpValue);
204             tmpValue = props.getProperty(READ_TIMEOUT, "30000");
205             tmpReadTimeout = Integer.parseInt(tmpValue);
206         } catch(Exception exc) {
207             LOG.error("Failed setting connection timeout", exc);
208             tmpConnectionTimeout = 30000;
209             tmpReadTimeout = 30000;
210         }
211         connectionTimeout = tmpConnectionTimeout;
212         readTimeout = tmpReadTimeout;
213
214         networkVserverPath =props.getProperty(NETWORK_VSERVER_PATH);
215
216         props.getProperty(SVC_INSTANCE_PATH);
217         svc_inst_query_path    = props.getProperty(SVC_INST_QRY_PATH);
218         props.getProperty(PARAM_SERVICE_TYPE, "service-type");
219
220         props.getProperty(VNF_IMAGE_QUERY_PATH);
221
222         ubb_notify_path = props.getProperty(UBB_NOTIFY_PATH);
223         selflinkAvpn = props.getProperty(SELFLINK_AVPN);
224         selflinkFqdn = props.getProperty(SELFLINK_FQDN);
225
226         props.getProperty(SERVICE_PATH);
227
228         props.getProperty(SITE_PAIR_SET_PATH);
229
230         queryNodesPath = props.getProperty(QUERY_NODES_PATH);
231
232         String iche = props.getProperty(CERTIFICATE_HOST_ERROR);
233         boolean host_error = false;
234         if(iche != null && !iche.isEmpty()) {
235             host_error = Boolean.valueOf(iche);
236         }
237
238         ignoreCertificateHostError = host_error;
239
240         HttpsURLConnection.setDefaultHostnameVerifier( new HostnameVerifier(){
241             public boolean verify(String string,SSLSession ssls) {
242                 return ignoreCertificateHostError;
243             }
244         });
245
246         if(truststorePath != null && truststorePassword != null && (new File(truststorePath)).exists()) {
247             System.setProperty("javax.net.ssl.trustStore", truststorePath);
248             System.setProperty("javax.net.ssl.trustStorePassword", truststorePassword);
249         }
250
251         if(keystorePath != null && keystorePassword != null && (new File(keystorePath)).exists()) {
252         //DefaultClientConfig config = new DefaultClientConfig();
253         //both jersey and HttpURLConnection can use this
254         SSLContext ctx = null;
255         try {
256             ctx = SSLContext.getInstance("TLS");
257
258             KeyManagerFactory kmf = null;
259             try (FileInputStream fin = new FileInputStream(keystorePath)){
260                 String def = "SunX509";
261                 String storeType = "PKCS12";
262                 def = KeyStore.getDefaultType();
263                 kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
264
265                 String extension = keystorePath.substring(keystorePath.lastIndexOf(".") + 1);
266                 if("JKS".equalsIgnoreCase(extension)) {
267                     storeType = "JKS";
268                 }
269                 KeyStore ks = KeyStore.getInstance(storeType);
270
271                 char[] pwd = keystorePassword.toCharArray();
272                 ks.load(fin, pwd);
273                 kmf.init(ks, pwd);
274             } catch (Exception ex) {
275                 LOG.error("AAIResource", ex);
276             }
277
278             if(null!=kmf) {
279                 ctx.init(kmf.getKeyManagers(), null, null);
280             }
281                 /*
282                  * config.getProperties().put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES, new
283                  * HTTPSProperties( new HostnameVerifier() {
284                  * 
285                  * @Override public boolean verify( String s, SSLSession sslSession ) { return
286                  * ignoreCertificateHostError; } }, ctx));
287                  */
288
289             CTX = ctx;
290                 LOG.debug("SSLContext created");
291
292         } catch (KeyManagementException | NoSuchAlgorithmException exc) {
293             LOG.error("AAIResource", exc);
294         }
295         }
296
297         LOG.info("AAIResource.ctor initialized.");
298
299         try {
300             Field methodsField = HttpURLConnection.class.getDeclaredField("methods");
301             methodsField.setAccessible(true);
302             // get the methods field modifiers
303             Field modifiersField = Field.class.getDeclaredField("modifiers");
304             // bypass the "private" modifier
305             modifiersField.setAccessible(true);
306
307             // remove the "final" modifier
308             modifiersField.setInt(methodsField, methodsField.getModifiers() & ~Modifier.FINAL);
309
310             /* valid HTTP methods */
311             String[] methods = {
312                        "GET", "POST", "HEAD", "OPTIONS", "PUT", "DELETE", "TRACE", "PATCH"
313             };
314             // set the new methods - including patch
315             methodsField.set(null, methods);
316
317         } catch (SecurityException | IllegalArgumentException | IllegalAccessException | NoSuchFieldException e) {
318             LOG.error("Exception occured", e);
319         }
320
321     }
322
323     private static Properties getProperties(URL url) {
324         Properties properties = new Properties();
325         try {
326             properties.load(url.openStream());
327         } catch (IOException exc) {
328             LOG.error("getProperties", exc);
329         }
330         return properties;
331     }
332
333     public void setExecutor(AAIExecutorInterface executor) {
334         this.executor = executor;
335     }
336
337     public void cleanUp() {
338
339     }
340
341     /**
342      *
343      * @param http_req_url
344      * @param method
345      * @return
346      * @throws Exception
347      */
348     protected HttpURLConnection getConfiguredConnection(URL http_req_url, String method) throws Exception {
349         HttpURLConnection con = (HttpURLConnection) http_req_url.openConnection();
350
351         // Set up the connection properties
352         con.setRequestProperty( "Connection", "close" );
353         con.setDoInput(true);
354         con.setDoOutput(true);
355         con.setUseCaches(false);
356         con.setConnectTimeout( connectionTimeout );
357         con.setReadTimeout( readTimeout );
358         con.setRequestMethod( method );
359         con.setRequestProperty( "Accept", "application/json" );
360         con.setRequestProperty( "Content-Type",  "PATCH".equalsIgnoreCase(method) ? "application/merge-patch+json" : "application/json" );
361         con.setRequestProperty("X-FromAppId", applicationId);
362         con.setRequestProperty("X-TransactionId",TransactionIdTracker.getNextTransactionId());
363         String mlId = ml.getRequestID();
364         if(mlId != null && !mlId.isEmpty()) {
365             LOG.debug(String.format("MetricLogger requestId = %s", mlId));
366             con.setRequestProperty(MetricLogger.REQUEST_ID, mlId);
367         } else {
368             LOG.debug("MetricLogger requestId is null");
369         }
370         con.setRequestProperty("Transfer-Encoding","chunked");
371
372         if(userName != null && !userName.isEmpty() && userPassword != null && !userPassword.isEmpty()) {
373             String basicAuth = "Basic " + new String(Base64.encodeBase64((userName + ":" + userPassword).getBytes()));
374             con.setRequestProperty ("Authorization", basicAuth);
375         }
376
377         if(con instanceof HttpsURLConnection && CTX != null) {
378             SSLSocketFactory sockFact = CTX.getSocketFactory();
379             HttpsURLConnection.class.cast(con).setSSLSocketFactory( sockFact );
380         }
381         return con;
382     }
383
384
385     @Override
386     public GenericVnf requestGenericVnfData(String vnf_id) throws AAIServiceException {
387         GenericVnf response = null;
388
389         try {
390             AAIRequest request = AAIRequest.getRequestFromResource("generic-vnf");
391             request.addRequestProperty("generic-vnf.vnf-id", vnf_id);
392             String rv = executor.get(request);
393             if(rv != null) {
394                 ObjectMapper mapper = getObjectMapper();
395                 response = mapper.readValue(rv, GenericVnf.class);
396             }
397         } catch(AAIServiceException aaiexc) {
398             throw aaiexc;
399         } catch (Exception exc) {
400             LOG.warn(Object.class.getClass().getEnclosingMethod().getName(), exc);
401             throw new AAIServiceException(exc);
402         }
403
404         return response;
405
406     }
407
408     @Override
409     public boolean postGenericVnfData(String vnf_id, GenericVnf data) throws AAIServiceException {
410         try {
411             AAIRequest request = AAIRequest.getRequestFromResource("generic-vnf");
412             request.addRequestProperty("generic-vnf.vnf-id", vnf_id);
413             request.setRequestObject(data);
414             Object response = executor.post(request);
415             return true;
416         } catch(AAIServiceException aaiexc) {
417             throw aaiexc;
418         } catch (Exception exc) {
419             LOG.warn("requestGenericVnfData", exc);
420             throw new AAIServiceException(exc);
421         }
422     }
423
424     @Override
425     public SearchResults requestServiceInstanceURL(String svc_instance_id) throws AAIServiceException {
426         SearchResults response = null;
427         InputStream inputStream = null;
428
429         try {
430             String path = svc_inst_query_path;
431             path = path.replace("{svc-instance-id}", encodeQuery(svc_instance_id));
432
433             String request_url = targetUri+path;
434             URL http_req_url =    new URL(request_url);
435
436             HttpURLConnection con = getConfiguredConnection(http_req_url, HttpMethod.GET);
437
438             LOGwriteFirstTrace(HttpMethod.GET, http_req_url.toString());
439             LOGwriteDateTrace("svc_instance_id", svc_instance_id);
440
441             // Check for errors
442             int responseCode = con.getResponseCode();
443             if (responseCode == HttpURLConnection.HTTP_OK) {
444                 inputStream = con.getInputStream();
445             } else {
446                 inputStream = con.getErrorStream();
447             }
448
449             // Process the response
450             LOG.debug("HttpURLConnection result:" + responseCode);
451             if(inputStream == null) inputStream = new ByteArrayInputStream("".getBytes(StandardCharsets.UTF_8));
452             BufferedReader reader = new BufferedReader( new InputStreamReader( inputStream ) );
453
454             ObjectMapper mapper = getObjectMapper();
455
456     if (responseCode == HttpURLConnection.HTTP_OK) {
457                 response = mapper.readValue(reader, SearchResults.class);
458                 LOGwriteEndingTrace(HttpURLConnection.HTTP_OK, "SUCCESS", mapper.writeValueAsString(response));
459             } else if(responseCode == HttpURLConnection.HTTP_NOT_FOUND ) {
460                 LOGwriteEndingTrace(responseCode, "HTTP_NOT_FOUND", "Entry does not exist.");
461                 return response;
462             } else {
463                 ErrorResponse errorresponse = mapper.readValue(reader, ErrorResponse.class);
464                 LOGwriteEndingTrace(responseCode, "FAILURE", mapper.writeValueAsString(errorresponse));
465                 throw new AAIServiceException(responseCode, errorresponse);
466             }
467
468         } catch(AAIServiceException aaiexc) {
469             throw aaiexc;
470         } catch (Exception exc) {
471             LOG.warn("requestServiceInstanceURL", exc);
472             throw new AAIServiceException(exc);
473         } finally {
474             if(inputStream != null){
475                 try {
476                     inputStream.close();
477                 } catch(Exception exc) {
478                     LOG.warn("Error closing Inputstream", exc);
479                 }
480             }
481         }
482         return response;
483     }
484
485
486     private static Properties initialize(URL url ) throws ConfigurationException {
487
488         if(url ==  null) {
489             throw new NullPointerException();
490         }
491
492         InputStream is = null;
493         Properties props = new Properties();
494
495         try {
496             if(LOG.isDebugEnabled())
497                 LOG.info("Property file is: " + url.toString());
498
499             is = url.openStream();
500
501             props.load(is);
502             if(LOG.isDebugEnabled()) {
503                 LOG.info("Properties loaded: " + props.size());
504                 Enumeration<Object> en = props.keys();
505
506                 while(en.hasMoreElements()) {
507                     String key = (String)en.nextElement();
508                     String property = props.getProperty(key);
509                     LOG.debug(key + " : " + property);
510                 }
511             }
512         } catch (Exception e) {
513             throw new ConfigurationException("Could not load properties file.", e);
514         }
515         return props;
516     }
517
518     static class TransactionIdTracker {
519 //        protected static AtomicLong tracker = new AtomicLong();
520
521         public static String getNextTransactionId() {
522             // Check if RequestId exists as MDC. If not, create new.
523             String transactionId = MDC.get("RequestId");
524             if ("".equals(transactionId) || transactionId == null) {
525                 transactionId = UUID.randomUUID().toString();
526                 LOG.info("Missing requestID. Assigned " + transactionId);
527                 MDC.put("RequestId", transactionId);
528             }
529             return transactionId;
530         }
531
532     }
533
534     protected void LOGwriteFirstTrace(String method, String url) {
535         String time = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'").format(System.currentTimeMillis());
536         LOG.info("A&AI transaction :");
537         LOG.info("Request Time : " + time + ", Method : " + method);
538         LOG.info("Request URL : "+ url);
539     }
540
541     protected void LOGwriteDateTrace(String name, String data) {
542         LOG.info("Input - " + name  + " : " + data);
543     }
544
545     protected void LOGwriteEndingTrace(int response_code, String comment, String data) {
546         LOG.info("Response code : " + response_code +", " + comment);
547         LOG.info(String.format("Response data : %s", data));
548     }
549
550     protected String encodeQuery(String param) throws UnsupportedEncodingException {
551         return URLEncoder.encode(param, "UTF-8").replace("+", "%20");
552     }
553
554     private String encodeCustomerURL(final String selection)
555     {
556         String encrypted_url = selection;
557         String apnpattern =
558                 "/aai/v11/business/customers/customer/(.+)/service-subscriptions/service-subscription/(.+)/service-instances/service-instance/(.+)/";
559         Pattern pattern = Pattern.compile(apnpattern);
560
561         try {
562             URL url =    new URL(selection);
563             String path = url.getPath();
564
565             LOG.info("Trying to match apn to <" + path + ">");
566
567             Matcher matcher = pattern.matcher(path);
568
569             while(matcher.find()) {
570                 String customer = matcher.group(1);
571                 String subscription = matcher.group(2);
572                 String service = matcher.group(3);
573
574                 encrypted_url = selection.replace(customer, encodeQuery(customer));
575                 encrypted_url = encrypted_url.replace(subscription, encodeQuery(subscription));
576                 encrypted_url = encrypted_url.replace(service, encodeQuery(service));
577             }
578         } catch (Exception e) {
579             LOG.warn("", e);
580         }
581
582         return encrypted_url;
583     }
584
585
586
587     /*
588      * (non-Javadoc)
589      * @see org.onap.sdnct.sli.aai.AAIClient#requestVServersData(java.lang.String, java.lang.String)
590      */
591     @Override
592     public Vserver requestVServerData(String tenantId, String vserverId, String cloudOwner, String cloudRegionId)    throws AAIServiceException {
593         Vserver response = null;
594
595         try {
596             AAIRequest request = AAIRequest.getRequestFromResource("vserver");
597             request.addRequestProperty("cloud-region.cloud-owner", cloudOwner);
598             request.addRequestProperty("cloud-region.cloud-region-id", cloudRegionId);
599             request.addRequestProperty("tenant.tenant-id", tenantId);
600             request.addRequestProperty("vserver.vserver-id", vserverId);
601
602             String rv = executor.get(request);
603             if(rv != null) {
604                 ObjectMapper mapper = getObjectMapper();
605                 response = mapper.readValue(rv, Vserver.class);
606             }
607         } catch(AAIServiceException aaiexc) {
608             throw aaiexc;
609         } catch (Exception exc) {
610             LOG.warn(Object.class.getClass().getEnclosingMethod().getName(), exc);
611             throw new AAIServiceException(exc);
612         }
613         return response;
614     }
615
616
617     //================== End of DvsSwitch =================
618     //==================== PhysicalLink ======================
619     @Override
620     public PhysicalLink  requestPhysicalLinkData(String linkName) throws AAIServiceException {
621         PhysicalLink response = null;
622
623         try {
624             AAIRequest request = AAIRequest.getRequestFromResource("physical-link");
625             request.addRequestProperty("physical-link.link-name", linkName);
626
627             String rv = executor.get(request);
628             if(rv != null) {
629                 ObjectMapper mapper = getObjectMapper();
630                 response = mapper.readValue(rv, PhysicalLink.class);
631             }
632         } catch(AAIServiceException aaiexc) {
633             throw aaiexc;
634         } catch (Exception exc) {
635             LOG.warn("requestPhysicalLinkData", exc);
636             throw new AAIServiceException(exc);
637         }
638         return response;
639     }
640
641     @Override
642     public boolean postPhysicalLinkData(String linkName, PhysicalLink data) throws AAIServiceException {
643         try {
644             AAIRequest request = AAIRequest.getRequestFromResource("physical-link");
645             request.addRequestProperty("physical-link.link-name", linkName);
646             request.setRequestObject(data);
647             Object response = executor.post(request);
648             return true;
649         } catch(AAIServiceException aaiexc) {
650             throw aaiexc;
651         } catch (Exception exc) {
652             LOG.warn(Object.class.getClass().getEnclosingMethod().getName(), exc);
653             throw new AAIServiceException(exc);
654         }
655     }
656
657     @Override
658     public boolean deletePhysicalLinkData(String linkName, String resourceVersion) throws AAIServiceException {
659         boolean response = false;
660
661         try {
662             AAIRequest request = AAIRequest.getRequestFromResource("physical-link");
663             request.addRequestProperty("physical-link.link-name", linkName);
664             response = executor.delete(request, resourceVersion);
665         } catch(AAIServiceException aaiexc) {
666             throw aaiexc;
667         } catch (Exception exc) {
668             LOG.warn("deletePhysicalLinkData", exc);
669             throw new AAIServiceException(exc);
670         }
671         return response;
672     }
673
674     public boolean deleteAAIEntity(URL url, String caller) throws AAIServiceException {
675
676         if(url ==  null) {
677             throw new NullPointerException();
678         }
679
680         boolean response = false;
681         InputStream inputStream = null;
682
683         try {
684             URL http_req_url =    url;
685
686             HttpURLConnection con = getConfiguredConnection(http_req_url, HttpMethod.DELETE);
687
688             LOGwriteFirstTrace("DELETE", http_req_url.toString());
689
690
691             // Check for errors
692             int responseCode = con.getResponseCode();
693             if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_NO_CONTENT) {
694                 inputStream = con.getInputStream();
695             } else {
696                 inputStream = con.getErrorStream();
697             }
698
699             // Process the response
700             LOG.debug("HttpURLConnection result:" + responseCode);
701             if(inputStream == null) inputStream = new ByteArrayInputStream("".getBytes(StandardCharsets.UTF_8));
702             BufferedReader reader = new BufferedReader( new InputStreamReader( inputStream ) );
703             String line = null;
704
705             ObjectMapper mapper = getObjectMapper();
706
707             if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_NO_CONTENT) {
708                 StringBuilder stringBuilder = new StringBuilder();
709
710                 while( ( line = reader.readLine() ) != null ) {
711                     stringBuilder.append( line );
712                 }
713                 LOGwriteEndingTrace(responseCode, "SUCCESS", stringBuilder.toString());
714                 response = true;
715             } else if(responseCode == HttpURLConnection.HTTP_NOT_FOUND ) {
716                 LOGwriteEndingTrace(responseCode, "HTTP_NOT_FOUND", "Entry does not exist.");
717                 response = false;
718             } else {
719                 ErrorResponse errorresponse = mapper.readValue(reader, ErrorResponse.class);
720                 LOGwriteEndingTrace(responseCode, "FAILURE", mapper.writeValueAsString(errorresponse));
721                 throw new AAIServiceException(responseCode, errorresponse);
722             }
723
724         } catch(AAIServiceException aaiexc) {
725             throw aaiexc;
726         } catch (Exception exc) {
727             LOG.warn(caller, exc);
728             throw new AAIServiceException(exc);
729         } finally {
730             if(inputStream != null){
731                 try {
732                     inputStream.close();
733                 } catch(Exception exc) {
734                     LOG.warn("Error closing InputStream", exc);
735                 }
736             }
737         }
738         return response;
739     }
740
741     /**
742      * Generic method to GET json data from an A&AI callback URL.
743      * Then convert that json to an Object.
744      * If successful the Object is attempted to be cast to the type parameter.
745      *
746      * @param key
747      *            callback url for A&AI
748      * @param type
749      *            the class of object that A&AI will return
750      * @return the object created from json or null if the response code is not 200
751      *
752      * @throws AAIServiceException
753      *             if empty or null key and or type or there's an error with processing
754      */
755     public <T> T dataChangeRequestAaiData(String key, Class<T> type) throws AAIServiceException {
756         if (StringUtils.isEmpty(key) || type == null) {
757             throw new AAIServiceException("Key is empty or null and or type is null");
758         }
759
760         T response = null;
761
762         SvcLogicContext ctx = new SvcLogicContext();
763         if(!key.contains(" = ") && isValidURL(key)) {
764             key = String.format("selflink = '%s'", key);
765         } else
766         if(!key.contains(" = ") && isValidURI(key)) {
767             key = String.format("resource-path = '%s'", key);
768         }
769
770         HashMap<String, String> nameValues = AAIServiceUtils.keyToHashMap(key, ctx);
771
772         SelfLinkRequest request = new SelfLinkRequest(type);
773         request.processRequestPathValues(nameValues);
774         Object obj = this.getExecutor().query(request, type);
775         response = type.cast(obj);
776
777         return response != null ? type.cast(response) : response;
778     }
779
780
781     public boolean sendNotify(NotifyEvent event, String serviceInstanceId, String pathCode) throws AAIServiceException {
782         InputStream inputStream = null;
783
784         try {
785
786             String selfLink = selflinkFqdn;
787             if(SELFLINK_AVPN != null && SELFLINK_AVPN.equals(pathCode)) {
788                 selfLink = selflinkAvpn;
789             }
790             selfLink = selfLink.replace("{service-instance-id}", encodeQuery(serviceInstanceId));
791             event.setSelflink(selfLink);
792
793             ObjectMapper mapper = getObjectMapper();
794             String json_text = mapper.writeValueAsString(event);
795
796             SSLSocketFactory sockFact = CTX.getSocketFactory();
797
798             String request_url = targetUri+ubb_notify_path;
799             URL http_req_url =    new URL(request_url);
800
801             HttpURLConnection con = getConfiguredConnection(http_req_url, HttpMethod.PUT);
802
803             if (json_text != null) {
804                 OutputStreamWriter osw = new OutputStreamWriter(con.getOutputStream());
805                 osw.write(json_text);
806                 osw.flush();
807                 osw.close();
808             }
809
810             LOGwriteFirstTrace("PUT", request_url);
811             LOGwriteDateTrace("NotifyEvent", json_text);
812
813             // Check for errors
814             int responseCode = con.getResponseCode();
815             if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_CREATED || responseCode == HttpURLConnection.HTTP_ACCEPTED || responseCode == HttpURLConnection.HTTP_NO_CONTENT) {
816                 inputStream = con.getInputStream();
817             } else {
818                 inputStream = con.getErrorStream();
819             }
820
821             // Process the response
822             BufferedReader reader;
823             String line = null;
824             reader = new BufferedReader( new InputStreamReader( inputStream ) );
825
826             if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_CREATED || responseCode == HttpURLConnection.HTTP_ACCEPTED || responseCode == HttpURLConnection.HTTP_NO_CONTENT) {
827                 StringBuilder stringBuilder = new StringBuilder();
828
829                 while( ( line = reader.readLine() ) != null ) {
830                     stringBuilder.append( line );
831                 }
832                 LOGwriteEndingTrace(responseCode, "SUCCESS", (stringBuilder.length() > 0) ? stringBuilder.toString() :
833                                                                                             "{no-data}");
834                 return true;
835             } else {
836                 ErrorResponse errorresponse = mapper.readValue(reader, ErrorResponse.class);
837                 LOGwriteEndingTrace(responseCode, "FAILURE", mapper.writeValueAsString(errorresponse));
838
839                 throw new AAIServiceException(responseCode, errorresponse);
840             }
841         } catch(AAIServiceException aaiexc) {
842             throw aaiexc;
843         } catch (Exception exc) {
844             LOG.warn("sendNotify", exc);
845             throw new AAIServiceException(exc);
846         } finally {
847             try {
848                 if(inputStream != null)
849                 inputStream.close();
850             } catch (Exception exc) {
851                 LOG.warn("Error closing Input stream", exc);
852             }
853         }
854     }
855
856     @Override
857     public SearchResults requestNodeQuery(String node_type, String entityIdentifier, String entityName) throws AAIServiceException {
858         SearchResults response = null;
859         InputStream inputStream = null;
860
861         try {
862             String request_url = targetUri+queryNodesPath;
863             request_url = request_url.replace("{node-type}", encodeQuery(node_type)) ;
864             request_url = request_url.replace("{entity-identifier}", entityIdentifier) ;
865             request_url = request_url.replace("{entity-name}", encodeQuery(entityName)) ;
866             URL http_req_url =    new URL(request_url);
867
868             HttpURLConnection con = getConfiguredConnection(http_req_url, HttpMethod.GET);
869
870             LOGwriteFirstTrace(HttpMethod.GET, http_req_url.toString());
871             LOGwriteDateTrace("node_type", node_type);
872             LOGwriteDateTrace("vnf_name", entityName);
873
874             // Check for errors
875             int responseCode = con.getResponseCode();
876             if (responseCode == HttpURLConnection.HTTP_OK) {
877                 inputStream = con.getInputStream();
878             } else {
879                 inputStream = con.getErrorStream();
880             }
881
882             // Process the response
883             LOG.debug("HttpURLConnection result:" + responseCode);
884             if(inputStream == null) inputStream = new ByteArrayInputStream("".getBytes(StandardCharsets.UTF_8));
885             BufferedReader reader = new BufferedReader( new InputStreamReader( inputStream ) );
886
887             ObjectMapper mapper = getObjectMapper();
888
889             if (responseCode == HttpURLConnection.HTTP_OK) {
890                 response = mapper.readValue(reader, SearchResults.class);
891                 LOGwriteEndingTrace(HttpURLConnection.HTTP_OK, "SUCCESS", mapper.writeValueAsString(response));
892             } else if (responseCode == HttpURLConnection.HTTP_NOT_FOUND) {
893                 LOGwriteEndingTrace(responseCode, "HTTP_NOT_FOUND", "Entry does not exist.");
894                 return response;
895             } else {
896                 ErrorResponse errorresponse = mapper.readValue(reader, ErrorResponse.class);
897                 LOGwriteEndingTrace(responseCode, "FAILURE", mapper.writeValueAsString(errorresponse));
898                 throw new AAIServiceException(responseCode, errorresponse);
899             }
900
901         } catch(AAIServiceException aaiexc) {
902             throw aaiexc;
903         } catch (Exception exc) {
904             LOG.warn("requestNodeQuery", exc);
905             throw new AAIServiceException(exc);
906         } finally {
907             if(inputStream != null){
908                 try {
909                     inputStream.close();
910                 } catch(Exception exc) {
911                     LOG.warn("Error closing Input stream", exc);
912                 }
913             }
914         }
915         return response;
916
917     }
918
919
920     @Override
921     public String requestDataByURL(URL url) throws AAIServiceException {
922
923         if(url ==  null) {
924             throw new NullPointerException();
925         }
926
927         String response = null;
928         InputStream inputStream = null;
929
930         try {
931             URL http_req_url = url;
932
933             HttpURLConnection con = getConfiguredConnection(http_req_url, HttpMethod.GET);
934
935             LOGwriteFirstTrace(HttpMethod.GET, http_req_url.toString());
936
937             // Check for errors
938             int responseCode = con.getResponseCode();
939             if (responseCode == HttpURLConnection.HTTP_OK) {
940                 inputStream = con.getInputStream();
941             } else {
942                 inputStream = con.getErrorStream();
943             }
944
945             // Process the response
946             LOG.debug("HttpURLConnection result:" + responseCode);
947             if(inputStream == null) inputStream = new ByteArrayInputStream("".getBytes(StandardCharsets.UTF_8));
948             BufferedReader reader = new BufferedReader( new InputStreamReader( inputStream ) );
949
950             ObjectMapper mapper = getObjectMapper();
951
952             if (responseCode == HttpURLConnection.HTTP_OK) {
953                 StringBuilder stringBuilder = new StringBuilder("\n");
954                 String line = null;
955                 while( ( line = reader.readLine() ) != null ) {
956                     stringBuilder.append( line );
957                 }
958                 LOG.info(stringBuilder.toString());
959 //                response = mapper.readValue(reader, String.class);
960                 response = stringBuilder.toString();
961                 LOGwriteEndingTrace(HttpURLConnection.HTTP_OK, "SUCCESS", mapper.writeValueAsString(response));
962             } else if(responseCode == HttpURLConnection.HTTP_NOT_FOUND ) {
963                 LOGwriteEndingTrace(responseCode, "HTTP_NOT_FOUND", "Entry does not exist.");
964                 response = null;
965             } else {
966                 ErrorResponse errorresponse = mapper.readValue(reader, ErrorResponse.class);
967                 LOGwriteEndingTrace(responseCode, "FAILURE", mapper.writeValueAsString(errorresponse));
968                 throw new AAIServiceException(responseCode, errorresponse);
969             }
970
971         } catch(AAIServiceException aaiexc) {
972             throw aaiexc;
973         } catch (Exception exc) {
974             LOG.warn("requestNetworkVceData", exc);
975             throw new AAIServiceException(exc);
976         } finally {
977             if(inputStream != null){
978                 try {
979                     inputStream.close();
980                 } catch(Exception exc) {
981                     LOG.warn("Error closing Input stream", exc);
982                 }
983             }
984         }
985         return response;
986     }
987
988
989     @Override
990     public GenericVnf requestGenericVnfeNodeQuery(String vnf_name) throws AAIServiceException {
991
992         if(vnf_name == null) {
993             throw new NullPointerException();
994         }
995
996         GenericVnf entity = null;
997         SearchResults resp = this.requestNodeQuery("generic-vnf", "vnf-name", vnf_name);
998
999         List<ResultData> resultDataList = resp.getResultData();
1000
1001         try {
1002             for (ResultData datum : resultDataList) {
1003                 URI url = new URI(datum.getResourceLink());
1004                 entity = this.getResource(url.toString(), GenericVnf.class);
1005             }
1006         }
1007         catch (Exception e)
1008         {
1009             LOG.error("Caught exception", e);
1010         }
1011         return entity;
1012     }
1013
1014     @Override
1015     public Vserver requestVServerDataByURL(URL url) throws AAIServiceException {
1016
1017         if(url == null) {
1018             throw new NullPointerException();
1019         }
1020
1021         Vserver entity = null;
1022
1023         try {
1024                 entity = this.getResource(url.toString(), Vserver.class);
1025         } catch (AAIServiceException exc) {
1026             throw exc;
1027         } catch (Exception e) {
1028             throw new AAIServiceException(e);
1029         }
1030         return entity;
1031     }
1032
1033     @Override
1034     public URL requestVserverURLNodeQuery(String vserver_name) throws AAIServiceException {
1035
1036         if(vserver_name == null) {
1037             throw new NullPointerException();
1038         }
1039
1040         URL entity = null;
1041         SearchResults resp = this.requestNodeQuery("vserver", "vserver-name", vserver_name);
1042
1043         List<ResultData> resultDataList = resp.getResultData();
1044
1045         try {
1046             for (ResultData datum : resultDataList) {
1047                 String data_type = datum.getResourceType();
1048                 String resourceLink = datum.getResourceLink();
1049                 if(!resourceLink.isEmpty() && !resourceLink.toLowerCase().startsWith("http")) {
1050                     resourceLink = (new EchoRequest()).targetUri + resourceLink;
1051                 }
1052                 entity = new URL(resourceLink);
1053             }
1054         } catch (Exception e) {
1055             throw new AAIServiceException(e);
1056         }
1057         return entity;
1058     }
1059
1060     @Override
1061     public String getTenantIdFromVserverUrl(URL url) {
1062
1063         String path = url.getPath();
1064
1065         String[] split = path.split("/tenants/tenant/");
1066         if(split.length > 1) {
1067             split = split[1].split("/");
1068             return split[0];
1069         } else {
1070             return null;
1071         }
1072     }
1073
1074     @Override
1075     public String getCloudOwnerFromVserverUrl(URL url) {
1076
1077         String path = url.getPath();
1078
1079         String[] split = path.split("/cloud-regions/cloud-region/");
1080         if(split.length > 1) {
1081             split = split[1].split("/");
1082             return split[0];
1083         } else {
1084             return null;
1085         }
1086     }
1087
1088     @Override
1089     public String getCloudRegionFromVserverUrl(URL url) {
1090
1091         String path = url.getPath();
1092
1093         String[] split = path.split("/cloud-regions/cloud-region/");
1094         if(split.length > 1) {
1095             split = split[1].split("/");
1096             return split[1];
1097         } else {
1098             return null;
1099         }
1100     }
1101
1102     @Override
1103     public String getVServerIdFromVserverUrl(URL url, String tenantId) {
1104         String pattern =  networkVserverPath;
1105         pattern = pattern.replace("{tenant-id}", tenantId);
1106
1107         int end = pattern.indexOf("{vserver-id}");
1108         String prefix = pattern.substring(0, end);
1109
1110         String path = url.getPath();
1111
1112         if(path.startsWith(prefix)) {
1113             path = path.substring(prefix.length());
1114         }
1115
1116         return path;
1117     }
1118
1119     protected  Logger getLogger(){
1120         return LOG;
1121     }
1122
1123
1124     @Override
1125     public AAIExecutorInterface getExecutor() {
1126         return executor;
1127     }
1128
1129     /**
1130      * Creates a current time stamp in UTC i.e. 2016-03-08T22:15:13.343Z.
1131      * If there are any parameters the values are appended to the time stamp.
1132      *
1133      * @param parameters
1134      *            values to be appended to current time stamp
1135      * @param ctx
1136      *            used to set an attribute for a DG
1137      * @throws SvcLogicException
1138      */
1139     public void setStatusMethod(Map<String, String> parameters, SvcLogicContext ctx) throws SvcLogicException {
1140         if (ctx == null) {
1141             throw new SvcLogicException("SvcLogicContext is null.");
1142         }
1143
1144         StringBuilder sb = new StringBuilder();
1145         sb.append(String.format("%tFT%<tTZ", Calendar.getInstance(TimeZone.getTimeZone("Z")))).append(" - ");
1146
1147         for (Entry<String, String> entry : parameters.entrySet()) {
1148             sb.append(entry.getValue()).append("  ");
1149         }
1150
1151         if (sb.length() > 0) {
1152             sb.setLength(sb.length() - 2);
1153         }
1154
1155         ctx.setAttribute("aai-summary-status-message", sb.toString());
1156         LOG.info("aai-summary-status-message: " + sb.toString());
1157     }
1158
1159     /**
1160      * Generic method to GET json data from an A&AI using key structure.
1161      * Then convert that json to an Object.
1162      * If successful the Object is attempted to be cast to the type parameter.
1163      *
1164      * @param key
1165      *            key identifying the resource to be retrieved from AAI
1166      * @param type
1167      *            the class of object that A&AI will return
1168      * @return the object created from json or null if the response code is not 200
1169      *
1170      * @throws AAIServiceException
1171      *             if empty or null key and or type or there's an error with processing
1172      */
1173
1174     public <T> T getResource(String key, Class<T> type) throws AAIServiceException {
1175             if (StringUtils.isEmpty(key) || type == null) {
1176                 throw new AAIServiceException("Key is empty or null and or type is null");
1177             }
1178
1179             T response = null;
1180
1181             SvcLogicContext ctx = new SvcLogicContext();
1182             if(!key.contains(" = ")) {
1183                 if(isValidURL(key)) {
1184                     key = String.format("selflink = '%s'", key);
1185                 } else if(isValidURI(key)) {
1186                     key = String.format("resource-path = '%s'", key);
1187                 } else {
1188                     return response;
1189                 }
1190             }
1191
1192             HashMap<String, String> nameValues = AAIServiceUtils.keyToHashMap(key, ctx);
1193
1194             AAIRequest request = new SelfLinkRequest(type);
1195             if(nameValues.containsKey(PathRequest.RESOURCE_PATH.replaceAll("-", "_"))) {
1196                 request = new PathRequest(type);
1197             }
1198
1199             request.processRequestPathValues(nameValues);
1200             Object obj = this.getExecutor().query(request, type);
1201             response = type.cast(obj);
1202
1203             return response != null ? type.cast(response) : response;
1204      }
1205
1206      public boolean isValidURL(String url) {
1207
1208             URL u = null;
1209
1210             try {
1211                 u = new URL(url);
1212             } catch (MalformedURLException e) {
1213                 LOG.warn("MalformedURLException", e);
1214                 return false;
1215             }
1216
1217             try {
1218                 u.toURI();
1219             } catch (URISyntaxException e) {
1220                 LOG.warn("URISyntaxException", e);
1221                 return false;
1222             }
1223
1224             return true;
1225         }
1226
1227
1228     public boolean isValidURI(String url) {
1229
1230         URI u = null;
1231
1232         try {
1233             u = new URI(url);
1234         } catch (URISyntaxException e) {
1235             LOG.warn("URISyntaxException", e);
1236             return false;
1237         }
1238
1239         return true;
1240     }
1241
1242
1243     protected boolean deleteList(URL httpReqUrl, String json_text) throws AAIServiceException {
1244         if(httpReqUrl ==  null) {
1245             throw new NullPointerException();
1246         }
1247
1248         boolean response = false;
1249         InputStream inputStream = null;
1250
1251         try {
1252             HttpURLConnection con = getConfiguredConnection(httpReqUrl, HttpMethod.DELETE);
1253
1254 //            SSLSocketFactory sockFact = CTX.getSocketFactory();
1255 //            con.setSSLSocketFactory( sockFact );
1256             if (json_text != null) {
1257                 OutputStreamWriter osw = new OutputStreamWriter(con.getOutputStream());
1258                 osw.write(json_text);
1259                 osw.flush();
1260                 osw.close();
1261             }
1262
1263             LOGwriteFirstTrace("DELETE", httpReqUrl.toString());
1264             LOGwriteDateTrace("data", json_text);
1265
1266             // Check for errors
1267             int responseCode = con.getResponseCode();
1268             if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_NO_CONTENT) {
1269                 inputStream = con.getInputStream();
1270             } else {
1271                 inputStream = con.getErrorStream();
1272             }
1273
1274             // Process the response
1275             LOG.debug("HttpURLConnection result:" + responseCode);
1276             if(inputStream == null) inputStream = new ByteArrayInputStream("".getBytes(StandardCharsets.UTF_8));
1277             BufferedReader reader = new BufferedReader( new InputStreamReader( inputStream ) );
1278             String line = null;
1279
1280             ObjectMapper mapper = getObjectMapper();
1281
1282             if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_NO_CONTENT) {
1283                 StringBuilder stringBuilder = new StringBuilder();
1284
1285                 while( ( line = reader.readLine() ) != null ) {
1286                     stringBuilder.append( line );
1287                 }
1288                 LOGwriteEndingTrace(responseCode, "SUCCESS", stringBuilder.toString());
1289                 response = true;
1290             } else if(responseCode == HttpURLConnection.HTTP_NOT_FOUND ) {
1291                 LOGwriteEndingTrace(responseCode, "HTTP_NOT_FOUND", "Entry does not exist.");
1292                 response = false;
1293             } else {
1294                 ErrorResponse errorresponse = mapper.readValue(reader, ErrorResponse.class);
1295                 LOGwriteEndingTrace(responseCode, "FAILURE", mapper.writeValueAsString(errorresponse));
1296                 throw new AAIServiceException(responseCode, errorresponse);
1297             }
1298
1299         } catch(AAIServiceException aaiexc) {
1300             throw aaiexc;
1301         } catch (Exception exc) {
1302             LOG.warn("deleteList", exc);
1303             throw new AAIServiceException(exc);
1304         } finally {
1305             if(inputStream != null){
1306                 try {
1307                     inputStream.close();
1308                 } catch(Exception exc) {
1309
1310                 }
1311             }
1312         }
1313         return response;
1314     }
1315
1316     public static ObjectMapper getObjectMapper() {
1317         ObjectMapper mapper = new ObjectMapper();
1318         AnnotationIntrospector introspector = new JaxbAnnotationIntrospector(TypeFactory.defaultInstance());
1319         AnnotationIntrospector secondary = new JacksonAnnotationIntrospector();
1320         mapper.setAnnotationIntrospector(AnnotationIntrospector.pair(introspector, secondary));
1321         mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
1322         mapper.setSerializationInclusion(Include.NON_NULL);
1323         mapper.setSerializationInclusion(Include.NON_EMPTY);
1324         return mapper;
1325     }
1326
1327     public void logMetricRequest(String requestId, String targetServiceName, String msg, String path){
1328         String svcInstanceId = "";
1329         String svcName = null;
1330         String partnerName = null;
1331         String targetEntity = "A&AI";
1332         String targetVirtualEntity = null;
1333
1334         ml.logRequest(svcInstanceId, svcName, partnerName, targetEntity, targetServiceName, targetVirtualEntity, msg);
1335     }
1336
1337     public void logMetricResponse(String requestId, int responseCode, String responseDescription){
1338         ml.logResponse(responseCode < 400 ? "COMPLETE" : "ERROR", Integer.toString(responseCode), responseDescription);
1339     }
1340
1341     public void logKeyError(String keys){
1342         LOG.error("Atleast one of the keys [" + keys + "] should have been populated. This will cause a NPE.");
1343     }
1344
1345
1346     /**
1347      * Retrofit code
1348      */
1349     @Override
1350     public QueryStatus save(String resource, boolean force, boolean localOnly, String key, Map<String, String> params, String prefix, SvcLogicContext ctx)
1351             throws SvcLogicException {
1352         String normResource = resource.split(":")[0];
1353
1354         switch(normResource){
1355         case "custom-query":
1356         case "formatted-query":
1357         case "generic-query":
1358         case "nodes-query":
1359         case "linterface":
1360         case "l2-bridge-sbg":
1361         case "l2-bridge-bgf":
1362         case "echo":
1363         case "test":
1364             break;
1365
1366         default:
1367             if(key.contains("selflink =")) {
1368                 break;
1369             }
1370             if(!key.contains(String.format("%s.", normResource))) {
1371                 key = rewriteKey(resource, key, ctx);
1372             }
1373         }
1374         return super.save(resource, force, localOnly, key, params, prefix, ctx);
1375     }
1376
1377     @Override
1378     public QueryStatus query(String resource, boolean localOnly, String select, String key, String prefix, String orderBy, SvcLogicContext ctx)
1379         throws SvcLogicException {
1380         String normResource = resource.split(":")[0];
1381
1382         switch(normResource){
1383         case "custom-query":
1384         case "formatted-query":
1385         case "generic-query":
1386         case "nodes-query":
1387         case "linterface":
1388         case "l2-bridge-sbg":
1389         case "l2-bridge-bgf":
1390         case "echo":
1391         case "test":
1392             break;
1393
1394         default:
1395             if(key.contains("selflink =")) {
1396                 break;
1397             }
1398             if(!key.contains(String.format("%s.", normResource))) {
1399                 key = rewriteKey(resource, key, ctx);
1400             }
1401         }
1402
1403         return super.query(resource, localOnly, select, key, prefix, orderBy, ctx);
1404     }
1405
1406     @Override
1407     public QueryStatus delete(String resource, String key, SvcLogicContext ctx) throws SvcLogicException {
1408         String normResource = resource.split(":")[0];
1409
1410         switch(normResource){
1411         case "custom-query":
1412         case "formatted-query":
1413         case "generic-query":
1414         case "nodes-query":
1415         case "linterface":
1416         case "l2-bridge-sbg":
1417         case "l2-bridge-bgf":
1418         case "echo":
1419         case "test":
1420             break;
1421
1422         default:
1423             if(key.contains("selflink =")) {
1424                 break;
1425             }
1426             if(!key.contains(String.format("%s.", normResource))) {
1427                 key = rewriteKey(resource, key, ctx);
1428             }
1429         }
1430
1431         return super.delete(resource, key, ctx);
1432     }
1433
1434     @Override
1435     public QueryStatus update(String resource, String key, Map<String, String> params, String prefix, SvcLogicContext ctx) throws SvcLogicException {
1436         String normResource = resource.split(":")[0];
1437
1438         switch(normResource){
1439         case "custom-query":
1440         case "formatted-query":
1441         case "generic-query":
1442         case "nodes-query":
1443         case "linterface":
1444         case "l2-bridge-sbg":
1445         case "l2-bridge-bgf":
1446         case "echo":
1447         case "test":
1448             break;
1449
1450         default:
1451             if(key.contains("selflink =")) {
1452                 break;
1453             }
1454             if(!key.contains(String.format("%s.", normResource))) {
1455                 key = rewriteKey(resource, key, ctx);
1456             }
1457         }
1458
1459         return super.update(resource, key, params, prefix, ctx);
1460     }
1461
1462     private String rewriteKey(String resource, String key, SvcLogicContext ctx) {
1463         LOG.info("AAI Deprecation - the format of request key is no longer supported. Please rewrite this key : " + key);
1464
1465         String normResource = resource.split(":")[0];
1466         Class<? extends AAIDatum> clazz = AAIRequest.getClassFromResource(normResource) ;
1467
1468         if(clazz == null)
1469             return key;
1470
1471         List<String> fieldAnnotatedNames = new LinkedList<>();
1472
1473         Field[] fields = clazz.getDeclaredFields();
1474         for(Field field : fields) {
1475             String fieldName = field.getName();
1476             XmlElement annotation = field.getAnnotation(XmlElement.class);
1477             if(annotation == null)
1478                 continue;
1479             String primaryId = annotation.name();
1480             if("##default".equals(primaryId)) {
1481                 primaryId = fieldName;
1482             }
1483             fieldAnnotatedNames.add(primaryId);
1484         }
1485
1486         HashMap<String, String> nameValues = AAIServiceUtils.keyToHashMap(key, ctx);
1487         Set<String> keyset = nameValues.keySet();
1488         for(String keyName : keyset) {
1489             if(keyName.contains("."))
1490                 continue;
1491             else {
1492                 String tmpKeyName = keyName.replaceAll("_", "-");
1493                 String valueToSubstitute = String.format("%s =", tmpKeyName);
1494                 if(fieldAnnotatedNames.contains(tmpKeyName) && key.contains(valueToSubstitute)) {
1495                     key = key.replace(valueToSubstitute, String.format("%s.%s =", normResource, tmpKeyName));
1496                 }
1497             }
1498         }
1499
1500
1501         return key;
1502     }
1503
1504     @Override
1505     public String getPathTemplateForResource(String resoourceName, String keys, SvcLogicContext ctx) throws MalformedURLException {
1506         return AAIServiceUtils.getPathForResource(resoourceName, StringUtils.join(keys, " AND "), ctx);
1507     }
1508
1509     @Override
1510     public boolean isDeprecatedFormat(String resource, Map<String, String> nameValues) {
1511         return !AAIServiceUtils.isValidFormat(resource, nameValues);
1512     }
1513
1514     public AAIRequest getRequestFromResource(String resoourceName) {
1515         return AAIRequest.getRequestFromResource(resoourceName);
1516     }
1517
1518     /* (non-Javadoc)
1519      * @see org.onap.ccsdk.sli.core.sli.aai.haha#query(org.onap.ccsdk.sli.core.sli.aai.AAIRequest)
1520      */
1521     @Override
1522     public String query(AAIRequest request) throws AAIServiceException {
1523         return executor.get(request);
1524     }
1525
1526     /* (non-Javadoc)
1527      * @see org.onap.ccsdk.sli.core.sli.aai.haha#save(org.onap.ccsdk.sli.core.sli.aai.AAIRequest)
1528      */
1529     @Override
1530     public String save(AAIRequest request) throws AAIServiceException {
1531         return executor.post(request);
1532     }
1533
1534     public boolean update(AAIRequest request, String resourceVersion) throws AAIServiceException {
1535         return executor.patch(request, resourceVersion);
1536     }
1537
1538     /* (non-Javadoc)
1539      * @see org.onap.ccsdk.sli.core.sli.aai.haha#delete(org.onap.ccsdk.sli.core.sli.aai.AAIRequest, java.lang.String)
1540      */
1541     @Override
1542     public boolean delete(AAIRequest request, String resourceVersion) throws AAIServiceException {
1543         return executor.delete(request, resourceVersion);
1544     }
1545
1546 }