2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights
7 * ================================================================================
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 * ============LICENSE_END=========================================================
22 package org.onap.ccsdk.sli.adaptors.aai;
25 import java.io.BufferedReader;
26 import java.io.ByteArrayInputStream;
28 import java.io.FileInputStream;
29 import java.io.IOException;
30 import java.io.InputStream;
31 import java.io.InputStreamReader;
32 import java.io.OutputStreamWriter;
33 import java.io.UnsupportedEncodingException;
34 import java.lang.reflect.Field;
35 import java.lang.reflect.Modifier;
36 import java.net.HttpURLConnection;
37 import java.net.MalformedURLException;
39 import java.net.URISyntaxException;
41 import java.net.URLEncoder;
42 import java.nio.charset.StandardCharsets;
43 import java.security.KeyManagementException;
44 import java.security.KeyStore;
45 import java.security.NoSuchAlgorithmException;
46 import java.text.SimpleDateFormat;
47 import java.util.Calendar;
48 import java.util.Enumeration;
49 import java.util.HashMap;
50 import java.util.LinkedList;
51 import java.util.List;
53 import java.util.Map.Entry;
54 import java.util.Properties;
56 import java.util.TimeZone;
57 import java.util.UUID;
58 import java.util.regex.Matcher;
59 import java.util.regex.Pattern;
61 import javax.net.ssl.HostnameVerifier;
62 import javax.net.ssl.HttpsURLConnection;
63 import javax.net.ssl.KeyManagerFactory;
64 import javax.net.ssl.SSLContext;
65 import javax.net.ssl.SSLSession;
66 import javax.net.ssl.SSLSocketFactory;
67 import javax.ws.rs.HttpMethod;
68 import javax.xml.bind.annotation.XmlElement;
70 import org.apache.commons.codec.binary.Base64;
71 import org.apache.commons.lang3.StringUtils;
72 import org.onap.ccsdk.sli.adaptors.aai.data.AAIDatum;
73 import org.onap.ccsdk.sli.adaptors.aai.data.ErrorResponse;
74 import org.onap.ccsdk.sli.adaptors.aai.data.notify.NotifyEvent;
75 import org.onap.ccsdk.sli.core.sli.ConfigurationException;
76 import org.onap.ccsdk.sli.core.sli.MetricLogger;
77 import org.onap.ccsdk.sli.core.sli.SvcLogicContext;
78 import org.onap.ccsdk.sli.core.sli.SvcLogicException;
79 import org.onap.ccsdk.sli.core.sli.SvcLogicResource;
80 import org.openecomp.aai.inventory.v11.GenericVnf;
81 import org.openecomp.aai.inventory.v11.PhysicalLink;
82 import org.openecomp.aai.inventory.v11.ResultData;
83 import org.openecomp.aai.inventory.v11.SearchResults;
84 import org.openecomp.aai.inventory.v11.Vserver;
85 import org.slf4j.Logger;
86 import org.slf4j.LoggerFactory;
89 import com.fasterxml.jackson.annotation.JsonInclude.Include;
90 import com.fasterxml.jackson.databind.AnnotationIntrospector;
91 import com.fasterxml.jackson.databind.DeserializationFeature;
92 import com.fasterxml.jackson.databind.ObjectMapper;
93 import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector;
94 import com.fasterxml.jackson.databind.type.TypeFactory;
95 import com.fasterxml.jackson.module.jaxb.JaxbAnnotationIntrospector;
96 import com.sun.jersey.api.client.config.DefaultClientConfig;
97 import com.sun.jersey.client.urlconnection.HTTPSProperties;
100 public class AAIService extends AAIDeclarations implements AAIClient, SvcLogicResource {
102 public static final String AAICLIENT_PROPERTIES = "/aaiclient.properties";
103 public static final String PATH_PROPERTIES = "/aai-path.properties";
105 private static final Logger LOG = LoggerFactory.getLogger(AAIService.class);
107 private final String truststorePath;
108 private final String truststorePassword;
109 private final String keystorePath;
110 private final String keystorePassword;
111 private final Boolean ignoreCertificateHostError;
113 private final String targetUri;
114 private final String queryPath;
116 private final String networkVserverPath;
118 private final String svcInstancePath;
119 private final String svc_inst_qry_path;
121 private final String vnf_image_query_path;
123 private final String param_service_type; //= "service-type";
125 private final String ubb_notify_path;
126 private final String selflinkAvpn;
127 private final String selflinkFqdn;
129 private final String pInterfacePath;
131 private final String servicePath;
132 private final String sitePairSetPath;
134 private final int connectionTimeout;
135 private final int readTimeout;
138 private final String queryNodesPath;
139 private final String updatePath;
141 private final String applicationId;
143 // authentication credentials
144 private String userName;
145 private String userPassword;
148 private final boolean runtimeOSGI;
150 private SSLContext CTX;
152 private final MetricLogger ml = new MetricLogger();
154 private AAIExecutorInterface executor;
156 public AAIService(final UtilsProvider configuration) {
157 this(configuration.getProperties());
160 public AAIService(final URL url) {
161 this(getProperties(url));
164 private static Properties getProperties(URL url) {
165 Properties properties = new Properties();
167 properties.load(url.openStream());
168 } catch (IOException exc) {
169 LOG.error("getProperties", exc);
174 public AAIService(Properties props) {
175 LOG.info("Entered AAIService.ctor");
177 String runtime = System.getProperty("aaiclient.runtime");
178 if("OSGI".equals(runtime)) {
185 AAIRequest.setProperties(props, this);
187 } catch(Exception exc){
188 LOG.error("AicAAIResource.static", exc);
191 executor = new AAIClientRESTExecutor(props);
193 userName = props.getProperty(CLIENT_NAME);
194 userPassword = props.getProperty(CLIENT_PWWD);
196 if(userName == null || userName.isEmpty()){
197 LOG.debug("Basic user name is not set");
199 if(userPassword == null || userPassword.isEmpty()) {
200 LOG.debug("Basic password is not set");
203 truststorePath = props.getProperty(TRUSTSTORE_PATH);
204 truststorePassword = props.getProperty(TRUSTSTORE_PSSWD);
205 keystorePath = props.getProperty(KEYSTORE_PATH);
206 keystorePassword = props.getProperty(KEYSTORE_PSSWD);
208 targetUri = props.getProperty(TARGET_URI);
209 queryPath = props.getProperty(QUERY_PATH);
210 updatePath = props.getProperty(UPDATE_PATH);
212 String tmpApplicationId = props.getProperty(APPLICATION_ID);
213 if(tmpApplicationId == null || tmpApplicationId.isEmpty()) {
214 tmpApplicationId = "SDNC";
216 this.applicationId = tmpApplicationId;
218 // connection timeout
219 int tmpConnectionTimeout = 30000;
220 int tmpReadTimeout = 30000;
223 String tmpValue = null;
224 tmpValue = props.getProperty(CONNECTION_TIMEOUT, "30000");
225 tmpConnectionTimeout = Integer.parseInt(tmpValue);
226 tmpValue = props.getProperty(READ_TIMEOUT, "30000");
227 tmpReadTimeout = Integer.parseInt(tmpValue);
228 } catch(Exception exc) {
229 LOG.error("Failed setting connection timeout", exc);
230 tmpConnectionTimeout = 30000;
231 tmpReadTimeout = 30000;
233 connectionTimeout = tmpConnectionTimeout;
234 readTimeout = tmpReadTimeout;
236 networkVserverPath =props.getProperty(NETWORK_VSERVER_PATH);
238 svcInstancePath = props.getProperty(SVC_INSTANCE_PATH);
239 svc_inst_qry_path = props.getProperty(SVC_INST_QRY_PATH);
240 param_service_type = props.getProperty(PARAM_SERVICE_TYPE, "service-type");
243 pInterfacePath = props.getProperty(P_INTERFACE_PATH);
245 vnf_image_query_path = props.getProperty(VNF_IMAGE_QUERY_PATH);
247 ubb_notify_path = props.getProperty(UBB_NOTIFY_PATH);
248 selflinkAvpn = props.getProperty(SELFLINK_AVPN);
249 selflinkFqdn = props.getProperty(SELFLINK_FQDN);
251 servicePath = props.getProperty(SERVICE_PATH);
253 sitePairSetPath = props.getProperty(SITE_PAIR_SET_PATH);
255 queryNodesPath = props.getProperty(QUERY_NODES_PATH);
257 String iche = props.getProperty(CERTIFICATE_HOST_ERROR);
258 boolean host_error = false;
259 if(iche != null && !iche.isEmpty()) {
260 host_error = Boolean.valueOf(iche);
263 ignoreCertificateHostError = host_error;
265 HttpsURLConnection.setDefaultHostnameVerifier( new HostnameVerifier(){
266 public boolean verify(String string,SSLSession ssls) {
267 return ignoreCertificateHostError;
271 if(truststorePath != null && truststorePassword != null && (new File(truststorePath)).exists()) {
272 System.setProperty("javax.net.ssl.trustStore", truststorePath);
273 System.setProperty("javax.net.ssl.trustStorePassword", truststorePassword);
276 if(keystorePath != null && keystorePassword != null && (new File(keystorePath)).exists()) {
277 DefaultClientConfig config = new DefaultClientConfig();
278 //both jersey and HttpURLConnection can use this
279 SSLContext ctx = null;
281 ctx = SSLContext.getInstance("TLS");
283 KeyManagerFactory kmf = null;
284 try (FileInputStream fin = new FileInputStream(keystorePath)){
285 String def = "SunX509";
286 String storeType = "PKCS12";
287 def = KeyStore.getDefaultType();
288 kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
290 String extension = keystorePath.substring(keystorePath.lastIndexOf(".") + 1);
291 if("JKS".equalsIgnoreCase(extension)) {
294 KeyStore ks = KeyStore.getInstance(storeType);
296 char[] pwd = keystorePassword.toCharArray();
299 } catch (Exception ex) {
300 LOG.error("AAIResource", ex);
303 ctx.init(kmf.getKeyManagers(), null, null);
304 config.getProperties().put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES, new HTTPSProperties( new HostnameVerifier() {
306 public boolean verify( String s, SSLSession sslSession ) {
307 return ignoreCertificateHostError;
312 LOG.debug("SSLContext created");
314 } catch (KeyManagementException | NoSuchAlgorithmException exc) {
315 LOG.error("AAIResource", exc);
319 LOG.info("AAIResource.ctor initialized.");
322 Field methodsField = HttpURLConnection.class.getDeclaredField("methods");
323 methodsField.setAccessible(true);
324 // get the methods field modifiers
325 Field modifiersField = Field.class.getDeclaredField("modifiers");
326 // bypass the "private" modifier
327 modifiersField.setAccessible(true);
329 // remove the "final" modifier
330 modifiersField.setInt(methodsField, methodsField.getModifiers() & ~Modifier.FINAL);
332 /* valid HTTP methods */
334 "GET", "POST", "HEAD", "OPTIONS", "PUT", "DELETE", "TRACE", "PATCH"
336 // set the new methods - including patch
337 methodsField.set(null, methods);
339 } catch (SecurityException | IllegalArgumentException | IllegalAccessException | NoSuchFieldException e) {
345 public void setExecutor(AAIExecutorInterface executor) {
346 this.executor = executor;
349 public void cleanUp() {
355 * @param http_req_url
360 protected HttpURLConnection getConfiguredConnection(URL http_req_url, String method) throws Exception {
361 HttpURLConnection con = (HttpURLConnection) http_req_url.openConnection();
363 // Set up the connection properties
364 con.setRequestProperty( "Connection", "close" );
365 con.setDoInput(true);
366 con.setDoOutput(true);
367 con.setUseCaches(false);
368 con.setConnectTimeout( connectionTimeout );
369 con.setReadTimeout( readTimeout );
370 con.setRequestMethod( method );
371 con.setRequestProperty( "Accept", "application/json" );
372 con.setRequestProperty( "Content-Type", "PATCH".equalsIgnoreCase(method) ? "application/merge-patch+json" : "application/json" );
373 con.setRequestProperty("X-FromAppId", applicationId);
374 con.setRequestProperty("X-TransactionId",TransactionIdTracker.getNextTransactionId());
375 String mlId = ml.getRequestID();
376 if(mlId != null && !mlId.isEmpty()) {
377 LOG.debug(String.format("MetricLogger requestId = %s", mlId));
378 con.setRequestProperty(MetricLogger.REQUEST_ID, mlId);
380 LOG.debug("MetricLogger requestId is null");
382 con.setRequestProperty("Transfer-Encoding","chunked");
384 if(userName != null && !userName.isEmpty() && userPassword != null && !userPassword.isEmpty()) {
385 String basicAuth = "Basic " + new String(Base64.encodeBase64((userName + ":" + userPassword).getBytes()));
386 con.setRequestProperty ("Authorization", basicAuth);
389 if(con instanceof HttpsURLConnection && CTX != null) {
390 SSLSocketFactory sockFact = CTX.getSocketFactory();
391 HttpsURLConnection.class.cast(con).setSSLSocketFactory( sockFact );
398 public GenericVnf requestGenericVnfData(String vnf_id) throws AAIServiceException {
399 GenericVnf response = null;
402 AAIRequest request = AAIRequest.getRequestFromResource("generic-vnf");
403 request.addRequestProperty("generic-vnf.vnf-id", vnf_id);
404 String rv = executor.get(request);
406 ObjectMapper mapper = getObjectMapper();
407 response = mapper.readValue(rv, GenericVnf.class);
409 } catch(AAIServiceException aaiexc) {
411 } catch (Exception exc) {
412 LOG.warn(Object.class.getClass().getEnclosingMethod().getName(), exc);
413 throw new AAIServiceException(exc);
421 public boolean postGenericVnfData(String vnf_id, GenericVnf data) throws AAIServiceException {
423 AAIRequest request = AAIRequest.getRequestFromResource("generic-vnf");
424 request.addRequestProperty("generic-vnf.vnf-id", vnf_id);
425 request.setRequestObject(data);
426 Object response = executor.post(request);
428 } catch(AAIServiceException aaiexc) {
430 } catch (Exception exc) {
431 LOG.warn("requestGenericVnfData", exc);
432 throw new AAIServiceException(exc);
437 public SearchResults requestServiceInstanceURL(String svc_instance_id) throws AAIServiceException {
438 SearchResults response = null;
439 InputStream inputStream = null;
442 String path = svc_inst_qry_path;
443 path = path.replace("{svc-instance-id}", encodeQuery(svc_instance_id));
445 String request_url = targetUri+path;
446 URL http_req_url = new URL(request_url);
448 HttpURLConnection con = getConfiguredConnection(http_req_url, HttpMethod.GET);
450 LOGwriteFirstTrace(HttpMethod.GET, http_req_url.toString());
451 LOGwriteDateTrace("svc_instance_id", svc_instance_id);
454 int responseCode = con.getResponseCode();
455 if (responseCode == HttpURLConnection.HTTP_OK) {
456 inputStream = con.getInputStream();
458 inputStream = con.getErrorStream();
461 // Process the response
462 LOG.debug("HttpURLConnection result:" + responseCode);
463 if(inputStream == null) inputStream = new ByteArrayInputStream("".getBytes(StandardCharsets.UTF_8));
464 BufferedReader reader = new BufferedReader( new InputStreamReader( inputStream ) );
466 ObjectMapper mapper = getObjectMapper();
468 if (responseCode == HttpURLConnection.HTTP_OK) {
469 response = mapper.readValue(reader, SearchResults.class);
470 LOGwriteEndingTrace(HttpURLConnection.HTTP_OK, "SUCCESS", mapper.writeValueAsString(response));
471 } else if(responseCode == HttpURLConnection.HTTP_NOT_FOUND ) {
472 LOGwriteEndingTrace(responseCode, "HTTP_NOT_FOUND", "Entry does not exist.");
475 ErrorResponse errorresponse = mapper.readValue(reader, ErrorResponse.class);
476 LOGwriteEndingTrace(responseCode, "FAILURE", mapper.writeValueAsString(errorresponse));
477 throw new AAIServiceException(responseCode, errorresponse);
480 } catch(AAIServiceException aaiexc) {
482 } catch (Exception exc) {
483 LOG.warn("requestServiceInstanceURL", exc);
484 throw new AAIServiceException(exc);
486 if(inputStream != null){
489 } catch(Exception exc) {
497 private static Properties initialize(URL url ) throws ConfigurationException {
500 throw new NullPointerException();
503 InputStream is = null;
504 Properties props = new Properties();
507 if(LOG.isDebugEnabled())
508 LOG.info("Property file is: " + url.toString());
510 is = url.openStream();
513 if(LOG.isDebugEnabled()) {
514 LOG.info("Properties loaded: " + props.size());
515 Enumeration<Object> en = props.keys();
517 while(en.hasMoreElements()) {
518 String key = (String)en.nextElement();
519 String property = props.getProperty(key);
520 LOG.debug(key + " : " + property);
523 } catch (Exception e) {
524 throw new ConfigurationException("Could not load properties file.", e);
529 static class TransactionIdTracker {
530 // protected static AtomicLong tracker = new AtomicLong();
532 public static String getNextTransactionId() {
533 // Check if RequestId exists as MDC. If not, create new.
534 String transactionId = MDC.get("RequestId");
535 if ("".equals(transactionId) || transactionId == null) {
536 transactionId = UUID.randomUUID().toString();
537 LOG.info("Missing requestID. Assigned " + transactionId);
538 MDC.put("RequestId", transactionId);
540 return transactionId;
545 protected void LOGwriteFirstTrace(String method, String url) {
546 String time = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'").format(System.currentTimeMillis());
547 LOG.info("A&AI transaction :");
548 LOG.info("Request Time : " + time + ", Method : " + method);
549 LOG.info("Request URL : "+ url);
552 protected void LOGwriteDateTrace(String name, String data) {
553 LOG.info("Input - " + name + " : " + data);
556 protected void LOGwriteEndingTrace(int response_code, String comment, String data) {
557 LOG.info("Response code : " + response_code +", " + comment);
558 LOG.info(String.format("Response data : %s", data));
561 protected String encodeQuery(String param) throws UnsupportedEncodingException {
562 return URLEncoder.encode(param, "UTF-8").replace("+", "%20");
565 private String encodeCustomerURL(final String selection)
567 String encrypted_url = selection;
569 "/aai/v11/business/customers/customer/(.+)/service-subscriptions/service-subscription/(.+)/service-instances/service-instance/(.+)/";
570 Pattern pattern = Pattern.compile(apnpattern);
573 URL url = new URL(selection);
574 String path = url.getPath();
576 LOG.info("Trying to match apn to <" + path + ">");
578 Matcher matcher = pattern.matcher(path);
580 while(matcher.find()) {
581 String customer = matcher.group(1);
582 String subscription = matcher.group(2);
583 String service = matcher.group(3);
585 encrypted_url = selection.replace(customer, encodeQuery(customer));
586 encrypted_url = encrypted_url.replace(subscription, encodeQuery(subscription));
587 encrypted_url = encrypted_url.replace(service, encodeQuery(service));
589 } catch (Exception e) {
593 return encrypted_url;
600 * @see org.openecomp.sdnct.sli.aai.AAIClient#requestVServersData(java.lang.String, java.lang.String)
603 public Vserver requestVServerData(String tenantId, String vserverId, String cloudOwner, String cloudRegionId) throws AAIServiceException {
604 Vserver response = null;
607 AAIRequest request = AAIRequest.getRequestFromResource("vserver");
608 request.addRequestProperty("cloud-region.cloud-owner", cloudOwner);
609 request.addRequestProperty("cloud-region.cloud-region-id", cloudRegionId);
610 request.addRequestProperty("tenant.tenant-id", tenantId);
611 request.addRequestProperty("vserver.vserver-id", vserverId);
613 String rv = executor.get(request);
615 ObjectMapper mapper = getObjectMapper();
616 response = mapper.readValue(rv, Vserver.class);
618 } catch(AAIServiceException aaiexc) {
620 } catch (Exception exc) {
621 LOG.warn(Object.class.getClass().getEnclosingMethod().getName(), exc);
622 throw new AAIServiceException(exc);
628 //================== End of DvsSwitch =================
629 //==================== PhysicalLink ======================
631 public PhysicalLink requestPhysicalLinkData(String linkName) throws AAIServiceException {
632 PhysicalLink response = null;
635 AAIRequest request = AAIRequest.getRequestFromResource("physical-link");
636 request.addRequestProperty("physical-link.link-name", linkName);
638 String rv = executor.get(request);
640 ObjectMapper mapper = getObjectMapper();
641 response = mapper.readValue(rv, PhysicalLink.class);
643 } catch(AAIServiceException aaiexc) {
645 } catch (Exception exc) {
646 LOG.warn("requestPhysicalLinkData", exc);
647 throw new AAIServiceException(exc);
653 public boolean postPhysicalLinkData(String linkName, PhysicalLink data) throws AAIServiceException {
655 AAIRequest request = AAIRequest.getRequestFromResource("physical-link");
656 request.addRequestProperty("physical-link.link-name", linkName);
657 request.setRequestObject(data);
658 Object response = executor.post(request);
660 } catch(AAIServiceException aaiexc) {
662 } catch (Exception exc) {
663 LOG.warn(Object.class.getClass().getEnclosingMethod().getName(), exc);
664 throw new AAIServiceException(exc);
669 public boolean deletePhysicalLinkData(String linkName, String resourceVersion) throws AAIServiceException {
670 boolean response = false;
673 AAIRequest request = AAIRequest.getRequestFromResource("physical-link");
674 request.addRequestProperty("physical-link.link-name", linkName);
675 response = executor.delete(request, resourceVersion);
676 } catch(AAIServiceException aaiexc) {
678 } catch (Exception exc) {
679 LOG.warn("deletePhysicalLinkData", exc);
680 throw new AAIServiceException(exc);
685 public boolean deleteAAIEntity(URL url, String caller) throws AAIServiceException {
688 throw new NullPointerException();
691 boolean response = false;
692 InputStream inputStream = null;
695 URL http_req_url = url;
697 HttpURLConnection con = getConfiguredConnection(http_req_url, HttpMethod.DELETE);
699 LOGwriteFirstTrace("DELETE", http_req_url.toString());
703 int responseCode = con.getResponseCode();
704 if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_NO_CONTENT) {
705 inputStream = con.getInputStream();
707 inputStream = con.getErrorStream();
710 // Process the response
711 LOG.debug("HttpURLConnection result:" + responseCode);
712 if(inputStream == null) inputStream = new ByteArrayInputStream("".getBytes(StandardCharsets.UTF_8));
713 BufferedReader reader = new BufferedReader( new InputStreamReader( inputStream ) );
716 ObjectMapper mapper = getObjectMapper();
718 if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_NO_CONTENT) {
719 StringBuilder stringBuilder = new StringBuilder();
721 while( ( line = reader.readLine() ) != null ) {
722 stringBuilder.append( line );
724 LOGwriteEndingTrace(responseCode, "SUCCESS", stringBuilder.toString());
726 } else if(responseCode == HttpURLConnection.HTTP_NOT_FOUND ) {
727 LOGwriteEndingTrace(responseCode, "HTTP_NOT_FOUND", "Entry does not exist.");
730 ErrorResponse errorresponse = mapper.readValue(reader, ErrorResponse.class);
731 LOGwriteEndingTrace(responseCode, "FAILURE", mapper.writeValueAsString(errorresponse));
732 throw new AAIServiceException(responseCode, errorresponse);
735 } catch(AAIServiceException aaiexc) {
737 } catch (Exception exc) {
738 LOG.warn(caller, exc);
739 throw new AAIServiceException(exc);
741 if(inputStream != null){
744 } catch(Exception exc) {
753 * Generic method to GET json data from an A&AI callback URL.
754 * Then convert that json to an Object.
755 * If successful the Object is attempted to be cast to the type parameter.
758 * callback url for A&AI
760 * the class of object that A&AI will return
761 * @return the object created from json or null if the response code is not 200
763 * @throws AAIServiceException
764 * if empty or null key and or type or there's an error with processing
766 public <T> T dataChangeRequestAaiData(String key, Class<T> type) throws AAIServiceException {
767 if (StringUtils.isEmpty(key) || type == null) {
768 throw new AAIServiceException("Key is empty or null and or type is null");
773 SvcLogicContext ctx = new SvcLogicContext();
774 if(!key.contains(" = ") && isValidURL(key)) {
775 key = String.format("selflink = '%s'", key);
777 if(!key.contains(" = ") && isValidURI(key)) {
778 key = String.format("resource-path = '%s'", key);
781 HashMap<String, String> nameValues = AAIServiceUtils.keyToHashMap(key, ctx);
783 SelfLinkRequest request = new SelfLinkRequest(type);
784 request.processRequestPathValues(nameValues);
785 Object obj = this.getExecutor().query(request, type);
786 response = type.cast(obj);
788 return response != null ? type.cast(response) : response;
792 public boolean sendNotify(NotifyEvent event, String serviceInstanceId, String pathCode) throws AAIServiceException {
793 InputStream inputStream = null;
797 String selfLink = selflinkFqdn;
798 if(SELFLINK_AVPN != null && SELFLINK_AVPN.equals(pathCode)) {
799 selfLink = selflinkAvpn;
801 selfLink = selfLink.replace("{service-instance-id}", encodeQuery(serviceInstanceId));
802 event.setSelflink(selfLink);
804 ObjectMapper mapper = getObjectMapper();
805 String json_text = mapper.writeValueAsString(event);
807 SSLSocketFactory sockFact = CTX.getSocketFactory();
809 String request_url = targetUri+ubb_notify_path;
810 URL http_req_url = new URL(request_url);
812 HttpURLConnection con = getConfiguredConnection(http_req_url, HttpMethod.PUT);
814 if (json_text != null) {
815 OutputStreamWriter osw = new OutputStreamWriter(con.getOutputStream());
816 osw.write(json_text);
821 LOGwriteFirstTrace("PUT", request_url);
822 LOGwriteDateTrace("NotifyEvent", json_text);
825 int responseCode = con.getResponseCode();
826 if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_CREATED || responseCode == HttpURLConnection.HTTP_ACCEPTED || responseCode == HttpURLConnection.HTTP_NO_CONTENT) {
827 inputStream = con.getInputStream();
829 inputStream = con.getErrorStream();
832 // Process the response
833 BufferedReader reader;
835 reader = new BufferedReader( new InputStreamReader( inputStream ) );
837 if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_CREATED || responseCode == HttpURLConnection.HTTP_ACCEPTED || responseCode == HttpURLConnection.HTTP_NO_CONTENT) {
838 StringBuilder stringBuilder = new StringBuilder();
840 while( ( line = reader.readLine() ) != null ) {
841 stringBuilder.append( line );
843 LOGwriteEndingTrace(responseCode, "SUCCESS", (stringBuilder.length() > 0) ? stringBuilder.toString() :
847 ErrorResponse errorresponse = mapper.readValue(reader, ErrorResponse.class);
848 LOGwriteEndingTrace(responseCode, "FAILURE", mapper.writeValueAsString(errorresponse));
850 throw new AAIServiceException(responseCode, errorresponse);
852 } catch(AAIServiceException aaiexc) {
854 } catch (Exception exc) {
855 LOG.warn("sendNotify", exc);
856 throw new AAIServiceException(exc);
859 if(inputStream != null)
861 } catch (Exception exc) {
868 public SearchResults requestNodeQuery(String node_type, String entityIdentifier, String entityName) throws AAIServiceException {
869 SearchResults response = null;
870 InputStream inputStream = null;
873 String request_url = targetUri+queryNodesPath;
874 request_url = request_url.replace("{node-type}", encodeQuery(node_type)) ;
875 request_url = request_url.replace("{entity-identifier}", entityIdentifier) ;
876 request_url = request_url.replace("{entity-name}", encodeQuery(entityName)) ;
877 URL http_req_url = new URL(request_url);
879 HttpURLConnection con = getConfiguredConnection(http_req_url, HttpMethod.GET);
881 LOGwriteFirstTrace(HttpMethod.GET, http_req_url.toString());
882 LOGwriteDateTrace("node_type", node_type);
883 LOGwriteDateTrace("vnf_name", entityName);
886 int responseCode = con.getResponseCode();
887 if (responseCode == HttpURLConnection.HTTP_OK) {
888 inputStream = con.getInputStream();
890 inputStream = con.getErrorStream();
893 // Process the response
894 LOG.debug("HttpURLConnection result:" + responseCode);
895 if(inputStream == null) inputStream = new ByteArrayInputStream("".getBytes(StandardCharsets.UTF_8));
896 BufferedReader reader = new BufferedReader( new InputStreamReader( inputStream ) );
898 ObjectMapper mapper = getObjectMapper();
900 if (responseCode == HttpURLConnection.HTTP_OK) {
901 response = mapper.readValue(reader, SearchResults.class);
902 LOGwriteEndingTrace(HttpURLConnection.HTTP_OK, "SUCCESS", mapper.writeValueAsString(response));
903 } else if (responseCode == HttpURLConnection.HTTP_NOT_FOUND) {
904 LOGwriteEndingTrace(responseCode, "HTTP_NOT_FOUND", "Entry does not exist.");
907 ErrorResponse errorresponse = mapper.readValue(reader, ErrorResponse.class);
908 LOGwriteEndingTrace(responseCode, "FAILURE", mapper.writeValueAsString(errorresponse));
909 throw new AAIServiceException(responseCode, errorresponse);
912 } catch(AAIServiceException aaiexc) {
914 } catch (Exception exc) {
915 LOG.warn("requestNodeQuery", exc);
916 throw new AAIServiceException(exc);
918 if(inputStream != null){
921 } catch(Exception exc) {
932 public String requestDataByURL(URL url) throws AAIServiceException {
935 throw new NullPointerException();
938 String response = null;
939 InputStream inputStream = null;
942 URL http_req_url = url;
944 HttpURLConnection con = getConfiguredConnection(http_req_url, HttpMethod.GET);
946 LOGwriteFirstTrace(HttpMethod.GET, http_req_url.toString());
949 int responseCode = con.getResponseCode();
950 if (responseCode == HttpURLConnection.HTTP_OK) {
951 inputStream = con.getInputStream();
953 inputStream = con.getErrorStream();
956 // Process the response
957 LOG.debug("HttpURLConnection result:" + responseCode);
958 if(inputStream == null) inputStream = new ByteArrayInputStream("".getBytes(StandardCharsets.UTF_8));
959 BufferedReader reader = new BufferedReader( new InputStreamReader( inputStream ) );
961 ObjectMapper mapper = getObjectMapper();
963 if (responseCode == HttpURLConnection.HTTP_OK) {
964 StringBuilder stringBuilder = new StringBuilder("\n");
966 while( ( line = reader.readLine() ) != null ) {
967 stringBuilder.append( line );
969 LOG.info(stringBuilder.toString());
970 // response = mapper.readValue(reader, String.class);
971 response = stringBuilder.toString();
972 LOGwriteEndingTrace(HttpURLConnection.HTTP_OK, "SUCCESS", mapper.writeValueAsString(response));
973 } else if(responseCode == HttpURLConnection.HTTP_NOT_FOUND ) {
974 LOGwriteEndingTrace(responseCode, "HTTP_NOT_FOUND", "Entry does not exist.");
977 ErrorResponse errorresponse = mapper.readValue(reader, ErrorResponse.class);
978 LOGwriteEndingTrace(responseCode, "FAILURE", mapper.writeValueAsString(errorresponse));
979 throw new AAIServiceException(responseCode, errorresponse);
982 } catch(AAIServiceException aaiexc) {
984 } catch (Exception exc) {
985 LOG.warn("requestNetworkVceData", exc);
986 throw new AAIServiceException(exc);
988 if(inputStream != null){
991 } catch(Exception exc) {
1001 public GenericVnf requestGenericVnfeNodeQuery(String vnf_name) throws AAIServiceException {
1003 if(vnf_name == null) {
1004 throw new NullPointerException();
1007 GenericVnf entity = null;
1008 SearchResults resp = this.requestNodeQuery("generic-vnf", "vnf-name", vnf_name);
1010 List<ResultData> resultDataList = resp.getResultData();
1013 for (ResultData datum : resultDataList) {
1014 String data_type = datum.getResourceType();
1015 URL url = new URL(datum.getResourceLink());
1016 entity = this.getResource(url.toString(), GenericVnf.class);
1021 LOG.error("Caught exception", e);
1027 public Vserver requestVServerDataByURL(URL url) throws AAIServiceException {
1030 throw new NullPointerException();
1033 Vserver entity = null;
1036 entity = this.getResource(url.toString(), Vserver.class);
1037 } catch (AAIServiceException exc) {
1039 } catch (Exception e) {
1040 throw new AAIServiceException(e);
1046 public URL requestVserverURLNodeQuery(String vserver_name) throws AAIServiceException {
1048 if(vserver_name == null) {
1049 throw new NullPointerException();
1053 SearchResults resp = this.requestNodeQuery("vserver", "vserver-name", vserver_name);
1055 List<ResultData> resultDataList = resp.getResultData();
1058 for (ResultData datum : resultDataList) {
1059 String data_type = datum.getResourceType();
1060 String resourceLink = datum.getResourceLink();
1061 if(!resourceLink.isEmpty() && !resourceLink.toLowerCase().startsWith("http")) {
1062 resourceLink = (new EchoRequest()).targetUri + resourceLink;
1064 entity = new URL(resourceLink);
1066 } catch (Exception e) {
1067 throw new AAIServiceException(e);
1073 public String getTenantIdFromVserverUrl(URL url) {
1075 String path = url.getPath();
1077 String[] split = path.split("/tenants/tenant/");
1078 if(split.length > 1) {
1079 split = split[1].split("/");
1087 public String getCloudOwnerFromVserverUrl(URL url) {
1089 String path = url.getPath();
1091 String[] split = path.split("/cloud-regions/cloud-region/");
1092 if(split.length > 1) {
1093 split = split[1].split("/");
1101 public String getCloudRegionFromVserverUrl(URL url) {
1103 String path = url.getPath();
1105 String[] split = path.split("/cloud-regions/cloud-region/");
1106 if(split.length > 1) {
1107 split = split[1].split("/");
1115 public String getVServerIdFromVserverUrl(URL url, String tenantId) {
1116 String pattern = networkVserverPath;
1117 pattern = pattern.replace("{tenant-id}", tenantId);
1119 int end = pattern.indexOf("{vserver-id}");
1120 String prefix = pattern.substring(0, end);
1122 String path = url.getPath();
1124 if(path.startsWith(prefix)) {
1125 path = path.substring(prefix.length());
1131 protected Logger getLogger(){
1137 public AAIExecutorInterface getExecutor() {
1142 * Creates a current time stamp in UTC i.e. 2016-03-08T22:15:13.343Z.
1143 * If there are any parameters the values are appended to the time stamp.
1146 * values to be appended to current time stamp
1148 * used to set an attribute for a DG
1149 * @throws SvcLogicException
1151 public void setStatusMethod(Map<String, String> parameters, SvcLogicContext ctx) throws SvcLogicException {
1153 throw new SvcLogicException("SvcLogicContext is null.");
1156 StringBuilder sb = new StringBuilder();
1157 sb.append(String.format("%tFT%<tTZ", Calendar.getInstance(TimeZone.getTimeZone("Z")))).append(" - ");
1159 for (Entry<String, String> entry : parameters.entrySet()) {
1160 sb.append(entry.getValue()).append(" ");
1163 if (sb.length() > 0) {
1164 sb.setLength(sb.length() - 2);
1167 ctx.setAttribute("aai-summary-status-message", sb.toString());
1168 LOG.info("aai-summary-status-message: " + sb.toString());
1172 * Generic method to GET json data from an A&AI using key structure.
1173 * Then convert that json to an Object.
1174 * If successful the Object is attempted to be cast to the type parameter.
1177 * key identifying the resource to be retrieved from AAI
1179 * the class of object that A&AI will return
1180 * @return the object created from json or null if the response code is not 200
1182 * @throws AAIServiceException
1183 * if empty or null key and or type or there's an error with processing
1186 public <T> T getResource(String key, Class<T> type) throws AAIServiceException {
1187 if (StringUtils.isEmpty(key) || type == null) {
1188 throw new AAIServiceException("Key is empty or null and or type is null");
1193 SvcLogicContext ctx = new SvcLogicContext();
1194 if(!key.contains(" = ")) {
1195 if(isValidURL(key)) {
1196 key = String.format("selflink = '%s'", key);
1197 } else if(isValidURI(key)) {
1198 key = String.format("resource-path = '%s'", key);
1204 HashMap<String, String> nameValues = AAIServiceUtils.keyToHashMap(key, ctx);
1206 AAIRequest request = new SelfLinkRequest(type);
1207 if(nameValues.containsKey(PathRequest.RESOURCE_PATH.replaceAll("-", "_"))) {
1208 request = new PathRequest(type);
1211 request.processRequestPathValues(nameValues);
1212 Object obj = this.getExecutor().query(request, type);
1213 response = type.cast(obj);
1215 return response != null ? type.cast(response) : response;
1218 public boolean isValidURL(String url) {
1224 } catch (MalformedURLException e) {
1230 } catch (URISyntaxException e) {
1238 public boolean isValidURI(String url) {
1244 } catch (URISyntaxException e) {
1252 protected boolean deleteList(URL httpReqUrl, String json_text) throws AAIServiceException {
1253 if(httpReqUrl == null) {
1254 throw new NullPointerException();
1257 boolean response = false;
1258 InputStream inputStream = null;
1261 HttpURLConnection con = getConfiguredConnection(httpReqUrl, HttpMethod.DELETE);
1263 // SSLSocketFactory sockFact = CTX.getSocketFactory();
1264 // con.setSSLSocketFactory( sockFact );
1265 if (json_text != null) {
1266 OutputStreamWriter osw = new OutputStreamWriter(con.getOutputStream());
1267 osw.write(json_text);
1272 LOGwriteFirstTrace("DELETE", httpReqUrl.toString());
1273 LOGwriteDateTrace("data", json_text);
1276 int responseCode = con.getResponseCode();
1277 if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_NO_CONTENT) {
1278 inputStream = con.getInputStream();
1280 inputStream = con.getErrorStream();
1283 // Process the response
1284 LOG.debug("HttpURLConnection result:" + responseCode);
1285 if(inputStream == null) inputStream = new ByteArrayInputStream("".getBytes(StandardCharsets.UTF_8));
1286 BufferedReader reader = new BufferedReader( new InputStreamReader( inputStream ) );
1289 ObjectMapper mapper = getObjectMapper();
1291 if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_NO_CONTENT) {
1292 StringBuilder stringBuilder = new StringBuilder();
1294 while( ( line = reader.readLine() ) != null ) {
1295 stringBuilder.append( line );
1297 LOGwriteEndingTrace(responseCode, "SUCCESS", stringBuilder.toString());
1299 } else if(responseCode == HttpURLConnection.HTTP_NOT_FOUND ) {
1300 LOGwriteEndingTrace(responseCode, "HTTP_NOT_FOUND", "Entry does not exist.");
1303 ErrorResponse errorresponse = mapper.readValue(reader, ErrorResponse.class);
1304 LOGwriteEndingTrace(responseCode, "FAILURE", mapper.writeValueAsString(errorresponse));
1305 throw new AAIServiceException(responseCode, errorresponse);
1308 } catch(AAIServiceException aaiexc) {
1310 } catch (Exception exc) {
1311 LOG.warn("deleteList", exc);
1312 throw new AAIServiceException(exc);
1314 if(inputStream != null){
1316 inputStream.close();
1317 } catch(Exception exc) {
1325 public static ObjectMapper getObjectMapper() {
1326 ObjectMapper mapper = new ObjectMapper();
1327 AnnotationIntrospector introspector = new JaxbAnnotationIntrospector(TypeFactory.defaultInstance());
1328 AnnotationIntrospector secondary = new JacksonAnnotationIntrospector();
1329 mapper.setAnnotationIntrospector(AnnotationIntrospector.pair(introspector, secondary));
1330 mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
1331 mapper.setSerializationInclusion(Include.NON_NULL);
1332 mapper.setSerializationInclusion(Include.NON_EMPTY);
1336 public void logMetricRequest(String requestId, String targetServiceName, String msg, String path){
1337 String svcInstanceId = "";
1338 String svcName = null;
1339 String partnerName = null;
1340 String targetEntity = "A&AI";
1341 String targetVirtualEntity = null;
1343 ml.logRequest(svcInstanceId, svcName, partnerName, targetEntity, targetServiceName, targetVirtualEntity, msg);
1346 public void logMetricResponse(String requestId, int responseCode, String responseDescription){
1347 ml.logResponse(responseCode < 400 ? "SUCCESS" : "FAILURE", Integer.toString(responseCode), responseDescription);
1350 public void logKeyError(String keys){
1351 LOG.error("Atleast one of the keys [" + keys + "] should have been populated. This will cause a NPE.");
1359 public QueryStatus save(String resource, boolean force, boolean localOnly, String key, Map<String, String> params, String prefix, SvcLogicContext ctx)
1360 throws SvcLogicException {
1361 String normResource = resource.split(":")[0];
1363 switch(normResource){
1364 case "custom-query":
1365 case "formatted-query":
1366 case "generic-query":
1370 case "l2-bridge-sbg":
1371 case "l2-bridge-bgf":
1377 if(key.contains("selflink =")) {
1380 if(!key.contains(String.format("%s.", normResource))) {
1381 key = rewriteKey(resource, key, ctx);
1384 return super.save(resource, force, localOnly, key, params, prefix, ctx);
1388 public QueryStatus query(String resource, boolean localOnly, String select, String key, String prefix, String orderBy, SvcLogicContext ctx)
1389 throws SvcLogicException {
1390 String normResource = resource.split(":")[0];
1392 switch(normResource){
1393 case "custom-query":
1394 case "formatted-query":
1395 case "generic-query":
1399 case "l2-bridge-sbg":
1400 case "l2-bridge-bgf":
1406 if(key.contains("selflink =")) {
1409 if(!key.contains(String.format("%s.", normResource))) {
1410 key = rewriteKey(resource, key, ctx);
1414 return super.query(resource, localOnly, select, key, prefix, orderBy, ctx);
1418 public QueryStatus delete(String resource, String key, SvcLogicContext ctx) throws SvcLogicException {
1419 String normResource = resource.split(":")[0];
1421 switch(normResource){
1422 case "custom-query":
1423 case "formatted-query":
1424 case "generic-query":
1428 case "l2-bridge-sbg":
1429 case "l2-bridge-bgf":
1435 if(key.contains("selflink =")) {
1438 if(!key.contains(String.format("%s.", normResource))) {
1439 key = rewriteKey(resource, key, ctx);
1443 return super.delete(resource, key, ctx);
1447 public QueryStatus update(String resource, String key, Map<String, String> params, String prefix, SvcLogicContext ctx) throws SvcLogicException {
1448 String normResource = resource.split(":")[0];
1450 switch(normResource){
1451 case "custom-query":
1452 case "formatted-query":
1453 case "generic-query":
1457 case "l2-bridge-sbg":
1458 case "l2-bridge-bgf":
1464 if(key.contains("selflink =")) {
1467 if(!key.contains(String.format("%s.", normResource))) {
1468 key = rewriteKey(resource, key, ctx);
1472 return super.update(resource, key, params, prefix, ctx);
1475 private String rewriteKey(String resource, String key, SvcLogicContext ctx) {
1476 LOG.info("AAI Deprecation - the format of request key is no longer supported. Please rewrite this key : " + key);
1478 String normResource = resource.split(":")[0];
1479 Class<? extends AAIDatum> clazz = null;
1481 clazz = AAIRequest.getClassFromResource(normResource) ;
1482 } catch (ClassNotFoundException e) {
1483 LOG.warn("AAIRequest does not support class: " + e.getMessage());
1489 List<String> fieldAnnotatedNames = new LinkedList<>();
1491 Field[] fields = clazz.getDeclaredFields();
1492 for(Field field : fields) {
1493 String fieldName = field.getName();
1494 XmlElement annotation = field.getAnnotation(XmlElement.class);
1495 if(annotation == null)
1497 String primaryId = annotation.name();
1498 if("##default".equals(primaryId)) {
1499 primaryId = fieldName;
1501 fieldAnnotatedNames.add(primaryId);
1504 HashMap<String, String> nameValues = AAIServiceUtils.keyToHashMap(key, ctx);
1505 Set<String> keyset = nameValues.keySet();
1506 for(String keyName : keyset) {
1507 if(keyName.contains("."))
1510 String tmpKeyName = keyName.replaceAll("_", "-");
1511 String valueToSubstitute = String.format("%s =", tmpKeyName);
1512 if(fieldAnnotatedNames.contains(tmpKeyName) && key.contains(valueToSubstitute)) {
1513 key = key.replace(valueToSubstitute, String.format("%s.%s =", normResource, tmpKeyName));
1523 public String getPathTemplateForResource(String resoourceName, String keys, SvcLogicContext ctx) throws MalformedURLException {
1524 return AAIServiceUtils.getPathForResource(resoourceName, StringUtils.join(keys, " AND "), ctx);
1528 public boolean isDeprecatedFormat(String resource, HashMap<String, String> nameValues) {
1529 return !AAIServiceUtils.isValidFormat(resource, nameValues);
1532 public AAIRequest getRequestFromResource(String resoourceName) {
1533 return AAIRequest.getRequestFromResource(resoourceName);
1537 * @see org.onap.ccsdk.sli.core.sli.aai.haha#query(org.onap.ccsdk.sli.core.sli.aai.AAIRequest)
1540 public String query(AAIRequest request) throws AAIServiceException {
1541 return executor.get(request);
1545 * @see org.onap.ccsdk.sli.core.sli.aai.haha#save(org.onap.ccsdk.sli.core.sli.aai.AAIRequest)
1548 public String save(AAIRequest request) throws AAIServiceException {
1549 return executor.post(request);
1552 public boolean update(AAIRequest request, String resourceVersion) throws AAIServiceException {
1553 return executor.patch(request, resourceVersion);
1557 * @see org.onap.ccsdk.sli.core.sli.aai.haha#delete(org.onap.ccsdk.sli.core.sli.aai.AAIRequest, java.lang.String)
1560 public boolean delete(AAIRequest request, String resourceVersion) throws AAIServiceException {
1561 return executor.delete(request, resourceVersion);