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.v19.GenericVnf;
85 import org.onap.aai.inventory.v19.PhysicalLink;
86 import org.onap.aai.inventory.v19.ResultData;
87 import org.onap.aai.inventory.v19.SearchResults;
88 import org.onap.aai.inventory.v19.Vserver;
89 import org.onap.logging.ref.slf4j.ONAPLogConstants;
90 import org.slf4j.Logger;
91 import org.slf4j.LoggerFactory;
94 import com.fasterxml.jackson.annotation.JsonInclude.Include;
95 import com.fasterxml.jackson.databind.AnnotationIntrospector;
96 import com.fasterxml.jackson.databind.DeserializationFeature;
97 import com.fasterxml.jackson.databind.ObjectMapper;
98 import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector;
99 import com.fasterxml.jackson.databind.type.TypeFactory;
100 import com.fasterxml.jackson.module.jaxb.JaxbAnnotationIntrospector;
103 public class AAIService extends AAIDeclarations implements AAIClient, SvcLogicResource {
105 public static final String AAICLIENT_PROPERTIES = "/aaiclient.properties";
106 public static final String PATH_PROPERTIES = "/aai-path.properties";
108 private static final Logger LOG = LoggerFactory.getLogger(AAIService.class);
110 private final String truststorePath;
111 private final String truststorePassword;
112 private final String keystorePath;
113 private final String keystorePassword;
114 private final Boolean ignoreCertificateHostError;
116 private final String targetUri;
117 private final String networkVserverPath;
119 private final String svc_inst_query_path;
121 private final String ubb_notify_path;
122 private final String selflinkAvpn;
123 private final String selflinkFqdn;
125 private final int connectionTimeout;
126 private final int readTimeout;
129 private final String queryNodesPath;
130 private final String applicationId;
132 // authentication credentials
133 private String userName;
134 private String userPassword;
137 private final boolean runtimeOSGI;
139 private SSLContext CTX;
141 private final MetricLogger ml = new MetricLogger();
143 private AAIExecutorInterface executor;
145 public AAIService(final UtilsProvider configuration) {
146 this(configuration.getProperties());
149 public AAIService(final URL url) {
150 this(getProperties(url));
153 public AAIService(Properties props) {
154 LOG.info("Entered AAIService.ctor");
156 String runtime = System.getProperty("aaiclient.runtime");
157 if("OSGI".equals(runtime)) {
164 AAIRequest.setProperties(props, this);
166 } catch(Exception exc){
167 LOG.error("AicAAIResource.static", exc);
170 executor = new AAIClientRESTExecutor(props);
172 userName = props.getProperty(CLIENT_NAME);
173 userPassword = props.getProperty(CLIENT_PWWD);
175 if(userName == null || userName.isEmpty()){
176 LOG.debug("Basic user name is not set");
178 if(userPassword == null || userPassword.isEmpty()) {
179 LOG.debug("Basic password is not set");
182 truststorePath = props.getProperty(TRUSTSTORE_PATH);
183 truststorePassword = props.getProperty(TRUSTSTORE_PSSWD);
184 keystorePath = props.getProperty(KEYSTORE_PATH);
185 keystorePassword = props.getProperty(KEYSTORE_PSSWD);
187 targetUri = props.getProperty(TARGET_URI);
188 props.getProperty(QUERY_PATH);
189 props.getProperty(UPDATE_PATH);
191 String tmpApplicationId = props.getProperty(APPLICATION_ID);
192 if(tmpApplicationId == null || tmpApplicationId.isEmpty()) {
193 tmpApplicationId = "SDNC";
195 this.applicationId = tmpApplicationId;
197 // connection timeout
198 int tmpConnectionTimeout = 30000;
199 int tmpReadTimeout = 30000;
202 String tmpValue = null;
203 tmpValue = props.getProperty(CONNECTION_TIMEOUT, "30000");
204 tmpConnectionTimeout = Integer.parseInt(tmpValue);
205 tmpValue = props.getProperty(READ_TIMEOUT, "30000");
206 tmpReadTimeout = Integer.parseInt(tmpValue);
207 } catch(Exception exc) {
208 LOG.error("Failed setting connection timeout", exc);
209 tmpConnectionTimeout = 30000;
210 tmpReadTimeout = 30000;
212 connectionTimeout = tmpConnectionTimeout;
213 readTimeout = tmpReadTimeout;
215 networkVserverPath =props.getProperty(NETWORK_VSERVER_PATH);
217 props.getProperty(SVC_INSTANCE_PATH);
218 svc_inst_query_path = props.getProperty(SVC_INST_QRY_PATH);
219 props.getProperty(PARAM_SERVICE_TYPE, "service-type");
221 props.getProperty(VNF_IMAGE_QUERY_PATH);
223 ubb_notify_path = props.getProperty(UBB_NOTIFY_PATH);
224 selflinkAvpn = props.getProperty(SELFLINK_AVPN);
225 selflinkFqdn = props.getProperty(SELFLINK_FQDN);
227 props.getProperty(SERVICE_PATH);
229 props.getProperty(SITE_PAIR_SET_PATH);
231 queryNodesPath = props.getProperty(QUERY_NODES_PATH);
233 String iche = props.getProperty(CERTIFICATE_HOST_ERROR);
234 boolean host_error = false;
235 if(iche != null && !iche.isEmpty()) {
236 host_error = Boolean.valueOf(iche);
239 ignoreCertificateHostError = host_error;
241 HttpsURLConnection.setDefaultHostnameVerifier( new HostnameVerifier(){
242 public boolean verify(String string,SSLSession ssls) {
243 return ignoreCertificateHostError;
247 if(truststorePath != null && truststorePassword != null && (new File(truststorePath)).exists()) {
248 System.setProperty("javax.net.ssl.trustStore", truststorePath);
249 System.setProperty("javax.net.ssl.trustStorePassword", truststorePassword);
252 if(keystorePath != null && keystorePassword != null && (new File(keystorePath)).exists()) {
253 //DefaultClientConfig config = new DefaultClientConfig();
254 //both jersey and HttpURLConnection can use this
255 SSLContext ctx = null;
257 ctx = SSLContext.getInstance("TLS");
259 KeyManagerFactory kmf = null;
260 try (FileInputStream fin = new FileInputStream(keystorePath)){
261 String def = "SunX509";
262 String storeType = "PKCS12";
263 def = KeyStore.getDefaultType();
264 kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
266 String extension = keystorePath.substring(keystorePath.lastIndexOf(".") + 1);
267 if("JKS".equalsIgnoreCase(extension)) {
270 KeyStore ks = KeyStore.getInstance(storeType);
272 char[] pwd = keystorePassword.toCharArray();
275 } catch (Exception ex) {
276 LOG.error("AAIResource", ex);
280 ctx.init(kmf.getKeyManagers(), null, null);
283 * config.getProperties().put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES, new
284 * HTTPSProperties( new HostnameVerifier() {
286 * @Override public boolean verify( String s, SSLSession sslSession ) { return
287 * ignoreCertificateHostError; } }, ctx));
291 LOG.debug("SSLContext created");
293 } catch (KeyManagementException | NoSuchAlgorithmException exc) {
294 LOG.error("AAIResource", exc);
298 LOG.info("AAIResource.ctor initialized.");
301 Field methodsField = HttpURLConnection.class.getDeclaredField("methods");
302 methodsField.setAccessible(true);
303 // get the methods field modifiers
304 Field modifiersField = Field.class.getDeclaredField("modifiers");
305 // bypass the "private" modifier
306 modifiersField.setAccessible(true);
308 // remove the "final" modifier
309 modifiersField.setInt(methodsField, methodsField.getModifiers() & ~Modifier.FINAL);
311 /* valid HTTP methods */
313 "GET", "POST", "HEAD", "OPTIONS", "PUT", "DELETE", "TRACE", "PATCH"
315 // set the new methods - including patch
316 methodsField.set(null, methods);
318 } catch (SecurityException | IllegalArgumentException | IllegalAccessException | NoSuchFieldException e) {
319 LOG.error("Exception occured", e);
324 private static Properties getProperties(URL url) {
325 Properties properties = new Properties();
327 properties.load(url.openStream());
328 } catch (IOException exc) {
329 LOG.error("getProperties", exc);
334 public void setExecutor(AAIExecutorInterface executor) {
335 this.executor = executor;
338 public void cleanUp() {
344 * @param http_req_url
349 protected HttpURLConnection getConfiguredConnection(URL http_req_url, String method) throws Exception {
350 HttpURLConnection con = (HttpURLConnection) http_req_url.openConnection();
352 // Set up the connection properties
353 con.setRequestProperty( "Connection", "close" );
354 con.setDoInput(true);
355 con.setDoOutput(true);
356 con.setUseCaches(false);
357 con.setConnectTimeout( connectionTimeout );
358 con.setReadTimeout( readTimeout );
359 con.setRequestMethod( method );
360 con.setRequestProperty( "Accept", "application/json" );
361 con.setRequestProperty( "Content-Type", "PATCH".equalsIgnoreCase(method) ? "application/merge-patch+json" : "application/json" );
362 con.setRequestProperty("X-FromAppId", applicationId);
363 con.setRequestProperty("X-TransactionId",TransactionIdTracker.getNextTransactionId());
364 String mlId = ml.getRequestID();
365 if(mlId != null && !mlId.isEmpty()) {
366 LOG.debug(String.format("MetricLogger requestId = %s", mlId));
367 con.setRequestProperty(ONAPLogConstants.MDCs.REQUEST_ID, mlId);
369 LOG.debug("MetricLogger requestId is null");
371 con.setRequestProperty("Transfer-Encoding","chunked");
373 if(userName != null && !userName.isEmpty() && userPassword != null && !userPassword.isEmpty()) {
374 String basicAuth = "Basic " + new String(Base64.encodeBase64((userName + ":" + userPassword).getBytes()));
375 con.setRequestProperty ("Authorization", basicAuth);
378 if(con instanceof HttpsURLConnection && CTX != null) {
379 SSLSocketFactory sockFact = CTX.getSocketFactory();
380 HttpsURLConnection.class.cast(con).setSSLSocketFactory( sockFact );
387 public GenericVnf requestGenericVnfData(String vnf_id) throws AAIServiceException {
388 GenericVnf response = null;
391 AAIRequest request = AAIRequest.getRequestFromResource("generic-vnf");
392 request.addRequestProperty("generic-vnf.vnf-id", vnf_id);
393 String rv = executor.get(request);
395 ObjectMapper mapper = getObjectMapper();
396 response = mapper.readValue(rv, GenericVnf.class);
398 } catch(AAIServiceException aaiexc) {
400 } catch (Exception exc) {
401 LOG.warn(Object.class.getClass().getEnclosingMethod().getName(), exc);
402 throw new AAIServiceException(exc);
410 public boolean postGenericVnfData(String vnf_id, GenericVnf data) throws AAIServiceException {
412 AAIRequest request = AAIRequest.getRequestFromResource("generic-vnf");
413 request.addRequestProperty("generic-vnf.vnf-id", vnf_id);
414 request.setRequestObject(data);
415 Object response = executor.post(request);
417 } catch(AAIServiceException aaiexc) {
419 } catch (Exception exc) {
420 LOG.warn("requestGenericVnfData", exc);
421 throw new AAIServiceException(exc);
426 public SearchResults requestServiceInstanceURL(String svc_instance_id) throws AAIServiceException {
427 SearchResults response = null;
428 InputStream inputStream = null;
431 String path = svc_inst_query_path;
432 path = path.replace("{svc-instance-id}", encodeQuery(svc_instance_id));
434 String request_url = targetUri+path;
435 URL http_req_url = new URL(request_url);
437 HttpURLConnection con = getConfiguredConnection(http_req_url, HttpMethod.GET);
439 LOGwriteFirstTrace(HttpMethod.GET, http_req_url.toString());
440 LOGwriteDateTrace("svc_instance_id", svc_instance_id);
443 int responseCode = con.getResponseCode();
444 if (responseCode == HttpURLConnection.HTTP_OK) {
445 inputStream = con.getInputStream();
447 inputStream = con.getErrorStream();
450 // Process the response
451 LOG.debug("HttpURLConnection result:" + responseCode);
452 if(inputStream == null) inputStream = new ByteArrayInputStream("".getBytes(StandardCharsets.UTF_8));
453 BufferedReader reader = new BufferedReader( new InputStreamReader( inputStream ) );
455 ObjectMapper mapper = getObjectMapper();
457 if (responseCode == HttpURLConnection.HTTP_OK) {
458 response = mapper.readValue(reader, SearchResults.class);
459 LOGwriteEndingTrace(HttpURLConnection.HTTP_OK, "SUCCESS", mapper.writeValueAsString(response));
460 } else if(responseCode == HttpURLConnection.HTTP_NOT_FOUND ) {
461 LOGwriteEndingTrace(responseCode, "HTTP_NOT_FOUND", "Entry does not exist.");
464 ErrorResponse errorresponse = mapper.readValue(reader, ErrorResponse.class);
465 LOGwriteEndingTrace(responseCode, "FAILURE", mapper.writeValueAsString(errorresponse));
466 throw new AAIServiceException(responseCode, errorresponse);
469 } catch(AAIServiceException aaiexc) {
471 } catch (Exception exc) {
472 LOG.warn("requestServiceInstanceURL", exc);
473 throw new AAIServiceException(exc);
475 if(inputStream != null){
478 } catch(Exception exc) {
479 LOG.warn("Error closing Inputstream", exc);
487 private static Properties initialize(URL url ) throws ConfigurationException {
490 throw new NullPointerException();
493 InputStream is = null;
494 Properties props = new Properties();
497 if(LOG.isDebugEnabled())
498 LOG.info("Property file is: " + url.toString());
500 is = url.openStream();
503 if(LOG.isDebugEnabled()) {
504 LOG.info("Properties loaded: " + props.size());
505 Enumeration<Object> en = props.keys();
507 while(en.hasMoreElements()) {
508 String key = (String)en.nextElement();
509 String property = props.getProperty(key);
510 LOG.debug(key + " : " + property);
513 } catch (Exception e) {
514 throw new ConfigurationException("Could not load properties file.", e);
519 static class TransactionIdTracker {
520 // protected static AtomicLong tracker = new AtomicLong();
522 public static String getNextTransactionId() {
523 // Check if RequestId exists as MDC. If not, create new.
524 String transactionId = MDC.get("RequestId");
525 if ("".equals(transactionId) || transactionId == null) {
526 transactionId = UUID.randomUUID().toString();
527 LOG.info("Missing requestID. Assigned " + transactionId);
528 MDC.put("RequestId", transactionId);
530 return transactionId;
535 protected void LOGwriteFirstTrace(String method, String url) {
536 String time = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'").format(System.currentTimeMillis());
537 LOG.info("A&AI transaction :");
538 LOG.info("Request Time : " + time + ", Method : " + method);
539 LOG.info("Request URL : "+ url);
542 protected void LOGwriteDateTrace(String name, String data) {
543 LOG.info("Input - " + name + " : " + data);
546 protected void LOGwriteEndingTrace(int response_code, String comment, String data) {
547 LOG.info("Response code : " + response_code +", " + comment);
548 LOG.info(String.format("Response data : %s", data));
551 protected String encodeQuery(String param) throws UnsupportedEncodingException {
552 return URLEncoder.encode(param, "UTF-8").replace("+", "%20");
555 private String encodeCustomerURL(final String selection)
557 String encrypted_url = selection;
559 "/aai/v11/business/customers/customer/(.+)/service-subscriptions/service-subscription/(.+)/service-instances/service-instance/(.+)/";
560 Pattern pattern = Pattern.compile(apnpattern);
563 URL url = new URL(selection);
564 String path = url.getPath();
566 LOG.info("Trying to match apn to <" + path + ">");
568 Matcher matcher = pattern.matcher(path);
570 while(matcher.find()) {
571 String customer = matcher.group(1);
572 String subscription = matcher.group(2);
573 String service = matcher.group(3);
575 encrypted_url = selection.replace(customer, encodeQuery(customer));
576 encrypted_url = encrypted_url.replace(subscription, encodeQuery(subscription));
577 encrypted_url = encrypted_url.replace(service, encodeQuery(service));
579 } catch (Exception e) {
583 return encrypted_url;
590 * @see org.onap.sdnct.sli.aai.AAIClient#requestVServersData(java.lang.String, java.lang.String)
593 public Vserver requestVServerData(String tenantId, String vserverId, String cloudOwner, String cloudRegionId) throws AAIServiceException {
594 Vserver response = null;
597 AAIRequest request = AAIRequest.getRequestFromResource("vserver");
598 request.addRequestProperty("cloud-region.cloud-owner", cloudOwner);
599 request.addRequestProperty("cloud-region.cloud-region-id", cloudRegionId);
600 request.addRequestProperty("tenant.tenant-id", tenantId);
601 request.addRequestProperty("vserver.vserver-id", vserverId);
603 String rv = executor.get(request);
605 ObjectMapper mapper = getObjectMapper();
606 response = mapper.readValue(rv, Vserver.class);
608 } catch(AAIServiceException aaiexc) {
610 } catch (Exception exc) {
611 LOG.warn(Object.class.getClass().getEnclosingMethod().getName(), exc);
612 throw new AAIServiceException(exc);
618 //================== End of DvsSwitch =================
619 //==================== PhysicalLink ======================
621 public PhysicalLink requestPhysicalLinkData(String linkName) throws AAIServiceException {
622 PhysicalLink response = null;
625 AAIRequest request = AAIRequest.getRequestFromResource("physical-link");
626 request.addRequestProperty("physical-link.link-name", linkName);
628 String rv = executor.get(request);
630 ObjectMapper mapper = getObjectMapper();
631 response = mapper.readValue(rv, PhysicalLink.class);
633 } catch(AAIServiceException aaiexc) {
635 } catch (Exception exc) {
636 LOG.warn("requestPhysicalLinkData", exc);
637 throw new AAIServiceException(exc);
643 public boolean postPhysicalLinkData(String linkName, PhysicalLink data) throws AAIServiceException {
645 AAIRequest request = AAIRequest.getRequestFromResource("physical-link");
646 request.addRequestProperty("physical-link.link-name", linkName);
647 request.setRequestObject(data);
648 Object response = executor.post(request);
650 } catch(AAIServiceException aaiexc) {
652 } catch (Exception exc) {
653 LOG.warn(Object.class.getClass().getEnclosingMethod().getName(), exc);
654 throw new AAIServiceException(exc);
659 public boolean deletePhysicalLinkData(String linkName, String resourceVersion) throws AAIServiceException {
660 boolean response = false;
663 AAIRequest request = AAIRequest.getRequestFromResource("physical-link");
664 request.addRequestProperty("physical-link.link-name", linkName);
665 response = executor.delete(request, resourceVersion);
666 } catch(AAIServiceException aaiexc) {
668 } catch (Exception exc) {
669 LOG.warn("deletePhysicalLinkData", exc);
670 throw new AAIServiceException(exc);
675 public boolean deleteAAIEntity(URL url, String caller) throws AAIServiceException {
678 throw new NullPointerException();
681 boolean response = false;
682 InputStream inputStream = null;
685 URL http_req_url = url;
687 HttpURLConnection con = getConfiguredConnection(http_req_url, HttpMethod.DELETE);
689 LOGwriteFirstTrace("DELETE", http_req_url.toString());
693 int responseCode = con.getResponseCode();
694 if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_NO_CONTENT) {
695 inputStream = con.getInputStream();
697 inputStream = con.getErrorStream();
700 // Process the response
701 LOG.debug("HttpURLConnection result:" + responseCode);
702 if(inputStream == null) inputStream = new ByteArrayInputStream("".getBytes(StandardCharsets.UTF_8));
703 BufferedReader reader = new BufferedReader( new InputStreamReader( inputStream ) );
706 ObjectMapper mapper = getObjectMapper();
708 if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_NO_CONTENT) {
709 StringBuilder stringBuilder = new StringBuilder();
711 while( ( line = reader.readLine() ) != null ) {
712 stringBuilder.append( line );
714 LOGwriteEndingTrace(responseCode, "SUCCESS", stringBuilder.toString());
716 } else if(responseCode == HttpURLConnection.HTTP_NOT_FOUND ) {
717 LOGwriteEndingTrace(responseCode, "HTTP_NOT_FOUND", "Entry does not exist.");
720 ErrorResponse errorresponse = mapper.readValue(reader, ErrorResponse.class);
721 LOGwriteEndingTrace(responseCode, "FAILURE", mapper.writeValueAsString(errorresponse));
722 throw new AAIServiceException(responseCode, errorresponse);
725 } catch(AAIServiceException aaiexc) {
727 } catch (Exception exc) {
728 LOG.warn(caller, exc);
729 throw new AAIServiceException(exc);
731 if(inputStream != null){
734 } catch(Exception exc) {
735 LOG.warn("Error closing InputStream", exc);
743 * Generic method to GET json data from an A&AI callback URL.
744 * Then convert that json to an Object.
745 * If successful the Object is attempted to be cast to the type parameter.
748 * callback url for A&AI
750 * the class of object that A&AI will return
751 * @return the object created from json or null if the response code is not 200
753 * @throws AAIServiceException
754 * if empty or null key and or type or there's an error with processing
756 public <T> T dataChangeRequestAaiData(String key, Class<T> type) throws AAIServiceException {
757 if (StringUtils.isEmpty(key) || type == null) {
758 throw new AAIServiceException("Key is empty or null and or type is null");
763 SvcLogicContext ctx = new SvcLogicContext();
764 if(!key.contains(" = ") && isValidURL(key)) {
765 key = String.format("selflink = '%s'", key);
767 if(!key.contains(" = ") && isValidURI(key)) {
768 key = String.format("resource-path = '%s'", key);
771 HashMap<String, String> nameValues = AAIServiceUtils.keyToHashMap(key, ctx);
773 SelfLinkRequest request = new SelfLinkRequest(type);
774 request.processRequestPathValues(nameValues);
775 Object obj = this.getExecutor().query(request, type);
776 response = type.cast(obj);
778 return response != null ? type.cast(response) : response;
782 public boolean sendNotify(NotifyEvent event, String serviceInstanceId, String pathCode) throws AAIServiceException {
783 InputStream inputStream = null;
787 String selfLink = selflinkFqdn;
788 if(SELFLINK_AVPN != null && SELFLINK_AVPN.equals(pathCode)) {
789 selfLink = selflinkAvpn;
791 selfLink = selfLink.replace("{service-instance-id}", encodeQuery(serviceInstanceId));
792 event.setSelflink(selfLink);
794 ObjectMapper mapper = getObjectMapper();
795 String json_text = mapper.writeValueAsString(event);
797 SSLSocketFactory sockFact = CTX.getSocketFactory();
799 String request_url = targetUri+ubb_notify_path;
800 URL http_req_url = new URL(request_url);
802 HttpURLConnection con = getConfiguredConnection(http_req_url, HttpMethod.PUT);
804 if (json_text != null) {
805 OutputStreamWriter osw = new OutputStreamWriter(con.getOutputStream());
806 osw.write(json_text);
811 LOGwriteFirstTrace("PUT", request_url);
812 LOGwriteDateTrace("NotifyEvent", json_text);
815 int responseCode = con.getResponseCode();
816 if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_CREATED || responseCode == HttpURLConnection.HTTP_ACCEPTED || responseCode == HttpURLConnection.HTTP_NO_CONTENT) {
817 inputStream = con.getInputStream();
819 inputStream = con.getErrorStream();
822 // Process the response
823 BufferedReader reader;
825 reader = new BufferedReader( new InputStreamReader( inputStream ) );
827 if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_CREATED || responseCode == HttpURLConnection.HTTP_ACCEPTED || responseCode == HttpURLConnection.HTTP_NO_CONTENT) {
828 StringBuilder stringBuilder = new StringBuilder();
830 while( ( line = reader.readLine() ) != null ) {
831 stringBuilder.append( line );
833 LOGwriteEndingTrace(responseCode, "SUCCESS", (stringBuilder.length() > 0) ? stringBuilder.toString() :
837 ErrorResponse errorresponse = mapper.readValue(reader, ErrorResponse.class);
838 LOGwriteEndingTrace(responseCode, "FAILURE", mapper.writeValueAsString(errorresponse));
840 throw new AAIServiceException(responseCode, errorresponse);
842 } catch(AAIServiceException aaiexc) {
844 } catch (Exception exc) {
845 LOG.warn("sendNotify", exc);
846 throw new AAIServiceException(exc);
849 if(inputStream != null)
851 } catch (Exception exc) {
852 LOG.warn("Error closing Input stream", exc);
858 public SearchResults requestNodeQuery(String node_type, String entityIdentifier, String entityName) throws AAIServiceException {
859 SearchResults response = null;
860 InputStream inputStream = null;
863 String request_url = targetUri+queryNodesPath;
864 request_url = request_url.replace("{node-type}", encodeQuery(node_type)) ;
865 request_url = request_url.replace("{entity-identifier}", entityIdentifier) ;
866 request_url = request_url.replace("{entity-name}", encodeQuery(entityName)) ;
867 URL http_req_url = new URL(request_url);
869 HttpURLConnection con = getConfiguredConnection(http_req_url, HttpMethod.GET);
871 LOGwriteFirstTrace(HttpMethod.GET, http_req_url.toString());
872 LOGwriteDateTrace("node_type", node_type);
873 LOGwriteDateTrace("vnf_name", entityName);
876 int responseCode = con.getResponseCode();
877 if (responseCode == HttpURLConnection.HTTP_OK) {
878 inputStream = con.getInputStream();
880 inputStream = con.getErrorStream();
883 // Process the response
884 LOG.debug("HttpURLConnection result:" + responseCode);
885 if(inputStream == null) inputStream = new ByteArrayInputStream("".getBytes(StandardCharsets.UTF_8));
886 BufferedReader reader = new BufferedReader( new InputStreamReader( inputStream ) );
888 ObjectMapper mapper = getObjectMapper();
890 if (responseCode == HttpURLConnection.HTTP_OK) {
891 response = mapper.readValue(reader, SearchResults.class);
892 LOGwriteEndingTrace(HttpURLConnection.HTTP_OK, "SUCCESS", mapper.writeValueAsString(response));
893 } else if (responseCode == HttpURLConnection.HTTP_NOT_FOUND) {
894 LOGwriteEndingTrace(responseCode, "HTTP_NOT_FOUND", "Entry does not exist.");
897 ErrorResponse errorresponse = mapper.readValue(reader, ErrorResponse.class);
898 LOGwriteEndingTrace(responseCode, "FAILURE", mapper.writeValueAsString(errorresponse));
899 throw new AAIServiceException(responseCode, errorresponse);
902 } catch(AAIServiceException aaiexc) {
904 } catch (Exception exc) {
905 LOG.warn("requestNodeQuery", exc);
906 throw new AAIServiceException(exc);
908 if(inputStream != null){
911 } catch(Exception exc) {
912 LOG.warn("Error closing Input stream", exc);
922 public String requestDataByURL(URL url) throws AAIServiceException {
925 throw new NullPointerException();
928 String response = null;
929 InputStream inputStream = null;
932 URL http_req_url = url;
934 HttpURLConnection con = getConfiguredConnection(http_req_url, HttpMethod.GET);
936 LOGwriteFirstTrace(HttpMethod.GET, http_req_url.toString());
939 int responseCode = con.getResponseCode();
940 if (responseCode == HttpURLConnection.HTTP_OK) {
941 inputStream = con.getInputStream();
943 inputStream = con.getErrorStream();
946 // Process the response
947 LOG.debug("HttpURLConnection result:" + responseCode);
948 if(inputStream == null) inputStream = new ByteArrayInputStream("".getBytes(StandardCharsets.UTF_8));
949 BufferedReader reader = new BufferedReader( new InputStreamReader( inputStream ) );
951 ObjectMapper mapper = getObjectMapper();
953 if (responseCode == HttpURLConnection.HTTP_OK) {
954 StringBuilder stringBuilder = new StringBuilder("\n");
956 while( ( line = reader.readLine() ) != null ) {
957 stringBuilder.append( line );
959 LOG.info(stringBuilder.toString());
960 // response = mapper.readValue(reader, String.class);
961 response = stringBuilder.toString();
962 LOGwriteEndingTrace(HttpURLConnection.HTTP_OK, "SUCCESS", mapper.writeValueAsString(response));
963 } else if(responseCode == HttpURLConnection.HTTP_NOT_FOUND ) {
964 LOGwriteEndingTrace(responseCode, "HTTP_NOT_FOUND", "Entry does not exist.");
967 ErrorResponse errorresponse = mapper.readValue(reader, ErrorResponse.class);
968 LOGwriteEndingTrace(responseCode, "FAILURE", mapper.writeValueAsString(errorresponse));
969 throw new AAIServiceException(responseCode, errorresponse);
972 } catch(AAIServiceException aaiexc) {
974 } catch (Exception exc) {
975 LOG.warn("requestNetworkVceData", exc);
976 throw new AAIServiceException(exc);
978 if(inputStream != null){
981 } catch(Exception exc) {
982 LOG.warn("Error closing Input stream", exc);
991 public GenericVnf requestGenericVnfeNodeQuery(String vnf_name) throws AAIServiceException {
993 if(vnf_name == null) {
994 throw new NullPointerException();
997 GenericVnf entity = null;
998 SearchResults resp = this.requestNodeQuery("generic-vnf", "vnf-name", vnf_name);
1000 List<ResultData> resultDataList = resp.getResultData();
1003 for (ResultData datum : resultDataList) {
1004 URI url = new URI(datum.getResourceLink());
1005 entity = this.getResource(url.toString(), GenericVnf.class);
1010 LOG.error("Caught exception", e);
1016 public Vserver requestVServerDataByURL(URL url) throws AAIServiceException {
1019 throw new NullPointerException();
1022 Vserver entity = null;
1025 entity = this.getResource(url.toString(), Vserver.class);
1026 } catch (AAIServiceException exc) {
1028 } catch (Exception e) {
1029 throw new AAIServiceException(e);
1035 public URL requestVserverURLNodeQuery(String vserver_name) throws AAIServiceException {
1037 if(vserver_name == null) {
1038 throw new NullPointerException();
1042 SearchResults resp = this.requestNodeQuery("vserver", "vserver-name", vserver_name);
1044 List<ResultData> resultDataList = resp.getResultData();
1047 for (ResultData datum : resultDataList) {
1048 String data_type = datum.getResourceType();
1049 String resourceLink = datum.getResourceLink();
1050 if(!resourceLink.isEmpty() && !resourceLink.toLowerCase().startsWith("http")) {
1051 resourceLink = (new EchoRequest()).targetUri + resourceLink;
1053 entity = new URL(resourceLink);
1055 } catch (Exception e) {
1056 throw new AAIServiceException(e);
1062 public String getTenantIdFromVserverUrl(URL url) {
1064 String path = url.getPath();
1066 String[] split = path.split("/tenants/tenant/");
1067 if(split.length > 1) {
1068 split = split[1].split("/");
1076 public String getCloudOwnerFromVserverUrl(URL url) {
1078 String path = url.getPath();
1080 String[] split = path.split("/cloud-regions/cloud-region/");
1081 if(split.length > 1) {
1082 split = split[1].split("/");
1090 public String getCloudRegionFromVserverUrl(URL url) {
1092 String path = url.getPath();
1094 String[] split = path.split("/cloud-regions/cloud-region/");
1095 if(split.length > 1) {
1096 split = split[1].split("/");
1104 public String getVServerIdFromVserverUrl(URL url, String tenantId) {
1105 String pattern = networkVserverPath;
1106 pattern = pattern.replace("{tenant-id}", tenantId);
1108 int end = pattern.indexOf("{vserver-id}");
1109 String prefix = pattern.substring(0, end);
1111 String path = url.getPath();
1113 if(path.startsWith(prefix)) {
1114 path = path.substring(prefix.length());
1120 protected Logger getLogger(){
1126 public AAIExecutorInterface getExecutor() {
1131 * Creates a current time stamp in UTC i.e. 2016-03-08T22:15:13.343Z.
1132 * If there are any parameters the values are appended to the time stamp.
1135 * values to be appended to current time stamp
1137 * used to set an attribute for a DG
1138 * @throws SvcLogicException
1140 public void setStatusMethod(Map<String, String> parameters, SvcLogicContext ctx) throws SvcLogicException {
1142 throw new SvcLogicException("SvcLogicContext is null.");
1145 StringBuilder sb = new StringBuilder();
1146 sb.append(String.format("%tFT%<tTZ", Calendar.getInstance(TimeZone.getTimeZone("Z")))).append(" - ");
1148 for (Entry<String, String> entry : parameters.entrySet()) {
1149 sb.append(entry.getValue()).append(" ");
1152 if (sb.length() > 0) {
1153 sb.setLength(sb.length() - 2);
1156 ctx.setAttribute("aai-summary-status-message", sb.toString());
1157 LOG.info("aai-summary-status-message: " + sb.toString());
1161 * Generic method to GET json data from an A&AI using key structure.
1162 * Then convert that json to an Object.
1163 * If successful the Object is attempted to be cast to the type parameter.
1166 * key identifying the resource to be retrieved from AAI
1168 * the class of object that A&AI will return
1169 * @return the object created from json or null if the response code is not 200
1171 * @throws AAIServiceException
1172 * if empty or null key and or type or there's an error with processing
1175 public <T> T getResource(String key, Class<T> type) throws AAIServiceException {
1176 if (StringUtils.isEmpty(key) || type == null) {
1177 throw new AAIServiceException("Key is empty or null and or type is null");
1182 SvcLogicContext ctx = new SvcLogicContext();
1183 if(!key.contains(" = ")) {
1184 if(isValidURL(key)) {
1185 key = String.format("selflink = '%s'", key);
1186 } else if(isValidURI(key)) {
1187 key = String.format("resource-path = '%s'", key);
1193 HashMap<String, String> nameValues = AAIServiceUtils.keyToHashMap(key, ctx);
1195 AAIRequest request = new SelfLinkRequest(type);
1196 if(nameValues.containsKey(PathRequest.RESOURCE_PATH.replaceAll("-", "_"))) {
1197 request = new PathRequest(type);
1200 request.processRequestPathValues(nameValues);
1201 Object obj = this.getExecutor().query(request, type);
1202 response = type.cast(obj);
1204 return response != null ? type.cast(response) : response;
1207 public boolean isValidURL(String url) {
1213 } catch (MalformedURLException e) {
1214 LOG.warn("MalformedURLException", e);
1220 } catch (URISyntaxException e) {
1221 LOG.warn("URISyntaxException", e);
1229 public boolean isValidURI(String url) {
1235 } catch (URISyntaxException e) {
1236 LOG.warn("URISyntaxException", e);
1244 protected boolean deleteList(URL httpReqUrl, String jsonText) throws AAIServiceException {
1245 if(httpReqUrl == null) {
1246 throw new NullPointerException();
1249 boolean response = false;
1250 InputStream inputStream = null;
1253 HttpURLConnection con = getConfiguredConnection(httpReqUrl, HttpMethod.DELETE);
1255 // SSLSocketFactory sockFact = CTX.getSocketFactory();
1256 // con.setSSLSocketFactory( sockFact );
1257 if (jsonText != null) {
1258 OutputStreamWriter osw = new OutputStreamWriter(con.getOutputStream());
1259 osw.write(jsonText);
1264 LOGwriteFirstTrace("DELETE", httpReqUrl.toString());
1265 LOGwriteDateTrace("data", jsonText);
1268 int responseCode = con.getResponseCode();
1269 if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_NO_CONTENT) {
1270 inputStream = con.getInputStream();
1272 inputStream = con.getErrorStream();
1275 // Process the response
1276 LOG.debug("HttpURLConnection result:" + responseCode);
1277 if(inputStream == null) inputStream = new ByteArrayInputStream("".getBytes(StandardCharsets.UTF_8));
1278 BufferedReader reader = new BufferedReader( new InputStreamReader( inputStream ) );
1281 ObjectMapper mapper = getObjectMapper();
1283 if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_NO_CONTENT) {
1284 StringBuilder stringBuilder = new StringBuilder();
1286 while( ( line = reader.readLine() ) != null ) {
1287 stringBuilder.append( line );
1289 LOGwriteEndingTrace(responseCode, "SUCCESS", stringBuilder.toString());
1291 } else if(responseCode == HttpURLConnection.HTTP_NOT_FOUND ) {
1292 LOGwriteEndingTrace(responseCode, "HTTP_NOT_FOUND", "Entry does not exist.");
1295 ErrorResponse errorresponse = mapper.readValue(reader, ErrorResponse.class);
1296 LOGwriteEndingTrace(responseCode, "FAILURE", mapper.writeValueAsString(errorresponse));
1297 throw new AAIServiceException(responseCode, errorresponse);
1300 } catch(AAIServiceException aaiexc) {
1302 } catch (Exception exc) {
1303 LOG.warn("deleteList", exc);
1304 throw new AAIServiceException(exc);
1306 if(inputStream != null){
1308 inputStream.close();
1309 } catch(Exception exc) {
1317 public static ObjectMapper getObjectMapper() {
1318 ObjectMapper mapper = new ObjectMapper();
1319 AnnotationIntrospector introspector = new JaxbAnnotationIntrospector(TypeFactory.defaultInstance());
1320 AnnotationIntrospector secondary = new JacksonAnnotationIntrospector();
1321 mapper.setAnnotationIntrospector(AnnotationIntrospector.pair(introspector, secondary));
1322 mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
1323 mapper.setSerializationInclusion(Include.NON_NULL);
1324 mapper.setSerializationInclusion(Include.NON_EMPTY);
1328 public void logMetricRequest(String requestId, String targetServiceName, String msg, String path){
1329 String svcInstanceId = "";
1330 String svcName = null;
1331 String partnerName = null;
1332 String targetEntity = "A&AI";
1333 String targetVirtualEntity = null;
1335 ml.logRequest(svcInstanceId, svcName, partnerName, targetEntity, targetServiceName, targetVirtualEntity, msg);
1338 public void logMetricResponse(String requestId, int responseCode, String responseDescription){
1339 ml.logResponse(responseCode < 400 ? "COMPLETE" : "ERROR", Integer.toString(responseCode), responseDescription);
1342 public void logKeyError(String keys){
1343 LOG.error("Atleast one of the keys [" + keys + "] should have been populated. This will cause a NPE.");
1351 public QueryStatus save(String resource, boolean force, boolean localOnly, String key, Map<String, String> params, String prefix, SvcLogicContext ctx)
1352 throws SvcLogicException {
1353 String normResource = resource.split(":")[0];
1355 switch(normResource){
1356 case "custom-query":
1357 case "formatted-query":
1358 case "generic-query":
1361 case "l2-bridge-sbg":
1362 case "l2-bridge-bgf":
1368 if(key.contains("selflink =")) {
1371 if(!key.contains(String.format("%s.", normResource))) {
1372 key = rewriteKey(resource, key, ctx);
1375 return super.save(resource, force, localOnly, key, params, prefix, ctx);
1379 public QueryStatus query(String resource, boolean localOnly, String select, String key, String prefix, String orderBy, SvcLogicContext ctx)
1380 throws SvcLogicException {
1381 String normResource = resource.split(":")[0];
1383 switch(normResource){
1384 case "custom-query":
1385 case "formatted-query":
1386 case "generic-query":
1389 case "l2-bridge-sbg":
1390 case "l2-bridge-bgf":
1396 if(key.contains("selflink =")) {
1399 if(!key.contains(String.format("%s.", normResource))) {
1400 key = rewriteKey(resource, key, ctx);
1404 return super.query(resource, localOnly, select, key, prefix, orderBy, ctx);
1408 public QueryStatus delete(String resource, String key, SvcLogicContext ctx) throws SvcLogicException {
1409 String normResource = resource.split(":")[0];
1411 switch(normResource){
1412 case "custom-query":
1413 case "formatted-query":
1414 case "generic-query":
1417 case "l2-bridge-sbg":
1418 case "l2-bridge-bgf":
1424 if(key.contains("selflink =")) {
1427 if(!key.contains(String.format("%s.", normResource))) {
1428 key = rewriteKey(resource, key, ctx);
1432 return super.delete(resource, key, ctx);
1436 public QueryStatus update(String resource, String key, Map<String, String> params, String prefix, SvcLogicContext ctx) throws SvcLogicException {
1437 String normResource = resource.split(":")[0];
1439 switch(normResource){
1440 case "custom-query":
1441 case "formatted-query":
1442 case "generic-query":
1445 case "l2-bridge-sbg":
1446 case "l2-bridge-bgf":
1452 if(key.contains("selflink =")) {
1455 if(!key.contains(String.format("%s.", normResource))) {
1456 key = rewriteKey(resource, key, ctx);
1460 return super.update(resource, key, params, prefix, ctx);
1463 private String rewriteKey(String resource, String key, SvcLogicContext ctx) {
1464 LOG.info("AAI Deprecation - the format of request key is no longer supported. Please rewrite this key : " + key);
1466 String normResource = resource.split(":")[0];
1467 Class<? extends AAIDatum> clazz = AAIRequest.getClassFromResource(normResource) ;
1472 List<String> fieldAnnotatedNames = new LinkedList<>();
1474 Field[] fields = clazz.getDeclaredFields();
1475 for(Field field : fields) {
1476 String fieldName = field.getName();
1477 XmlElement annotation = field.getAnnotation(XmlElement.class);
1478 if(annotation == null)
1480 String primaryId = annotation.name();
1481 if("##default".equals(primaryId)) {
1482 primaryId = fieldName;
1484 fieldAnnotatedNames.add(primaryId);
1487 HashMap<String, String> nameValues = AAIServiceUtils.keyToHashMap(key, ctx);
1488 Set<String> keyset = nameValues.keySet();
1489 for(String keyName : keyset) {
1490 if(keyName.contains("."))
1493 String tmpKeyName = keyName.replaceAll("_", "-");
1494 String valueToSubstitute = String.format("%s =", tmpKeyName);
1495 if(fieldAnnotatedNames.contains(tmpKeyName) && key.contains(valueToSubstitute)) {
1496 key = key.replace(valueToSubstitute, String.format("%s.%s =", normResource, tmpKeyName));
1506 public String getPathTemplateForResource(String resoourceName, String keys, SvcLogicContext ctx) throws MalformedURLException {
1507 return AAIServiceUtils.getPathForResource(resoourceName, StringUtils.join(keys, " AND "), ctx);
1511 public boolean isDeprecatedFormat(String resource, Map<String, String> nameValues) {
1512 return !AAIServiceUtils.isValidFormat(resource, nameValues);
1515 public AAIRequest getRequestFromResource(String resoourceName) {
1516 return AAIRequest.getRequestFromResource(resoourceName);
1520 * @see org.onap.ccsdk.sli.core.sli.aai.haha#query(org.onap.ccsdk.sli.core.sli.aai.AAIRequest)
1523 public String query(AAIRequest request) throws AAIServiceException {
1524 return executor.get(request);
1528 * @see org.onap.ccsdk.sli.core.sli.aai.haha#save(org.onap.ccsdk.sli.core.sli.aai.AAIRequest)
1531 public String save(AAIRequest request) throws AAIServiceException {
1532 return executor.post(request);
1535 public boolean update(AAIRequest request, String resourceVersion) throws AAIServiceException {
1536 return executor.patch(request, resourceVersion);
1540 * @see org.onap.ccsdk.sli.core.sli.aai.haha#delete(org.onap.ccsdk.sli.core.sli.aai.AAIRequest, java.lang.String)
1543 public boolean delete(AAIRequest request, String resourceVersion) throws AAIServiceException {
1544 return executor.delete(request, resourceVersion);