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.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;
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;
102 public class AAIService extends AAIDeclarations implements AAIClient, SvcLogicResource {
104 public static final String AAICLIENT_PROPERTIES = "/aaiclient.properties";
105 public static final String PATH_PROPERTIES = "/aai-path.properties";
107 private static final Logger LOG = LoggerFactory.getLogger(AAIService.class);
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;
115 private final String targetUri;
116 private final String networkVserverPath;
118 private final String svc_inst_query_path;
120 private final String ubb_notify_path;
121 private final String selflinkAvpn;
122 private final String selflinkFqdn;
124 private final int connectionTimeout;
125 private final int readTimeout;
128 private final String queryNodesPath;
129 private final String applicationId;
131 // authentication credentials
132 private String userName;
133 private String userPassword;
136 private final boolean runtimeOSGI;
138 private SSLContext CTX;
140 private final MetricLogger ml = new MetricLogger();
142 private AAIExecutorInterface executor;
144 public AAIService(final UtilsProvider configuration) {
145 this(configuration.getProperties());
148 public AAIService(final URL url) {
149 this(getProperties(url));
152 public AAIService(Properties props) {
153 LOG.info("Entered AAIService.ctor");
155 String runtime = System.getProperty("aaiclient.runtime");
156 if("OSGI".equals(runtime)) {
163 AAIRequest.setProperties(props, this);
165 } catch(Exception exc){
166 LOG.error("AicAAIResource.static", exc);
169 executor = new AAIClientRESTExecutor(props);
171 userName = props.getProperty(CLIENT_NAME);
172 userPassword = props.getProperty(CLIENT_PWWD);
174 if(userName == null || userName.isEmpty()){
175 LOG.debug("Basic user name is not set");
177 if(userPassword == null || userPassword.isEmpty()) {
178 LOG.debug("Basic password is not set");
181 truststorePath = props.getProperty(TRUSTSTORE_PATH);
182 truststorePassword = props.getProperty(TRUSTSTORE_PSSWD);
183 keystorePath = props.getProperty(KEYSTORE_PATH);
184 keystorePassword = props.getProperty(KEYSTORE_PSSWD);
186 targetUri = props.getProperty(TARGET_URI);
187 props.getProperty(QUERY_PATH);
188 props.getProperty(UPDATE_PATH);
190 String tmpApplicationId = props.getProperty(APPLICATION_ID);
191 if(tmpApplicationId == null || tmpApplicationId.isEmpty()) {
192 tmpApplicationId = "SDNC";
194 this.applicationId = tmpApplicationId;
196 // connection timeout
197 int tmpConnectionTimeout = 30000;
198 int tmpReadTimeout = 30000;
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;
211 connectionTimeout = tmpConnectionTimeout;
212 readTimeout = tmpReadTimeout;
214 networkVserverPath =props.getProperty(NETWORK_VSERVER_PATH);
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");
220 props.getProperty(VNF_IMAGE_QUERY_PATH);
222 ubb_notify_path = props.getProperty(UBB_NOTIFY_PATH);
223 selflinkAvpn = props.getProperty(SELFLINK_AVPN);
224 selflinkFqdn = props.getProperty(SELFLINK_FQDN);
226 props.getProperty(SERVICE_PATH);
228 props.getProperty(SITE_PAIR_SET_PATH);
230 queryNodesPath = props.getProperty(QUERY_NODES_PATH);
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);
238 ignoreCertificateHostError = host_error;
240 HttpsURLConnection.setDefaultHostnameVerifier( new HostnameVerifier(){
241 public boolean verify(String string,SSLSession ssls) {
242 return ignoreCertificateHostError;
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);
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;
256 ctx = SSLContext.getInstance("TLS");
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());
265 String extension = keystorePath.substring(keystorePath.lastIndexOf(".") + 1);
266 if("JKS".equalsIgnoreCase(extension)) {
269 KeyStore ks = KeyStore.getInstance(storeType);
271 char[] pwd = keystorePassword.toCharArray();
274 } catch (Exception ex) {
275 LOG.error("AAIResource", ex);
279 ctx.init(kmf.getKeyManagers(), null, null);
282 * config.getProperties().put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES, new
283 * HTTPSProperties( new HostnameVerifier() {
285 * @Override public boolean verify( String s, SSLSession sslSession ) { return
286 * ignoreCertificateHostError; } }, ctx));
290 LOG.debug("SSLContext created");
292 } catch (KeyManagementException | NoSuchAlgorithmException exc) {
293 LOG.error("AAIResource", exc);
297 LOG.info("AAIResource.ctor initialized.");
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);
307 // remove the "final" modifier
308 modifiersField.setInt(methodsField, methodsField.getModifiers() & ~Modifier.FINAL);
310 /* valid HTTP methods */
312 "GET", "POST", "HEAD", "OPTIONS", "PUT", "DELETE", "TRACE", "PATCH"
314 // set the new methods - including patch
315 methodsField.set(null, methods);
317 } catch (SecurityException | IllegalArgumentException | IllegalAccessException | NoSuchFieldException e) {
318 LOG.error("Exception occured", e);
323 private static Properties getProperties(URL url) {
324 Properties properties = new Properties();
326 properties.load(url.openStream());
327 } catch (IOException exc) {
328 LOG.error("getProperties", exc);
333 public void setExecutor(AAIExecutorInterface executor) {
334 this.executor = executor;
337 public void cleanUp() {
343 * @param http_req_url
348 protected HttpURLConnection getConfiguredConnection(URL http_req_url, String method) throws Exception {
349 HttpURLConnection con = (HttpURLConnection) http_req_url.openConnection();
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);
368 LOG.debug("MetricLogger requestId is null");
370 con.setRequestProperty("Transfer-Encoding","chunked");
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);
377 if(con instanceof HttpsURLConnection && CTX != null) {
378 SSLSocketFactory sockFact = CTX.getSocketFactory();
379 HttpsURLConnection.class.cast(con).setSSLSocketFactory( sockFact );
386 public GenericVnf requestGenericVnfData(String vnf_id) throws AAIServiceException {
387 GenericVnf response = null;
390 AAIRequest request = AAIRequest.getRequestFromResource("generic-vnf");
391 request.addRequestProperty("generic-vnf.vnf-id", vnf_id);
392 String rv = executor.get(request);
394 ObjectMapper mapper = getObjectMapper();
395 response = mapper.readValue(rv, GenericVnf.class);
397 } catch(AAIServiceException aaiexc) {
399 } catch (Exception exc) {
400 LOG.warn(Object.class.getClass().getEnclosingMethod().getName(), exc);
401 throw new AAIServiceException(exc);
409 public boolean postGenericVnfData(String vnf_id, GenericVnf data) throws AAIServiceException {
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);
416 } catch(AAIServiceException aaiexc) {
418 } catch (Exception exc) {
419 LOG.warn("requestGenericVnfData", exc);
420 throw new AAIServiceException(exc);
425 public SearchResults requestServiceInstanceURL(String svc_instance_id) throws AAIServiceException {
426 SearchResults response = null;
427 InputStream inputStream = null;
430 String path = svc_inst_query_path;
431 path = path.replace("{svc-instance-id}", encodeQuery(svc_instance_id));
433 String request_url = targetUri+path;
434 URL http_req_url = new URL(request_url);
436 HttpURLConnection con = getConfiguredConnection(http_req_url, HttpMethod.GET);
438 LOGwriteFirstTrace(HttpMethod.GET, http_req_url.toString());
439 LOGwriteDateTrace("svc_instance_id", svc_instance_id);
442 int responseCode = con.getResponseCode();
443 if (responseCode == HttpURLConnection.HTTP_OK) {
444 inputStream = con.getInputStream();
446 inputStream = con.getErrorStream();
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 ) );
454 ObjectMapper mapper = getObjectMapper();
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.");
463 ErrorResponse errorresponse = mapper.readValue(reader, ErrorResponse.class);
464 LOGwriteEndingTrace(responseCode, "FAILURE", mapper.writeValueAsString(errorresponse));
465 throw new AAIServiceException(responseCode, errorresponse);
468 } catch(AAIServiceException aaiexc) {
470 } catch (Exception exc) {
471 LOG.warn("requestServiceInstanceURL", exc);
472 throw new AAIServiceException(exc);
474 if(inputStream != null){
477 } catch(Exception exc) {
478 LOG.warn("Error closing Inputstream", exc);
486 private static Properties initialize(URL url ) throws ConfigurationException {
489 throw new NullPointerException();
492 InputStream is = null;
493 Properties props = new Properties();
496 if(LOG.isDebugEnabled())
497 LOG.info("Property file is: " + url.toString());
499 is = url.openStream();
502 if(LOG.isDebugEnabled()) {
503 LOG.info("Properties loaded: " + props.size());
504 Enumeration<Object> en = props.keys();
506 while(en.hasMoreElements()) {
507 String key = (String)en.nextElement();
508 String property = props.getProperty(key);
509 LOG.debug(key + " : " + property);
512 } catch (Exception e) {
513 throw new ConfigurationException("Could not load properties file.", e);
518 static class TransactionIdTracker {
519 // protected static AtomicLong tracker = new AtomicLong();
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);
529 return transactionId;
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);
541 protected void LOGwriteDateTrace(String name, String data) {
542 LOG.info("Input - " + name + " : " + data);
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));
550 protected String encodeQuery(String param) throws UnsupportedEncodingException {
551 return URLEncoder.encode(param, "UTF-8").replace("+", "%20");
554 private String encodeCustomerURL(final String selection)
556 String encrypted_url = selection;
558 "/aai/v11/business/customers/customer/(.+)/service-subscriptions/service-subscription/(.+)/service-instances/service-instance/(.+)/";
559 Pattern pattern = Pattern.compile(apnpattern);
562 URL url = new URL(selection);
563 String path = url.getPath();
565 LOG.info("Trying to match apn to <" + path + ">");
567 Matcher matcher = pattern.matcher(path);
569 while(matcher.find()) {
570 String customer = matcher.group(1);
571 String subscription = matcher.group(2);
572 String service = matcher.group(3);
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));
578 } catch (Exception e) {
582 return encrypted_url;
589 * @see org.onap.sdnct.sli.aai.AAIClient#requestVServersData(java.lang.String, java.lang.String)
592 public Vserver requestVServerData(String tenantId, String vserverId, String cloudOwner, String cloudRegionId) throws AAIServiceException {
593 Vserver response = null;
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);
602 String rv = executor.get(request);
604 ObjectMapper mapper = getObjectMapper();
605 response = mapper.readValue(rv, Vserver.class);
607 } catch(AAIServiceException aaiexc) {
609 } catch (Exception exc) {
610 LOG.warn(Object.class.getClass().getEnclosingMethod().getName(), exc);
611 throw new AAIServiceException(exc);
617 //================== End of DvsSwitch =================
618 //==================== PhysicalLink ======================
620 public PhysicalLink requestPhysicalLinkData(String linkName) throws AAIServiceException {
621 PhysicalLink response = null;
624 AAIRequest request = AAIRequest.getRequestFromResource("physical-link");
625 request.addRequestProperty("physical-link.link-name", linkName);
627 String rv = executor.get(request);
629 ObjectMapper mapper = getObjectMapper();
630 response = mapper.readValue(rv, PhysicalLink.class);
632 } catch(AAIServiceException aaiexc) {
634 } catch (Exception exc) {
635 LOG.warn("requestPhysicalLinkData", exc);
636 throw new AAIServiceException(exc);
642 public boolean postPhysicalLinkData(String linkName, PhysicalLink data) throws AAIServiceException {
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);
649 } catch(AAIServiceException aaiexc) {
651 } catch (Exception exc) {
652 LOG.warn(Object.class.getClass().getEnclosingMethod().getName(), exc);
653 throw new AAIServiceException(exc);
658 public boolean deletePhysicalLinkData(String linkName, String resourceVersion) throws AAIServiceException {
659 boolean response = false;
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) {
667 } catch (Exception exc) {
668 LOG.warn("deletePhysicalLinkData", exc);
669 throw new AAIServiceException(exc);
674 public boolean deleteAAIEntity(URL url, String caller) throws AAIServiceException {
677 throw new NullPointerException();
680 boolean response = false;
681 InputStream inputStream = null;
684 URL http_req_url = url;
686 HttpURLConnection con = getConfiguredConnection(http_req_url, HttpMethod.DELETE);
688 LOGwriteFirstTrace("DELETE", http_req_url.toString());
692 int responseCode = con.getResponseCode();
693 if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_NO_CONTENT) {
694 inputStream = con.getInputStream();
696 inputStream = con.getErrorStream();
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 ) );
705 ObjectMapper mapper = getObjectMapper();
707 if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_NO_CONTENT) {
708 StringBuilder stringBuilder = new StringBuilder();
710 while( ( line = reader.readLine() ) != null ) {
711 stringBuilder.append( line );
713 LOGwriteEndingTrace(responseCode, "SUCCESS", stringBuilder.toString());
715 } else if(responseCode == HttpURLConnection.HTTP_NOT_FOUND ) {
716 LOGwriteEndingTrace(responseCode, "HTTP_NOT_FOUND", "Entry does not exist.");
719 ErrorResponse errorresponse = mapper.readValue(reader, ErrorResponse.class);
720 LOGwriteEndingTrace(responseCode, "FAILURE", mapper.writeValueAsString(errorresponse));
721 throw new AAIServiceException(responseCode, errorresponse);
724 } catch(AAIServiceException aaiexc) {
726 } catch (Exception exc) {
727 LOG.warn(caller, exc);
728 throw new AAIServiceException(exc);
730 if(inputStream != null){
733 } catch(Exception exc) {
734 LOG.warn("Error closing InputStream", exc);
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.
747 * callback url for A&AI
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
752 * @throws AAIServiceException
753 * if empty or null key and or type or there's an error with processing
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");
762 SvcLogicContext ctx = new SvcLogicContext();
763 if(!key.contains(" = ") && isValidURL(key)) {
764 key = String.format("selflink = '%s'", key);
766 if(!key.contains(" = ") && isValidURI(key)) {
767 key = String.format("resource-path = '%s'", key);
770 HashMap<String, String> nameValues = AAIServiceUtils.keyToHashMap(key, ctx);
772 SelfLinkRequest request = new SelfLinkRequest(type);
773 request.processRequestPathValues(nameValues);
774 Object obj = this.getExecutor().query(request, type);
775 response = type.cast(obj);
777 return response != null ? type.cast(response) : response;
781 public boolean sendNotify(NotifyEvent event, String serviceInstanceId, String pathCode) throws AAIServiceException {
782 InputStream inputStream = null;
786 String selfLink = selflinkFqdn;
787 if(SELFLINK_AVPN != null && SELFLINK_AVPN.equals(pathCode)) {
788 selfLink = selflinkAvpn;
790 selfLink = selfLink.replace("{service-instance-id}", encodeQuery(serviceInstanceId));
791 event.setSelflink(selfLink);
793 ObjectMapper mapper = getObjectMapper();
794 String json_text = mapper.writeValueAsString(event);
796 SSLSocketFactory sockFact = CTX.getSocketFactory();
798 String request_url = targetUri+ubb_notify_path;
799 URL http_req_url = new URL(request_url);
801 HttpURLConnection con = getConfiguredConnection(http_req_url, HttpMethod.PUT);
803 if (json_text != null) {
804 OutputStreamWriter osw = new OutputStreamWriter(con.getOutputStream());
805 osw.write(json_text);
810 LOGwriteFirstTrace("PUT", request_url);
811 LOGwriteDateTrace("NotifyEvent", json_text);
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();
818 inputStream = con.getErrorStream();
821 // Process the response
822 BufferedReader reader;
824 reader = new BufferedReader( new InputStreamReader( inputStream ) );
826 if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_CREATED || responseCode == HttpURLConnection.HTTP_ACCEPTED || responseCode == HttpURLConnection.HTTP_NO_CONTENT) {
827 StringBuilder stringBuilder = new StringBuilder();
829 while( ( line = reader.readLine() ) != null ) {
830 stringBuilder.append( line );
832 LOGwriteEndingTrace(responseCode, "SUCCESS", (stringBuilder.length() > 0) ? stringBuilder.toString() :
836 ErrorResponse errorresponse = mapper.readValue(reader, ErrorResponse.class);
837 LOGwriteEndingTrace(responseCode, "FAILURE", mapper.writeValueAsString(errorresponse));
839 throw new AAIServiceException(responseCode, errorresponse);
841 } catch(AAIServiceException aaiexc) {
843 } catch (Exception exc) {
844 LOG.warn("sendNotify", exc);
845 throw new AAIServiceException(exc);
848 if(inputStream != null)
850 } catch (Exception exc) {
851 LOG.warn("Error closing Input stream", exc);
857 public SearchResults requestNodeQuery(String node_type, String entityIdentifier, String entityName) throws AAIServiceException {
858 SearchResults response = null;
859 InputStream inputStream = null;
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);
868 HttpURLConnection con = getConfiguredConnection(http_req_url, HttpMethod.GET);
870 LOGwriteFirstTrace(HttpMethod.GET, http_req_url.toString());
871 LOGwriteDateTrace("node_type", node_type);
872 LOGwriteDateTrace("vnf_name", entityName);
875 int responseCode = con.getResponseCode();
876 if (responseCode == HttpURLConnection.HTTP_OK) {
877 inputStream = con.getInputStream();
879 inputStream = con.getErrorStream();
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 ) );
887 ObjectMapper mapper = getObjectMapper();
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.");
896 ErrorResponse errorresponse = mapper.readValue(reader, ErrorResponse.class);
897 LOGwriteEndingTrace(responseCode, "FAILURE", mapper.writeValueAsString(errorresponse));
898 throw new AAIServiceException(responseCode, errorresponse);
901 } catch(AAIServiceException aaiexc) {
903 } catch (Exception exc) {
904 LOG.warn("requestNodeQuery", exc);
905 throw new AAIServiceException(exc);
907 if(inputStream != null){
910 } catch(Exception exc) {
911 LOG.warn("Error closing Input stream", exc);
921 public String requestDataByURL(URL url) throws AAIServiceException {
924 throw new NullPointerException();
927 String response = null;
928 InputStream inputStream = null;
931 URL http_req_url = url;
933 HttpURLConnection con = getConfiguredConnection(http_req_url, HttpMethod.GET);
935 LOGwriteFirstTrace(HttpMethod.GET, http_req_url.toString());
938 int responseCode = con.getResponseCode();
939 if (responseCode == HttpURLConnection.HTTP_OK) {
940 inputStream = con.getInputStream();
942 inputStream = con.getErrorStream();
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 ) );
950 ObjectMapper mapper = getObjectMapper();
952 if (responseCode == HttpURLConnection.HTTP_OK) {
953 StringBuilder stringBuilder = new StringBuilder("\n");
955 while( ( line = reader.readLine() ) != null ) {
956 stringBuilder.append( line );
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.");
966 ErrorResponse errorresponse = mapper.readValue(reader, ErrorResponse.class);
967 LOGwriteEndingTrace(responseCode, "FAILURE", mapper.writeValueAsString(errorresponse));
968 throw new AAIServiceException(responseCode, errorresponse);
971 } catch(AAIServiceException aaiexc) {
973 } catch (Exception exc) {
974 LOG.warn("requestNetworkVceData", exc);
975 throw new AAIServiceException(exc);
977 if(inputStream != null){
980 } catch(Exception exc) {
981 LOG.warn("Error closing Input stream", exc);
990 public GenericVnf requestGenericVnfeNodeQuery(String vnf_name) throws AAIServiceException {
992 if(vnf_name == null) {
993 throw new NullPointerException();
996 GenericVnf entity = null;
997 SearchResults resp = this.requestNodeQuery("generic-vnf", "vnf-name", vnf_name);
999 List<ResultData> resultDataList = resp.getResultData();
1002 for (ResultData datum : resultDataList) {
1003 URI url = new URI(datum.getResourceLink());
1004 entity = this.getResource(url.toString(), GenericVnf.class);
1009 LOG.error("Caught exception", e);
1015 public Vserver requestVServerDataByURL(URL url) throws AAIServiceException {
1018 throw new NullPointerException();
1021 Vserver entity = null;
1024 entity = this.getResource(url.toString(), Vserver.class);
1025 } catch (AAIServiceException exc) {
1027 } catch (Exception e) {
1028 throw new AAIServiceException(e);
1034 public URL requestVserverURLNodeQuery(String vserver_name) throws AAIServiceException {
1036 if(vserver_name == null) {
1037 throw new NullPointerException();
1041 SearchResults resp = this.requestNodeQuery("vserver", "vserver-name", vserver_name);
1043 List<ResultData> resultDataList = resp.getResultData();
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;
1052 entity = new URL(resourceLink);
1054 } catch (Exception e) {
1055 throw new AAIServiceException(e);
1061 public String getTenantIdFromVserverUrl(URL url) {
1063 String path = url.getPath();
1065 String[] split = path.split("/tenants/tenant/");
1066 if(split.length > 1) {
1067 split = split[1].split("/");
1075 public String getCloudOwnerFromVserverUrl(URL url) {
1077 String path = url.getPath();
1079 String[] split = path.split("/cloud-regions/cloud-region/");
1080 if(split.length > 1) {
1081 split = split[1].split("/");
1089 public String getCloudRegionFromVserverUrl(URL url) {
1091 String path = url.getPath();
1093 String[] split = path.split("/cloud-regions/cloud-region/");
1094 if(split.length > 1) {
1095 split = split[1].split("/");
1103 public String getVServerIdFromVserverUrl(URL url, String tenantId) {
1104 String pattern = networkVserverPath;
1105 pattern = pattern.replace("{tenant-id}", tenantId);
1107 int end = pattern.indexOf("{vserver-id}");
1108 String prefix = pattern.substring(0, end);
1110 String path = url.getPath();
1112 if(path.startsWith(prefix)) {
1113 path = path.substring(prefix.length());
1119 protected Logger getLogger(){
1125 public AAIExecutorInterface getExecutor() {
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.
1134 * values to be appended to current time stamp
1136 * used to set an attribute for a DG
1137 * @throws SvcLogicException
1139 public void setStatusMethod(Map<String, String> parameters, SvcLogicContext ctx) throws SvcLogicException {
1141 throw new SvcLogicException("SvcLogicContext is null.");
1144 StringBuilder sb = new StringBuilder();
1145 sb.append(String.format("%tFT%<tTZ", Calendar.getInstance(TimeZone.getTimeZone("Z")))).append(" - ");
1147 for (Entry<String, String> entry : parameters.entrySet()) {
1148 sb.append(entry.getValue()).append(" ");
1151 if (sb.length() > 0) {
1152 sb.setLength(sb.length() - 2);
1155 ctx.setAttribute("aai-summary-status-message", sb.toString());
1156 LOG.info("aai-summary-status-message: " + sb.toString());
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.
1165 * key identifying the resource to be retrieved from AAI
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
1170 * @throws AAIServiceException
1171 * if empty or null key and or type or there's an error with processing
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");
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);
1192 HashMap<String, String> nameValues = AAIServiceUtils.keyToHashMap(key, ctx);
1194 AAIRequest request = new SelfLinkRequest(type);
1195 if(nameValues.containsKey(PathRequest.RESOURCE_PATH.replaceAll("-", "_"))) {
1196 request = new PathRequest(type);
1199 request.processRequestPathValues(nameValues);
1200 Object obj = this.getExecutor().query(request, type);
1201 response = type.cast(obj);
1203 return response != null ? type.cast(response) : response;
1206 public boolean isValidURL(String url) {
1212 } catch (MalformedURLException e) {
1213 LOG.warn("MalformedURLException", e);
1219 } catch (URISyntaxException e) {
1220 LOG.warn("URISyntaxException", e);
1228 public boolean isValidURI(String url) {
1234 } catch (URISyntaxException e) {
1235 LOG.warn("URISyntaxException", e);
1243 protected boolean deleteList(URL httpReqUrl, String json_text) throws AAIServiceException {
1244 if(httpReqUrl == null) {
1245 throw new NullPointerException();
1248 boolean response = false;
1249 InputStream inputStream = null;
1252 HttpURLConnection con = getConfiguredConnection(httpReqUrl, HttpMethod.DELETE);
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);
1263 LOGwriteFirstTrace("DELETE", httpReqUrl.toString());
1264 LOGwriteDateTrace("data", json_text);
1267 int responseCode = con.getResponseCode();
1268 if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_NO_CONTENT) {
1269 inputStream = con.getInputStream();
1271 inputStream = con.getErrorStream();
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 ) );
1280 ObjectMapper mapper = getObjectMapper();
1282 if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_NO_CONTENT) {
1283 StringBuilder stringBuilder = new StringBuilder();
1285 while( ( line = reader.readLine() ) != null ) {
1286 stringBuilder.append( line );
1288 LOGwriteEndingTrace(responseCode, "SUCCESS", stringBuilder.toString());
1290 } else if(responseCode == HttpURLConnection.HTTP_NOT_FOUND ) {
1291 LOGwriteEndingTrace(responseCode, "HTTP_NOT_FOUND", "Entry does not exist.");
1294 ErrorResponse errorresponse = mapper.readValue(reader, ErrorResponse.class);
1295 LOGwriteEndingTrace(responseCode, "FAILURE", mapper.writeValueAsString(errorresponse));
1296 throw new AAIServiceException(responseCode, errorresponse);
1299 } catch(AAIServiceException aaiexc) {
1301 } catch (Exception exc) {
1302 LOG.warn("deleteList", exc);
1303 throw new AAIServiceException(exc);
1305 if(inputStream != null){
1307 inputStream.close();
1308 } catch(Exception exc) {
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);
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;
1334 ml.logRequest(svcInstanceId, svcName, partnerName, targetEntity, targetServiceName, targetVirtualEntity, msg);
1337 public void logMetricResponse(String requestId, int responseCode, String responseDescription){
1338 ml.logResponse(responseCode < 400 ? "COMPLETE" : "ERROR", Integer.toString(responseCode), responseDescription);
1341 public void logKeyError(String keys){
1342 LOG.error("Atleast one of the keys [" + keys + "] should have been populated. This will cause a NPE.");
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];
1354 switch(normResource){
1355 case "custom-query":
1356 case "formatted-query":
1357 case "generic-query":
1360 case "l2-bridge-sbg":
1361 case "l2-bridge-bgf":
1367 if(key.contains("selflink =")) {
1370 if(!key.contains(String.format("%s.", normResource))) {
1371 key = rewriteKey(resource, key, ctx);
1374 return super.save(resource, force, localOnly, key, params, prefix, ctx);
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];
1382 switch(normResource){
1383 case "custom-query":
1384 case "formatted-query":
1385 case "generic-query":
1388 case "l2-bridge-sbg":
1389 case "l2-bridge-bgf":
1395 if(key.contains("selflink =")) {
1398 if(!key.contains(String.format("%s.", normResource))) {
1399 key = rewriteKey(resource, key, ctx);
1403 return super.query(resource, localOnly, select, key, prefix, orderBy, ctx);
1407 public QueryStatus delete(String resource, String key, SvcLogicContext ctx) throws SvcLogicException {
1408 String normResource = resource.split(":")[0];
1410 switch(normResource){
1411 case "custom-query":
1412 case "formatted-query":
1413 case "generic-query":
1416 case "l2-bridge-sbg":
1417 case "l2-bridge-bgf":
1423 if(key.contains("selflink =")) {
1426 if(!key.contains(String.format("%s.", normResource))) {
1427 key = rewriteKey(resource, key, ctx);
1431 return super.delete(resource, key, ctx);
1435 public QueryStatus update(String resource, String key, Map<String, String> params, String prefix, SvcLogicContext ctx) throws SvcLogicException {
1436 String normResource = resource.split(":")[0];
1438 switch(normResource){
1439 case "custom-query":
1440 case "formatted-query":
1441 case "generic-query":
1444 case "l2-bridge-sbg":
1445 case "l2-bridge-bgf":
1451 if(key.contains("selflink =")) {
1454 if(!key.contains(String.format("%s.", normResource))) {
1455 key = rewriteKey(resource, key, ctx);
1459 return super.update(resource, key, params, prefix, ctx);
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);
1465 String normResource = resource.split(":")[0];
1466 Class<? extends AAIDatum> clazz = AAIRequest.getClassFromResource(normResource) ;
1471 List<String> fieldAnnotatedNames = new LinkedList<>();
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)
1479 String primaryId = annotation.name();
1480 if("##default".equals(primaryId)) {
1481 primaryId = fieldName;
1483 fieldAnnotatedNames.add(primaryId);
1486 HashMap<String, String> nameValues = AAIServiceUtils.keyToHashMap(key, ctx);
1487 Set<String> keyset = nameValues.keySet();
1488 for(String keyName : keyset) {
1489 if(keyName.contains("."))
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));
1505 public String getPathTemplateForResource(String resoourceName, String keys, SvcLogicContext ctx) throws MalformedURLException {
1506 return AAIServiceUtils.getPathForResource(resoourceName, StringUtils.join(keys, " AND "), ctx);
1510 public boolean isDeprecatedFormat(String resource, Map<String, String> nameValues) {
1511 return !AAIServiceUtils.isValidFormat(resource, nameValues);
1514 public AAIRequest getRequestFromResource(String resoourceName) {
1515 return AAIRequest.getRequestFromResource(resoourceName);
1519 * @see org.onap.ccsdk.sli.core.sli.aai.haha#query(org.onap.ccsdk.sli.core.sli.aai.AAIRequest)
1522 public String query(AAIRequest request) throws AAIServiceException {
1523 return executor.get(request);
1527 * @see org.onap.ccsdk.sli.core.sli.aai.haha#save(org.onap.ccsdk.sli.core.sli.aai.AAIRequest)
1530 public String save(AAIRequest request) throws AAIServiceException {
1531 return executor.post(request);
1534 public boolean update(AAIRequest request, String resourceVersion) throws AAIServiceException {
1535 return executor.patch(request, resourceVersion);
1539 * @see org.onap.ccsdk.sli.core.sli.aai.haha#delete(org.onap.ccsdk.sli.core.sli.aai.AAIRequest, java.lang.String)
1542 public boolean delete(AAIRequest request, String resourceVersion) throws AAIServiceException {
1543 return executor.delete(request, resourceVersion);