2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights
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
14 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
24 * @author Rich Tabedzki
27 package org.onap.ccsdk.sli.adaptors.aai;
29 import java.io.BufferedReader;
30 import java.io.ByteArrayInputStream;
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;
43 import java.net.URISyntaxException;
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;
57 import java.util.Map.Entry;
58 import java.util.Properties;
60 import java.util.TimeZone;
61 import java.util.UUID;
62 import java.util.regex.Matcher;
63 import java.util.regex.Pattern;
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;
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.v14.GenericVnf;
85 import org.onap.aai.inventory.v14.PhysicalLink;
86 import org.onap.aai.inventory.v14.ResultData;
87 import org.onap.aai.inventory.v14.SearchResults;
88 import org.onap.aai.inventory.v14.Vserver;
89 import org.slf4j.Logger;
90 import org.slf4j.LoggerFactory;
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 import com.sun.jersey.api.client.config.DefaultClientConfig;
101 import com.sun.jersey.client.urlconnection.HTTPSProperties;
104 public class AAIService extends AAIDeclarations implements AAIClient, SvcLogicResource {
106 public static final String AAICLIENT_PROPERTIES = "/aaiclient.properties";
107 public static final String PATH_PROPERTIES = "/aai-path.properties";
109 private static final Logger LOG = LoggerFactory.getLogger(AAIService.class);
111 private final String truststorePath;
112 private final String truststorePassword;
113 private final String keystorePath;
114 private final String keystorePassword;
115 private final Boolean ignoreCertificateHostError;
117 private final String targetUri;
118 private final String networkVserverPath;
120 private final String svc_inst_query_path;
122 private final String ubb_notify_path;
123 private final String selflinkAvpn;
124 private final String selflinkFqdn;
126 private final int connectionTimeout;
127 private final int readTimeout;
130 private final String queryNodesPath;
131 private final String applicationId;
133 // authentication credentials
134 private String userName;
135 private String userPassword;
138 private final boolean runtimeOSGI;
140 private SSLContext CTX;
142 private final MetricLogger ml = new MetricLogger();
144 private AAIExecutorInterface executor;
146 public AAIService(final UtilsProvider configuration) {
147 this(configuration.getProperties());
150 public AAIService(final URL url) {
151 this(getProperties(url));
154 public AAIService(Properties props) {
155 LOG.info("Entered AAIService.ctor");
157 String runtime = System.getProperty("aaiclient.runtime");
158 if("OSGI".equals(runtime)) {
165 AAIRequest.setProperties(props, this);
167 } catch(Exception exc){
168 LOG.error("AicAAIResource.static", exc);
171 executor = new AAIClientRESTExecutor(props);
173 userName = props.getProperty(CLIENT_NAME);
174 userPassword = props.getProperty(CLIENT_PWWD);
176 if(userName == null || userName.isEmpty()){
177 LOG.debug("Basic user name is not set");
179 if(userPassword == null || userPassword.isEmpty()) {
180 LOG.debug("Basic password is not set");
183 truststorePath = props.getProperty(TRUSTSTORE_PATH);
184 truststorePassword = props.getProperty(TRUSTSTORE_PSSWD);
185 keystorePath = props.getProperty(KEYSTORE_PATH);
186 keystorePassword = props.getProperty(KEYSTORE_PSSWD);
188 targetUri = props.getProperty(TARGET_URI);
189 props.getProperty(QUERY_PATH);
190 props.getProperty(UPDATE_PATH);
192 String tmpApplicationId = props.getProperty(APPLICATION_ID);
193 if(tmpApplicationId == null || tmpApplicationId.isEmpty()) {
194 tmpApplicationId = "SDNC";
196 this.applicationId = tmpApplicationId;
198 // connection timeout
199 int tmpConnectionTimeout = 30000;
200 int tmpReadTimeout = 30000;
203 String tmpValue = null;
204 tmpValue = props.getProperty(CONNECTION_TIMEOUT, "30000");
205 tmpConnectionTimeout = Integer.parseInt(tmpValue);
206 tmpValue = props.getProperty(READ_TIMEOUT, "30000");
207 tmpReadTimeout = Integer.parseInt(tmpValue);
208 } catch(Exception exc) {
209 LOG.error("Failed setting connection timeout", exc);
210 tmpConnectionTimeout = 30000;
211 tmpReadTimeout = 30000;
213 connectionTimeout = tmpConnectionTimeout;
214 readTimeout = tmpReadTimeout;
216 networkVserverPath =props.getProperty(NETWORK_VSERVER_PATH);
218 props.getProperty(SVC_INSTANCE_PATH);
219 svc_inst_query_path = props.getProperty(SVC_INST_QRY_PATH);
220 props.getProperty(PARAM_SERVICE_TYPE, "service-type");
222 props.getProperty(P_INTERFACE_PATH);
224 props.getProperty(VNF_IMAGE_QUERY_PATH);
226 ubb_notify_path = props.getProperty(UBB_NOTIFY_PATH);
227 selflinkAvpn = props.getProperty(SELFLINK_AVPN);
228 selflinkFqdn = props.getProperty(SELFLINK_FQDN);
230 props.getProperty(SERVICE_PATH);
232 props.getProperty(SITE_PAIR_SET_PATH);
234 queryNodesPath = props.getProperty(QUERY_NODES_PATH);
236 String iche = props.getProperty(CERTIFICATE_HOST_ERROR);
237 boolean host_error = false;
238 if(iche != null && !iche.isEmpty()) {
239 host_error = Boolean.valueOf(iche);
242 ignoreCertificateHostError = host_error;
244 HttpsURLConnection.setDefaultHostnameVerifier( new HostnameVerifier(){
245 public boolean verify(String string,SSLSession ssls) {
246 return ignoreCertificateHostError;
250 if(truststorePath != null && truststorePassword != null && (new File(truststorePath)).exists()) {
251 System.setProperty("javax.net.ssl.trustStore", truststorePath);
252 System.setProperty("javax.net.ssl.trustStorePassword", truststorePassword);
255 if(keystorePath != null && keystorePassword != null && (new File(keystorePath)).exists()) {
256 DefaultClientConfig config = new DefaultClientConfig();
257 //both jersey and HttpURLConnection can use this
258 SSLContext ctx = null;
260 ctx = SSLContext.getInstance("TLS");
262 KeyManagerFactory kmf = null;
263 try (FileInputStream fin = new FileInputStream(keystorePath)){
264 String def = "SunX509";
265 String storeType = "PKCS12";
266 def = KeyStore.getDefaultType();
267 kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
269 String extension = keystorePath.substring(keystorePath.lastIndexOf(".") + 1);
270 if("JKS".equalsIgnoreCase(extension)) {
273 KeyStore ks = KeyStore.getInstance(storeType);
275 char[] pwd = keystorePassword.toCharArray();
278 } catch (Exception ex) {
279 LOG.error("AAIResource", ex);
283 ctx.init(kmf.getKeyManagers(), null, null);
285 config.getProperties().put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES, new HTTPSProperties( new HostnameVerifier() {
287 public boolean verify( String s, SSLSession sslSession ) {
288 return ignoreCertificateHostError;
293 LOG.debug("SSLContext created");
295 } catch (KeyManagementException | NoSuchAlgorithmException exc) {
296 LOG.error("AAIResource", exc);
300 LOG.info("AAIResource.ctor initialized.");
303 Field methodsField = HttpURLConnection.class.getDeclaredField("methods");
304 methodsField.setAccessible(true);
305 // get the methods field modifiers
306 Field modifiersField = Field.class.getDeclaredField("modifiers");
307 // bypass the "private" modifier
308 modifiersField.setAccessible(true);
310 // remove the "final" modifier
311 modifiersField.setInt(methodsField, methodsField.getModifiers() & ~Modifier.FINAL);
313 /* valid HTTP methods */
315 "GET", "POST", "HEAD", "OPTIONS", "PUT", "DELETE", "TRACE", "PATCH"
317 // set the new methods - including patch
318 methodsField.set(null, methods);
320 } catch (SecurityException | IllegalArgumentException | IllegalAccessException | NoSuchFieldException e) {
321 LOG.error("Exception occured", e);
326 private static Properties getProperties(URL url) {
327 Properties properties = new Properties();
329 properties.load(url.openStream());
330 } catch (IOException exc) {
331 LOG.error("getProperties", exc);
336 public void setExecutor(AAIExecutorInterface executor) {
337 this.executor = executor;
340 public void cleanUp() {
346 * @param http_req_url
351 protected HttpURLConnection getConfiguredConnection(URL http_req_url, String method) throws Exception {
352 HttpURLConnection con = (HttpURLConnection) http_req_url.openConnection();
354 // Set up the connection properties
355 con.setRequestProperty( "Connection", "close" );
356 con.setDoInput(true);
357 con.setDoOutput(true);
358 con.setUseCaches(false);
359 con.setConnectTimeout( connectionTimeout );
360 con.setReadTimeout( readTimeout );
361 con.setRequestMethod( method );
362 con.setRequestProperty( "Accept", "application/json" );
363 con.setRequestProperty( "Content-Type", "PATCH".equalsIgnoreCase(method) ? "application/merge-patch+json" : "application/json" );
364 con.setRequestProperty("X-FromAppId", applicationId);
365 con.setRequestProperty("X-TransactionId",TransactionIdTracker.getNextTransactionId());
366 String mlId = ml.getRequestID();
367 if(mlId != null && !mlId.isEmpty()) {
368 LOG.debug(String.format("MetricLogger requestId = %s", mlId));
369 con.setRequestProperty(MetricLogger.REQUEST_ID, mlId);
371 LOG.debug("MetricLogger requestId is null");
373 con.setRequestProperty("Transfer-Encoding","chunked");
375 if(userName != null && !userName.isEmpty() && userPassword != null && !userPassword.isEmpty()) {
376 String basicAuth = "Basic " + new String(Base64.encodeBase64((userName + ":" + userPassword).getBytes()));
377 con.setRequestProperty ("Authorization", basicAuth);
380 if(con instanceof HttpsURLConnection && CTX != null) {
381 SSLSocketFactory sockFact = CTX.getSocketFactory();
382 HttpsURLConnection.class.cast(con).setSSLSocketFactory( sockFact );
389 public GenericVnf requestGenericVnfData(String vnf_id) throws AAIServiceException {
390 GenericVnf response = null;
393 AAIRequest request = AAIRequest.getRequestFromResource("generic-vnf");
394 request.addRequestProperty("generic-vnf.vnf-id", vnf_id);
395 String rv = executor.get(request);
397 ObjectMapper mapper = getObjectMapper();
398 response = mapper.readValue(rv, GenericVnf.class);
400 } catch(AAIServiceException aaiexc) {
402 } catch (Exception exc) {
403 LOG.warn(Object.class.getClass().getEnclosingMethod().getName(), exc);
404 throw new AAIServiceException(exc);
412 public boolean postGenericVnfData(String vnf_id, GenericVnf data) throws AAIServiceException {
414 AAIRequest request = AAIRequest.getRequestFromResource("generic-vnf");
415 request.addRequestProperty("generic-vnf.vnf-id", vnf_id);
416 request.setRequestObject(data);
417 Object response = executor.post(request);
419 } catch(AAIServiceException aaiexc) {
421 } catch (Exception exc) {
422 LOG.warn("requestGenericVnfData", exc);
423 throw new AAIServiceException(exc);
428 public SearchResults requestServiceInstanceURL(String svc_instance_id) throws AAIServiceException {
429 SearchResults response = null;
430 InputStream inputStream = null;
433 String path = svc_inst_query_path;
434 path = path.replace("{svc-instance-id}", encodeQuery(svc_instance_id));
436 String request_url = targetUri+path;
437 URL http_req_url = new URL(request_url);
439 HttpURLConnection con = getConfiguredConnection(http_req_url, HttpMethod.GET);
441 LOGwriteFirstTrace(HttpMethod.GET, http_req_url.toString());
442 LOGwriteDateTrace("svc_instance_id", svc_instance_id);
445 int responseCode = con.getResponseCode();
446 if (responseCode == HttpURLConnection.HTTP_OK) {
447 inputStream = con.getInputStream();
449 inputStream = con.getErrorStream();
452 // Process the response
453 LOG.debug("HttpURLConnection result:" + responseCode);
454 if(inputStream == null) inputStream = new ByteArrayInputStream("".getBytes(StandardCharsets.UTF_8));
455 BufferedReader reader = new BufferedReader( new InputStreamReader( inputStream ) );
457 ObjectMapper mapper = getObjectMapper();
459 if (responseCode == HttpURLConnection.HTTP_OK) {
460 response = mapper.readValue(reader, SearchResults.class);
461 LOGwriteEndingTrace(HttpURLConnection.HTTP_OK, "SUCCESS", mapper.writeValueAsString(response));
462 } else if(responseCode == HttpURLConnection.HTTP_NOT_FOUND ) {
463 LOGwriteEndingTrace(responseCode, "HTTP_NOT_FOUND", "Entry does not exist.");
466 ErrorResponse errorresponse = mapper.readValue(reader, ErrorResponse.class);
467 LOGwriteEndingTrace(responseCode, "FAILURE", mapper.writeValueAsString(errorresponse));
468 throw new AAIServiceException(responseCode, errorresponse);
471 } catch(AAIServiceException aaiexc) {
473 } catch (Exception exc) {
474 LOG.warn("requestServiceInstanceURL", exc);
475 throw new AAIServiceException(exc);
477 if(inputStream != null){
480 } catch(Exception exc) {
481 LOG.warn("Error closing Inputstream", exc);
489 private static Properties initialize(URL url ) throws ConfigurationException {
492 throw new NullPointerException();
495 InputStream is = null;
496 Properties props = new Properties();
499 if(LOG.isDebugEnabled())
500 LOG.info("Property file is: " + url.toString());
502 is = url.openStream();
505 if(LOG.isDebugEnabled()) {
506 LOG.info("Properties loaded: " + props.size());
507 Enumeration<Object> en = props.keys();
509 while(en.hasMoreElements()) {
510 String key = (String)en.nextElement();
511 String property = props.getProperty(key);
512 LOG.debug(key + " : " + property);
515 } catch (Exception e) {
516 throw new ConfigurationException("Could not load properties file.", e);
521 static class TransactionIdTracker {
522 // protected static AtomicLong tracker = new AtomicLong();
524 public static String getNextTransactionId() {
525 // Check if RequestId exists as MDC. If not, create new.
526 String transactionId = MDC.get("RequestId");
527 if ("".equals(transactionId) || transactionId == null) {
528 transactionId = UUID.randomUUID().toString();
529 LOG.info("Missing requestID. Assigned " + transactionId);
530 MDC.put("RequestId", transactionId);
532 return transactionId;
537 protected void LOGwriteFirstTrace(String method, String url) {
538 String time = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'").format(System.currentTimeMillis());
539 LOG.info("A&AI transaction :");
540 LOG.info("Request Time : " + time + ", Method : " + method);
541 LOG.info("Request URL : "+ url);
544 protected void LOGwriteDateTrace(String name, String data) {
545 LOG.info("Input - " + name + " : " + data);
548 protected void LOGwriteEndingTrace(int response_code, String comment, String data) {
549 LOG.info("Response code : " + response_code +", " + comment);
550 LOG.info(String.format("Response data : %s", data));
553 protected String encodeQuery(String param) throws UnsupportedEncodingException {
554 return URLEncoder.encode(param, "UTF-8").replace("+", "%20");
557 private String encodeCustomerURL(final String selection)
559 String encrypted_url = selection;
561 "/aai/v11/business/customers/customer/(.+)/service-subscriptions/service-subscription/(.+)/service-instances/service-instance/(.+)/";
562 Pattern pattern = Pattern.compile(apnpattern);
565 URL url = new URL(selection);
566 String path = url.getPath();
568 LOG.info("Trying to match apn to <" + path + ">");
570 Matcher matcher = pattern.matcher(path);
572 while(matcher.find()) {
573 String customer = matcher.group(1);
574 String subscription = matcher.group(2);
575 String service = matcher.group(3);
577 encrypted_url = selection.replace(customer, encodeQuery(customer));
578 encrypted_url = encrypted_url.replace(subscription, encodeQuery(subscription));
579 encrypted_url = encrypted_url.replace(service, encodeQuery(service));
581 } catch (Exception e) {
585 return encrypted_url;
592 * @see org.onap.sdnct.sli.aai.AAIClient#requestVServersData(java.lang.String, java.lang.String)
595 public Vserver requestVServerData(String tenantId, String vserverId, String cloudOwner, String cloudRegionId) throws AAIServiceException {
596 Vserver response = null;
599 AAIRequest request = AAIRequest.getRequestFromResource("vserver");
600 request.addRequestProperty("cloud-region.cloud-owner", cloudOwner);
601 request.addRequestProperty("cloud-region.cloud-region-id", cloudRegionId);
602 request.addRequestProperty("tenant.tenant-id", tenantId);
603 request.addRequestProperty("vserver.vserver-id", vserverId);
605 String rv = executor.get(request);
607 ObjectMapper mapper = getObjectMapper();
608 response = mapper.readValue(rv, Vserver.class);
610 } catch(AAIServiceException aaiexc) {
612 } catch (Exception exc) {
613 LOG.warn(Object.class.getClass().getEnclosingMethod().getName(), exc);
614 throw new AAIServiceException(exc);
620 //================== End of DvsSwitch =================
621 //==================== PhysicalLink ======================
623 public PhysicalLink requestPhysicalLinkData(String linkName) throws AAIServiceException {
624 PhysicalLink response = null;
627 AAIRequest request = AAIRequest.getRequestFromResource("physical-link");
628 request.addRequestProperty("physical-link.link-name", linkName);
630 String rv = executor.get(request);
632 ObjectMapper mapper = getObjectMapper();
633 response = mapper.readValue(rv, PhysicalLink.class);
635 } catch(AAIServiceException aaiexc) {
637 } catch (Exception exc) {
638 LOG.warn("requestPhysicalLinkData", exc);
639 throw new AAIServiceException(exc);
645 public boolean postPhysicalLinkData(String linkName, PhysicalLink data) throws AAIServiceException {
647 AAIRequest request = AAIRequest.getRequestFromResource("physical-link");
648 request.addRequestProperty("physical-link.link-name", linkName);
649 request.setRequestObject(data);
650 Object response = executor.post(request);
652 } catch(AAIServiceException aaiexc) {
654 } catch (Exception exc) {
655 LOG.warn(Object.class.getClass().getEnclosingMethod().getName(), exc);
656 throw new AAIServiceException(exc);
661 public boolean deletePhysicalLinkData(String linkName, String resourceVersion) throws AAIServiceException {
662 boolean response = false;
665 AAIRequest request = AAIRequest.getRequestFromResource("physical-link");
666 request.addRequestProperty("physical-link.link-name", linkName);
667 response = executor.delete(request, resourceVersion);
668 } catch(AAIServiceException aaiexc) {
670 } catch (Exception exc) {
671 LOG.warn("deletePhysicalLinkData", exc);
672 throw new AAIServiceException(exc);
677 public boolean deleteAAIEntity(URL url, String caller) throws AAIServiceException {
680 throw new NullPointerException();
683 boolean response = false;
684 InputStream inputStream = null;
687 URL http_req_url = url;
689 HttpURLConnection con = getConfiguredConnection(http_req_url, HttpMethod.DELETE);
691 LOGwriteFirstTrace("DELETE", http_req_url.toString());
695 int responseCode = con.getResponseCode();
696 if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_NO_CONTENT) {
697 inputStream = con.getInputStream();
699 inputStream = con.getErrorStream();
702 // Process the response
703 LOG.debug("HttpURLConnection result:" + responseCode);
704 if(inputStream == null) inputStream = new ByteArrayInputStream("".getBytes(StandardCharsets.UTF_8));
705 BufferedReader reader = new BufferedReader( new InputStreamReader( inputStream ) );
708 ObjectMapper mapper = getObjectMapper();
710 if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_NO_CONTENT) {
711 StringBuilder stringBuilder = new StringBuilder();
713 while( ( line = reader.readLine() ) != null ) {
714 stringBuilder.append( line );
716 LOGwriteEndingTrace(responseCode, "SUCCESS", stringBuilder.toString());
718 } else if(responseCode == HttpURLConnection.HTTP_NOT_FOUND ) {
719 LOGwriteEndingTrace(responseCode, "HTTP_NOT_FOUND", "Entry does not exist.");
722 ErrorResponse errorresponse = mapper.readValue(reader, ErrorResponse.class);
723 LOGwriteEndingTrace(responseCode, "FAILURE", mapper.writeValueAsString(errorresponse));
724 throw new AAIServiceException(responseCode, errorresponse);
727 } catch(AAIServiceException aaiexc) {
729 } catch (Exception exc) {
730 LOG.warn(caller, exc);
731 throw new AAIServiceException(exc);
733 if(inputStream != null){
736 } catch(Exception exc) {
737 LOG.warn("Error closing InputStream", exc);
745 * Generic method to GET json data from an A&AI callback URL.
746 * Then convert that json to an Object.
747 * If successful the Object is attempted to be cast to the type parameter.
750 * callback url for A&AI
752 * the class of object that A&AI will return
753 * @return the object created from json or null if the response code is not 200
755 * @throws AAIServiceException
756 * if empty or null key and or type or there's an error with processing
758 public <T> T dataChangeRequestAaiData(String key, Class<T> type) throws AAIServiceException {
759 if (StringUtils.isEmpty(key) || type == null) {
760 throw new AAIServiceException("Key is empty or null and or type is null");
765 SvcLogicContext ctx = new SvcLogicContext();
766 if(!key.contains(" = ") && isValidURL(key)) {
767 key = String.format("selflink = '%s'", key);
769 if(!key.contains(" = ") && isValidURI(key)) {
770 key = String.format("resource-path = '%s'", key);
773 HashMap<String, String> nameValues = AAIServiceUtils.keyToHashMap(key, ctx);
775 SelfLinkRequest request = new SelfLinkRequest(type);
776 request.processRequestPathValues(nameValues);
777 Object obj = this.getExecutor().query(request, type);
778 response = type.cast(obj);
780 return response != null ? type.cast(response) : response;
784 public boolean sendNotify(NotifyEvent event, String serviceInstanceId, String pathCode) throws AAIServiceException {
785 InputStream inputStream = null;
789 String selfLink = selflinkFqdn;
790 if(SELFLINK_AVPN != null && SELFLINK_AVPN.equals(pathCode)) {
791 selfLink = selflinkAvpn;
793 selfLink = selfLink.replace("{service-instance-id}", encodeQuery(serviceInstanceId));
794 event.setSelflink(selfLink);
796 ObjectMapper mapper = getObjectMapper();
797 String json_text = mapper.writeValueAsString(event);
799 SSLSocketFactory sockFact = CTX.getSocketFactory();
801 String request_url = targetUri+ubb_notify_path;
802 URL http_req_url = new URL(request_url);
804 HttpURLConnection con = getConfiguredConnection(http_req_url, HttpMethod.PUT);
806 if (json_text != null) {
807 OutputStreamWriter osw = new OutputStreamWriter(con.getOutputStream());
808 osw.write(json_text);
813 LOGwriteFirstTrace("PUT", request_url);
814 LOGwriteDateTrace("NotifyEvent", json_text);
817 int responseCode = con.getResponseCode();
818 if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_CREATED || responseCode == HttpURLConnection.HTTP_ACCEPTED || responseCode == HttpURLConnection.HTTP_NO_CONTENT) {
819 inputStream = con.getInputStream();
821 inputStream = con.getErrorStream();
824 // Process the response
825 BufferedReader reader;
827 reader = new BufferedReader( new InputStreamReader( inputStream ) );
829 if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_CREATED || responseCode == HttpURLConnection.HTTP_ACCEPTED || responseCode == HttpURLConnection.HTTP_NO_CONTENT) {
830 StringBuilder stringBuilder = new StringBuilder();
832 while( ( line = reader.readLine() ) != null ) {
833 stringBuilder.append( line );
835 LOGwriteEndingTrace(responseCode, "SUCCESS", (stringBuilder.length() > 0) ? stringBuilder.toString() :
839 ErrorResponse errorresponse = mapper.readValue(reader, ErrorResponse.class);
840 LOGwriteEndingTrace(responseCode, "FAILURE", mapper.writeValueAsString(errorresponse));
842 throw new AAIServiceException(responseCode, errorresponse);
844 } catch(AAIServiceException aaiexc) {
846 } catch (Exception exc) {
847 LOG.warn("sendNotify", exc);
848 throw new AAIServiceException(exc);
851 if(inputStream != null)
853 } catch (Exception exc) {
854 LOG.warn("Error closing Input stream", exc);
860 public SearchResults requestNodeQuery(String node_type, String entityIdentifier, String entityName) throws AAIServiceException {
861 SearchResults response = null;
862 InputStream inputStream = null;
865 String request_url = targetUri+queryNodesPath;
866 request_url = request_url.replace("{node-type}", encodeQuery(node_type)) ;
867 request_url = request_url.replace("{entity-identifier}", entityIdentifier) ;
868 request_url = request_url.replace("{entity-name}", encodeQuery(entityName)) ;
869 URL http_req_url = new URL(request_url);
871 HttpURLConnection con = getConfiguredConnection(http_req_url, HttpMethod.GET);
873 LOGwriteFirstTrace(HttpMethod.GET, http_req_url.toString());
874 LOGwriteDateTrace("node_type", node_type);
875 LOGwriteDateTrace("vnf_name", entityName);
878 int responseCode = con.getResponseCode();
879 if (responseCode == HttpURLConnection.HTTP_OK) {
880 inputStream = con.getInputStream();
882 inputStream = con.getErrorStream();
885 // Process the response
886 LOG.debug("HttpURLConnection result:" + responseCode);
887 if(inputStream == null) inputStream = new ByteArrayInputStream("".getBytes(StandardCharsets.UTF_8));
888 BufferedReader reader = new BufferedReader( new InputStreamReader( inputStream ) );
890 ObjectMapper mapper = getObjectMapper();
892 if (responseCode == HttpURLConnection.HTTP_OK) {
893 response = mapper.readValue(reader, SearchResults.class);
894 LOGwriteEndingTrace(HttpURLConnection.HTTP_OK, "SUCCESS", mapper.writeValueAsString(response));
895 } else if (responseCode == HttpURLConnection.HTTP_NOT_FOUND) {
896 LOGwriteEndingTrace(responseCode, "HTTP_NOT_FOUND", "Entry does not exist.");
899 ErrorResponse errorresponse = mapper.readValue(reader, ErrorResponse.class);
900 LOGwriteEndingTrace(responseCode, "FAILURE", mapper.writeValueAsString(errorresponse));
901 throw new AAIServiceException(responseCode, errorresponse);
904 } catch(AAIServiceException aaiexc) {
906 } catch (Exception exc) {
907 LOG.warn("requestNodeQuery", exc);
908 throw new AAIServiceException(exc);
910 if(inputStream != null){
913 } catch(Exception exc) {
914 LOG.warn("Error closing Input stream", exc);
924 public String requestDataByURL(URL url) throws AAIServiceException {
927 throw new NullPointerException();
930 String response = null;
931 InputStream inputStream = null;
934 URL http_req_url = url;
936 HttpURLConnection con = getConfiguredConnection(http_req_url, HttpMethod.GET);
938 LOGwriteFirstTrace(HttpMethod.GET, http_req_url.toString());
941 int responseCode = con.getResponseCode();
942 if (responseCode == HttpURLConnection.HTTP_OK) {
943 inputStream = con.getInputStream();
945 inputStream = con.getErrorStream();
948 // Process the response
949 LOG.debug("HttpURLConnection result:" + responseCode);
950 if(inputStream == null) inputStream = new ByteArrayInputStream("".getBytes(StandardCharsets.UTF_8));
951 BufferedReader reader = new BufferedReader( new InputStreamReader( inputStream ) );
953 ObjectMapper mapper = getObjectMapper();
955 if (responseCode == HttpURLConnection.HTTP_OK) {
956 StringBuilder stringBuilder = new StringBuilder("\n");
958 while( ( line = reader.readLine() ) != null ) {
959 stringBuilder.append( line );
961 LOG.info(stringBuilder.toString());
962 // response = mapper.readValue(reader, String.class);
963 response = stringBuilder.toString();
964 LOGwriteEndingTrace(HttpURLConnection.HTTP_OK, "SUCCESS", mapper.writeValueAsString(response));
965 } else if(responseCode == HttpURLConnection.HTTP_NOT_FOUND ) {
966 LOGwriteEndingTrace(responseCode, "HTTP_NOT_FOUND", "Entry does not exist.");
969 ErrorResponse errorresponse = mapper.readValue(reader, ErrorResponse.class);
970 LOGwriteEndingTrace(responseCode, "FAILURE", mapper.writeValueAsString(errorresponse));
971 throw new AAIServiceException(responseCode, errorresponse);
974 } catch(AAIServiceException aaiexc) {
976 } catch (Exception exc) {
977 LOG.warn("requestNetworkVceData", exc);
978 throw new AAIServiceException(exc);
980 if(inputStream != null){
983 } catch(Exception exc) {
984 LOG.warn("Error closing Input stream", exc);
993 public GenericVnf requestGenericVnfeNodeQuery(String vnf_name) throws AAIServiceException {
995 if(vnf_name == null) {
996 throw new NullPointerException();
999 GenericVnf entity = null;
1000 SearchResults resp = this.requestNodeQuery("generic-vnf", "vnf-name", vnf_name);
1002 List<ResultData> resultDataList = resp.getResultData();
1005 for (ResultData datum : resultDataList) {
1006 URI url = new URI(datum.getResourceLink());
1007 entity = this.getResource(url.toString(), GenericVnf.class);
1012 LOG.error("Caught exception", e);
1018 public Vserver requestVServerDataByURL(URL url) throws AAIServiceException {
1021 throw new NullPointerException();
1024 Vserver entity = null;
1027 entity = this.getResource(url.toString(), Vserver.class);
1028 } catch (AAIServiceException exc) {
1030 } catch (Exception e) {
1031 throw new AAIServiceException(e);
1037 public URL requestVserverURLNodeQuery(String vserver_name) throws AAIServiceException {
1039 if(vserver_name == null) {
1040 throw new NullPointerException();
1044 SearchResults resp = this.requestNodeQuery("vserver", "vserver-name", vserver_name);
1046 List<ResultData> resultDataList = resp.getResultData();
1049 for (ResultData datum : resultDataList) {
1050 String data_type = datum.getResourceType();
1051 String resourceLink = datum.getResourceLink();
1052 if(!resourceLink.isEmpty() && !resourceLink.toLowerCase().startsWith("http")) {
1053 resourceLink = (new EchoRequest()).targetUri + resourceLink;
1055 entity = new URL(resourceLink);
1057 } catch (Exception e) {
1058 throw new AAIServiceException(e);
1064 public String getTenantIdFromVserverUrl(URL url) {
1066 String path = url.getPath();
1068 String[] split = path.split("/tenants/tenant/");
1069 if(split.length > 1) {
1070 split = split[1].split("/");
1078 public String getCloudOwnerFromVserverUrl(URL url) {
1080 String path = url.getPath();
1082 String[] split = path.split("/cloud-regions/cloud-region/");
1083 if(split.length > 1) {
1084 split = split[1].split("/");
1092 public String getCloudRegionFromVserverUrl(URL url) {
1094 String path = url.getPath();
1096 String[] split = path.split("/cloud-regions/cloud-region/");
1097 if(split.length > 1) {
1098 split = split[1].split("/");
1106 public String getVServerIdFromVserverUrl(URL url, String tenantId) {
1107 String pattern = networkVserverPath;
1108 pattern = pattern.replace("{tenant-id}", tenantId);
1110 int end = pattern.indexOf("{vserver-id}");
1111 String prefix = pattern.substring(0, end);
1113 String path = url.getPath();
1115 if(path.startsWith(prefix)) {
1116 path = path.substring(prefix.length());
1122 protected Logger getLogger(){
1128 public AAIExecutorInterface getExecutor() {
1133 * Creates a current time stamp in UTC i.e. 2016-03-08T22:15:13.343Z.
1134 * If there are any parameters the values are appended to the time stamp.
1137 * values to be appended to current time stamp
1139 * used to set an attribute for a DG
1140 * @throws SvcLogicException
1142 public void setStatusMethod(Map<String, String> parameters, SvcLogicContext ctx) throws SvcLogicException {
1144 throw new SvcLogicException("SvcLogicContext is null.");
1147 StringBuilder sb = new StringBuilder();
1148 sb.append(String.format("%tFT%<tTZ", Calendar.getInstance(TimeZone.getTimeZone("Z")))).append(" - ");
1150 for (Entry<String, String> entry : parameters.entrySet()) {
1151 sb.append(entry.getValue()).append(" ");
1154 if (sb.length() > 0) {
1155 sb.setLength(sb.length() - 2);
1158 ctx.setAttribute("aai-summary-status-message", sb.toString());
1159 LOG.info("aai-summary-status-message: " + sb.toString());
1163 * Generic method to GET json data from an A&AI using key structure.
1164 * Then convert that json to an Object.
1165 * If successful the Object is attempted to be cast to the type parameter.
1168 * key identifying the resource to be retrieved from AAI
1170 * the class of object that A&AI will return
1171 * @return the object created from json or null if the response code is not 200
1173 * @throws AAIServiceException
1174 * if empty or null key and or type or there's an error with processing
1177 public <T> T getResource(String key, Class<T> type) throws AAIServiceException {
1178 if (StringUtils.isEmpty(key) || type == null) {
1179 throw new AAIServiceException("Key is empty or null and or type is null");
1184 SvcLogicContext ctx = new SvcLogicContext();
1185 if(!key.contains(" = ")) {
1186 if(isValidURL(key)) {
1187 key = String.format("selflink = '%s'", key);
1188 } else if(isValidURI(key)) {
1189 key = String.format("resource-path = '%s'", key);
1195 HashMap<String, String> nameValues = AAIServiceUtils.keyToHashMap(key, ctx);
1197 AAIRequest request = new SelfLinkRequest(type);
1198 if(nameValues.containsKey(PathRequest.RESOURCE_PATH.replaceAll("-", "_"))) {
1199 request = new PathRequest(type);
1202 request.processRequestPathValues(nameValues);
1203 Object obj = this.getExecutor().query(request, type);
1204 response = type.cast(obj);
1206 return response != null ? type.cast(response) : response;
1209 public boolean isValidURL(String url) {
1215 } catch (MalformedURLException e) {
1216 LOG.warn("MalformedURLException", e);
1222 } catch (URISyntaxException e) {
1223 LOG.warn("URISyntaxException", e);
1231 public boolean isValidURI(String url) {
1237 } catch (URISyntaxException e) {
1238 LOG.warn("URISyntaxException", e);
1246 protected boolean deleteList(URL httpReqUrl, String json_text) throws AAIServiceException {
1247 if(httpReqUrl == null) {
1248 throw new NullPointerException();
1251 boolean response = false;
1252 InputStream inputStream = null;
1255 HttpURLConnection con = getConfiguredConnection(httpReqUrl, HttpMethod.DELETE);
1257 // SSLSocketFactory sockFact = CTX.getSocketFactory();
1258 // con.setSSLSocketFactory( sockFact );
1259 if (json_text != null) {
1260 OutputStreamWriter osw = new OutputStreamWriter(con.getOutputStream());
1261 osw.write(json_text);
1266 LOGwriteFirstTrace("DELETE", httpReqUrl.toString());
1267 LOGwriteDateTrace("data", json_text);
1270 int responseCode = con.getResponseCode();
1271 if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_NO_CONTENT) {
1272 inputStream = con.getInputStream();
1274 inputStream = con.getErrorStream();
1277 // Process the response
1278 LOG.debug("HttpURLConnection result:" + responseCode);
1279 if(inputStream == null) inputStream = new ByteArrayInputStream("".getBytes(StandardCharsets.UTF_8));
1280 BufferedReader reader = new BufferedReader( new InputStreamReader( inputStream ) );
1283 ObjectMapper mapper = getObjectMapper();
1285 if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_NO_CONTENT) {
1286 StringBuilder stringBuilder = new StringBuilder();
1288 while( ( line = reader.readLine() ) != null ) {
1289 stringBuilder.append( line );
1291 LOGwriteEndingTrace(responseCode, "SUCCESS", stringBuilder.toString());
1293 } else if(responseCode == HttpURLConnection.HTTP_NOT_FOUND ) {
1294 LOGwriteEndingTrace(responseCode, "HTTP_NOT_FOUND", "Entry does not exist.");
1297 ErrorResponse errorresponse = mapper.readValue(reader, ErrorResponse.class);
1298 LOGwriteEndingTrace(responseCode, "FAILURE", mapper.writeValueAsString(errorresponse));
1299 throw new AAIServiceException(responseCode, errorresponse);
1302 } catch(AAIServiceException aaiexc) {
1304 } catch (Exception exc) {
1305 LOG.warn("deleteList", exc);
1306 throw new AAIServiceException(exc);
1308 if(inputStream != null){
1310 inputStream.close();
1311 } catch(Exception exc) {
1319 public static ObjectMapper getObjectMapper() {
1320 ObjectMapper mapper = new ObjectMapper();
1321 AnnotationIntrospector introspector = new JaxbAnnotationIntrospector(TypeFactory.defaultInstance());
1322 AnnotationIntrospector secondary = new JacksonAnnotationIntrospector();
1323 mapper.setAnnotationIntrospector(AnnotationIntrospector.pair(introspector, secondary));
1324 mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
1325 mapper.setSerializationInclusion(Include.NON_NULL);
1326 mapper.setSerializationInclusion(Include.NON_EMPTY);
1330 public void logMetricRequest(String requestId, String targetServiceName, String msg, String path){
1331 String svcInstanceId = "";
1332 String svcName = null;
1333 String partnerName = null;
1334 String targetEntity = "A&AI";
1335 String targetVirtualEntity = null;
1337 ml.logRequest(svcInstanceId, svcName, partnerName, targetEntity, targetServiceName, targetVirtualEntity, msg);
1340 public void logMetricResponse(String requestId, int responseCode, String responseDescription){
1341 ml.logResponse(responseCode < 400 ? "COMPLETE" : "ERROR", Integer.toString(responseCode), responseDescription);
1344 public void logKeyError(String keys){
1345 LOG.error("Atleast one of the keys [" + keys + "] should have been populated. This will cause a NPE.");
1353 public QueryStatus save(String resource, boolean force, boolean localOnly, String key, Map<String, String> params, String prefix, SvcLogicContext ctx)
1354 throws SvcLogicException {
1355 String normResource = resource.split(":")[0];
1357 switch(normResource){
1358 case "custom-query":
1359 case "formatted-query":
1360 case "generic-query":
1364 case "l2-bridge-sbg":
1365 case "l2-bridge-bgf":
1371 if(key.contains("selflink =")) {
1374 if(!key.contains(String.format("%s.", normResource))) {
1375 key = rewriteKey(resource, key, ctx);
1378 return super.save(resource, force, localOnly, key, params, prefix, ctx);
1382 public QueryStatus query(String resource, boolean localOnly, String select, String key, String prefix, String orderBy, SvcLogicContext ctx)
1383 throws SvcLogicException {
1384 String normResource = resource.split(":")[0];
1386 switch(normResource){
1387 case "custom-query":
1388 case "formatted-query":
1389 case "generic-query":
1393 case "l2-bridge-sbg":
1394 case "l2-bridge-bgf":
1400 if(key.contains("selflink =")) {
1403 if(!key.contains(String.format("%s.", normResource))) {
1404 key = rewriteKey(resource, key, ctx);
1408 return super.query(resource, localOnly, select, key, prefix, orderBy, ctx);
1412 public QueryStatus delete(String resource, String key, SvcLogicContext ctx) throws SvcLogicException {
1413 String normResource = resource.split(":")[0];
1415 switch(normResource){
1416 case "custom-query":
1417 case "formatted-query":
1418 case "generic-query":
1422 case "l2-bridge-sbg":
1423 case "l2-bridge-bgf":
1429 if(key.contains("selflink =")) {
1432 if(!key.contains(String.format("%s.", normResource))) {
1433 key = rewriteKey(resource, key, ctx);
1437 return super.delete(resource, key, ctx);
1441 public QueryStatus update(String resource, String key, Map<String, String> params, String prefix, SvcLogicContext ctx) throws SvcLogicException {
1442 String normResource = resource.split(":")[0];
1444 switch(normResource){
1445 case "custom-query":
1446 case "formatted-query":
1447 case "generic-query":
1451 case "l2-bridge-sbg":
1452 case "l2-bridge-bgf":
1458 if(key.contains("selflink =")) {
1461 if(!key.contains(String.format("%s.", normResource))) {
1462 key = rewriteKey(resource, key, ctx);
1466 return super.update(resource, key, params, prefix, ctx);
1469 private String rewriteKey(String resource, String key, SvcLogicContext ctx) {
1470 LOG.info("AAI Deprecation - the format of request key is no longer supported. Please rewrite this key : " + key);
1472 String normResource = resource.split(":")[0];
1473 Class<? extends AAIDatum> clazz = AAIRequest.getClassFromResource(normResource) ;
1478 List<String> fieldAnnotatedNames = new LinkedList<>();
1480 Field[] fields = clazz.getDeclaredFields();
1481 for(Field field : fields) {
1482 String fieldName = field.getName();
1483 XmlElement annotation = field.getAnnotation(XmlElement.class);
1484 if(annotation == null)
1486 String primaryId = annotation.name();
1487 if("##default".equals(primaryId)) {
1488 primaryId = fieldName;
1490 fieldAnnotatedNames.add(primaryId);
1493 HashMap<String, String> nameValues = AAIServiceUtils.keyToHashMap(key, ctx);
1494 Set<String> keyset = nameValues.keySet();
1495 for(String keyName : keyset) {
1496 if(keyName.contains("."))
1499 String tmpKeyName = keyName.replaceAll("_", "-");
1500 String valueToSubstitute = String.format("%s =", tmpKeyName);
1501 if(fieldAnnotatedNames.contains(tmpKeyName) && key.contains(valueToSubstitute)) {
1502 key = key.replace(valueToSubstitute, String.format("%s.%s =", normResource, tmpKeyName));
1512 public String getPathTemplateForResource(String resoourceName, String keys, SvcLogicContext ctx) throws MalformedURLException {
1513 return AAIServiceUtils.getPathForResource(resoourceName, StringUtils.join(keys, " AND "), ctx);
1517 public boolean isDeprecatedFormat(String resource, Map<String, String> nameValues) {
1518 return !AAIServiceUtils.isValidFormat(resource, nameValues);
1521 public AAIRequest getRequestFromResource(String resoourceName) {
1522 return AAIRequest.getRequestFromResource(resoourceName);
1526 * @see org.onap.ccsdk.sli.core.sli.aai.haha#query(org.onap.ccsdk.sli.core.sli.aai.AAIRequest)
1529 public String query(AAIRequest request) throws AAIServiceException {
1530 return executor.get(request);
1534 * @see org.onap.ccsdk.sli.core.sli.aai.haha#save(org.onap.ccsdk.sli.core.sli.aai.AAIRequest)
1537 public String save(AAIRequest request) throws AAIServiceException {
1538 return executor.post(request);
1541 public boolean update(AAIRequest request, String resourceVersion) throws AAIServiceException {
1542 return executor.patch(request, resourceVersion);
1546 * @see org.onap.ccsdk.sli.core.sli.aai.haha#delete(org.onap.ccsdk.sli.core.sli.aai.AAIRequest, java.lang.String)
1549 public boolean delete(AAIRequest request, String resourceVersion) throws AAIServiceException {
1550 return executor.delete(request, resourceVersion);