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.InputStream;
30 import java.io.InputStreamReader;
31 import java.io.OutputStreamWriter;
32 import java.io.UnsupportedEncodingException;
33 import java.lang.reflect.Field;
34 import java.lang.reflect.Modifier;
35 import java.net.HttpURLConnection;
36 import java.net.MalformedURLException;
38 import java.net.URISyntaxException;
40 import java.net.URLEncoder;
41 import java.nio.charset.StandardCharsets;
42 import java.security.KeyManagementException;
43 import java.security.KeyStore;
44 import java.security.NoSuchAlgorithmException;
45 import java.text.SimpleDateFormat;
46 import java.util.Calendar;
47 import java.util.Enumeration;
48 import java.util.HashMap;
49 import java.util.LinkedList;
50 import java.util.List;
52 import java.util.Map.Entry;
53 import java.util.Properties;
55 import java.util.TimeZone;
56 import java.util.UUID;
57 import java.util.regex.Matcher;
58 import java.util.regex.Pattern;
60 import javax.net.ssl.HostnameVerifier;
61 import javax.net.ssl.HttpsURLConnection;
62 import javax.net.ssl.KeyManagerFactory;
63 import javax.net.ssl.SSLContext;
64 import javax.net.ssl.SSLSession;
65 import javax.net.ssl.SSLSocketFactory;
66 import javax.ws.rs.HttpMethod;
67 import javax.xml.bind.annotation.XmlElement;
69 import org.apache.commons.codec.binary.Base64;
70 import org.apache.commons.lang3.StringUtils;
71 import org.onap.ccsdk.sli.adaptors.aai.data.AAIDatum;
72 import org.onap.ccsdk.sli.adaptors.aai.data.ErrorResponse;
73 import org.onap.ccsdk.sli.adaptors.aai.data.notify.NotifyEvent;
74 import org.onap.ccsdk.sli.core.sli.ConfigurationException;
75 import org.onap.ccsdk.sli.core.sli.MetricLogger;
76 import org.onap.ccsdk.sli.core.sli.SvcLogicContext;
77 import org.onap.ccsdk.sli.core.sli.SvcLogicException;
78 import org.onap.ccsdk.sli.core.sli.SvcLogicResource;
79 import org.openecomp.aai.inventory.v11.GenericVnf;
80 import org.openecomp.aai.inventory.v11.PhysicalLink;
81 import org.openecomp.aai.inventory.v11.ResultData;
82 import org.openecomp.aai.inventory.v11.SearchResults;
83 import org.openecomp.aai.inventory.v11.Vserver;
84 import org.slf4j.Logger;
85 import org.slf4j.LoggerFactory;
88 import com.fasterxml.jackson.annotation.JsonInclude.Include;
89 import com.fasterxml.jackson.databind.AnnotationIntrospector;
90 import com.fasterxml.jackson.databind.DeserializationFeature;
91 import com.fasterxml.jackson.databind.ObjectMapper;
92 import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector;
93 import com.fasterxml.jackson.databind.type.TypeFactory;
94 import com.fasterxml.jackson.module.jaxb.JaxbAnnotationIntrospector;
95 import com.sun.jersey.api.client.config.DefaultClientConfig;
96 import com.sun.jersey.client.urlconnection.HTTPSProperties;
99 public class AAIService extends AAIDeclarations implements AAIClient, SvcLogicResource {
101 public static final String AAICLIENT_PROPERTIES = "/aaiclient.properties";
102 public static final String PATH_PROPERTIES = "/aai-path.properties";
104 private static final Logger LOG = LoggerFactory.getLogger(AAIService.class);
106 private final String truststorePath;
107 private final String truststorePassword;
108 private final String keystorePath;
109 private final String keystorePassword;
110 private final Boolean ignoreCertificateHostError;
112 private final String targetUri;
113 private final String queryPath;
115 private final String networkVserverPath;
117 private final String svcInstancePath;
118 private final String svc_inst_qry_path;
120 private final String vnf_image_query_path;
122 private final String param_service_type; //= "service-type";
124 private final String ubb_notify_path;
125 private final String selflinkAvpn;
126 private final String selflinkFqdn;
128 private final String pInterfacePath;
130 private final String servicePath;
131 private final String sitePairSetPath;
133 private final int connectionTimeout;
134 private final int readTimeout;
137 private final String queryNodesPath;
138 private final String updatePath;
140 private final String applicationId;
142 // authentication credentials
143 private String userName;
144 private String userPassword;
147 private final boolean runtimeOSGI;
149 private SSLContext CTX;
151 private final MetricLogger ml = new MetricLogger();
153 private AAIExecutorInterface executor;
155 public void setExecutor(AAIExecutorInterface executor) {
156 this.executor = executor;
159 public AAIService(URL propURL) {
160 LOG.info("Entered AAIService.ctor");
162 String runtime = System.getProperty("aaiclient.runtime");
163 if("OSGI".equals(runtime)) {
169 Properties props = null;
171 props = initialize(propURL);
172 AAIRequest.setProperties(props, this);
174 } catch(Exception exc){
175 LOG.error("AicAAIResource.static", exc);
178 executor = new AAIClientRESTExecutor(props);
180 userName = props.getProperty(CLIENT_NAME);
181 userPassword = props.getProperty(CLIENT_PWWD);
183 if(userName == null || userName.isEmpty()){
184 LOG.debug("Basic user name is not set");
186 if(userPassword == null || userPassword.isEmpty()) {
187 LOG.debug("Basic password is not set");
190 truststorePath = props.getProperty(TRUSTSTORE_PATH);
191 truststorePassword = props.getProperty(TRUSTSTORE_PSSWD);
192 keystorePath = props.getProperty(KEYSTORE_PATH);
193 keystorePassword = props.getProperty(KEYSTORE_PSSWD);
195 targetUri = props.getProperty(TARGET_URI);
196 queryPath = props.getProperty(QUERY_PATH);
197 updatePath = props.getProperty(UPDATE_PATH);
199 String tmpApplicationId = props.getProperty(APPLICATION_ID);
200 if(tmpApplicationId == null || tmpApplicationId.isEmpty()) {
201 tmpApplicationId = "SDNC";
203 this.applicationId = tmpApplicationId;
205 // connection timeout
206 int tmpConnectionTimeout = 30000;
207 int tmpReadTimeout = 30000;
210 String tmpValue = null;
211 tmpValue = props.getProperty(CONNECTION_TIMEOUT, "30000");
212 tmpConnectionTimeout = Integer.parseInt(tmpValue);
213 tmpValue = props.getProperty(READ_TIMEOUT, "30000");
214 tmpReadTimeout = Integer.parseInt(tmpValue);
215 } catch(Exception exc) {
216 LOG.error("Failed setting connection timeout", exc);
217 tmpConnectionTimeout = 30000;
218 tmpReadTimeout = 30000;
220 connectionTimeout = tmpConnectionTimeout;
221 readTimeout = tmpReadTimeout;
223 networkVserverPath =props.getProperty(NETWORK_VSERVER_PATH);
225 svcInstancePath = props.getProperty(SVC_INSTANCE_PATH);
226 svc_inst_qry_path = props.getProperty(SVC_INST_QRY_PATH);
227 param_service_type = props.getProperty(PARAM_SERVICE_TYPE, "service-type");
230 pInterfacePath = props.getProperty(P_INTERFACE_PATH);
232 vnf_image_query_path = props.getProperty(VNF_IMAGE_QUERY_PATH);
234 ubb_notify_path = props.getProperty(UBB_NOTIFY_PATH);
235 selflinkAvpn = props.getProperty(SELFLINK_AVPN);
236 selflinkFqdn = props.getProperty(SELFLINK_FQDN);
238 servicePath = props.getProperty(SERVICE_PATH);
240 sitePairSetPath = props.getProperty(SITE_PAIR_SET_PATH);
242 queryNodesPath = props.getProperty(QUERY_NODES_PATH);
244 String iche = props.getProperty(CERTIFICATE_HOST_ERROR);
245 boolean host_error = false;
246 if(iche != null && !iche.isEmpty()) {
247 host_error = Boolean.valueOf(iche);
250 ignoreCertificateHostError = host_error;
252 HttpsURLConnection.setDefaultHostnameVerifier( new HostnameVerifier(){
253 public boolean verify(String string,SSLSession ssls) {
254 return ignoreCertificateHostError;
258 if(truststorePath != null && truststorePassword != null && (new File(truststorePath)).exists()) {
259 System.setProperty("javax.net.ssl.trustStore", truststorePath);
260 System.setProperty("javax.net.ssl.trustStorePassword", truststorePassword);
263 if(keystorePath != null && keystorePassword != null && (new File(keystorePath)).exists()) {
264 DefaultClientConfig config = new DefaultClientConfig();
265 //both jersey and HttpURLConnection can use this
266 SSLContext ctx = null;
268 ctx = SSLContext.getInstance("TLS");
270 KeyManagerFactory kmf = null;
271 try (FileInputStream fin = new FileInputStream(keystorePath)){
272 String def = "SunX509";
273 String storeType = "PKCS12";
274 def = KeyStore.getDefaultType();
275 kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
277 String extension = keystorePath.substring(keystorePath.lastIndexOf(".") + 1);
278 if("JKS".equalsIgnoreCase(extension)) {
281 KeyStore ks = KeyStore.getInstance(storeType);
283 char[] pwd = keystorePassword.toCharArray();
286 } catch (Exception ex) {
287 LOG.error("AAIResource", ex);
290 ctx.init(kmf.getKeyManagers(), null, null);
291 config.getProperties().put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES, new HTTPSProperties( new HostnameVerifier() {
293 public boolean verify( String s, SSLSession sslSession ) {
294 return ignoreCertificateHostError;
299 LOG.debug("SSLContext created");
301 } catch (KeyManagementException | NoSuchAlgorithmException exc) {
302 LOG.error("AAIResource", exc);
306 LOG.info("AAIResource.ctor initialized.");
309 Field methodsField = HttpURLConnection.class.getDeclaredField("methods");
310 methodsField.setAccessible(true);
311 // get the methods field modifiers
312 Field modifiersField = Field.class.getDeclaredField("modifiers");
313 // bypass the "private" modifier
314 modifiersField.setAccessible(true);
316 // remove the "final" modifier
317 modifiersField.setInt(methodsField, methodsField.getModifiers() & ~Modifier.FINAL);
319 /* valid HTTP methods */
321 "GET", "POST", "HEAD", "OPTIONS", "PUT", "DELETE", "TRACE", "PATCH"
323 // set the new methods - including patch
324 methodsField.set(null, methods);
326 } catch (SecurityException | IllegalArgumentException | IllegalAccessException | NoSuchFieldException e) {
332 public void cleanUp() {
338 * @param http_req_url
343 protected HttpURLConnection getConfiguredConnection(URL http_req_url, String method) throws Exception {
344 HttpURLConnection con = (HttpURLConnection) http_req_url.openConnection();
346 // Set up the connection properties
347 con.setRequestProperty( "Connection", "close" );
348 con.setDoInput(true);
349 con.setDoOutput(true);
350 con.setUseCaches(false);
351 con.setConnectTimeout( connectionTimeout );
352 con.setReadTimeout( readTimeout );
353 con.setRequestMethod( method );
354 con.setRequestProperty( "Accept", "application/json" );
355 con.setRequestProperty( "Content-Type", "PATCH".equalsIgnoreCase(method) ? "application/merge-patch+json" : "application/json" );
356 con.setRequestProperty("X-FromAppId", applicationId);
357 con.setRequestProperty("X-TransactionId",TransactionIdTracker.getNextTransactionId());
358 String mlId = ml.getRequestID();
359 if(mlId != null && !mlId.isEmpty()) {
360 LOG.debug(String.format("MetricLogger requestId = %s", mlId));
361 con.setRequestProperty(MetricLogger.REQUEST_ID, mlId);
363 LOG.debug("MetricLogger requestId is null");
365 con.setRequestProperty("Transfer-Encoding","chunked");
367 if(userName != null && !userName.isEmpty() && userPassword != null && !userPassword.isEmpty()) {
368 String basicAuth = "Basic " + new String(Base64.encodeBase64((userName + ":" + userPassword).getBytes()));
369 con.setRequestProperty ("Authorization", basicAuth);
372 if(con instanceof HttpsURLConnection && CTX != null) {
373 SSLSocketFactory sockFact = CTX.getSocketFactory();
374 HttpsURLConnection.class.cast(con).setSSLSocketFactory( sockFact );
381 public GenericVnf requestGenericVnfData(String vnf_id) throws AAIServiceException {
382 GenericVnf response = null;
385 AAIRequest request = AAIRequest.getRequestFromResource("generic-vnf");
386 request.addRequestProperty("generic-vnf.vnf-id", vnf_id);
387 String rv = executor.get(request);
389 ObjectMapper mapper = getObjectMapper();
390 response = mapper.readValue(rv, GenericVnf.class);
392 } catch(AAIServiceException aaiexc) {
394 } catch (Exception exc) {
395 LOG.warn(Object.class.getClass().getEnclosingMethod().getName(), exc);
396 throw new AAIServiceException(exc);
404 public boolean postGenericVnfData(String vnf_id, GenericVnf data) throws AAIServiceException {
406 AAIRequest request = AAIRequest.getRequestFromResource("generic-vnf");
407 request.addRequestProperty("generic-vnf.vnf-id", vnf_id);
408 request.setRequestObject(data);
409 Object response = executor.post(request);
411 } catch(AAIServiceException aaiexc) {
413 } catch (Exception exc) {
414 LOG.warn("requestGenericVnfData", exc);
415 throw new AAIServiceException(exc);
420 public SearchResults requestServiceInstanceURL(String svc_instance_id) throws AAIServiceException {
421 SearchResults response = null;
422 InputStream inputStream = null;
425 String path = svc_inst_qry_path;
426 path = path.replace("{svc-instance-id}", encodeQuery(svc_instance_id));
428 String request_url = targetUri+path;
429 URL http_req_url = new URL(request_url);
431 HttpURLConnection con = getConfiguredConnection(http_req_url, HttpMethod.GET);
433 LOGwriteFirstTrace(HttpMethod.GET, http_req_url.toString());
434 LOGwriteDateTrace("svc_instance_id", svc_instance_id);
437 int responseCode = con.getResponseCode();
438 if (responseCode == HttpURLConnection.HTTP_OK) {
439 inputStream = con.getInputStream();
441 inputStream = con.getErrorStream();
444 // Process the response
445 LOG.debug("HttpURLConnection result:" + responseCode);
446 if(inputStream == null) inputStream = new ByteArrayInputStream("".getBytes(StandardCharsets.UTF_8));
447 BufferedReader reader = new BufferedReader( new InputStreamReader( inputStream ) );
449 ObjectMapper mapper = getObjectMapper();
451 if (responseCode == HttpURLConnection.HTTP_OK) {
452 response = mapper.readValue(reader, SearchResults.class);
453 LOGwriteEndingTrace(HttpURLConnection.HTTP_OK, "SUCCESS", mapper.writeValueAsString(response));
454 } else if(responseCode == HttpURLConnection.HTTP_NOT_FOUND ) {
455 LOGwriteEndingTrace(responseCode, "HTTP_NOT_FOUND", "Entry does not exist.");
458 ErrorResponse errorresponse = mapper.readValue(reader, ErrorResponse.class);
459 LOGwriteEndingTrace(responseCode, "FAILURE", mapper.writeValueAsString(errorresponse));
460 throw new AAIServiceException(responseCode, errorresponse);
463 } catch(AAIServiceException aaiexc) {
465 } catch (Exception exc) {
466 LOG.warn("requestServiceInstanceURL", exc);
467 throw new AAIServiceException(exc);
469 if(inputStream != null){
472 } catch(Exception exc) {
480 private static Properties initialize(URL url ) throws ConfigurationException {
483 throw new NullPointerException();
486 InputStream is = null;
487 Properties props = new Properties();
490 if(LOG.isDebugEnabled())
491 LOG.info("Property file is: " + url.toString());
493 is = url.openStream();
496 if(LOG.isDebugEnabled()) {
497 LOG.info("Properties loaded: " + props.size());
498 Enumeration<Object> en = props.keys();
500 while(en.hasMoreElements()) {
501 String key = (String)en.nextElement();
502 String property = props.getProperty(key);
503 LOG.debug(key + " : " + property);
506 } catch (Exception e) {
507 throw new ConfigurationException("Could not load properties file.", e);
512 static class TransactionIdTracker {
513 // protected static AtomicLong tracker = new AtomicLong();
515 public static String getNextTransactionId() {
516 // Check if RequestId exists as MDC. If not, create new.
517 String transactionId = MDC.get("RequestId");
518 if ("".equals(transactionId) || transactionId == null) {
519 transactionId = UUID.randomUUID().toString();
520 LOG.info("Missing requestID. Assigned " + transactionId);
521 MDC.put("RequestId", transactionId);
523 return transactionId;
528 protected void LOGwriteFirstTrace(String method, String url) {
529 String time = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'").format(System.currentTimeMillis());
530 LOG.info("A&AI transaction :");
531 LOG.info("Request Time : " + time + ", Method : " + method);
532 LOG.info("Request URL : "+ url);
535 protected void LOGwriteDateTrace(String name, String data) {
536 LOG.info("Input - " + name + " : " + data);
539 protected void LOGwriteEndingTrace(int response_code, String comment, String data) {
540 LOG.info("Response code : " + response_code +", " + comment);
541 LOG.info(String.format("Response data : %s", data));
544 protected String encodeQuery(String param) throws UnsupportedEncodingException {
545 return URLEncoder.encode(param, "UTF-8").replace("+", "%20");
548 private String encodeCustomerURL(final String selection)
550 String encrypted_url = selection;
552 "/aai/v11/business/customers/customer/(.+)/service-subscriptions/service-subscription/(.+)/service-instances/service-instance/(.+)/";
553 Pattern pattern = Pattern.compile(apnpattern);
556 URL url = new URL(selection);
557 String path = url.getPath();
559 LOG.info("Trying to match apn to <" + path + ">");
561 Matcher matcher = pattern.matcher(path);
563 while(matcher.find()) {
564 String customer = matcher.group(1);
565 String subscription = matcher.group(2);
566 String service = matcher.group(3);
568 encrypted_url = selection.replace(customer, encodeQuery(customer));
569 encrypted_url = encrypted_url.replace(subscription, encodeQuery(subscription));
570 encrypted_url = encrypted_url.replace(service, encodeQuery(service));
572 } catch (Exception e) {
576 return encrypted_url;
583 * @see org.openecomp.sdnct.sli.aai.AAIClient#requestVServersData(java.lang.String, java.lang.String)
586 public Vserver requestVServerData(String tenantId, String vserverId, String cloudOwner, String cloudRegionId) throws AAIServiceException {
587 Vserver response = null;
590 AAIRequest request = AAIRequest.getRequestFromResource("vserver");
591 request.addRequestProperty("cloud-region.cloud-owner", cloudOwner);
592 request.addRequestProperty("cloud-region.cloud-region-id", cloudRegionId);
593 request.addRequestProperty("tenant.tenant-id", tenantId);
594 request.addRequestProperty("vserver.vserver-id", vserverId);
596 String rv = executor.get(request);
598 ObjectMapper mapper = getObjectMapper();
599 response = mapper.readValue(rv, Vserver.class);
601 } catch(AAIServiceException aaiexc) {
603 } catch (Exception exc) {
604 LOG.warn(Object.class.getClass().getEnclosingMethod().getName(), exc);
605 throw new AAIServiceException(exc);
611 //================== End of DvsSwitch =================
612 //==================== PhysicalLink ======================
614 public PhysicalLink requestPhysicalLinkData(String linkName) throws AAIServiceException {
615 PhysicalLink response = null;
618 AAIRequest request = AAIRequest.getRequestFromResource("physical-link");
619 request.addRequestProperty("physical-link.link-name", linkName);
621 String rv = executor.get(request);
623 ObjectMapper mapper = getObjectMapper();
624 response = mapper.readValue(rv, PhysicalLink.class);
626 } catch(AAIServiceException aaiexc) {
628 } catch (Exception exc) {
629 LOG.warn("requestPhysicalLinkData", exc);
630 throw new AAIServiceException(exc);
636 public boolean postPhysicalLinkData(String linkName, PhysicalLink data) throws AAIServiceException {
638 AAIRequest request = AAIRequest.getRequestFromResource("physical-link");
639 request.addRequestProperty("physical-link.link-name", linkName);
640 request.setRequestObject(data);
641 Object response = executor.post(request);
643 } catch(AAIServiceException aaiexc) {
645 } catch (Exception exc) {
646 LOG.warn(Object.class.getClass().getEnclosingMethod().getName(), exc);
647 throw new AAIServiceException(exc);
652 public boolean deletePhysicalLinkData(String linkName, String resourceVersion) throws AAIServiceException {
653 boolean response = false;
656 AAIRequest request = AAIRequest.getRequestFromResource("physical-link");
657 request.addRequestProperty("physical-link.link-name", linkName);
658 response = executor.delete(request, resourceVersion);
659 } catch(AAIServiceException aaiexc) {
661 } catch (Exception exc) {
662 LOG.warn("deletePhysicalLinkData", exc);
663 throw new AAIServiceException(exc);
668 public boolean deleteAAIEntity(URL url, String caller) throws AAIServiceException {
671 throw new NullPointerException();
674 boolean response = false;
675 InputStream inputStream = null;
678 URL http_req_url = url;
680 HttpURLConnection con = getConfiguredConnection(http_req_url, HttpMethod.DELETE);
682 LOGwriteFirstTrace("DELETE", http_req_url.toString());
686 int responseCode = con.getResponseCode();
687 if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_NO_CONTENT) {
688 inputStream = con.getInputStream();
690 inputStream = con.getErrorStream();
693 // Process the response
694 LOG.debug("HttpURLConnection result:" + responseCode);
695 if(inputStream == null) inputStream = new ByteArrayInputStream("".getBytes(StandardCharsets.UTF_8));
696 BufferedReader reader = new BufferedReader( new InputStreamReader( inputStream ) );
699 ObjectMapper mapper = getObjectMapper();
701 if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_NO_CONTENT) {
702 StringBuilder stringBuilder = new StringBuilder();
704 while( ( line = reader.readLine() ) != null ) {
705 stringBuilder.append( line );
707 LOGwriteEndingTrace(responseCode, "SUCCESS", stringBuilder.toString());
709 } else if(responseCode == HttpURLConnection.HTTP_NOT_FOUND ) {
710 LOGwriteEndingTrace(responseCode, "HTTP_NOT_FOUND", "Entry does not exist.");
713 ErrorResponse errorresponse = mapper.readValue(reader, ErrorResponse.class);
714 LOGwriteEndingTrace(responseCode, "FAILURE", mapper.writeValueAsString(errorresponse));
715 throw new AAIServiceException(responseCode, errorresponse);
718 } catch(AAIServiceException aaiexc) {
720 } catch (Exception exc) {
721 LOG.warn(caller, exc);
722 throw new AAIServiceException(exc);
724 if(inputStream != null){
727 } catch(Exception exc) {
736 * Generic method to GET json data from an A&AI callback URL.
737 * Then convert that json to an Object.
738 * If successful the Object is attempted to be cast to the type parameter.
741 * callback url for A&AI
743 * the class of object that A&AI will return
744 * @return the object created from json or null if the response code is not 200
746 * @throws AAIServiceException
747 * if empty or null key and or type or there's an error with processing
749 public <T> T dataChangeRequestAaiData(String key, Class<T> type) throws AAIServiceException {
750 if (StringUtils.isEmpty(key) || type == null) {
751 throw new AAIServiceException("Key is empty or null and or type is null");
756 SvcLogicContext ctx = new SvcLogicContext();
757 if(!key.contains(" = ") && isValidURL(key)) {
758 key = String.format("selflink = '%s'", key);
760 if(!key.contains(" = ") && isValidURI(key)) {
761 key = String.format("resource-path = '%s'", key);
764 HashMap<String, String> nameValues = AAIServiceUtils.keyToHashMap(key, ctx);
766 SelfLinkRequest request = new SelfLinkRequest(type);
767 request.processRequestPathValues(nameValues);
768 Object obj = this.getExecutor().query(request, type);
769 response = type.cast(obj);
771 return response != null ? type.cast(response) : response;
775 public boolean sendNotify(NotifyEvent event, String serviceInstanceId, String pathCode) throws AAIServiceException {
776 InputStream inputStream = null;
780 String selfLink = selflinkFqdn;
781 if(SELFLINK_AVPN != null && SELFLINK_AVPN.equals(pathCode)) {
782 selfLink = selflinkAvpn;
784 selfLink = selfLink.replace("{service-instance-id}", encodeQuery(serviceInstanceId));
785 event.setSelflink(selfLink);
787 ObjectMapper mapper = getObjectMapper();
788 String json_text = mapper.writeValueAsString(event);
790 SSLSocketFactory sockFact = CTX.getSocketFactory();
792 String request_url = targetUri+ubb_notify_path;
793 URL http_req_url = new URL(request_url);
795 HttpURLConnection con = getConfiguredConnection(http_req_url, HttpMethod.PUT);
797 if (json_text != null) {
798 OutputStreamWriter osw = new OutputStreamWriter(con.getOutputStream());
799 osw.write(json_text);
804 LOGwriteFirstTrace("PUT", request_url);
805 LOGwriteDateTrace("NotifyEvent", json_text);
808 int responseCode = con.getResponseCode();
809 if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_CREATED || responseCode == HttpURLConnection.HTTP_ACCEPTED || responseCode == HttpURLConnection.HTTP_NO_CONTENT) {
810 inputStream = con.getInputStream();
812 inputStream = con.getErrorStream();
815 // Process the response
816 BufferedReader reader;
818 reader = new BufferedReader( new InputStreamReader( inputStream ) );
820 if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_CREATED || responseCode == HttpURLConnection.HTTP_ACCEPTED || responseCode == HttpURLConnection.HTTP_NO_CONTENT) {
821 StringBuilder stringBuilder = new StringBuilder();
823 while( ( line = reader.readLine() ) != null ) {
824 stringBuilder.append( line );
826 LOGwriteEndingTrace(responseCode, "SUCCESS", (stringBuilder.length() > 0) ? stringBuilder.toString() :
830 ErrorResponse errorresponse = mapper.readValue(reader, ErrorResponse.class);
831 LOGwriteEndingTrace(responseCode, "FAILURE", mapper.writeValueAsString(errorresponse));
833 throw new AAIServiceException(responseCode, errorresponse);
835 } catch(AAIServiceException aaiexc) {
837 } catch (Exception exc) {
838 LOG.warn("sendNotify", exc);
839 throw new AAIServiceException(exc);
842 if(inputStream != null)
844 } catch (Exception exc) {
851 public SearchResults requestNodeQuery(String node_type, String entityIdentifier, String entityName) throws AAIServiceException {
852 SearchResults response = null;
853 InputStream inputStream = null;
856 String request_url = targetUri+queryNodesPath;
857 request_url = request_url.replace("{node-type}", encodeQuery(node_type)) ;
858 request_url = request_url.replace("{entity-identifier}", entityIdentifier) ;
859 request_url = request_url.replace("{entity-name}", encodeQuery(entityName)) ;
860 URL http_req_url = new URL(request_url);
862 HttpURLConnection con = getConfiguredConnection(http_req_url, HttpMethod.GET);
864 LOGwriteFirstTrace(HttpMethod.GET, http_req_url.toString());
865 LOGwriteDateTrace("node_type", node_type);
866 LOGwriteDateTrace("vnf_name", entityName);
869 int responseCode = con.getResponseCode();
870 if (responseCode == HttpURLConnection.HTTP_OK) {
871 inputStream = con.getInputStream();
873 inputStream = con.getErrorStream();
876 // Process the response
877 LOG.debug("HttpURLConnection result:" + responseCode);
878 if(inputStream == null) inputStream = new ByteArrayInputStream("".getBytes(StandardCharsets.UTF_8));
879 BufferedReader reader = new BufferedReader( new InputStreamReader( inputStream ) );
881 ObjectMapper mapper = getObjectMapper();
883 if (responseCode == HttpURLConnection.HTTP_OK) {
884 response = mapper.readValue(reader, SearchResults.class);
885 LOGwriteEndingTrace(HttpURLConnection.HTTP_OK, "SUCCESS", mapper.writeValueAsString(response));
886 } else if (responseCode == HttpURLConnection.HTTP_NOT_FOUND) {
887 LOGwriteEndingTrace(responseCode, "HTTP_NOT_FOUND", "Entry does not exist.");
890 ErrorResponse errorresponse = mapper.readValue(reader, ErrorResponse.class);
891 LOGwriteEndingTrace(responseCode, "FAILURE", mapper.writeValueAsString(errorresponse));
892 throw new AAIServiceException(responseCode, errorresponse);
895 } catch(AAIServiceException aaiexc) {
897 } catch (Exception exc) {
898 LOG.warn("requestNodeQuery", exc);
899 throw new AAIServiceException(exc);
901 if(inputStream != null){
904 } catch(Exception exc) {
915 public String requestDataByURL(URL url) throws AAIServiceException {
918 throw new NullPointerException();
921 String response = null;
922 InputStream inputStream = null;
925 URL http_req_url = url;
927 HttpURLConnection con = getConfiguredConnection(http_req_url, HttpMethod.GET);
929 LOGwriteFirstTrace(HttpMethod.GET, http_req_url.toString());
932 int responseCode = con.getResponseCode();
933 if (responseCode == HttpURLConnection.HTTP_OK) {
934 inputStream = con.getInputStream();
936 inputStream = con.getErrorStream();
939 // Process the response
940 LOG.debug("HttpURLConnection result:" + responseCode);
941 if(inputStream == null) inputStream = new ByteArrayInputStream("".getBytes(StandardCharsets.UTF_8));
942 BufferedReader reader = new BufferedReader( new InputStreamReader( inputStream ) );
944 ObjectMapper mapper = getObjectMapper();
946 if (responseCode == HttpURLConnection.HTTP_OK) {
947 StringBuilder stringBuilder = new StringBuilder("\n");
949 while( ( line = reader.readLine() ) != null ) {
950 stringBuilder.append( line );
952 LOG.info(stringBuilder.toString());
953 // response = mapper.readValue(reader, String.class);
954 response = stringBuilder.toString();
955 LOGwriteEndingTrace(HttpURLConnection.HTTP_OK, "SUCCESS", mapper.writeValueAsString(response));
956 } else if(responseCode == HttpURLConnection.HTTP_NOT_FOUND ) {
957 LOGwriteEndingTrace(responseCode, "HTTP_NOT_FOUND", "Entry does not exist.");
960 ErrorResponse errorresponse = mapper.readValue(reader, ErrorResponse.class);
961 LOGwriteEndingTrace(responseCode, "FAILURE", mapper.writeValueAsString(errorresponse));
962 throw new AAIServiceException(responseCode, errorresponse);
965 } catch(AAIServiceException aaiexc) {
967 } catch (Exception exc) {
968 LOG.warn("requestNetworkVceData", exc);
969 throw new AAIServiceException(exc);
971 if(inputStream != null){
974 } catch(Exception exc) {
984 public GenericVnf requestGenericVnfeNodeQuery(String vnf_name) throws AAIServiceException {
986 if(vnf_name == null) {
987 throw new NullPointerException();
990 GenericVnf entity = null;
991 SearchResults resp = this.requestNodeQuery("generic-vnf", "vnf-name", vnf_name);
993 List<ResultData> resultDataList = resp.getResultData();
996 for (ResultData datum : resultDataList) {
997 String data_type = datum.getResourceType();
998 URL url = new URL(datum.getResourceLink());
999 entity = this.getResource(url.toString(), GenericVnf.class);
1004 LOG.error("Caught exception", e);
1010 public Vserver requestVServerDataByURL(URL url) throws AAIServiceException {
1013 throw new NullPointerException();
1016 Vserver entity = null;
1019 entity = this.getResource(url.toString(), Vserver.class);
1020 } catch (AAIServiceException exc) {
1022 } catch (Exception e) {
1023 throw new AAIServiceException(e);
1029 public URL requestVserverURLNodeQuery(String vserver_name) throws AAIServiceException {
1031 if(vserver_name == null) {
1032 throw new NullPointerException();
1036 SearchResults resp = this.requestNodeQuery("vserver", "vserver-name", vserver_name);
1038 List<ResultData> resultDataList = resp.getResultData();
1041 for (ResultData datum : resultDataList) {
1042 String data_type = datum.getResourceType();
1043 String resourceLink = datum.getResourceLink();
1044 if(!resourceLink.isEmpty() && !resourceLink.toLowerCase().startsWith("http")) {
1045 resourceLink = (new EchoRequest()).targetUri + resourceLink;
1047 entity = new URL(resourceLink);
1049 } catch (Exception e) {
1050 throw new AAIServiceException(e);
1056 public String getTenantIdFromVserverUrl(URL url) {
1058 String path = url.getPath();
1060 String[] split = path.split("/tenants/tenant/");
1061 if(split.length > 1) {
1062 split = split[1].split("/");
1070 public String getCloudOwnerFromVserverUrl(URL url) {
1072 String path = url.getPath();
1074 String[] split = path.split("/cloud-regions/cloud-region/");
1075 if(split.length > 1) {
1076 split = split[1].split("/");
1084 public String getCloudRegionFromVserverUrl(URL url) {
1086 String path = url.getPath();
1088 String[] split = path.split("/cloud-regions/cloud-region/");
1089 if(split.length > 1) {
1090 split = split[1].split("/");
1098 public String getVServerIdFromVserverUrl(URL url, String tenantId) {
1099 String pattern = networkVserverPath;
1100 pattern = pattern.replace("{tenant-id}", tenantId);
1102 int end = pattern.indexOf("{vserver-id}");
1103 String prefix = pattern.substring(0, end);
1105 String path = url.getPath();
1107 if(path.startsWith(prefix)) {
1108 path = path.substring(prefix.length());
1114 protected Logger getLogger(){
1120 public AAIExecutorInterface getExecutor() {
1125 * Creates a current time stamp in UTC i.e. 2016-03-08T22:15:13.343Z.
1126 * If there are any parameters the values are appended to the time stamp.
1129 * values to be appended to current time stamp
1131 * used to set an attribute for a DG
1132 * @throws SvcLogicException
1134 public void setStatusMethod(Map<String, String> parameters, SvcLogicContext ctx) throws SvcLogicException {
1136 throw new SvcLogicException("SvcLogicContext is null.");
1139 StringBuilder sb = new StringBuilder();
1140 sb.append(String.format("%tFT%<tTZ", Calendar.getInstance(TimeZone.getTimeZone("Z")))).append(" - ");
1142 for (Entry<String, String> entry : parameters.entrySet()) {
1143 sb.append(entry.getValue()).append(" ");
1146 if (sb.length() > 0) {
1147 sb.setLength(sb.length() - 2);
1150 ctx.setAttribute("aai-summary-status-message", sb.toString());
1151 LOG.info("aai-summary-status-message: " + sb.toString());
1155 * Generic method to GET json data from an A&AI using key structure.
1156 * Then convert that json to an Object.
1157 * If successful the Object is attempted to be cast to the type parameter.
1160 * key identifying the resource to be retrieved from AAI
1162 * the class of object that A&AI will return
1163 * @return the object created from json or null if the response code is not 200
1165 * @throws AAIServiceException
1166 * if empty or null key and or type or there's an error with processing
1169 public <T> T getResource(String key, Class<T> type) throws AAIServiceException {
1170 if (StringUtils.isEmpty(key) || type == null) {
1171 throw new AAIServiceException("Key is empty or null and or type is null");
1176 SvcLogicContext ctx = new SvcLogicContext();
1177 if(!key.contains(" = ")) {
1178 if(isValidURL(key)) {
1179 key = String.format("selflink = '%s'", key);
1180 } else if(isValidURI(key)) {
1181 key = String.format("resource-path = '%s'", key);
1187 HashMap<String, String> nameValues = AAIServiceUtils.keyToHashMap(key, ctx);
1189 AAIRequest request = new SelfLinkRequest(type);
1190 if(nameValues.containsKey(PathRequest.RESOURCE_PATH.replaceAll("-", "_"))) {
1191 request = new PathRequest(type);
1194 request.processRequestPathValues(nameValues);
1195 Object obj = this.getExecutor().query(request, type);
1196 response = type.cast(obj);
1198 return response != null ? type.cast(response) : response;
1201 public boolean isValidURL(String url) {
1207 } catch (MalformedURLException e) {
1213 } catch (URISyntaxException e) {
1221 public boolean isValidURI(String url) {
1227 } catch (URISyntaxException e) {
1235 protected boolean deleteList(URL httpReqUrl, String json_text) throws AAIServiceException {
1236 if(httpReqUrl == null) {
1237 throw new NullPointerException();
1240 boolean response = false;
1241 InputStream inputStream = null;
1244 HttpURLConnection con = getConfiguredConnection(httpReqUrl, HttpMethod.DELETE);
1246 // SSLSocketFactory sockFact = CTX.getSocketFactory();
1247 // con.setSSLSocketFactory( sockFact );
1248 if (json_text != null) {
1249 OutputStreamWriter osw = new OutputStreamWriter(con.getOutputStream());
1250 osw.write(json_text);
1255 LOGwriteFirstTrace("DELETE", httpReqUrl.toString());
1256 LOGwriteDateTrace("data", json_text);
1259 int responseCode = con.getResponseCode();
1260 if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_NO_CONTENT) {
1261 inputStream = con.getInputStream();
1263 inputStream = con.getErrorStream();
1266 // Process the response
1267 LOG.debug("HttpURLConnection result:" + responseCode);
1268 if(inputStream == null) inputStream = new ByteArrayInputStream("".getBytes(StandardCharsets.UTF_8));
1269 BufferedReader reader = new BufferedReader( new InputStreamReader( inputStream ) );
1272 ObjectMapper mapper = getObjectMapper();
1274 if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_NO_CONTENT) {
1275 StringBuilder stringBuilder = new StringBuilder();
1277 while( ( line = reader.readLine() ) != null ) {
1278 stringBuilder.append( line );
1280 LOGwriteEndingTrace(responseCode, "SUCCESS", stringBuilder.toString());
1282 } else if(responseCode == HttpURLConnection.HTTP_NOT_FOUND ) {
1283 LOGwriteEndingTrace(responseCode, "HTTP_NOT_FOUND", "Entry does not exist.");
1286 ErrorResponse errorresponse = mapper.readValue(reader, ErrorResponse.class);
1287 LOGwriteEndingTrace(responseCode, "FAILURE", mapper.writeValueAsString(errorresponse));
1288 throw new AAIServiceException(responseCode, errorresponse);
1291 } catch(AAIServiceException aaiexc) {
1293 } catch (Exception exc) {
1294 LOG.warn("deleteList", exc);
1295 throw new AAIServiceException(exc);
1297 if(inputStream != null){
1299 inputStream.close();
1300 } catch(Exception exc) {
1308 public static ObjectMapper getObjectMapper() {
1309 ObjectMapper mapper = new ObjectMapper();
1310 AnnotationIntrospector introspector = new JaxbAnnotationIntrospector(TypeFactory.defaultInstance());
1311 AnnotationIntrospector secondary = new JacksonAnnotationIntrospector();
1312 mapper.setAnnotationIntrospector(AnnotationIntrospector.pair(introspector, secondary));
1313 mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
1314 mapper.setSerializationInclusion(Include.NON_NULL);
1315 mapper.setSerializationInclusion(Include.NON_EMPTY);
1319 public void logMetricRequest(String requestId, String targetServiceName, String msg, String path){
1320 String svcInstanceId = "";
1321 String svcName = null;
1322 String partnerName = null;
1323 String targetEntity = "A&AI";
1324 String targetVirtualEntity = null;
1326 ml.logRequest(svcInstanceId, svcName, partnerName, targetEntity, targetServiceName, targetVirtualEntity, msg);
1329 public void logMetricResponse(String requestId, int responseCode, String responseDescription){
1330 ml.logResponse(responseCode < 400 ? "SUCCESS" : "FAILURE", Integer.toString(responseCode), responseDescription);
1333 public void logKeyError(String keys){
1334 LOG.error("Atleast one of the keys [" + keys + "] should have been populated. This will cause a NPE.");
1342 public QueryStatus save(String resource, boolean force, boolean localOnly, String key, Map<String, String> params, String prefix, SvcLogicContext ctx)
1343 throws SvcLogicException {
1344 String normResource = resource.split(":")[0];
1346 switch(normResource){
1347 case "custom-query":
1348 case "formatted-query":
1349 case "generic-query":
1353 case "l2-bridge-sbg":
1354 case "l2-bridge-bgf":
1360 if(key.contains("selflink =")) {
1363 if(!key.contains(String.format("%s.", normResource))) {
1364 key = rewriteKey(resource, key, ctx);
1367 return super.save(resource, force, localOnly, key, params, prefix, ctx);
1371 public QueryStatus query(String resource, boolean localOnly, String select, String key, String prefix, String orderBy, SvcLogicContext ctx)
1372 throws SvcLogicException {
1373 String normResource = resource.split(":")[0];
1375 switch(normResource){
1376 case "custom-query":
1377 case "formatted-query":
1378 case "generic-query":
1382 case "l2-bridge-sbg":
1383 case "l2-bridge-bgf":
1389 if(key.contains("selflink =")) {
1392 if(!key.contains(String.format("%s.", normResource))) {
1393 key = rewriteKey(resource, key, ctx);
1397 return super.query(resource, localOnly, select, key, prefix, orderBy, ctx);
1401 public QueryStatus delete(String resource, String key, SvcLogicContext ctx) throws SvcLogicException {
1402 String normResource = resource.split(":")[0];
1404 switch(normResource){
1405 case "custom-query":
1406 case "formatted-query":
1407 case "generic-query":
1411 case "l2-bridge-sbg":
1412 case "l2-bridge-bgf":
1418 if(key.contains("selflink =")) {
1421 if(!key.contains(String.format("%s.", normResource))) {
1422 key = rewriteKey(resource, key, ctx);
1426 return super.delete(resource, key, ctx);
1430 public QueryStatus update(String resource, String key, Map<String, String> params, String prefix, SvcLogicContext ctx) throws SvcLogicException {
1431 String normResource = resource.split(":")[0];
1433 switch(normResource){
1434 case "custom-query":
1435 case "formatted-query":
1436 case "generic-query":
1440 case "l2-bridge-sbg":
1441 case "l2-bridge-bgf":
1447 if(key.contains("selflink =")) {
1450 if(!key.contains(String.format("%s.", normResource))) {
1451 key = rewriteKey(resource, key, ctx);
1455 return super.update(resource, key, params, prefix, ctx);
1458 private String rewriteKey(String resource, String key, SvcLogicContext ctx) {
1459 LOG.info("AAI Deprecation - the format of request key is no longer supported. Please rewrite this key : " + key);
1461 String normResource = resource.split(":")[0];
1462 Class<? extends AAIDatum> clazz = null;
1464 clazz = AAIRequest.getClassFromResource(normResource) ;
1465 } catch (ClassNotFoundException e) {
1466 LOG.warn("AAIRequest does not support class: " + e.getMessage());
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, HashMap<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);