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.onap.aai.inventory.v14.GenericVnf;
81 import org.onap.aai.inventory.v14.PhysicalLink;
82 import org.onap.aai.inventory.v14.ResultData;
83 import org.onap.aai.inventory.v14.SearchResults;
84 import org.onap.aai.inventory.v14.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 networkVserverPath;
116 private final String svc_inst_qry_path;
118 private final String ubb_notify_path;
119 private final String selflinkAvpn;
120 private final String selflinkFqdn;
122 private final int connectionTimeout;
123 private final int readTimeout;
126 private final String queryNodesPath;
127 private final String applicationId;
129 // authentication credentials
130 private String userName;
131 private String userPassword;
134 private final boolean runtimeOSGI;
136 private SSLContext CTX;
138 private final MetricLogger ml = new MetricLogger();
140 private AAIExecutorInterface executor;
142 public AAIService(final UtilsProvider configuration) {
143 this(configuration.getProperties());
146 public AAIService(final URL url) {
147 this(getProperties(url));
150 private static Properties getProperties(URL url) {
151 Properties properties = new Properties();
153 properties.load(url.openStream());
154 } catch (IOException exc) {
155 LOG.error("getProperties", exc);
160 public AAIService(Properties props) {
161 LOG.info("Entered AAIService.ctor");
163 String runtime = System.getProperty("aaiclient.runtime");
164 if("OSGI".equals(runtime)) {
171 AAIRequest.setProperties(props, this);
173 } catch(Exception exc){
174 LOG.error("AicAAIResource.static", exc);
177 executor = new AAIClientRESTExecutor(props);
179 userName = props.getProperty(CLIENT_NAME);
180 userPassword = props.getProperty(CLIENT_PWWD);
182 if(userName == null || userName.isEmpty()){
183 LOG.debug("Basic user name is not set");
185 if(userPassword == null || userPassword.isEmpty()) {
186 LOG.debug("Basic password is not set");
189 truststorePath = props.getProperty(TRUSTSTORE_PATH);
190 truststorePassword = props.getProperty(TRUSTSTORE_PSSWD);
191 keystorePath = props.getProperty(KEYSTORE_PATH);
192 keystorePassword = props.getProperty(KEYSTORE_PSSWD);
194 targetUri = props.getProperty(TARGET_URI);
195 props.getProperty(QUERY_PATH);
196 props.getProperty(UPDATE_PATH);
198 String tmpApplicationId = props.getProperty(APPLICATION_ID);
199 if(tmpApplicationId == null || tmpApplicationId.isEmpty()) {
200 tmpApplicationId = "SDNC";
202 this.applicationId = tmpApplicationId;
204 // connection timeout
205 int tmpConnectionTimeout = 30000;
206 int tmpReadTimeout = 30000;
209 String tmpValue = null;
210 tmpValue = props.getProperty(CONNECTION_TIMEOUT, "30000");
211 tmpConnectionTimeout = Integer.parseInt(tmpValue);
212 tmpValue = props.getProperty(READ_TIMEOUT, "30000");
213 tmpReadTimeout = Integer.parseInt(tmpValue);
214 } catch(Exception exc) {
215 LOG.error("Failed setting connection timeout", exc);
216 tmpConnectionTimeout = 30000;
217 tmpReadTimeout = 30000;
219 connectionTimeout = tmpConnectionTimeout;
220 readTimeout = tmpReadTimeout;
222 networkVserverPath =props.getProperty(NETWORK_VSERVER_PATH);
224 props.getProperty(SVC_INSTANCE_PATH);
225 svc_inst_qry_path = props.getProperty(SVC_INST_QRY_PATH);
226 props.getProperty(PARAM_SERVICE_TYPE, "service-type");
228 props.getProperty(P_INTERFACE_PATH);
230 props.getProperty(VNF_IMAGE_QUERY_PATH);
232 ubb_notify_path = props.getProperty(UBB_NOTIFY_PATH);
233 selflinkAvpn = props.getProperty(SELFLINK_AVPN);
234 selflinkFqdn = props.getProperty(SELFLINK_FQDN);
236 props.getProperty(SERVICE_PATH);
238 props.getProperty(SITE_PAIR_SET_PATH);
240 queryNodesPath = props.getProperty(QUERY_NODES_PATH);
242 String iche = props.getProperty(CERTIFICATE_HOST_ERROR);
243 boolean host_error = false;
244 if(iche != null && !iche.isEmpty()) {
245 host_error = Boolean.valueOf(iche);
248 ignoreCertificateHostError = host_error;
250 HttpsURLConnection.setDefaultHostnameVerifier( new HostnameVerifier(){
251 public boolean verify(String string,SSLSession ssls) {
252 return ignoreCertificateHostError;
256 if(truststorePath != null && truststorePassword != null && (new File(truststorePath)).exists()) {
257 System.setProperty("javax.net.ssl.trustStore", truststorePath);
258 System.setProperty("javax.net.ssl.trustStorePassword", truststorePassword);
261 if(keystorePath != null && keystorePassword != null && (new File(keystorePath)).exists()) {
262 DefaultClientConfig config = new DefaultClientConfig();
263 //both jersey and HttpURLConnection can use this
264 SSLContext ctx = null;
266 ctx = SSLContext.getInstance("TLS");
268 KeyManagerFactory kmf = null;
269 try (FileInputStream fin = new FileInputStream(keystorePath)){
270 String def = "SunX509";
271 String storeType = "PKCS12";
272 def = KeyStore.getDefaultType();
273 kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
275 String extension = keystorePath.substring(keystorePath.lastIndexOf(".") + 1);
276 if("JKS".equalsIgnoreCase(extension)) {
279 KeyStore ks = KeyStore.getInstance(storeType);
281 char[] pwd = keystorePassword.toCharArray();
284 } catch (Exception ex) {
285 LOG.error("AAIResource", ex);
288 ctx.init(kmf.getKeyManagers(), null, null);
289 config.getProperties().put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES, new HTTPSProperties( new HostnameVerifier() {
291 public boolean verify( String s, SSLSession sslSession ) {
292 return ignoreCertificateHostError;
297 LOG.debug("SSLContext created");
299 } catch (KeyManagementException | NoSuchAlgorithmException exc) {
300 LOG.error("AAIResource", exc);
304 LOG.info("AAIResource.ctor initialized.");
307 Field methodsField = HttpURLConnection.class.getDeclaredField("methods");
308 methodsField.setAccessible(true);
309 // get the methods field modifiers
310 Field modifiersField = Field.class.getDeclaredField("modifiers");
311 // bypass the "private" modifier
312 modifiersField.setAccessible(true);
314 // remove the "final" modifier
315 modifiersField.setInt(methodsField, methodsField.getModifiers() & ~Modifier.FINAL);
317 /* valid HTTP methods */
319 "GET", "POST", "HEAD", "OPTIONS", "PUT", "DELETE", "TRACE", "PATCH"
321 // set the new methods - including patch
322 methodsField.set(null, methods);
324 } catch (SecurityException | IllegalArgumentException | IllegalAccessException | NoSuchFieldException e) {
330 public void setExecutor(AAIExecutorInterface executor) {
331 this.executor = executor;
334 public void cleanUp() {
340 * @param http_req_url
345 protected HttpURLConnection getConfiguredConnection(URL http_req_url, String method) throws Exception {
346 HttpURLConnection con = (HttpURLConnection) http_req_url.openConnection();
348 // Set up the connection properties
349 con.setRequestProperty( "Connection", "close" );
350 con.setDoInput(true);
351 con.setDoOutput(true);
352 con.setUseCaches(false);
353 con.setConnectTimeout( connectionTimeout );
354 con.setReadTimeout( readTimeout );
355 con.setRequestMethod( method );
356 con.setRequestProperty( "Accept", "application/json" );
357 con.setRequestProperty( "Content-Type", "PATCH".equalsIgnoreCase(method) ? "application/merge-patch+json" : "application/json" );
358 con.setRequestProperty("X-FromAppId", applicationId);
359 con.setRequestProperty("X-TransactionId",TransactionIdTracker.getNextTransactionId());
360 String mlId = ml.getRequestID();
361 if(mlId != null && !mlId.isEmpty()) {
362 LOG.debug(String.format("MetricLogger requestId = %s", mlId));
363 con.setRequestProperty(MetricLogger.REQUEST_ID, mlId);
365 LOG.debug("MetricLogger requestId is null");
367 con.setRequestProperty("Transfer-Encoding","chunked");
369 if(userName != null && !userName.isEmpty() && userPassword != null && !userPassword.isEmpty()) {
370 String basicAuth = "Basic " + new String(Base64.encodeBase64((userName + ":" + userPassword).getBytes()));
371 con.setRequestProperty ("Authorization", basicAuth);
374 if(con instanceof HttpsURLConnection && CTX != null) {
375 SSLSocketFactory sockFact = CTX.getSocketFactory();
376 HttpsURLConnection.class.cast(con).setSSLSocketFactory( sockFact );
383 public GenericVnf requestGenericVnfData(String vnf_id) throws AAIServiceException {
384 GenericVnf response = null;
387 AAIRequest request = AAIRequest.getRequestFromResource("generic-vnf");
388 request.addRequestProperty("generic-vnf.vnf-id", vnf_id);
389 String rv = executor.get(request);
391 ObjectMapper mapper = getObjectMapper();
392 response = mapper.readValue(rv, GenericVnf.class);
394 } catch(AAIServiceException aaiexc) {
396 } catch (Exception exc) {
397 LOG.warn(Object.class.getClass().getEnclosingMethod().getName(), exc);
398 throw new AAIServiceException(exc);
406 public boolean postGenericVnfData(String vnf_id, GenericVnf data) throws AAIServiceException {
408 AAIRequest request = AAIRequest.getRequestFromResource("generic-vnf");
409 request.addRequestProperty("generic-vnf.vnf-id", vnf_id);
410 request.setRequestObject(data);
411 Object response = executor.post(request);
413 } catch(AAIServiceException aaiexc) {
415 } catch (Exception exc) {
416 LOG.warn("requestGenericVnfData", exc);
417 throw new AAIServiceException(exc);
422 public SearchResults requestServiceInstanceURL(String svc_instance_id) throws AAIServiceException {
423 SearchResults response = null;
424 InputStream inputStream = null;
427 String path = svc_inst_qry_path;
428 path = path.replace("{svc-instance-id}", encodeQuery(svc_instance_id));
430 String request_url = targetUri+path;
431 URL http_req_url = new URL(request_url);
433 HttpURLConnection con = getConfiguredConnection(http_req_url, HttpMethod.GET);
435 LOGwriteFirstTrace(HttpMethod.GET, http_req_url.toString());
436 LOGwriteDateTrace("svc_instance_id", svc_instance_id);
439 int responseCode = con.getResponseCode();
440 if (responseCode == HttpURLConnection.HTTP_OK) {
441 inputStream = con.getInputStream();
443 inputStream = con.getErrorStream();
446 // Process the response
447 LOG.debug("HttpURLConnection result:" + responseCode);
448 if(inputStream == null) inputStream = new ByteArrayInputStream("".getBytes(StandardCharsets.UTF_8));
449 BufferedReader reader = new BufferedReader( new InputStreamReader( inputStream ) );
451 ObjectMapper mapper = getObjectMapper();
453 if (responseCode == HttpURLConnection.HTTP_OK) {
454 response = mapper.readValue(reader, SearchResults.class);
455 LOGwriteEndingTrace(HttpURLConnection.HTTP_OK, "SUCCESS", mapper.writeValueAsString(response));
456 } else if(responseCode == HttpURLConnection.HTTP_NOT_FOUND ) {
457 LOGwriteEndingTrace(responseCode, "HTTP_NOT_FOUND", "Entry does not exist.");
460 ErrorResponse errorresponse = mapper.readValue(reader, ErrorResponse.class);
461 LOGwriteEndingTrace(responseCode, "FAILURE", mapper.writeValueAsString(errorresponse));
462 throw new AAIServiceException(responseCode, errorresponse);
465 } catch(AAIServiceException aaiexc) {
467 } catch (Exception exc) {
468 LOG.warn("requestServiceInstanceURL", exc);
469 throw new AAIServiceException(exc);
471 if(inputStream != null){
474 } catch(Exception exc) {
482 private static Properties initialize(URL url ) throws ConfigurationException {
485 throw new NullPointerException();
488 InputStream is = null;
489 Properties props = new Properties();
492 if(LOG.isDebugEnabled())
493 LOG.info("Property file is: " + url.toString());
495 is = url.openStream();
498 if(LOG.isDebugEnabled()) {
499 LOG.info("Properties loaded: " + props.size());
500 Enumeration<Object> en = props.keys();
502 while(en.hasMoreElements()) {
503 String key = (String)en.nextElement();
504 String property = props.getProperty(key);
505 LOG.debug(key + " : " + property);
508 } catch (Exception e) {
509 throw new ConfigurationException("Could not load properties file.", e);
514 static class TransactionIdTracker {
515 // protected static AtomicLong tracker = new AtomicLong();
517 public static String getNextTransactionId() {
518 // Check if RequestId exists as MDC. If not, create new.
519 String transactionId = MDC.get("RequestId");
520 if ("".equals(transactionId) || transactionId == null) {
521 transactionId = UUID.randomUUID().toString();
522 LOG.info("Missing requestID. Assigned " + transactionId);
523 MDC.put("RequestId", transactionId);
525 return transactionId;
530 protected void LOGwriteFirstTrace(String method, String url) {
531 String time = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'").format(System.currentTimeMillis());
532 LOG.info("A&AI transaction :");
533 LOG.info("Request Time : " + time + ", Method : " + method);
534 LOG.info("Request URL : "+ url);
537 protected void LOGwriteDateTrace(String name, String data) {
538 LOG.info("Input - " + name + " : " + data);
541 protected void LOGwriteEndingTrace(int response_code, String comment, String data) {
542 LOG.info("Response code : " + response_code +", " + comment);
543 LOG.info(String.format("Response data : %s", data));
546 protected String encodeQuery(String param) throws UnsupportedEncodingException {
547 return URLEncoder.encode(param, "UTF-8").replace("+", "%20");
550 private String encodeCustomerURL(final String selection)
552 String encrypted_url = selection;
554 "/aai/v11/business/customers/customer/(.+)/service-subscriptions/service-subscription/(.+)/service-instances/service-instance/(.+)/";
555 Pattern pattern = Pattern.compile(apnpattern);
558 URL url = new URL(selection);
559 String path = url.getPath();
561 LOG.info("Trying to match apn to <" + path + ">");
563 Matcher matcher = pattern.matcher(path);
565 while(matcher.find()) {
566 String customer = matcher.group(1);
567 String subscription = matcher.group(2);
568 String service = matcher.group(3);
570 encrypted_url = selection.replace(customer, encodeQuery(customer));
571 encrypted_url = encrypted_url.replace(subscription, encodeQuery(subscription));
572 encrypted_url = encrypted_url.replace(service, encodeQuery(service));
574 } catch (Exception e) {
578 return encrypted_url;
585 * @see org.onap.sdnct.sli.aai.AAIClient#requestVServersData(java.lang.String, java.lang.String)
588 public Vserver requestVServerData(String tenantId, String vserverId, String cloudOwner, String cloudRegionId) throws AAIServiceException {
589 Vserver response = null;
592 AAIRequest request = AAIRequest.getRequestFromResource("vserver");
593 request.addRequestProperty("cloud-region.cloud-owner", cloudOwner);
594 request.addRequestProperty("cloud-region.cloud-region-id", cloudRegionId);
595 request.addRequestProperty("tenant.tenant-id", tenantId);
596 request.addRequestProperty("vserver.vserver-id", vserverId);
598 String rv = executor.get(request);
600 ObjectMapper mapper = getObjectMapper();
601 response = mapper.readValue(rv, Vserver.class);
603 } catch(AAIServiceException aaiexc) {
605 } catch (Exception exc) {
606 LOG.warn(Object.class.getClass().getEnclosingMethod().getName(), exc);
607 throw new AAIServiceException(exc);
613 //================== End of DvsSwitch =================
614 //==================== PhysicalLink ======================
616 public PhysicalLink requestPhysicalLinkData(String linkName) throws AAIServiceException {
617 PhysicalLink response = null;
620 AAIRequest request = AAIRequest.getRequestFromResource("physical-link");
621 request.addRequestProperty("physical-link.link-name", linkName);
623 String rv = executor.get(request);
625 ObjectMapper mapper = getObjectMapper();
626 response = mapper.readValue(rv, PhysicalLink.class);
628 } catch(AAIServiceException aaiexc) {
630 } catch (Exception exc) {
631 LOG.warn("requestPhysicalLinkData", exc);
632 throw new AAIServiceException(exc);
638 public boolean postPhysicalLinkData(String linkName, PhysicalLink data) throws AAIServiceException {
640 AAIRequest request = AAIRequest.getRequestFromResource("physical-link");
641 request.addRequestProperty("physical-link.link-name", linkName);
642 request.setRequestObject(data);
643 Object response = executor.post(request);
645 } catch(AAIServiceException aaiexc) {
647 } catch (Exception exc) {
648 LOG.warn(Object.class.getClass().getEnclosingMethod().getName(), exc);
649 throw new AAIServiceException(exc);
654 public boolean deletePhysicalLinkData(String linkName, String resourceVersion) throws AAIServiceException {
655 boolean response = false;
658 AAIRequest request = AAIRequest.getRequestFromResource("physical-link");
659 request.addRequestProperty("physical-link.link-name", linkName);
660 response = executor.delete(request, resourceVersion);
661 } catch(AAIServiceException aaiexc) {
663 } catch (Exception exc) {
664 LOG.warn("deletePhysicalLinkData", exc);
665 throw new AAIServiceException(exc);
670 public boolean deleteAAIEntity(URL url, String caller) throws AAIServiceException {
673 throw new NullPointerException();
676 boolean response = false;
677 InputStream inputStream = null;
680 URL http_req_url = url;
682 HttpURLConnection con = getConfiguredConnection(http_req_url, HttpMethod.DELETE);
684 LOGwriteFirstTrace("DELETE", http_req_url.toString());
688 int responseCode = con.getResponseCode();
689 if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_NO_CONTENT) {
690 inputStream = con.getInputStream();
692 inputStream = con.getErrorStream();
695 // Process the response
696 LOG.debug("HttpURLConnection result:" + responseCode);
697 if(inputStream == null) inputStream = new ByteArrayInputStream("".getBytes(StandardCharsets.UTF_8));
698 BufferedReader reader = new BufferedReader( new InputStreamReader( inputStream ) );
701 ObjectMapper mapper = getObjectMapper();
703 if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_NO_CONTENT) {
704 StringBuilder stringBuilder = new StringBuilder();
706 while( ( line = reader.readLine() ) != null ) {
707 stringBuilder.append( line );
709 LOGwriteEndingTrace(responseCode, "SUCCESS", stringBuilder.toString());
711 } else if(responseCode == HttpURLConnection.HTTP_NOT_FOUND ) {
712 LOGwriteEndingTrace(responseCode, "HTTP_NOT_FOUND", "Entry does not exist.");
715 ErrorResponse errorresponse = mapper.readValue(reader, ErrorResponse.class);
716 LOGwriteEndingTrace(responseCode, "FAILURE", mapper.writeValueAsString(errorresponse));
717 throw new AAIServiceException(responseCode, errorresponse);
720 } catch(AAIServiceException aaiexc) {
722 } catch (Exception exc) {
723 LOG.warn(caller, exc);
724 throw new AAIServiceException(exc);
726 if(inputStream != null){
729 } catch(Exception exc) {
738 * Generic method to GET json data from an A&AI callback URL.
739 * Then convert that json to an Object.
740 * If successful the Object is attempted to be cast to the type parameter.
743 * callback url for A&AI
745 * the class of object that A&AI will return
746 * @return the object created from json or null if the response code is not 200
748 * @throws AAIServiceException
749 * if empty or null key and or type or there's an error with processing
751 public <T> T dataChangeRequestAaiData(String key, Class<T> type) throws AAIServiceException {
752 if (StringUtils.isEmpty(key) || type == null) {
753 throw new AAIServiceException("Key is empty or null and or type is null");
758 SvcLogicContext ctx = new SvcLogicContext();
759 if(!key.contains(" = ") && isValidURL(key)) {
760 key = String.format("selflink = '%s'", key);
762 if(!key.contains(" = ") && isValidURI(key)) {
763 key = String.format("resource-path = '%s'", key);
766 HashMap<String, String> nameValues = AAIServiceUtils.keyToHashMap(key, ctx);
768 SelfLinkRequest request = new SelfLinkRequest(type);
769 request.processRequestPathValues(nameValues);
770 Object obj = this.getExecutor().query(request, type);
771 response = type.cast(obj);
773 return response != null ? type.cast(response) : response;
777 public boolean sendNotify(NotifyEvent event, String serviceInstanceId, String pathCode) throws AAIServiceException {
778 InputStream inputStream = null;
782 String selfLink = selflinkFqdn;
783 if(SELFLINK_AVPN != null && SELFLINK_AVPN.equals(pathCode)) {
784 selfLink = selflinkAvpn;
786 selfLink = selfLink.replace("{service-instance-id}", encodeQuery(serviceInstanceId));
787 event.setSelflink(selfLink);
789 ObjectMapper mapper = getObjectMapper();
790 String json_text = mapper.writeValueAsString(event);
792 SSLSocketFactory sockFact = CTX.getSocketFactory();
794 String request_url = targetUri+ubb_notify_path;
795 URL http_req_url = new URL(request_url);
797 HttpURLConnection con = getConfiguredConnection(http_req_url, HttpMethod.PUT);
799 if (json_text != null) {
800 OutputStreamWriter osw = new OutputStreamWriter(con.getOutputStream());
801 osw.write(json_text);
806 LOGwriteFirstTrace("PUT", request_url);
807 LOGwriteDateTrace("NotifyEvent", json_text);
810 int responseCode = con.getResponseCode();
811 if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_CREATED || responseCode == HttpURLConnection.HTTP_ACCEPTED || responseCode == HttpURLConnection.HTTP_NO_CONTENT) {
812 inputStream = con.getInputStream();
814 inputStream = con.getErrorStream();
817 // Process the response
818 BufferedReader reader;
820 reader = new BufferedReader( new InputStreamReader( inputStream ) );
822 if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_CREATED || responseCode == HttpURLConnection.HTTP_ACCEPTED || responseCode == HttpURLConnection.HTTP_NO_CONTENT) {
823 StringBuilder stringBuilder = new StringBuilder();
825 while( ( line = reader.readLine() ) != null ) {
826 stringBuilder.append( line );
828 LOGwriteEndingTrace(responseCode, "SUCCESS", (stringBuilder.length() > 0) ? stringBuilder.toString() :
832 ErrorResponse errorresponse = mapper.readValue(reader, ErrorResponse.class);
833 LOGwriteEndingTrace(responseCode, "FAILURE", mapper.writeValueAsString(errorresponse));
835 throw new AAIServiceException(responseCode, errorresponse);
837 } catch(AAIServiceException aaiexc) {
839 } catch (Exception exc) {
840 LOG.warn("sendNotify", exc);
841 throw new AAIServiceException(exc);
844 if(inputStream != null)
846 } catch (Exception exc) {
853 public SearchResults requestNodeQuery(String node_type, String entityIdentifier, String entityName) throws AAIServiceException {
854 SearchResults response = null;
855 InputStream inputStream = null;
858 String request_url = targetUri+queryNodesPath;
859 request_url = request_url.replace("{node-type}", encodeQuery(node_type)) ;
860 request_url = request_url.replace("{entity-identifier}", entityIdentifier) ;
861 request_url = request_url.replace("{entity-name}", encodeQuery(entityName)) ;
862 URL http_req_url = new URL(request_url);
864 HttpURLConnection con = getConfiguredConnection(http_req_url, HttpMethod.GET);
866 LOGwriteFirstTrace(HttpMethod.GET, http_req_url.toString());
867 LOGwriteDateTrace("node_type", node_type);
868 LOGwriteDateTrace("vnf_name", entityName);
871 int responseCode = con.getResponseCode();
872 if (responseCode == HttpURLConnection.HTTP_OK) {
873 inputStream = con.getInputStream();
875 inputStream = con.getErrorStream();
878 // Process the response
879 LOG.debug("HttpURLConnection result:" + responseCode);
880 if(inputStream == null) inputStream = new ByteArrayInputStream("".getBytes(StandardCharsets.UTF_8));
881 BufferedReader reader = new BufferedReader( new InputStreamReader( inputStream ) );
883 ObjectMapper mapper = getObjectMapper();
885 if (responseCode == HttpURLConnection.HTTP_OK) {
886 response = mapper.readValue(reader, SearchResults.class);
887 LOGwriteEndingTrace(HttpURLConnection.HTTP_OK, "SUCCESS", mapper.writeValueAsString(response));
888 } else if (responseCode == HttpURLConnection.HTTP_NOT_FOUND) {
889 LOGwriteEndingTrace(responseCode, "HTTP_NOT_FOUND", "Entry does not exist.");
892 ErrorResponse errorresponse = mapper.readValue(reader, ErrorResponse.class);
893 LOGwriteEndingTrace(responseCode, "FAILURE", mapper.writeValueAsString(errorresponse));
894 throw new AAIServiceException(responseCode, errorresponse);
897 } catch(AAIServiceException aaiexc) {
899 } catch (Exception exc) {
900 LOG.warn("requestNodeQuery", exc);
901 throw new AAIServiceException(exc);
903 if(inputStream != null){
906 } catch(Exception exc) {
917 public String requestDataByURL(URL url) throws AAIServiceException {
920 throw new NullPointerException();
923 String response = null;
924 InputStream inputStream = null;
927 URL http_req_url = url;
929 HttpURLConnection con = getConfiguredConnection(http_req_url, HttpMethod.GET);
931 LOGwriteFirstTrace(HttpMethod.GET, http_req_url.toString());
934 int responseCode = con.getResponseCode();
935 if (responseCode == HttpURLConnection.HTTP_OK) {
936 inputStream = con.getInputStream();
938 inputStream = con.getErrorStream();
941 // Process the response
942 LOG.debug("HttpURLConnection result:" + responseCode);
943 if(inputStream == null) inputStream = new ByteArrayInputStream("".getBytes(StandardCharsets.UTF_8));
944 BufferedReader reader = new BufferedReader( new InputStreamReader( inputStream ) );
946 ObjectMapper mapper = getObjectMapper();
948 if (responseCode == HttpURLConnection.HTTP_OK) {
949 StringBuilder stringBuilder = new StringBuilder("\n");
951 while( ( line = reader.readLine() ) != null ) {
952 stringBuilder.append( line );
954 LOG.info(stringBuilder.toString());
955 // response = mapper.readValue(reader, String.class);
956 response = stringBuilder.toString();
957 LOGwriteEndingTrace(HttpURLConnection.HTTP_OK, "SUCCESS", mapper.writeValueAsString(response));
958 } else if(responseCode == HttpURLConnection.HTTP_NOT_FOUND ) {
959 LOGwriteEndingTrace(responseCode, "HTTP_NOT_FOUND", "Entry does not exist.");
962 ErrorResponse errorresponse = mapper.readValue(reader, ErrorResponse.class);
963 LOGwriteEndingTrace(responseCode, "FAILURE", mapper.writeValueAsString(errorresponse));
964 throw new AAIServiceException(responseCode, errorresponse);
967 } catch(AAIServiceException aaiexc) {
969 } catch (Exception exc) {
970 LOG.warn("requestNetworkVceData", exc);
971 throw new AAIServiceException(exc);
973 if(inputStream != null){
976 } catch(Exception exc) {
986 public GenericVnf requestGenericVnfeNodeQuery(String vnf_name) throws AAIServiceException {
988 if(vnf_name == null) {
989 throw new NullPointerException();
992 GenericVnf entity = null;
993 SearchResults resp = this.requestNodeQuery("generic-vnf", "vnf-name", vnf_name);
995 List<ResultData> resultDataList = resp.getResultData();
998 for (ResultData datum : resultDataList) {
999 URI url = new URI(datum.getResourceLink());
1000 entity = this.getResource(url.toString(), GenericVnf.class);
1005 LOG.error("Caught exception", e);
1011 public Vserver requestVServerDataByURL(URL url) throws AAIServiceException {
1014 throw new NullPointerException();
1017 Vserver entity = null;
1020 entity = this.getResource(url.toString(), Vserver.class);
1021 } catch (AAIServiceException exc) {
1023 } catch (Exception e) {
1024 throw new AAIServiceException(e);
1030 public URL requestVserverURLNodeQuery(String vserver_name) throws AAIServiceException {
1032 if(vserver_name == null) {
1033 throw new NullPointerException();
1037 SearchResults resp = this.requestNodeQuery("vserver", "vserver-name", vserver_name);
1039 List<ResultData> resultDataList = resp.getResultData();
1042 for (ResultData datum : resultDataList) {
1043 String data_type = datum.getResourceType();
1044 String resourceLink = datum.getResourceLink();
1045 if(!resourceLink.isEmpty() && !resourceLink.toLowerCase().startsWith("http")) {
1046 resourceLink = (new EchoRequest()).targetUri + resourceLink;
1048 entity = new URL(resourceLink);
1050 } catch (Exception e) {
1051 throw new AAIServiceException(e);
1057 public String getTenantIdFromVserverUrl(URL url) {
1059 String path = url.getPath();
1061 String[] split = path.split("/tenants/tenant/");
1062 if(split.length > 1) {
1063 split = split[1].split("/");
1071 public String getCloudOwnerFromVserverUrl(URL url) {
1073 String path = url.getPath();
1075 String[] split = path.split("/cloud-regions/cloud-region/");
1076 if(split.length > 1) {
1077 split = split[1].split("/");
1085 public String getCloudRegionFromVserverUrl(URL url) {
1087 String path = url.getPath();
1089 String[] split = path.split("/cloud-regions/cloud-region/");
1090 if(split.length > 1) {
1091 split = split[1].split("/");
1099 public String getVServerIdFromVserverUrl(URL url, String tenantId) {
1100 String pattern = networkVserverPath;
1101 pattern = pattern.replace("{tenant-id}", tenantId);
1103 int end = pattern.indexOf("{vserver-id}");
1104 String prefix = pattern.substring(0, end);
1106 String path = url.getPath();
1108 if(path.startsWith(prefix)) {
1109 path = path.substring(prefix.length());
1115 protected Logger getLogger(){
1121 public AAIExecutorInterface getExecutor() {
1126 * Creates a current time stamp in UTC i.e. 2016-03-08T22:15:13.343Z.
1127 * If there are any parameters the values are appended to the time stamp.
1130 * values to be appended to current time stamp
1132 * used to set an attribute for a DG
1133 * @throws SvcLogicException
1135 public void setStatusMethod(Map<String, String> parameters, SvcLogicContext ctx) throws SvcLogicException {
1137 throw new SvcLogicException("SvcLogicContext is null.");
1140 StringBuilder sb = new StringBuilder();
1141 sb.append(String.format("%tFT%<tTZ", Calendar.getInstance(TimeZone.getTimeZone("Z")))).append(" - ");
1143 for (Entry<String, String> entry : parameters.entrySet()) {
1144 sb.append(entry.getValue()).append(" ");
1147 if (sb.length() > 0) {
1148 sb.setLength(sb.length() - 2);
1151 ctx.setAttribute("aai-summary-status-message", sb.toString());
1152 LOG.info("aai-summary-status-message: " + sb.toString());
1156 * Generic method to GET json data from an A&AI using key structure.
1157 * Then convert that json to an Object.
1158 * If successful the Object is attempted to be cast to the type parameter.
1161 * key identifying the resource to be retrieved from AAI
1163 * the class of object that A&AI will return
1164 * @return the object created from json or null if the response code is not 200
1166 * @throws AAIServiceException
1167 * if empty or null key and or type or there's an error with processing
1170 public <T> T getResource(String key, Class<T> type) throws AAIServiceException {
1171 if (StringUtils.isEmpty(key) || type == null) {
1172 throw new AAIServiceException("Key is empty or null and or type is null");
1177 SvcLogicContext ctx = new SvcLogicContext();
1178 if(!key.contains(" = ")) {
1179 if(isValidURL(key)) {
1180 key = String.format("selflink = '%s'", key);
1181 } else if(isValidURI(key)) {
1182 key = String.format("resource-path = '%s'", key);
1188 HashMap<String, String> nameValues = AAIServiceUtils.keyToHashMap(key, ctx);
1190 AAIRequest request = new SelfLinkRequest(type);
1191 if(nameValues.containsKey(PathRequest.RESOURCE_PATH.replaceAll("-", "_"))) {
1192 request = new PathRequest(type);
1195 request.processRequestPathValues(nameValues);
1196 Object obj = this.getExecutor().query(request, type);
1197 response = type.cast(obj);
1199 return response != null ? type.cast(response) : response;
1202 public boolean isValidURL(String url) {
1208 } catch (MalformedURLException e) {
1214 } catch (URISyntaxException e) {
1222 public boolean isValidURI(String url) {
1228 } catch (URISyntaxException e) {
1236 protected boolean deleteList(URL httpReqUrl, String json_text) throws AAIServiceException {
1237 if(httpReqUrl == null) {
1238 throw new NullPointerException();
1241 boolean response = false;
1242 InputStream inputStream = null;
1245 HttpURLConnection con = getConfiguredConnection(httpReqUrl, HttpMethod.DELETE);
1247 // SSLSocketFactory sockFact = CTX.getSocketFactory();
1248 // con.setSSLSocketFactory( sockFact );
1249 if (json_text != null) {
1250 OutputStreamWriter osw = new OutputStreamWriter(con.getOutputStream());
1251 osw.write(json_text);
1256 LOGwriteFirstTrace("DELETE", httpReqUrl.toString());
1257 LOGwriteDateTrace("data", json_text);
1260 int responseCode = con.getResponseCode();
1261 if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_NO_CONTENT) {
1262 inputStream = con.getInputStream();
1264 inputStream = con.getErrorStream();
1267 // Process the response
1268 LOG.debug("HttpURLConnection result:" + responseCode);
1269 if(inputStream == null) inputStream = new ByteArrayInputStream("".getBytes(StandardCharsets.UTF_8));
1270 BufferedReader reader = new BufferedReader( new InputStreamReader( inputStream ) );
1273 ObjectMapper mapper = getObjectMapper();
1275 if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_NO_CONTENT) {
1276 StringBuilder stringBuilder = new StringBuilder();
1278 while( ( line = reader.readLine() ) != null ) {
1279 stringBuilder.append( line );
1281 LOGwriteEndingTrace(responseCode, "SUCCESS", stringBuilder.toString());
1283 } else if(responseCode == HttpURLConnection.HTTP_NOT_FOUND ) {
1284 LOGwriteEndingTrace(responseCode, "HTTP_NOT_FOUND", "Entry does not exist.");
1287 ErrorResponse errorresponse = mapper.readValue(reader, ErrorResponse.class);
1288 LOGwriteEndingTrace(responseCode, "FAILURE", mapper.writeValueAsString(errorresponse));
1289 throw new AAIServiceException(responseCode, errorresponse);
1292 } catch(AAIServiceException aaiexc) {
1294 } catch (Exception exc) {
1295 LOG.warn("deleteList", exc);
1296 throw new AAIServiceException(exc);
1298 if(inputStream != null){
1300 inputStream.close();
1301 } catch(Exception exc) {
1309 public static ObjectMapper getObjectMapper() {
1310 ObjectMapper mapper = new ObjectMapper();
1311 AnnotationIntrospector introspector = new JaxbAnnotationIntrospector(TypeFactory.defaultInstance());
1312 AnnotationIntrospector secondary = new JacksonAnnotationIntrospector();
1313 mapper.setAnnotationIntrospector(AnnotationIntrospector.pair(introspector, secondary));
1314 mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
1315 mapper.setSerializationInclusion(Include.NON_NULL);
1316 mapper.setSerializationInclusion(Include.NON_EMPTY);
1320 public void logMetricRequest(String requestId, String targetServiceName, String msg, String path){
1321 String svcInstanceId = "";
1322 String svcName = null;
1323 String partnerName = null;
1324 String targetEntity = "A&AI";
1325 String targetVirtualEntity = null;
1327 ml.logRequest(svcInstanceId, svcName, partnerName, targetEntity, targetServiceName, targetVirtualEntity, msg);
1330 public void logMetricResponse(String requestId, int responseCode, String responseDescription){
1331 ml.logResponse(responseCode < 400 ? "COMPLETE" : "ERROR", Integer.toString(responseCode), responseDescription);
1334 public void logKeyError(String keys){
1335 LOG.error("Atleast one of the keys [" + keys + "] should have been populated. This will cause a NPE.");
1343 public QueryStatus save(String resource, boolean force, boolean localOnly, String key, Map<String, String> params, String prefix, SvcLogicContext ctx)
1344 throws SvcLogicException {
1345 String normResource = resource.split(":")[0];
1347 switch(normResource){
1348 case "custom-query":
1349 case "formatted-query":
1350 case "generic-query":
1354 case "l2-bridge-sbg":
1355 case "l2-bridge-bgf":
1361 if(key.contains("selflink =")) {
1364 if(!key.contains(String.format("%s.", normResource))) {
1365 key = rewriteKey(resource, key, ctx);
1368 return super.save(resource, force, localOnly, key, params, prefix, ctx);
1372 public QueryStatus query(String resource, boolean localOnly, String select, String key, String prefix, String orderBy, SvcLogicContext ctx)
1373 throws SvcLogicException {
1374 String normResource = resource.split(":")[0];
1376 switch(normResource){
1377 case "custom-query":
1378 case "formatted-query":
1379 case "generic-query":
1383 case "l2-bridge-sbg":
1384 case "l2-bridge-bgf":
1390 if(key.contains("selflink =")) {
1393 if(!key.contains(String.format("%s.", normResource))) {
1394 key = rewriteKey(resource, key, ctx);
1398 return super.query(resource, localOnly, select, key, prefix, orderBy, ctx);
1402 public QueryStatus delete(String resource, String key, SvcLogicContext ctx) throws SvcLogicException {
1403 String normResource = resource.split(":")[0];
1405 switch(normResource){
1406 case "custom-query":
1407 case "formatted-query":
1408 case "generic-query":
1412 case "l2-bridge-sbg":
1413 case "l2-bridge-bgf":
1419 if(key.contains("selflink =")) {
1422 if(!key.contains(String.format("%s.", normResource))) {
1423 key = rewriteKey(resource, key, ctx);
1427 return super.delete(resource, key, ctx);
1431 public QueryStatus update(String resource, String key, Map<String, String> params, String prefix, SvcLogicContext ctx) throws SvcLogicException {
1432 String normResource = resource.split(":")[0];
1434 switch(normResource){
1435 case "custom-query":
1436 case "formatted-query":
1437 case "generic-query":
1441 case "l2-bridge-sbg":
1442 case "l2-bridge-bgf":
1448 if(key.contains("selflink =")) {
1451 if(!key.contains(String.format("%s.", normResource))) {
1452 key = rewriteKey(resource, key, ctx);
1456 return super.update(resource, key, params, prefix, ctx);
1459 private String rewriteKey(String resource, String key, SvcLogicContext ctx) {
1460 LOG.info("AAI Deprecation - the format of request key is no longer supported. Please rewrite this key : " + key);
1462 String normResource = resource.split(":")[0];
1463 Class<? extends AAIDatum> clazz = AAIRequest.getClassFromResource(normResource) ;
1468 List<String> fieldAnnotatedNames = new LinkedList<>();
1470 Field[] fields = clazz.getDeclaredFields();
1471 for(Field field : fields) {
1472 String fieldName = field.getName();
1473 XmlElement annotation = field.getAnnotation(XmlElement.class);
1474 if(annotation == null)
1476 String primaryId = annotation.name();
1477 if("##default".equals(primaryId)) {
1478 primaryId = fieldName;
1480 fieldAnnotatedNames.add(primaryId);
1483 HashMap<String, String> nameValues = AAIServiceUtils.keyToHashMap(key, ctx);
1484 Set<String> keyset = nameValues.keySet();
1485 for(String keyName : keyset) {
1486 if(keyName.contains("."))
1489 String tmpKeyName = keyName.replaceAll("_", "-");
1490 String valueToSubstitute = String.format("%s =", tmpKeyName);
1491 if(fieldAnnotatedNames.contains(tmpKeyName) && key.contains(valueToSubstitute)) {
1492 key = key.replace(valueToSubstitute, String.format("%s.%s =", normResource, tmpKeyName));
1502 public String getPathTemplateForResource(String resoourceName, String keys, SvcLogicContext ctx) throws MalformedURLException {
1503 return AAIServiceUtils.getPathForResource(resoourceName, StringUtils.join(keys, " AND "), ctx);
1507 public boolean isDeprecatedFormat(String resource, Map<String, String> nameValues) {
1508 return !AAIServiceUtils.isValidFormat(resource, nameValues);
1511 public AAIRequest getRequestFromResource(String resoourceName) {
1512 return AAIRequest.getRequestFromResource(resoourceName);
1516 * @see org.onap.ccsdk.sli.core.sli.aai.haha#query(org.onap.ccsdk.sli.core.sli.aai.AAIRequest)
1519 public String query(AAIRequest request) throws AAIServiceException {
1520 return executor.get(request);
1524 * @see org.onap.ccsdk.sli.core.sli.aai.haha#save(org.onap.ccsdk.sli.core.sli.aai.AAIRequest)
1527 public String save(AAIRequest request) throws AAIServiceException {
1528 return executor.post(request);
1531 public boolean update(AAIRequest request, String resourceVersion) throws AAIServiceException {
1532 return executor.patch(request, resourceVersion);
1536 * @see org.onap.ccsdk.sli.core.sli.aai.haha#delete(org.onap.ccsdk.sli.core.sli.aai.AAIRequest, java.lang.String)
1539 public boolean delete(AAIRequest request, String resourceVersion) throws AAIServiceException {
1540 return executor.delete(request, resourceVersion);