diff options
author | Matej Perina <matej.perina@pantheon.tech> | 2019-04-03 09:11:35 +0200 |
---|---|---|
committer | Timoney, Dan (dt5972) <dtimoney@att.com> | 2019-08-26 11:49:17 -0400 |
commit | b1dd81ede363508f83c86ed497b8c0815045f8e5 (patch) | |
tree | 878ee0532da4d02d3505fc6cbe93b77fd43fb45e | |
parent | 602de7cdf89676891604130d64e8bc4cc88c05f6 (diff) |
Proposal to remove OSGi dependencies from the CCSDK project
Dependencies on the OSGi frameworks and libraries are removed
by integrating the CCSDK project with the lighty.io.
It's a toolkit that allows to use ODL services (in this case
core services and the Restconf) without the dependency
on the Karaf framework and the Blueprint DI.
In this change are created the lighty.io modules which
initialize and expose same services as the Blueprint DI in
the blueprint.xml files.
More info about the lighty.io - https://lighty.io
Change-Id: Ia9eed2f60c71b7fc2e93b738c857d290b28e9420
Signed-off-by: Matej Perina <matej.perina@pantheon.tech>
Signed-off-by: Samuel Kontris <samuel.kontris@pantheon.tech>
46 files changed, 8199 insertions, 1 deletions
diff --git a/aai-service/lighty/pom.xml b/aai-service/lighty/pom.xml new file mode 100755 index 000000000..c53c9c3ee --- /dev/null +++ b/aai-service/lighty/pom.xml @@ -0,0 +1,48 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.onap.ccsdk.parent</groupId> + <artifactId>binding-parent</artifactId> + <version>1.4.0-SNAPSHOT</version> + <relativePath/> + </parent> + + <groupId>org.onap.ccsdk.sli.adaptors</groupId> + <artifactId>aai-service-lighty</artifactId> + <version>0.6.0-SNAPSHOT</version> + <packaging>jar</packaging> + + <name>ccsdk-sli-adaptors :: aai-service :: ${project.artifactId}</name> + <url>http://maven.apache.org</url> + + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + </properties> + + <dependencyManagement> + <dependencies> + <dependency> + <groupId>org.onap.ccsdk.sli.core</groupId> + <artifactId>ccsdk-lighty-dependency-versions</artifactId> + <version>${project.version}</version> + <type>pom</type> + <scope>import</scope> + </dependency> + </dependencies> + </dependencyManagement> + + <dependencies> + <dependency> + <groupId>io.lighty.core</groupId> + <artifactId>lighty-controller</artifactId> + </dependency> + <dependency> + <groupId>org.onap.ccsdk.sli.adaptors</groupId> + <artifactId>aai-service-provider</artifactId> + <version>${project.version}</version> + <scope>compile</scope> + </dependency> + </dependencies> +</project> diff --git a/aai-service/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/aai/AAIClientLighty.java b/aai-service/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/aai/AAIClientLighty.java new file mode 100755 index 000000000..67d8c07de --- /dev/null +++ b/aai-service/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/aai/AAIClientLighty.java @@ -0,0 +1,94 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : SDN-C + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights + * reserved. + * Modifications Copyright © 2018 IBM. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +/** + * @author Rich Tabedzki + * + */ +package org.onap.ccsdk.sli.adaptors.aai; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Map; +import org.onap.aai.inventory.v16.GenericVnf; +import org.onap.aai.inventory.v16.PhysicalLink; +import org.onap.aai.inventory.v16.SearchResults; +import org.onap.aai.inventory.v16.Vserver; +import org.onap.ccsdk.sli.adaptors.aai.data.notify.NotifyEvent; +import org.onap.ccsdk.sli.core.sli.SvcLogicContext; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.onap.ccsdk.sli.core.sli.SvcLogicJavaPlugin; +import org.onap.ccsdk.sli.core.sli.SvcLogicResource; + +/** + * THIS CLASS IS A COPY OF {@link AAIClient} WITH REMOVED OSGi DEPENDENCIES + */ +public interface AAIClientLighty extends SvcLogicResource, SvcLogicJavaPlugin { + + public SearchResults requestServiceInstanceURL(String svcInstanceId) throws AAIServiceException; + + // VServers + public Vserver requestVServerData(String tenantId, String vserverId, String cloudOwner, String cloudRegionId) throws AAIServiceException; + + public URL requestVserverURLNodeQuery(String vserverName) throws AAIServiceException; + public String getTenantIdFromVserverUrl(URL url); + public String getCloudOwnerFromVserverUrl(URL url); + public String getCloudRegionFromVserverUrl(URL url); + public String getVServerIdFromVserverUrl(URL url, String tennantId); + public Vserver requestVServerDataByURL(URL url) throws AAIServiceException; + + + + // ----------------- Release 1510 ---------------------- + // // GenericVNF + public GenericVnf requestGenericVnfData(String vnfId) throws AAIServiceException; + public boolean postGenericVnfData(String vnfId, GenericVnf request) throws AAIServiceException; + + // Physical Link + public PhysicalLink requestPhysicalLinkData(String vnfId) throws AAIServiceException; + public boolean postPhysicalLinkData(String vnfId, PhysicalLink request) throws AAIServiceException; + public boolean deletePhysicalLinkData(String vnfId, String resourceVersion) throws AAIServiceException; + + // UBB Notify + public boolean sendNotify(NotifyEvent event, String serviceInstanceId, String pathCode) throws AAIServiceException; + + // Node Query - 1602 + public SearchResults requestNodeQuery(String type, String entityIdentifier, String entityName) throws AAIServiceException; + public String requestDataByURL(URL url) throws AAIServiceException; + public GenericVnf requestGenericVnfeNodeQuery(String vnfName) throws AAIServiceException; + + public QueryStatus backup(Map<String, String> params, SvcLogicContext ctx) throws SvcLogicException; + public QueryStatus restore(Map<String, String> params, SvcLogicContext ctx) throws SvcLogicException; + + public void logKeyError(String keys); + + public QueryStatus processResponseData(String rv, String resource, AAIRequestLighty request, String prefix, + SvcLogicContext ctx, Map<String, String> nameValues, String modifier) throws IOException, AAIServiceException ; + public String getPathTemplateForResource(String resoourceName, String join, SvcLogicContext ctx) throws MalformedURLException; + public boolean isDeprecatedFormat(String resource, Map<String, String> nameValues); + + String query(AAIRequestLighty request) throws AAIServiceException; + String save(AAIRequestLighty request) throws AAIServiceException; + boolean delete(AAIRequestLighty request, String resourceVersion) throws AAIServiceException; + boolean update(AAIRequestLighty request, String resourceVersion) throws AAIServiceException; + +} diff --git a/aai-service/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/aai/AAIClientRESTExecutorLighty.java b/aai-service/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/aai/AAIClientRESTExecutorLighty.java new file mode 100755 index 000000000..f4cb55218 --- /dev/null +++ b/aai-service/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/aai/AAIClientRESTExecutorLighty.java @@ -0,0 +1,776 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : SDN-C + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights + * reserved. + * ================================================================================ + * Modifications Copyright (C) 2018 IBM. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.adaptors.aai; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.security.KeyManagementException; +import java.security.KeyStore; +import java.security.NoSuchAlgorithmException; +import java.text.SimpleDateFormat; +import java.util.Properties; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocketFactory; +import org.apache.commons.codec.binary.Base64; +import org.apache.http.impl.EnglishReasonPhraseCatalog; +import org.onap.ccsdk.sli.adaptors.aai.AAIService.TransactionIdTracker; +import org.onap.ccsdk.sli.adaptors.aai.data.AAIDatum; +import org.onap.ccsdk.sli.adaptors.aai.data.ErrorResponse; +import org.onap.ccsdk.sli.adaptors.aai.data.RequestError; +import org.onap.ccsdk.sli.adaptors.aai.data.ResourceVersion; +import org.onap.ccsdk.sli.adaptors.aai.data.ServiceException; +import org.onap.ccsdk.sli.core.sli.MetricLogger; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * THIS CLASS IS A COPY OF {@link AAIClientRESTExecutor} WITH REMOVED OSGi DEPENDENCIES + */ +public class AAIClientRESTExecutorLighty implements AAIExecutorInterfaceLighty { + + private final String truststorePath; + private final String truststorePassword; + private final String keystorePath; + private final String keystorePassword; + private final Boolean ignoreCertificateHostError; + // authentication credentials + private String userName; + private String userPassword; + private final String applicationId; + private static final String HTTP_URL_CONNECTION_RESULT="HttpURLConnection result: {} : {}"; + private static final String ENTRY_DOESNT_EXIST="Entry does not exist."; + + /** + * class Constructor + * @param props - properties to initialize an instance. + */ + public AAIClientRESTExecutorLighty(Properties props) { + super(); + + userName = props.getProperty(AAIService.CLIENT_NAME); + userPassword = props.getProperty(AAIService.CLIENT_PWWD); + + if(userName == null || userName.isEmpty()){ + LOG.debug("Basic user name is not set"); + } + if(userPassword == null || userPassword.isEmpty()) { + LOG.debug("Basic password is not set"); + } + + truststorePath = props.getProperty(AAIService.TRUSTSTORE_PATH); + truststorePassword = props.getProperty(AAIService.TRUSTSTORE_PSSWD); + keystorePath = props.getProperty(AAIService.KEYSTORE_PATH); + keystorePassword = props.getProperty(AAIService.KEYSTORE_PSSWD); + + String tmpApplicationId =props.getProperty(AAIService.APPLICATION_ID); + if(tmpApplicationId == null || tmpApplicationId.isEmpty()) { + tmpApplicationId = "SDNC"; + } + applicationId = tmpApplicationId; + + String iche = props.getProperty(AAIService.CERTIFICATE_HOST_ERROR); + boolean host_error = false; + if(iche != null && !iche.isEmpty()) { + host_error = Boolean.valueOf(iche); + } + + ignoreCertificateHostError = host_error; + + HttpsURLConnection.setDefaultHostnameVerifier( (String string,SSLSession ssls) -> { + return ignoreCertificateHostError; + + }); + + if(truststorePath != null && truststorePassword != null && (new File(truststorePath)).exists()) { + System.setProperty("javax.net.ssl.trustStore", truststorePath); + System.setProperty("javax.net.ssl.trustStorePassword", truststorePassword); + } + + if(keystorePath != null && keystorePassword != null && (new File(keystorePath)).exists()) + { + //both jersey and HttpURLConnection can use this + SSLContext ctx = null; + try { + ctx = SSLContext.getInstance("TLS"); + + KeyManagerFactory kmf = null; + try (FileInputStream fin = new FileInputStream(keystorePath)){ + String storeType = "PKCS12"; + String def = KeyStore.getDefaultType(); + kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + + String extension = keystorePath.substring(keystorePath.lastIndexOf(".") + 1); + + if(extension != null && !extension.isEmpty() && "JKS".equalsIgnoreCase(extension)) { + storeType = "JKS"; + } + KeyStore ks = KeyStore.getInstance(storeType); + + char[] pwd = keystorePassword.toCharArray(); + ks.load(fin, pwd); + kmf.init(ks, pwd); + } catch (Exception ex) { + LOG.error("AAIResource", ex); + } + + ctx.init(kmf.getKeyManagers(), null, null); + + CTX = ctx; + LOG.debug("SSLContext created"); + + } catch (KeyManagementException | NoSuchAlgorithmException exc) { + LOG.error("AAIResource", exc); + } + } + + try { + Field methodsField = HttpURLConnection.class.getDeclaredField("methods"); + methodsField.setAccessible(true); + // get the methods field modifiers + Field modifiersField = Field.class.getDeclaredField("modifiers"); + // bypass the "private" modifier + modifiersField.setAccessible(true); + + // remove the "final" modifier + modifiersField.setInt(methodsField, methodsField.getModifiers() & ~Modifier.FINAL); + + /* valid HTTP methods */ + String[] methods = { + "GET", "POST", "HEAD", "OPTIONS", "PUT", "DELETE", "TRACE", "PATCH" + }; + // set the new methods - including patch + methodsField.set(null, methods); + + } catch (SecurityException | IllegalArgumentException | IllegalAccessException | NoSuchFieldException e) { + LOG.warn("Adding PATCH method", e); + } + LOG.info("AAIResource.ctor initialized."); + + } + + private static final Logger LOG = LoggerFactory.getLogger(AAIService.class); + private static final String NOT_PROVIDED = "NOT PROVIDED"; + private final MetricLogger ml = new MetricLogger(); + + private SSLContext CTX; + + + private int connection_timeout = 300000; + + private int read_timeout = 300000; + + /** + * Returns an String that contains JSON data returned from the AAI Server. + * <p> + * This method always returns immediately, whether or not the + * data exists. + * + * @param request an instance of AAIRequiest representing + * the request made by DirectedGraph node. + * @return the JSON based representation of data instance requested. + * @see String + */ + @Override + public String get(AAIRequestLighty request) throws AAIServiceException { + String response = null; + InputStream inputStream = null; + HttpURLConnection con = null; + URL requestUrl = null; + + StringBuilder errorStringBuilder = new StringBuilder(); + + try { + + if(request.getRequestObject() != null) { + requestUrl = request.getRequestUrl(HttpMethod.POST, null); + requestUrl = appendDepth(requestUrl, request); + con = getConfiguredConnection(requestUrl, HttpMethod.POST); + String json_text = request.toJSONString(); + LOGwriteDateTrace("data", json_text); + logMetricRequest("POST "+requestUrl.getPath(), json_text, requestUrl.getPath()); + OutputStreamWriter osw = new OutputStreamWriter(con.getOutputStream()); + osw.write(json_text); + osw.flush(); + } else { + requestUrl = request.getRequestUrl(HttpMethod.GET, null); + requestUrl = appendDepth(requestUrl, request); + con = getConfiguredConnection(requestUrl, HttpMethod.GET); + logMetricRequest("GET "+requestUrl.getPath(), "", requestUrl.getPath()); + } + + // Check for errors + int responseCode = con.getResponseCode(); + if (responseCode == HttpURLConnection.HTTP_OK) { + inputStream = con.getInputStream(); + } else { + inputStream = con.getErrorStream(); + } + String responseMessage = null; + try { + responseMessage = con.getResponseMessage(); + } catch(Exception exc) { + responseMessage = EnglishReasonPhraseCatalog.INSTANCE.getReason(responseCode,null); + } finally { + if(responseMessage == null) + responseMessage = NOT_PROVIDED; + } + + // Process the response + LOG.info(HTTP_URL_CONNECTION_RESULT, responseCode, responseMessage); + logMetricResponse(responseCode, responseMessage); + + if(inputStream == null) inputStream = new ByteArrayInputStream("".getBytes(StandardCharsets.UTF_8)); + BufferedReader reader = new BufferedReader( new InputStreamReader( inputStream ) ); + + ObjectMapper mapper = AAIService.getObjectMapper(); + + if (responseCode == HttpURLConnection.HTTP_OK) { + StringBuilder stringBuilder = new StringBuilder(); + String line = null; + while( ( line = reader.readLine() ) != null ) { + stringBuilder.append( line ); + } + response = stringBuilder.toString(); + try { + Object object = mapper.readValue(response, Object.class); + LOGwriteEndingTrace(HttpURLConnection.HTTP_OK, responseMessage, mapper.writeValueAsString(object)); + } catch(Exception exc) { + LOGwriteEndingTrace(HttpURLConnection.HTTP_OK, responseMessage, mapper.writeValueAsString(response)); + } + } else if (responseCode == HttpURLConnection.HTTP_NOT_FOUND) { + LOGwriteEndingTrace(responseCode, responseMessage, ENTRY_DOESNT_EXIST); + ErrorResponse errorresponse = null; + try { + errorresponse = mapper.readValue(reader, ErrorResponse.class); + } catch(Exception exc) { + errorresponse = new ErrorResponse(); + RequestError requestError = new RequestError(); + ServiceException serviceException = new ServiceException(); + serviceException.setText(ENTRY_DOESNT_EXIST); + requestError.setServiceException(serviceException); + errorresponse.setRequestError(requestError ); + } + throw new AAIServiceException(responseCode, errorresponse); + } else if (responseCode == HttpURLConnection.HTTP_UNAUTHORIZED) { + StringBuilder stringBuilder = new StringBuilder(); + String line = null; + while( ( line = reader.readLine() ) != null ) { + stringBuilder.append( line ); + } + LOGwriteEndingTrace(responseCode, responseMessage, stringBuilder.toString()); + ServiceException serviceException = new ServiceException(); + serviceException.setMessageId("HTTP_UNAUTHORIZED"); + serviceException.setText(stringBuilder.toString()); + RequestError requestError = new RequestError(); + requestError.setServiceException(serviceException); + ErrorResponse errorresponse = new ErrorResponse(); + errorresponse.setRequestError(requestError); + throw new AAIServiceException(responseCode, errorresponse); + } else { + String line = null; + while( ( line = reader.readLine() ) != null ) { + errorStringBuilder.append("\n").append( line ); + } + + ErrorResponse errorresponse = mapper.readValue(errorStringBuilder.toString(), ErrorResponse.class); + LOGwriteEndingTrace(responseCode, responseMessage, mapper.writeValueAsString(errorresponse)); + throw new AAIServiceException(responseCode, errorresponse); + } + + } catch(AAIServiceException aaiexc) { + throw aaiexc; + } catch (Exception exc) { + LOG.warn(errorStringBuilder.toString(), exc); + throw new AAIServiceException(exc); + } finally { + if(inputStream != null){ + try { + inputStream.close(); + } catch(Exception exc) { + LOG.warn("", exc); + } + } + } + return response; + } + + /** + * Returns an String that contains JSON data returned from the AAI Server. + * <p> + * This method always returns immediately, whether or not the + * data exists. + * + * @param request an instance of AAIRequiest representing + * the request made by DirectedGraph node. + * @return the JSON based representation of data instance requested. + * @see String + */ + @Override + public String post(AAIRequestLighty request) throws AAIServiceException { + InputStream inputStream = null; + + try { + String resourceVersion = null; + AAIDatum instance = request.getRequestObject(); + + try { + Method getResourceVersionMethod = instance.getClass().getMethod("getResourceVersion"); + if(getResourceVersionMethod != null){ + try { + Object object = getResourceVersionMethod.invoke(instance); + if(object != null) + resourceVersion = object.toString(); + } catch (InvocationTargetException exc) { + LOG.warn("", exc); + } + } + } catch(Exception exc) { + LOG.error("", exc); + } + + URL requestUrl = request.getRequestUrl(HttpMethod.PUT, resourceVersion); + HttpURLConnection con = getConfiguredConnection(requestUrl, HttpMethod.PUT); + ObjectMapper mapper = AAIService.getObjectMapper(); + String jsonText = request.toJSONString(); + + LOGwriteDateTrace("data", jsonText); + logMetricRequest("PUT "+requestUrl.getPath(), jsonText, requestUrl.getPath()); + + OutputStreamWriter osw = new OutputStreamWriter(con.getOutputStream()); + osw.write(jsonText); + osw.flush(); + + // Check for errors + int responseCode = con.getResponseCode(); + if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_CREATED || responseCode == HttpURLConnection.HTTP_ACCEPTED || responseCode == HttpURLConnection.HTTP_NO_CONTENT) { + inputStream = con.getInputStream(); + } else { + inputStream = con.getErrorStream(); + } + String responseMessage = null; + try { + responseMessage = con.getResponseMessage(); + } catch(Exception exc) { + responseMessage = EnglishReasonPhraseCatalog.INSTANCE.getReason(responseCode,null); + } finally { + if(responseMessage == null) + responseMessage = NOT_PROVIDED; + } + + LOG.info(HTTP_URL_CONNECTION_RESULT, responseCode, responseMessage); + logMetricResponse(responseCode, responseMessage); + + // Process the response + BufferedReader reader; + String line = null; + reader = new BufferedReader( new InputStreamReader( inputStream ) ); + mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); + + if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_CREATED || responseCode == HttpURLConnection.HTTP_ACCEPTED || responseCode == HttpURLConnection.HTTP_NO_CONTENT) { + StringBuilder stringBuilder = new StringBuilder(); + + while( ( line = reader.readLine() ) != null ) { + stringBuilder.append( line ); + } + LOGwriteEndingTrace(responseCode, responseMessage, (stringBuilder.length() > 0) ? stringBuilder.toString() : "{no-data}"); + return stringBuilder.toString(); + } else { + ErrorResponse errorresponse = mapper.readValue(reader, ErrorResponse.class); + LOGwriteEndingTrace(responseCode, responseMessage, mapper.writeValueAsString(errorresponse)); + + throw new AAIServiceException(responseCode, errorresponse); + } + } catch(AAIServiceException aaiexc) { + throw aaiexc; + } catch (Exception exc) { + LOG.warn("AAIRequestExecutor.post", exc); + throw new AAIServiceException(exc); + } finally { + try { + if(inputStream != null) + inputStream.close(); + } catch (Exception exc) { + LOG.warn("AAIRequestExecutor.post", exc); + } + } + } + + /** + * Returns Boolean that contains completion state of the command executed. + * <p> + * This method always returns immediately, whether or not the + * data exists. + * + * @param request an instance of AAIRequiest representing + * @param resourceVersion a resource version of the data instacne to be deleted. + * the request made by DirectedGraph node. + * @return completion state of the command. + * @see String + */ + @Override + public Boolean delete(AAIRequestLighty request, String resourceVersion) throws AAIServiceException { + Boolean response = null; + InputStream inputStream = null; + + if(resourceVersion == null) { + throw new AAIServiceException("resource-version is required for DELETE request"); + } + + try { + URL requestUrl = request.getRequestUrl(HttpMethod.DELETE, resourceVersion); + HttpURLConnection conn = getConfiguredConnection(requestUrl, HttpMethod.DELETE); + logMetricRequest("DELETE "+requestUrl.getPath(), "", requestUrl.getPath()); + conn.setDoOutput(true); + + // Check for errors + int responseCode = conn.getResponseCode(); + if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_NO_CONTENT) { + inputStream = conn.getInputStream(); + } else { + inputStream = conn.getErrorStream(); + } + String responseMessage = null; + try { + responseMessage = conn.getResponseMessage(); + } catch(Exception exc) { + responseMessage = EnglishReasonPhraseCatalog.INSTANCE.getReason(responseCode,null); + } finally { + if(responseMessage == null) + responseMessage = NOT_PROVIDED; + } + + // Process the response + LOG.info(HTTP_URL_CONNECTION_RESULT, responseCode, responseMessage); + logMetricResponse(responseCode, responseMessage); + + if(inputStream == null) inputStream = new ByteArrayInputStream("".getBytes(StandardCharsets.UTF_8)); + BufferedReader reader = new BufferedReader( new InputStreamReader( inputStream ) ); + String line = null; + + ObjectMapper mapper = AAIService.getObjectMapper(); + + if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_NO_CONTENT) { + StringBuilder stringBuilder = new StringBuilder(); + + while( ( line = reader.readLine() ) != null ) { + stringBuilder.append( line ); + } + LOGwriteEndingTrace(responseCode, responseMessage, stringBuilder.toString()); + response = true; + } else if(responseCode == HttpURLConnection.HTTP_NOT_FOUND ) { + LOGwriteEndingTrace(responseCode, responseMessage, ENTRY_DOESNT_EXIST); + response = false; + } else { + ErrorResponse errorresponse = mapper.readValue(reader, ErrorResponse.class); + LOGwriteEndingTrace(responseCode, responseMessage, mapper.writeValueAsString(errorresponse)); + throw new AAIServiceException(responseCode, errorresponse); + } + } catch(AAIServiceException aaiexc) { + throw aaiexc; + } catch (Exception exc) { + LOG.warn("delete", exc); + throw new AAIServiceException(exc); + } finally { + if(inputStream != null){ + try { + inputStream.close(); + } catch(Exception exc) { + LOG.warn("delete", exc); + } + } + } + return response; + } + + /** + * Returns an String that contains JSON data returned from the AAI Server. + * <p> + * This method always returns immediately, whether or not the + * data exists. + * + * @param request an instance of AAIRequiest representing + * the request made by DirectedGraph node. + * @param clas an definition of the class for which data will be returned + * @return the instance of the class with data. + * @see String + */ + @Override + public Object query(AAIRequestLighty request, Class clas) throws AAIServiceException { + Object response = null; + InputStream inputStream = null; + + try { + URL requestUrl = request.getRequestQueryUrl(HttpMethod.GET); + HttpURLConnection con = getConfiguredConnection(requestUrl, HttpMethod.GET); + logMetricRequest("GET "+requestUrl.getPath(), "", requestUrl.getPath()); + + // Check for errors + int responseCode = con.getResponseCode(); + if (responseCode == HttpURLConnection.HTTP_OK) { + inputStream = con.getInputStream(); + } else { + inputStream = con.getErrorStream(); + } + String responseMessage = null; + try { + responseMessage = con.getResponseMessage(); + } catch(Exception exc) { + responseMessage = EnglishReasonPhraseCatalog.INSTANCE.getReason(responseCode,null); + } finally { + if(responseMessage == null) + responseMessage = NOT_PROVIDED; + } + + LOG.info(HTTP_URL_CONNECTION_RESULT, responseCode, responseMessage); + logMetricResponse(responseCode, responseMessage); + ObjectMapper mapper = AAIService.getObjectMapper(); + + if (responseCode == HttpURLConnection.HTTP_OK) { + // Process the response + BufferedReader reader = new BufferedReader( new InputStreamReader( inputStream ) ); + response = mapper.readValue(reader, clas); + LOGwriteEndingTrace(HttpURLConnection.HTTP_OK, "SUCCESS", mapper.writeValueAsString(response)); + } else if (responseCode == HttpURLConnection.HTTP_NOT_FOUND) { + LOGwriteEndingTrace(responseCode, "HTTP_NOT_FOUND", ENTRY_DOESNT_EXIST); + return response; + } else { + BufferedReader reader = new BufferedReader( new InputStreamReader( inputStream ) ); + ErrorResponse errorresponse = mapper.readValue(reader, ErrorResponse.class); + LOGwriteEndingTrace(responseCode, "FAILURE", mapper.writeValueAsString(errorresponse)); + throw new AAIServiceException(responseCode, errorresponse); + } + + } catch(AAIServiceException aaiexc) { + throw aaiexc; + } catch (Exception exc) { + LOG.warn("GET", exc); + throw new AAIServiceException(exc); + } finally { + if(inputStream != null){ + try { + inputStream.close(); + } catch(Exception exc) { + LOG.warn("GET", exc); + } + } + } + return response; + } + + @Override + public Boolean patch(AAIRequestLighty request, String resourceVersion) throws AAIServiceException { + InputStream inputStream = null; + + try { + AAIDatum instance = request.getRequestObject(); + if(instance instanceof ResourceVersion) { + resourceVersion = ((ResourceVersion)instance).getResourceVersion(); + } + + URL requestUrl = null; + requestUrl = request.getRequestUrl("PATCH", resourceVersion); + HttpURLConnection con = getConfiguredConnection(requestUrl, "PATCH"); + ObjectMapper mapper = AAIService.getObjectMapper(); + String jsonText = request.toJSONString(); + + LOGwriteDateTrace("data", jsonText); + logMetricRequest("PATCH "+requestUrl.getPath(), jsonText, requestUrl.getPath()); + + OutputStreamWriter osw = new OutputStreamWriter(con.getOutputStream()); + osw.write(jsonText); + osw.flush(); + + // Check for errors + int responseCode = con.getResponseCode(); + if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_CREATED || responseCode == HttpURLConnection.HTTP_ACCEPTED || responseCode == HttpURLConnection.HTTP_NO_CONTENT) { + inputStream = con.getInputStream(); + } else { + inputStream = con.getErrorStream(); + } + String responseMessage = null; + try { + responseMessage = con.getResponseMessage(); + } catch(Exception exc) { + LOG.info("Exception occured", exc.getMessage()); + responseMessage = EnglishReasonPhraseCatalog.INSTANCE.getReason(responseCode,null); + } finally { + if(responseMessage == null) + responseMessage = NOT_PROVIDED; + } + + LOG.info(HTTP_URL_CONNECTION_RESULT, responseCode, responseMessage); + logMetricResponse(responseCode, responseMessage); + + // Process the response + BufferedReader reader; + String line = null; + reader = new BufferedReader( new InputStreamReader( inputStream ) ); + mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); + + if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_CREATED || responseCode == HttpURLConnection.HTTP_ACCEPTED || responseCode == HttpURLConnection.HTTP_NO_CONTENT) { + StringBuilder stringBuilder = new StringBuilder(); + + while( ( line = reader.readLine() ) != null ) { + stringBuilder.append( line ); + } + LOGwriteEndingTrace(responseCode, responseMessage, (stringBuilder.length() > 0) ? stringBuilder.toString() : "{no-data}"); + return true; + } else { + StringBuilder stringBuilder = new StringBuilder(); + + while( ( line = reader.readLine() ) != null ) { + stringBuilder.append("\n").append( line ); + } + LOG.info(stringBuilder.toString()); + + + ErrorResponse errorresponse = mapper.readValue(reader, ErrorResponse.class); + LOGwriteEndingTrace(responseCode, responseMessage, mapper.writeValueAsString(errorresponse)); + + throw new AAIServiceException(responseCode, errorresponse); + } + } catch(AAIServiceException aaiexc) { + throw aaiexc; + } catch (Exception exc) { + LOG.warn("AAIRequestExecutor.patch", exc); + throw new AAIServiceException(exc); + } finally { + try { + if(inputStream != null) + inputStream.close(); + } catch (Exception exc) { + LOG.warn("AAIRequestExecutor.patch", exc); + } + } + } + + /** + * + * @param httpReqUrl + * @param method + * @return + * @throws Exception + */ + protected HttpURLConnection getConfiguredConnection(URL httpReqUrl, String method) throws Exception { + HttpURLConnection con = (HttpURLConnection) httpReqUrl.openConnection(); + + // Set up the connection properties + con.setRequestProperty("Connection", "close"); + con.setDoInput(true); + con.setDoOutput(true); + con.setUseCaches(false); + con.setConnectTimeout(connection_timeout); + con.setReadTimeout(read_timeout); + con.setRequestMethod(method); + con.setRequestProperty("Accept", "application/json"); + con.setRequestProperty("Transfer-Encoding","chunked"); + con.setRequestProperty("Content-Type", + "PATCH".equalsIgnoreCase(method) ? "application/merge-patch+json" : "application/json"); + con.setRequestProperty("X-FromAppId", applicationId); + con.setRequestProperty("X-TransactionId", TransactionIdTracker.getNextTransactionId()); + String mlId = ml.getRequestID(); + if (mlId != null && !mlId.isEmpty()) { + LOG.debug(String.format("MetricLogger requestId = %s", mlId)); + con.setRequestProperty(MetricLogger.REQUEST_ID, mlId); + } else { + LOG.debug("MetricLogger requestId is null"); + } + + if (userName != null && !userName.isEmpty() && userPassword != null && !userPassword.isEmpty()) { + String basicAuth = "Basic " + new String(Base64.encodeBase64((userName + ":" + userPassword).getBytes())); + con.setRequestProperty("Authorization", basicAuth); + } + + if (con instanceof HttpsURLConnection && CTX != null) { + SSLSocketFactory sockFact = CTX.getSocketFactory(); + HttpsURLConnection.class.cast(con).setSSLSocketFactory(sockFact); + } + return con; + } + + private URL appendDepth(URL requestUrl, AAIRequestLighty request) throws MalformedURLException { + + String depth = request.requestProperties.getProperty("depth", "1"); + String path = requestUrl.toString(); + if(path.contains("?depth=") || path.contains("&depth=")) { + return requestUrl; + } else { + if(path.contains("?")) { + path = String.format("%s&depth=%s", path, depth); + } else { + path = String.format("%s?depth=%s", path, depth); + } + return new URL(path); + } + } + + public void logMetricRequest(String targetServiceName, String msg, String path){ + String svcInstanceId = ""; + String svcName = null; + String partnerName = null; + String targetEntity = "A&AI"; + String targetVirtualEntity = null; + + ml.logRequest(svcInstanceId, svcName, partnerName, targetEntity, targetServiceName, targetVirtualEntity, msg); + } + + public void logMetricResponse(int responseCode, String responseDescription){ + ml.logResponse(responseCode < 400 ? "COMPLETE" : "ERROR", Integer.toString(responseCode), responseDescription); + } + + protected void LOGwriteFirstTrace(String method, String url) { + String time = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'").format(System.currentTimeMillis()); + LOG.info("A&AI transaction :"); + LOG.info("Request Time : " + time + ", Method : " + method); + LOG.info("Request URL : "+ url); + } + + protected void LOGwriteDateTrace(String name, String data) { + LOG.info("Input - " + name + " : " + data); + } + + protected void LOGwriteEndingTrace(int response_code, String comment, String data) { + LOG.info("Response code : " + response_code +", " + comment); + LOG.info(String.format("Response data : %s", data)); + } + +} diff --git a/aai-service/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/aai/AAIDeclarationsLighty.java b/aai-service/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/aai/AAIDeclarationsLighty.java new file mode 100755 index 000000000..1099f6586 --- /dev/null +++ b/aai-service/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/aai/AAIDeclarationsLighty.java @@ -0,0 +1,1997 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : SDN-C + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights + * reserved. + * ================================================================================ + * Modifications Copyright (C) 2018 IBM. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +/** + * @author Rich Tabedzki + * + */ +package org.onap.ccsdk.sli.adaptors.aai; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.MalformedURLException; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLDecoder; +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import javax.xml.bind.annotation.XmlType; +import org.apache.commons.lang.StringUtils; +import org.onap.aai.inventory.v16.GenericVnf; +import org.onap.aai.inventory.v16.Image; +import org.onap.aai.inventory.v16.Metadata; +import org.onap.aai.inventory.v16.Metadatum; +import org.onap.aai.inventory.v16.RelatedToProperty; +import org.onap.aai.inventory.v16.Relationship; +import org.onap.aai.inventory.v16.RelationshipData; +import org.onap.aai.inventory.v16.RelationshipList; +import org.onap.aai.inventory.v16.ResultData; +import org.onap.aai.inventory.v16.SearchResults; +import org.onap.aai.inventory.v16.ServiceInstance; +import org.onap.aai.inventory.v16.Vlan; +import org.onap.aai.inventory.v16.Vlans; +import org.onap.aai.inventory.v16.Vserver; +import org.onap.ccsdk.sli.adaptors.aai.data.AAIDatum; +import org.onap.ccsdk.sli.adaptors.aai.query.FormattedQueryResultList; +import org.onap.ccsdk.sli.adaptors.aai.query.Result; +import org.onap.ccsdk.sli.core.sli.SvcLogicContext; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * THIS CLASS IS A COPY OF {@link AAIDeclarations} WITH REMOVED OSGi DEPENDENCIES + */ +public abstract class AAIDeclarationsLighty implements AAIClientLighty { + + public static final String TRUSTSTORE_PATH = "org.onap.ccsdk.sli.adaptors.aai.ssl.trust"; + public static final String TRUSTSTORE_PSSWD = "org.onap.ccsdk.sli.adaptors.aai.ssl.trust.psswd"; + public static final String KEYSTORE_PATH = "org.onap.ccsdk.sli.adaptors.aai.ssl.key"; + public static final String KEYSTORE_PSSWD = "org.onap.ccsdk.sli.adaptors.aai.ssl.key.psswd"; + + public static final String APPLICATION_ID = "org.onap.ccsdk.sli.adaptors.aai.application"; + + public static final String CLIENT_NAME = "org.onap.ccsdk.sli.adaptors.aai.client.name"; + public static final String CLIENT_PWWD = "org.onap.ccsdk.sli.adaptors.aai.client.psswd"; + + + public static final String CONNECTION_TIMEOUT = "connection.timeout"; + public static final String READ_TIMEOUT = "read.timeout"; + + public static final String TARGET_URI = "org.onap.ccsdk.sli.adaptors.aai.uri"; + + public static final String AAI_VERSION = "org.onap.ccsdk.sli.adaptors.aai.version"; + + // Availability zones query + public static final String QUERY_PATH = "org.onap.ccsdk.sli.adaptors.aai.path.query"; + + // Update + public static final String UPDATE_PATH = "org.onap.ccsdk.sli.adaptors.aai.update"; + + // Service instance + public static final String SVC_INSTANCE_PATH = "org.onap.ccsdk.sli.adaptors.aai.path.svcinst"; + public static final String SVC_INST_QRY_PATH = "org.onap.ccsdk.sli.adaptors.aai.path.svcinst.query"; + + // VServer + public static final String NETWORK_VSERVER_PATH = "org.onap.ccsdk.sli.adaptors.aai.path.vserver"; + + public static final String VNF_IMAGE_QUERY_PATH = "org.onap.ccsdk.sli.adaptors.aai.path.vnf.image.query"; + + public static final String PARAM_SERVICE_TYPE = "org.onap.ccsdk.sli.adaptors.aai.param.service.type"; + public static final String CERTIFICATE_HOST_ERROR = "org.onap.ccsdk.sli.adaptors.aai.host.certificate.ignore"; + + // UBB Notify + public static final String UBB_NOTIFY_PATH = "org.onap.ccsdk.sli.adaptors.aai.path.notify"; + public static final String SELFLINK_AVPN = "org.onap.ccsdk.sli.adaptors.aai.notify.selflink.avpn"; + public static final String SELFLINK_FQDN = "org.onap.ccsdk.sli.adaptors.aai.notify.selflink.fqdn"; + + //Service + public static final String SERVICE_PATH = "org.onap.ccsdk.sli.adaptors.aai.path.service"; + + // site-pair-sets + public static final String SITE_PAIR_SET_PATH = "org.onap.ccsdk.sli.adaptors.aai.path.site.pair.set"; + + // node query (1602) + public static final String QUERY_NODES_PATH = "org.onap.ccsdk.sli.adaptors.aai.query.nodes"; + + private static final String VERSION_PATTERN = "/v$/"; + + private static final String AAI_SERVICE_EXCEPTION = "AAI Service Exception"; + + protected abstract Logger getLogger(); + public abstract AAIExecutorInterfaceLighty getExecutor(); + + private static final String RELATIONSHIP_DATA= "Retrofitting relationship data: "; + + + @Override + public QueryStatus query(String resource, boolean localOnly, String select, String key, String prefix, String orderBy, SvcLogicContext ctx) + throws SvcLogicException { + + getLogger().debug("AAIService.query \tresource = "+resource); + + String vnfId; + String vnfName = null; + HashMap<String, String> nameValues = AAIServiceUtils.keyToHashMap(key, ctx); + getLogger().debug("key = "+ nameValues.toString()); + + if(!AAIServiceUtils.isValidFormat(resource, nameValues)) { + ctx.setAttribute(String.format("%s.error.message", prefix), String.format("Resource %s is not supported. Key string contains invaid identifiers", resource)); + return QueryStatus.FAILURE; + } + + if(resource == null || resource.isEmpty() || AAIRequest.createRequest(resource, nameValues) == null) { + ctx.setAttribute(String.format("%s.error.message", prefix), String.format("Resource %s is not supported", resource)); + return QueryStatus.FAILURE; + } + + // process data using new model + boolean useNewModelProcessing = true; + // process server query by name the old way + if("vserver".equals(resource) || "vserver2".equals(resource)){ + if(nameValues.containsKey("vserver_name") || nameValues.containsKey("vserver-name") || nameValues.containsKey("vserver.vserver_name") || nameValues.containsKey("vserver.vserver-name")) + useNewModelProcessing = false; + } + if("generic-vnf".equals(resource)){ + if(nameValues.containsKey("vnf_name") || nameValues.containsKey("vnf-name") || nameValues.containsKey("generic_vnf.vnf_name") || nameValues.containsKey("generic-vnf.vnf-name")) + useNewModelProcessing = false; + } + + // process data using new model + if(useNewModelProcessing && AAIRequest.createRequest(resource, nameValues) != null) { + + try { + return newModelQuery(resource, localOnly, select, key, prefix, orderBy, ctx); + } catch (Exception exc) { + getLogger().warn("Failed query - returning FAILURE", exc); + return QueryStatus.FAILURE; + } + } + + ObjectMapper mapper = AAIService.getObjectMapper(); + Map<String,Object> attributes = new HashMap<>(); + + String modifier = null; + + if(resource.contains(":")) { + String[] tokens = resource.split(":"); + resource = tokens[0]; + if(tokens.length > 1) { + modifier = tokens[1]; + } + } + + resource = resource.toLowerCase().replace("-", "_"); + + try { + + switch(resource) { + case "generic_vnf": + vnfId = nameValues.get("vnf_id"); + if(nameValues.containsKey("vnf_id")) + vnfId = nameValues.get("vnf_id"); + else if(nameValues.containsKey("generic_vnf.vnf_name")) + vnfId = nameValues.get("generic_vnf.vserver_name"); + + if(nameValues.containsKey("vnf_name")) + vnfName = nameValues.get("vnf_name"); + else if(nameValues.containsKey("generic_vnf.vnf_name")) + vnfName = nameValues.get("generic_vnf.vnf_name"); + + if(vnfId != null && !vnfId.isEmpty()) { + // at this point of the project this part should not be executed + vnfId = vnfId.trim().replace("'", "").replace("$", "").replace("'", ""); + GenericVnf vnf = this.requestGenericVnfData(vnfId); + if(vnf == null) { + return QueryStatus.NOT_FOUND; + } + + attributes = mapper.convertValue(vnf, attributes.getClass()); + } else if(vnfName != null && !vnfName.isEmpty()) { + try { + vnfName = vnfName.trim().replace("'", "").replace("$", "").replace("'", ""); + GenericVnf vnf = this.requestGenericVnfeNodeQuery(vnfName); + if(vnf == null) { + return QueryStatus.NOT_FOUND; + } + vnfId=vnf.getVnfId(); + nameValues.put("vnf_id", vnfId); + attributes = mapper.convertValue(vnf, attributes.getClass()); + } catch (AAIServiceException exc) { + int errorCode = exc.getReturnCode(); + switch(errorCode) { + case 400: + case 404: + case 412: + break; + default: + getLogger().warn("Caught exception trying to refresh generic VNF", exc); + } + ctx.setAttribute(prefix + ".error.message", exc.getMessage()); + if(errorCode >= 300) { + ctx.setAttribute(prefix + ".error.http.response-code", + Integer.toString(exc.getReturnCode())); + } + return QueryStatus.FAILURE; + } + } else { + getLogger().warn("No arguments are available to process generic VNF"); + return QueryStatus.FAILURE; + } + break; + case "vserver": + case "vserver2": + String vserverName = null; + if(nameValues.containsKey("vserver_name")) + vserverName = nameValues.get("vserver_name"); + else if(nameValues.containsKey("vserver.vserver_name")) + vserverName = nameValues.get("vserver.vserver_name"); + + String vserverId = null; + if(nameValues.containsKey("vserver_id")) + vserverId = nameValues.get("vserver_id"); + if(nameValues.containsKey("vserver.vserver_id")) + vserverId = nameValues.get("vserver.vserver_id"); + String tenantId = nameValues.get("teannt_id"); + + if(vserverName != null) vserverName = vserverName.trim().replace("'", "").replace("$", "").replace("'", ""); + if(vserverId != null) vserverId = vserverId.trim().replace("'", "").replace("$", "").replace("'", ""); + if(tenantId != null) tenantId = tenantId.trim().replace("'", "").replace("$", "").replace("'", ""); + + if (vserverName != null) { + URL vserverUrl = null; + try { + vserverUrl = this.requestVserverURLNodeQuery(vserverName); + } catch (AAIServiceException aaiexc) { + getLogger().warn(AAI_SERVICE_EXCEPTION, aaiexc); + ctx.setAttribute(prefix + ".error.message", aaiexc.getMessage()); + if (aaiexc.getReturnCode() >= 300) { + ctx.setAttribute(prefix + ".error.http" + "" + ".response-code", Integer.toString(aaiexc.getReturnCode())); + } + + if (aaiexc.getReturnCode() == 404) + return QueryStatus.NOT_FOUND; + else + return QueryStatus.FAILURE; + } + if (vserverUrl == null) { + return QueryStatus.NOT_FOUND; + } + + tenantId = getTenantIdFromVserverUrl(vserverUrl); + String cloudOwner = getCloudOwnerFromVserverUrl(vserverUrl); + String cloudRegionId = getCloudRegionFromVserverUrl(vserverUrl); + + Vserver vserver = null; + try { + vserver = this.requestVServerDataByURL(vserverUrl); + } catch (AAIServiceException aaiexc) { + getLogger().warn(AAI_SERVICE_EXCEPTION, aaiexc); + ctx.setAttribute(prefix + ".error.message", aaiexc.getMessage()); + if (aaiexc.getReturnCode() >= 300) { + ctx.setAttribute(prefix + ".error.http" + ".response-code", Integer.toString(aaiexc.getReturnCode())); + } + + if (aaiexc.getReturnCode() == 404) + return QueryStatus.NOT_FOUND; + else + return QueryStatus.FAILURE; + } + if (vserver == null) { + return QueryStatus.NOT_FOUND; + } + attributes = mapper.convertValue(vserver, attributes.getClass()); + if (!attributes.containsKey("tenant-id") && tenantId != null) { + attributes.put("tenant-id", tenantId); + } + if (!attributes.containsKey("cloud-owner") && cloudOwner != null) { + attributes.put("cloud-owner", cloudOwner); + } + if (!attributes.containsKey("cloud-region-id") && cloudRegionId != null) { + attributes.put("cloud-region-id", cloudRegionId); + } + } else if (vserverId != null && tenantId != null) { + Vserver vserver = this.requestVServerData(tenantId, vserverId, "att-aic", "AAIAIC25"); + if(vserver == null) { + return QueryStatus.NOT_FOUND; + } + attributes = mapper.convertValue(vserver, attributes.getClass()); + if(!attributes.containsKey("tenant-id") && tenantId != null){ + attributes.put("tenant-id", tenantId); + } + } else { + return QueryStatus.FAILURE; + } + break; + + default: + return QueryStatus.FAILURE; + } + + QueryStatus retval = QueryStatus.SUCCESS; + + if (attributes == null || attributes.isEmpty()) { + retval = QueryStatus.NOT_FOUND; + getLogger().debug("No data found"); + } else { + if (ctx != null) { + if (prefix != null) { + ArrayList<String> keys = new ArrayList<>(attributes.keySet()); + + int numCols = keys.size(); + + for (int i = 0; i < numCols; i++) { + String colValue; + String colName = keys.get(i); + Object object = attributes.get(colName); + + if(object != null && object instanceof String) { + colValue = (String)object; + + if (prefix != null) { + getLogger().debug("Setting "+prefix + "." + colName.replaceAll("_", "-")+" = "+ colValue); + ctx.setAttribute(prefix + "." + colName.replaceAll("_", "-"), colValue); + } else { + getLogger().debug("Setting " + colValue.replaceAll("_", "-")+" = "+colValue); + ctx.setAttribute(colValue.replaceAll("_", "-"), colValue); + } + } else if(object != null && object instanceof Map) { + if(colName.equals(modifier) || "relationship-list".equals(colName)){ + String localNodifier = modifier; + if(localNodifier == null) + localNodifier = "relationship-list"; + Map<String, Object> properties = (Map<String, Object>)object; + writeMap(properties, prefix+"."+localNodifier, ctx); + } + } + } + } + } + } + getLogger().debug("Query - returning " + retval); + return retval; + + } catch (Exception exc) { + getLogger().warn("Failed query - returning FAILURE", exc); + return QueryStatus.FAILURE; + } + } + + + public void writeMap(Map<String, Object> properties, String prefix, SvcLogicContext ctx) { + Set<String> mapKeys = properties.keySet(); + + for(String mapKey : mapKeys) { + Object entity = properties.get(mapKey); + if(entity instanceof ArrayList) { + writeList((ArrayList<?>)entity, prefix + "." + mapKey, ctx); + } else + if(entity instanceof String || entity instanceof Long || entity instanceof Integer || entity instanceof Boolean) { + ctx.setAttribute(prefix + "." + mapKey, entity.toString()); + getLogger().debug(prefix + "." + mapKey + " : " + entity.toString()); + } else if(entity instanceof Map) { + String localPrefix = prefix; + if(mapKey != null) { + localPrefix = String.format("%s.%s", prefix, mapKey); + } + writeMap( (Map<String, Object>)entity, localPrefix, ctx); + } + } + } + + private void writeList(ArrayList<?> list, String prefix, SvcLogicContext ctx) { + for(int i = 0; i < list.size(); i++ ) { + Object entity = list.get(i); + if(entity instanceof Map) { + writeMap( (Map<String, Object>)entity, prefix + "[" + i + "]", ctx); + } else + if(entity instanceof String || entity instanceof Long || entity instanceof Integer || entity instanceof Boolean) { + ctx.setAttribute(prefix, entity.toString()); + getLogger().debug(prefix + " : " + entity.toString()); + } + } + + if(!list.isEmpty()) { + ctx.setAttribute(prefix + "_length", Integer.toString(list.size())); + getLogger().debug(prefix + "_length" + " : " + Integer.toString(list.size())); + } + } + + @Override + public QueryStatus save(String resource, boolean force, boolean localOnly, String key, Map<String, String> params, String prefix, SvcLogicContext ctx) + throws SvcLogicException { + + getLogger().debug("AAIService.save\tresource="+resource); + HashMap<String, String> nameValues = AAIServiceUtils.keyToHashMap(key, ctx); + + if(!AAIServiceUtils.isValidFormat(resource, nameValues)) { + ctx.setAttribute(String.format("%s.error.message", prefix), String.format("Resource %s is not supported. Key string contains invaid identifiers", resource)); + return QueryStatus.FAILURE; + } + + if(resource == null || resource.isEmpty() || AAIRequest.createRequest(resource, nameValues) == null) { + getLogger().warn("AAIService.save has unspecified resource"); + ctx.setAttribute(String.format("%s.error.message", prefix), String.format("Resource %s is not supported", resource)); + return QueryStatus.FAILURE; + } + // keys passed + getLogger().debug("key = "+ Arrays.toString(nameValues.entrySet().toArray())); + + // process params + if(params.containsKey("prefix")) { + Map<String, String> tmpParams = ctxGetBeginsWith(ctx, params.get("prefix")); + if(!tmpParams.isEmpty()) { + params.putAll(tmpParams); +// params.remove("prefix"); + } + } + // params passed + getLogger().debug("parms = "+ Arrays.toString(params.entrySet().toArray())); + + boolean useNewModelProcessing = true; + // process server query by name the old way + if("vserver".equals(resource) || "vserver2".equals(resource)){ + if(nameValues.containsKey("vserver-name")) { + useNewModelProcessing = false; + } + + if(!params.containsKey("vserver-selflink")) { + + AAIRequest request = AAIRequest.createRequest(resource, nameValues); + URL path = null; + try { + request.processRequestPathValues(nameValues); + path = request.getRequestUrl("GET", null); + params.put("vserver-selflink", path.toString()); + } catch (UnsupportedEncodingException | MalformedURLException | URISyntaxException e) { + getLogger().warn("URL error Exception", e); + params.put("vserver-selflink", "/vserver"); + } + } + } + + // process data using new model + if(useNewModelProcessing && AAIRequest.createRequest(resource, nameValues) != null) { + + try { + if(!resource.contains(":")){ + return newModelSave(resource, force, key, params, prefix, ctx); + } else { + String[] tokens = resource.split(":"); + String localResource = tokens[0]; + String dependency = tokens[1]; + + AAIDatum instance = newModelObjectRequest( localResource, nameValues, prefix, ctx); + if(instance == null) { + return QueryStatus.NOT_FOUND; + } + + switch(dependency){ + case "relationship-list": + newModelProcessRelationshipList(instance, params, prefix, ctx); + break; + case "metadata": + newModelProcessMetadata(instance, params, prefix, ctx); + break; + } + // create a method to update relationship-list + AAIRequestLighty request = AAIRequestLighty.createRequest(localResource, nameValues); + request.setRequestObject(instance); + request.processRequestPathValues(nameValues); + + getExecutor().post(request); + getLogger().debug("Save relationship list - returning SUCCESS"); + return QueryStatus.SUCCESS; + } + } catch (Exception exc) { + ctx.setAttribute(prefix + ".error.message", exc.getMessage()); + if(exc instanceof AAIServiceException) { + AAIServiceException aaiexc = (AAIServiceException)exc; + if(aaiexc.getReturnCode() >= 300) { + ctx.setAttribute(prefix + ".error.http" + ".response-code", Integer.toString(aaiexc.getReturnCode())); + } + + if(aaiexc.getReturnCode() == 404) { + return QueryStatus.NOT_FOUND; + } + } + getLogger().warn("Failed save() - returning FAILURE", exc); + return QueryStatus.FAILURE; + } + } else { + getLogger().debug("Save() request for {} is not supported- returning FAILURE", resource); + return QueryStatus.FAILURE; + } + } + + @Override + public QueryStatus update(String resource, String key, Map<String, String> params, String prefix, SvcLogicContext ctx) throws SvcLogicException { + + resource = resource.toLowerCase(); + HashMap<String, String> nameValues = AAIServiceUtils.keyToHashMap(key, ctx); + getLogger().debug("key = "+ Arrays.toString(nameValues.entrySet().toArray())); + if(!AAIServiceUtils.isValidFormat(resource, nameValues)) { + ctx.setAttribute(String.format("%s.error.message", prefix), String.format("Resource %s is not supported. Key string contains invaid identifiers", resource)); + return QueryStatus.FAILURE; + } + + if(resource == null || resource.isEmpty() || AAIRequest.createRequest(resource, nameValues) == null) { + ctx.setAttribute(String.format("%s.error.message", prefix), String.format("Resource %s is not supported", resource)); + return QueryStatus.FAILURE; + } + + // check if request is for groups + if(!AAIServiceUtils.containsResource(resource, nameValues)) { + ctx.setAttribute(String.format("%s.error.message", prefix), String.format("Resource %s is not permitted in 'update' operation", resource)); + return QueryStatus.FAILURE; + } + + getLogger().debug("parms = "+ Arrays.toString(params.entrySet().toArray())); + + AAIRequestLighty request = AAIRequestLighty.createRequest(resource, nameValues); + request = new UpdateRequestLighty(request, params); + + String[] arguments = request.getArgsList(); + for(String name : arguments) { + String modifiedKey = name.replaceAll("-", "_"); + if(nameValues.containsKey(modifiedKey)) { + String argValue = nameValues.get(modifiedKey); + if(argValue != null) argValue = argValue.trim().replace("'", "").replace("$", "").replace("'", ""); + request.addRequestProperty(name, argValue); + } + } + + try { + QueryStatus retval = QueryStatus.SUCCESS; + + retval = newModelQuery(resource, false, null, key, "tmpDelete", null, ctx); + + if(retval == null || retval != QueryStatus.SUCCESS) { + return retval; + } + + String resourceVersion = ctx.getAttribute("tmpDelete.resource-version"); + if(resourceVersion == null) { + return QueryStatus.NOT_FOUND; + } + params.put("resource-version", resourceVersion); + + request.processRequestPathValues(nameValues); + getExecutor().patch(request, resourceVersion); + } catch(AAIServiceException aaiexc) { + getLogger().warn(AAI_SERVICE_EXCEPTION, aaiexc); + if(aaiexc.getReturnCode() == 404) + return QueryStatus.NOT_FOUND; + else + return QueryStatus.FAILURE; + } catch (Exception exc) { + getLogger().warn("Failed update - returning FAILURE", exc); + return QueryStatus.FAILURE; + } + + getLogger().debug("Update - returning SUCCESS"); + return QueryStatus.SUCCESS; + } + + @Override + public QueryStatus delete(String resource, String key, SvcLogicContext ctx) throws SvcLogicException { + getLogger().debug("AAIService.delete\tresource="+resource); + HashMap<String, String> nameValues = AAIServiceUtils.keyToHashMap(key, ctx); + getLogger().debug("key = "+ Arrays.toString(nameValues.entrySet().toArray())); + + if(!AAIServiceUtils.isValidFormat(resource, nameValues)) { + ctx.setAttribute(String.format("%s.error.message", "aaiData"), String.format("Resource %s is not supported. Key string contains invaid identifiers", resource)); + return QueryStatus.FAILURE; + } + + if(resource == null || resource.isEmpty() || AAIRequest.createRequest(resource, nameValues) == null) { + ctx.setAttribute(String.format("%s.error.message", "tmpDelete"), String.format("Resource %s is not supported", resource)); + return QueryStatus.FAILURE; + } + + // check if request is for groups + if(!AAIServiceUtils.containsResource(resource, nameValues)) { + ctx.setAttribute(String.format("%s.error.message", "tmpDelete"), String.format("Resource %s is not permitted in 'delete' operation", resource)); + return QueryStatus.FAILURE; + } + + if(AAIRequest.createRequest(resource, nameValues) != null) { + if(resource.contains(":")) { + switch (resource.split(":")[1]){ + case "relationship-list": + return processDeleteRelationshipList(resource, key, ctx, nameValues); + case "metadata": + return processDeleteMetadata(resource, key, ctx, nameValues); + } + } + + + try { + QueryStatus retval = QueryStatus.SUCCESS; + + retval = newModelQuery(resource, false, null, key, "tmpDelete", null, ctx); + + if(retval == null || retval != QueryStatus.SUCCESS) { + return retval; + } + + String resourceVersion = ctx.getAttribute("tmpDelete.resource-version"); + if(resourceVersion == null) { + return QueryStatus.NOT_FOUND; + } + + try { + AAIRequestLighty request = AAIRequestLighty.createRequest(resource, nameValues); + if(request == null) { + return QueryStatus.FAILURE; + } + + request.processRequestPathValues(nameValues); + + if(getExecutor().delete(request, resourceVersion)) { + return QueryStatus.SUCCESS; + } + } catch(AAIServiceException aaiexc) { + getLogger().warn(AAI_SERVICE_EXCEPTION, aaiexc); + if(aaiexc.getReturnCode() == 404) + return QueryStatus.NOT_FOUND; + else + return QueryStatus.FAILURE; + + } catch (Exception exc) { + getLogger().warn("requestGenericVnfData", exc); + return QueryStatus.FAILURE; + } + + } catch (Exception exc) { + getLogger().warn("Failed delete - returning FAILURE", exc); + return QueryStatus.FAILURE; + } + } else { + String resourceName = resource; + String identifier = null; + + if(resourceName.contains(":")) { + String[] tokens = resourceName.split(":"); + if(tokens != null && tokens.length > 0) { + resourceName = tokens[0]; + identifier = tokens[1]; + } + } + if("relationship-list".equals(identifier) || "relationshipList".equals(identifier)) { +// RelationshipRequest relationshipRequest = new RelationshipRequest(); + if("generic-vnf".equals(resourceName)){ + String vnfId = nameValues.get("vnf_id"); + String relatedTo = nameValues.get("related_to"); + vnfId = vnfId.trim().replace("'", "").replace("$", "").replace("'", ""); + relatedTo = relatedTo.trim().replace("'", "").replace("$", "").replace("'", ""); + + GenericVnf vnf; + try { + vnf = this.requestGenericVnfData(vnfId); + if(vnf == null) + return QueryStatus.NOT_FOUND; + } catch (AAIServiceException exc) { + getLogger().warn("Failed delete - returning NOT_FOUND", exc); + return QueryStatus.NOT_FOUND; + } + boolean itemRemoved = false; + RelationshipList relationshipList = vnf.getRelationshipList(); + List<Relationship> relationships = relationshipList.getRelationship(); + List<Relationship> iterableList = new LinkedList<>(relationships); + for(Relationship relationship : iterableList) { + if(relationship.getRelatedTo().equals(relatedTo)) { + relationships.remove(relationship); + itemRemoved = true; + } + } + + if(!itemRemoved) + return QueryStatus.NOT_FOUND; + try { + this.postGenericVnfData(vnf.getVnfId(), vnf); + } catch (AAIServiceException exc) { + if(exc.getReturnCode() == 404){ + return QueryStatus.NOT_FOUND; + } else { + getLogger().warn("Failed delete - returning FAILURE", exc); + return QueryStatus.FAILURE; + } + } + return QueryStatus.SUCCESS; + } + } + } + return QueryStatus.FAILURE; + } + + @Override + public QueryStatus exists(String resource, String key, String prefix, SvcLogicContext ctx) throws SvcLogicException { + return query(resource, false, null, key, prefix, null, ctx); + } + + @Override + public QueryStatus isAvailable(String arg0, String arg1, String arg2, SvcLogicContext arg3) + throws SvcLogicException { + throw new SvcLogicException("Method AAIService.isAvailable() has not been implemented yet"); + } + + @Override + public QueryStatus notify(String resource, String action, String key, SvcLogicContext ctx) throws SvcLogicException { + throw new SvcLogicException("Method AAIService.notify() has not been implemented yet"); + } + + // @Override + public QueryStatus newModelQuery(String resource, boolean localOnly, String select, String key, String prefix, String orderBy, SvcLogicContext ctx) { + + QueryStatus retval = QueryStatus.SUCCESS; + String modifier = null; + + HashMap<String, String> nameValues = AAIServiceUtils.keyToHashMap(key, ctx); + if(resource.contains(":")) { + modifier = resource.split(":")[1]; + } + + try { + AAIRequestLighty request = AAIRequestLighty.createRequest(resource, nameValues); + if(request == null) { + return QueryStatus.FAILURE; + } + + Map<String, String> params = new HashMap<>(); + + request.processRequestPathValues(nameValues); + if(nameValues.containsKey("prefix")){ + Map<String, String> tmpParams = ctxGetBeginsWith(ctx, nameValues.get("prefix")); + if(!tmpParams.isEmpty()) { + params.putAll(tmpParams); + } + } + String rv = getExecutor().get(request); + + retval = processResponseData(rv, resource, request, prefix, ctx, nameValues, modifier); + + } catch(AAIServiceException aaiexc) { + getLogger().warn(AAI_SERVICE_EXCEPTION, aaiexc); + int errorCode = aaiexc.getReturnCode(); + ctx.setAttribute(prefix + ".error.message", aaiexc.getMessage()); + if(errorCode >= 300) { + ctx.setAttribute(prefix + ".error.http.response-code", + Integer.toString(aaiexc.getReturnCode())); + } + + if(aaiexc.getReturnCode() == 404) + return QueryStatus.NOT_FOUND; + + return QueryStatus.FAILURE; + } catch (Exception exc) { + getLogger().warn("requestGenericVnfData", exc); + ctx.setAttribute(prefix + ".error.message", exc.getMessage()); + return QueryStatus.FAILURE; + } + + return retval; + } + + public QueryStatus processResponseData(String rv, String resource, AAIRequestLighty request, String prefix, SvcLogicContext ctx, Map<String, String> nameValues, String modifier) throws JsonParseException, JsonMappingException, IOException, AAIServiceException + { + Object response; + + if(rv == null) { + return QueryStatus.NOT_FOUND; + } + + response = request.jsonStringToObject(rv); + if(response == null) { + return QueryStatus.NOT_FOUND; + } + + if("generic-query".equals(resource)) { + SearchResults rd = SearchResults.class.cast(response); + List<ResultData> rdList = rd.getResultData(); + if(rdList == null || rdList.isEmpty()) { + return QueryStatus.NOT_FOUND; + } + ResultData rDatum = rdList.get(0); + nameValues.put("selflink", rDatum.getResourceLink()); + AAIRequestLighty req2 = AAIRequestLighty.createRequest(rDatum.getResourceType(), nameValues); + req2.processRequestPathValues(nameValues); + rv = getExecutor().get(req2); + if(rv == null) { + return QueryStatus.NOT_FOUND; + } + + response = req2.jsonStringToObject(rv); + if(response == null) { + return QueryStatus.NOT_FOUND; + } + } + + if("nodes-query".equals(resource)) { + SearchResults rd = SearchResults.class.cast(response); + List<ResultData> rdList = rd.getResultData(); + if(rdList == null || rdList.isEmpty()) { + return QueryStatus.NOT_FOUND; + } + ResultData rDatum = rdList.get(0); + response = rDatum; + } + + if("formatted-query".equals(resource) || "custom-query".equals(resource)) { + FormattedQueryResultList rd = FormattedQueryResultList.class.cast(response); + List<Result> iRIlist = rd.getResults(); + if(iRIlist == null || iRIlist.isEmpty()) { + return QueryStatus.NOT_FOUND; + } + } + + // process relationship list + // this is a temporary soluton to address the realationship handling changes added in Release 17.07 + try { + Class<?> clazz = response.getClass(); + Method getter = clazz.getMethod("getRelationshipList"); + Object obj = getter.invoke(response); + if(obj != null && obj instanceof RelationshipList) { + RelationshipList list = RelationshipList.class.cast(obj); + AAIServiceUtils.populateRelationshipDataFromPath(list); + } + } catch(Exception exc) { + getLogger().debug(RELATIONSHIP_DATA + exc.getMessage()); + } + + String preFix; + if(prefix == null || prefix.isEmpty()) { + preFix = ""; + } else { + preFix = prefix + "."; + } + + Map<String,Object> props = objectToProperties(response); + Set<String> keys = props.keySet(); + for(String theKey: keys) { + if(getLogger().isTraceEnabled()) + getLogger().trace(theKey); + + Object value = props.get(theKey); + if(value == null) + continue; + Object type = value.getClass(); + if(value instanceof String) { + ctx.setAttribute(preFix + theKey, value.toString()); + continue; + } + if(value instanceof Boolean) { + ctx.setAttribute(preFix + theKey, value.toString()); + continue; + } + if(value instanceof Integer) { + ctx.setAttribute(preFix + theKey, value.toString()); + continue; + } + if(value instanceof Long) { + ctx.setAttribute(preFix + theKey, value.toString()); + continue; + } + + if(value instanceof ArrayList) { + ArrayList<?> array = ArrayList.class.cast(value); + for(int i = 0; i < array.size(); i++) { + writeList(array, String.format("%s.%s", prefix, theKey), ctx); + } + continue; + } + + if("relationship-list".equals(theKey)){ + Map<String, Object> relationshipList = (Map<String, Object>)value; + // we are interested in seeing just the selected relationship + if(theKey.equals(modifier)) { + List<?> relationships = (List<?>)relationshipList.get("relationship"); + if(relationships != null && !relationships.isEmpty()) { + + List newRelationships = new LinkedList(); + newRelationships.addAll(relationships); + + for(Object obj : newRelationships){ + if(obj instanceof Map<?, ?>) { + Map<?, ?> relProperties = (Map<?, ?>)obj; + if(relProperties.containsKey("related-to")) { + Object relPropsRelatedTo = relProperties.get("related-to"); + + String relatedTo = nameValues.get("related_to"); + if(relatedTo != null) { + relatedTo = relatedTo.trim().replace("'", "").replace("$", "").replace("'", ""); + if(!relatedTo.equals(relPropsRelatedTo)) { + relationships.remove(relProperties); + } + continue; + } else { + continue; + } + } + } + } + } + } + writeMap(relationshipList, String.format("%s.%s", prefix, theKey), ctx); + continue; + } + + if(value instanceof Map) { + Map<String, Object> subnetsList = (Map<String, Object>)value; + writeMap(subnetsList, String.format("%s.%s", prefix, theKey), ctx); + continue; + } + + } + return QueryStatus.SUCCESS; + } + + + public QueryStatus newModelBackupRequest(String resource, Map<String, String> params, String prefix, SvcLogicContext ctx) { + + QueryStatus retval = QueryStatus.SUCCESS; + HashMap<String, String> nameValues = new HashMap<>(); + + try { + AAIRequestLighty request = AAIRequestLighty.createRequest(resource, nameValues); + if(request == null) { + return QueryStatus.FAILURE; + } + + boolean argsFound = false; + String[] arguments = request.getArgsList(); + for(String name : arguments) { + String tmpName = name.replaceAll("-", "_"); + String value = params.get(tmpName); + if(value != null && !value.isEmpty()) { + value = value.trim().replace("'", "").replace("$", "").replace("'", ""); + request.addRequestProperty(name, value); + argsFound = true; + } + } + if(!argsFound) { + getLogger().warn("No arguments were found. Terminating backup request."); + return QueryStatus.FAILURE; + } + + String rv = getExecutor().get(request); + ctx.setAttribute(prefix, rv); + } catch(AAIServiceException aaiexc) { + getLogger().warn(AAI_SERVICE_EXCEPTION, aaiexc); + if(aaiexc.getReturnCode() == 404) + return QueryStatus.NOT_FOUND; + + return QueryStatus.FAILURE; + } catch (Exception exc) { + getLogger().warn("newModelBackupRequest", exc); + return QueryStatus.FAILURE; + } + + return retval; + } + + public AAIDatum newModelObjectRequest(String resource, Map<String, String> params, String prefix, SvcLogicContext ctx) + throws AAIServiceException { + + AAIDatum response = null; + + try { + AAIRequestLighty request = AAIRequestLighty.createRequest(resource, params); + if(request == null) { + return null; + } + + request.processRequestPathValues(params); + String rv = getExecutor().get(request); + response = request.jsonStringToObject(rv); + } catch(AAIServiceException aaiexc) { + throw aaiexc; + } catch (Exception exc) { + getLogger().warn("newModelBackupRequest", exc); + throw new AAIServiceException(exc); + } + + return response; + } + + + @Override + public QueryStatus release(String arg0, String arg1, SvcLogicContext arg2) throws SvcLogicException { + throw new SvcLogicException("Method AAIService.release() has not been implemented yet"); + } + + @Override + public QueryStatus reserve(String arg0, String arg1, String arg2, String arg3, SvcLogicContext arg4) + throws SvcLogicException { + throw new SvcLogicException("Method AAIService.reserve() has not been implemented yet"); + } + + private QueryStatus newModelSave(String resource, boolean force, String key, Map<String, String> params, String prefix, SvcLogicContext ctx) { + getLogger().debug("Executing newModelSave for resource : " + resource); + HashMap<String, String> nameValues = AAIServiceUtils.keyToHashMap(key, ctx); + + try { + ArrayList<String> subResources = new ArrayList<>(); + Set<String> set = params.keySet(); + Map<String, Method> setters = new HashMap<>(); + Map<String, Method> getters = new HashMap<>(); + + // 1. find class + AAIRequestLighty request = AAIRequestLighty.createRequest(resource, nameValues); + Class<? extends AAIDatum> resourceClass = request.getModelClass(); + getLogger().debug(resourceClass.getName()); + AAIDatum instance = resourceClass.newInstance(); + + { + Annotation[] annotations = resourceClass.getAnnotations(); + for(Annotation annotation : annotations) { + Class<? extends Annotation> anotationType = annotation.annotationType(); + String annotationName = anotationType.getName(); + + // 2. find string property setters and getters for the lists + if("javax.xml.bind.annotation.XmlType".equals(annotationName)){ + XmlType order = (XmlType)annotation; + String[] values = order.propOrder(); + for(String value : values) { + String id = AAIServiceUtils.camelCaseToDashedString(value); + Field field = resourceClass.getDeclaredField(value); + Class<?> type = field.getType(); + Method setter = null; + try { + setter = resourceClass.getMethod("set"+StringUtils.capitalize(value), type); + if(type.getName().startsWith("java.lang") || "boolean".equals(type.getName()) || "long".equals(type.getName()) || "int".equals(type.getName())) { + try { + Object arglist[] = new Object[1]; + arglist[0] = params.get(id); + + if(arglist[0] != null) { + if(!type.getName().equals("java.lang.String")) { +// getLogger().debug(String.format("Processing %s with parameter %s", types[0].getName(), value)); + if("java.lang.Long".equals(type.getName()) || "java.lang.Integer".equals(type.getName())) { + String fv = params.get(id); + if(fv == null || fv.isEmpty()) { + arglist[0] = null; + } else { + arglist[0] = valueOf(type, params.get(id)); + } + } else if("boolean".equals(type.getName())) { + arglist[0] = valueOf(Boolean.class, params.get(id)); + } else if("int".equals(type.getName())) { + arglist[0] = valueOf(Integer.class, params.get(id)); + } else if("long".equals(type.getName())) { + String fv = params.get(id); + if(fv == null || fv.isEmpty()) { + arglist[0] = null; + } else { + arglist[0] = valueOf(Long.class, params.get(id)); + } + } else { + arglist[0] = valueOf(type, params.get(id)); + } + } + Object obj = setter.invoke(instance, arglist); + } + set.remove(id); + + } catch (Exception x) { + Throwable cause = x.getCause(); + getLogger().warn("Failed process for " + resourceClass.getName(), x); + } + } else if("java.util.List".equals(type.getName())) { + List<String> newValues = new ArrayList<>(); + String length = id+"_length"; + if(!params.isEmpty() && params.containsKey(length)) { + String tmp = params.get(length); + int count = Integer.parseInt(tmp); + for(int i=0; i<count; i++) { + String tmpValue = params.get(String.format("%s[%d]", id, i)); + newValues.add(tmpValue); + } + if(!newValues.isEmpty()) { + Object o = setter.invoke(instance, newValues); + } + } + set.remove(id); + } else { + setters.put(id, setter); + } + } catch(Exception exc) { + getLogger().warn(AAI_SERVICE_EXCEPTION, exc); + } + + Method getter; + try { + getter = resourceClass.getMethod("get"+StringUtils.capitalize(value)); + if(!type.getName().equals("java.lang.String")) { + getters.put(id, getter); + } + } catch(Exception exc) { + getLogger().warn(AAI_SERVICE_EXCEPTION, exc); + } + + } + subResources.addAll(Arrays.asList(values)); + } + } + } + + // remove getters that have matching setter + for(String setKey : setters.keySet()) { + if(getters.containsKey(setKey)) { + getters.remove(setKey); + } + } + + Set<String> relationshipKeys = new TreeSet<>(); + Set<String> vlansKeys = new TreeSet<>(); + Set<String> metadataKeys = new TreeSet<>(); + + for(String attribute : set) { + String value = params.get(attribute); + if(attribute.startsWith("relationship-list")) { + relationshipKeys.add(attribute); + } else if(attribute.startsWith("vlans")) { + vlansKeys.add(attribute); + } else if(attribute.startsWith("metadata")) { + metadataKeys.add(attribute); + } + } + // 3. find list property getters + for(String attribute : set) { + String value = params.get(attribute); + Method method = getters.get(attribute); + if(method != null) { + try { + Object arglist[] = new Object[0]; +// arglist[0] = value; + Class<?>[] types = method.getParameterTypes(); + if(types.length == 0){ + Object o = method.invoke(instance, arglist); + if(o instanceof ArrayList) { + ArrayList<String> values = (ArrayList<String>)o; + value = value.replace("[", "").replace("]", ""); + List<String> items = Arrays.asList(value.split("\\s*,\\s*")); + for(String s : items) { + values.add(s.trim()); + } + } + } + } catch (Exception x) { + Throwable cause = x.getCause(); + getLogger().warn("Failed process for " + resourceClass.getName(), x); + } + } + } + // 4. Process Relationships + // add relationship list + if( (subResources.contains("relationship-list") || subResources.contains("relationshipList")) && !relationshipKeys.isEmpty()) { + RelationshipList relationshipList = null; + Object obj = null; + Method getRelationshipListMethod = null; + try { + getRelationshipListMethod = resourceClass.getMethod("getRelationshipList"); + } catch(Exception exc) { + getLogger().debug(RELATIONSHIP_DATA + exc.getMessage()); + } + + if(getRelationshipListMethod != null){ + try { + obj = getRelationshipListMethod.invoke(instance); + } catch (InvocationTargetException x) { + Throwable cause = x.getCause(); + } + } + if(obj != null && obj instanceof RelationshipList){ + relationshipList = (RelationshipList)obj; + } else { + relationshipList = new RelationshipList(); + Method setRelationshipListMethod = resourceClass.getMethod("setRelationshipList", RelationshipList.class); + if(setRelationshipListMethod != null){ + try { + Object arglist[] = new Object[1]; + arglist[0] = relationshipList; + + obj = setRelationshipListMethod.invoke(instance, arglist); + } catch (InvocationTargetException x) { + Throwable cause = x.getCause(); + } + } + } + + List<Relationship> relationships = relationshipList.getRelationship(); + + int i = 0; + while(true){ + String searchKey = "relationship-list.relationship[" + i + "].related-to"; + if(!params.containsKey(searchKey)) + break; + int j = 0; + String relatedTo = params.get(searchKey); + String relatedLinkKey = "relationship-list.relationship[" + i + "].related-link"; + String relatedLink = null; + if(params.containsKey(relatedLinkKey)) { + relatedLink = params.get(relatedLinkKey); + } + Relationship relationship = new Relationship(); + relationships.add(relationship); + relationship.setRelatedTo(relatedTo); + String relationshipLabel = "relationship-list.relationship[" + i + "].relationship-label"; + if(params.containsKey(searchKey)) { + relationship.setRelationshipLabel(params.get(relationshipLabel)); + } + getLogger().debug("About to process related link of {}", relatedLink); + if(relatedLink != null) { + if(relatedLink.contains("v$")) + relatedLink = relatedLink.replace(VERSION_PATTERN, "/v16/"); + relationship.setRelatedLink(relatedLink); + } else { + Map<String, String> relParams = new HashMap<>(); + + while(true) { + String searchRelationshipKey = "relationship-list.relationship[" + i + "].relationship-data[" + j + "].relationship-key"; + String searchRelationshipValue = "relationship-list.relationship[" + i + "].relationship-data[" + j + "].relationship-value"; + if(!params.containsKey(searchRelationshipKey)) + break; + + relParams.put(params.get(searchRelationshipKey), params.get(searchRelationshipValue)); + j++; + } + AAIRequest rlRequest = AAIRequest.createRequest(relatedTo, relParams); + for(Map.Entry<String,String> entry : relParams.entrySet()) { + rlRequest.addRequestProperty(entry.getKey(), entry.getValue()); + } + String path = rlRequest.updatePathDataValues(null); + relationship.setRelatedLink(path); + } + { + int k = 0; + // process related to properties + Map<String, String> relParams = new HashMap<String, String>(); + + while(true) { + String searchRelatedToKey = "relationship-list.relationship[" + i + "].related-to-property[" + k + "].property-key"; + String searchRelatedToValue = "relationship-list.relationship[" + i + "].related-to-property[" + k + "].property-value"; + if(!params.containsKey(searchRelatedToKey)) + break; + + RelatedToProperty relDatum = new RelatedToProperty(); + relDatum.setPropertyKey(params.get(searchRelatedToKey)); + relDatum.setPropertyValue(params.get(searchRelatedToValue)); + relationship.getRelatedToProperty().add(relDatum); + + relParams.put(params.get(searchRelatedToKey), params.get(searchRelatedToValue)); + k++; + } + } + i++; + } + } + + // 4. vlans + if(subResources.contains("vlans") && !vlansKeys.isEmpty()) { + Object obj = null; + Vlans vlanList = null; + Method getVLansMethod = resourceClass.getMethod("getVlans"); + if(getVLansMethod != null){ + try { + obj = getVLansMethod.invoke(instance); + } catch (InvocationTargetException x) { + Throwable cause = x.getCause(); + } + } + if(obj != null && obj instanceof Vlans){ + vlanList = (Vlans)obj; + } else { + vlanList = new Vlans(); + Method setVlansMethod = resourceClass.getMethod("setVlans", Vlans.class); + if(setVlansMethod != null){ + try { + Object arglist[] = new Object[1]; + arglist[0] = vlanList; + + obj = setVlansMethod.invoke(instance, arglist); + } catch (InvocationTargetException x) { + Throwable cause = x.getCause(); + } + } + } + + int i = 0; + while(true){ + String searchKey = "vlans.vlan[" + i + "].vlan-interface"; + if(!params.containsKey(searchKey)) + break; + + String vlanInterface = params.get("vlans.vlan[" + i + "].vlan-interface"); + String vlanIdInner = params.get("vlans.vlan[" + i + "].vlan-id-inner"); + String vlanIdOute = params.get("vlans.vlan[" + i + "].vlan-id-outer"); + String speedValue = params.get("vlans.vlan[" + i + "].speed-value"); + String speedUnits = params.get("vlans.vlan[" + i + "].speed-units"); + + Vlan vlan = new Vlan(); + vlan.setVlanInterface(vlanInterface); + + if(vlanIdInner != null) { + Long iVlanIdInner = Long.parseLong(vlanIdInner); + vlan.setVlanIdInner(iVlanIdInner); + } + + if(vlanIdOute != null) { + Long iVlanIdOuter = Long.parseLong(vlanIdOute); + vlan.setVlanIdOuter(iVlanIdOuter); + } + + if(speedValue != null) { + vlan.setSpeedValue(speedValue); + vlan.setSpeedUnits(speedUnits); + } + + vlanList.getVlan().add(vlan); + i++; + } + } + + // 5. metadata + if(subResources.contains("metadata") && !metadataKeys.isEmpty()) { + Object obj = null; + Metadata metadataList = null; + Method getMetadataMethod = resourceClass.getMethod("getMetadata"); + if(getMetadataMethod != null){ + try { + obj = getMetadataMethod.invoke(instance); + } catch (InvocationTargetException x) { + Throwable cause = x.getCause(); + } + } + if(obj != null && obj instanceof Metadata){ + metadataList = (Metadata)obj; + } else { + metadataList = new Metadata(); + Method setMetadataMethod = resourceClass.getMethod("setMetadata", Metadata.class); + if(setMetadataMethod != null){ + try { + Object arglist[] = new Object[1]; + arglist[0] = metadataList; + + obj = setMetadataMethod.invoke(instance, arglist); + } catch (InvocationTargetException x) { + Throwable cause = x.getCause(); + } + } + } + + // process data + int i = 0; + while(true){ + String metaKey = "metadata.metadatum[" + i + "].meta-key"; + if(!params.containsKey(metaKey)) + break; + + String metaValue = params.get("metadata.metadatum[" + i + "].meta-value"); + + Metadatum vlan = new Metadatum(); + vlan.setMetaname(metaKey); + vlan.setMetaval(metaValue); + + metadataList.getMetadatum().add(vlan); + i++; + } + + } + + + // 6. Prepare AAI request + String[] args = request.getArgsList(); + for(String arg : args) { + String modifiedKey = arg.replaceAll("-", "_"); + if(nameValues.containsKey(modifiedKey)) { + String argValue = nameValues.get(modifiedKey); + if(argValue != null) argValue = argValue.trim().replace("'", "").replace("$", "").replace("'", ""); + request.addRequestProperty(arg, argValue); + } + } + + request.processRequestPathValues(nameValues); + request.setRequestObject(instance); + Object response = getExecutor().post(request); + if(request.expectsDataFromPUTRequest()){ + if(response != null && response instanceof String) { + String rv = response.toString(); + QueryStatus retval = processResponseData(rv, resource, request, prefix, ctx, nameValues, null); + getLogger().debug("newModelSave - returning " + retval.toString()); + return retval; + } + } + + } catch(AAIServiceException exc){ + ctx.setAttribute(prefix + ".error.message", exc.getMessage()); + int returnCode = exc.getReturnCode(); + if(returnCode >= 300) { + ctx.setAttribute(prefix + ".error.http.response-code", + Integer.toString(exc.getReturnCode())); + } + + if(returnCode == 400 || returnCode == 412) + return QueryStatus.FAILURE; + else if(returnCode == 404) + return QueryStatus.NOT_FOUND; + else { + getLogger().warn("Failed newModelSave - returning FAILURE", exc); + return QueryStatus.FAILURE; + } + } catch(Exception exc){ + getLogger().warn("Failed newModelSave - returning FAILURE", exc); + ctx.setAttribute(prefix + ".error.message", exc.getMessage()); + return QueryStatus.FAILURE; + } + + getLogger().debug("newModelSave - returning SUCCESS"); + return QueryStatus.SUCCESS; + } + + private QueryStatus newModelProcessRelationshipList(Object instance, Map<String, String> params, String prefix, SvcLogicContext ctx) throws Exception { + + Class resourceClass = instance.getClass(); + + Set<String> relationshipKeys = new TreeSet<>(); + + Set<String> set = params.keySet(); + + for(String attribute : set) { + String value = params.get(attribute); + + if(attribute.startsWith("relationship-list")) { + relationshipKeys.add(attribute); + } + } + + // 3. Process Relationships + // add relationship list + if(!relationshipKeys.isEmpty()) { + RelationshipList relationshipList; + Object obj = null; + Method getRelationshipListMethod = null; + try { + getRelationshipListMethod = resourceClass.getMethod("getRelationshipList"); + } catch(Exception exc) { + getLogger().debug(RELATIONSHIP_DATA + exc.getMessage()); + } + if(getRelationshipListMethod != null){ + try { + obj = getRelationshipListMethod.invoke(instance); + } catch (InvocationTargetException x) { + Throwable cause = x.getCause(); + } + } + if(obj != null && obj instanceof RelationshipList){ + relationshipList = (RelationshipList)obj; + } else { + relationshipList = new RelationshipList(); + Method setRelationshipListMethod = resourceClass.getMethod("setRelationshipList", RelationshipList.class); + if(setRelationshipListMethod != null){ + try { + Object arglist[] = new Object[1]; + arglist[0] = relationshipList; + + obj = setRelationshipListMethod.invoke(instance, arglist); + } catch (InvocationTargetException x) { + Throwable cause = x.getCause(); + } + } + } + + boolean createdNewRelationships = false; + List<Relationship> relationships = relationshipList.getRelationship(); + if(relationships == null) { + relationships = new ArrayList<>(); + createdNewRelationships = true; + } + + int i = 0; + while(true){ + String searchKey = "relationship-list.relationship[" + i + "].related-to"; + if(!params.containsKey(searchKey)) + break; + + String relatedTo = params.get(searchKey); + String relatedLinkKey = "relationship-list.relationship[" + i + "].related-link"; + String relatedLink = null; + if(params.containsKey(relatedLinkKey)) { + relatedLink = params.get(relatedLinkKey); + } + + Relationship relationship = new Relationship(); + relationships.add(relationship); + relationship.setRelatedTo(relatedTo); + + String relationshipLabel = "relationship-list.relationship[" + i + "].relationship-label"; + if(params.containsKey(searchKey)) { + relationship.setRelationshipLabel(params.get(relationshipLabel)); + } + + if (relatedLink != null) { + if(relatedLink.contains("v$")) + relatedLink = relatedLink.replace(VERSION_PATTERN, AAIRequest.getSupportedAAIVersion()); + relationship.setRelatedLink(relatedLink); + } else { + Map<String, String> relParams = new HashMap<>(); + int j = 0; + + while (true) { + String searchRelationshipKey = "relationship-list.relationship[" + i + "].relationship-data[" + + j + "].relationship-key"; + String searchRelationshipValue = "relationship-list.relationship[" + i + "].relationship-data[" + + j + "].relationship-value"; + if (!params.containsKey(searchRelationshipKey)) + break; + + RelationshipData relDatum = new RelationshipData(); + relDatum.setRelationshipKey(params.get(searchRelationshipKey)); + relDatum.setRelationshipValue(params.get(searchRelationshipValue)); + relationship.getRelationshipData().add(relDatum); + + relParams.put(params.get(searchRelationshipKey), params.get(searchRelationshipValue)); + j++; + } + AAIRequest rlRequest = AAIRequest.createRequest(relatedTo, relParams); + for (Map.Entry<String, String> entry : relParams.entrySet()) { + rlRequest.addRequestProperty(entry.getKey(), entry.getValue()); + } + String path = rlRequest.updatePathDataValues(null); + relationship.setRelatedLink(path); + } + { + int k = 0; + // process related to properties + Map<String, String> relParams = new HashMap<String, String>(); + + while(true) { + String searchRelatedToKey = "relationship-list.relationship[" + i + "].related-to-property[" + k + "].property-key"; + String searchRelatedToValue = "relationship-list.relationship[" + i + "].related-to-property[" + k + "].property-value"; + if(!params.containsKey(searchRelatedToKey)) + break; + + RelatedToProperty relDatum = new RelatedToProperty(); + relDatum.setPropertyKey(params.get(searchRelatedToKey)); + relDatum.setPropertyValue(params.get(searchRelatedToValue)); + relationship.getRelatedToProperty().add(relDatum); + + relParams.put(params.get(searchRelatedToKey), params.get(searchRelatedToValue)); + k++; + } + } + + i++; + } + } + + return QueryStatus.SUCCESS; + } + + private QueryStatus newModelProcessMetadata(Object instance, Map<String, String> params, String prefix, SvcLogicContext ctx) throws Exception { + + if (!(instance instanceof ServiceInstance) && !(instance instanceof Image)) { + throw new IllegalArgumentException("request is not applicable for selected request"); + } + + Class resourceClass = instance.getClass(); + Set<String> metadataKeys = new TreeSet<String>(); + Set<String> set = params.keySet(); + for(String attribute : set) { + if(attribute.startsWith("metadata")) { + metadataKeys.add(attribute); + } + } + + // 3. Process Metadata + // add metadata + if(!metadataKeys.isEmpty()) { + Metadata metadata = null; + Object obj = null; + Method getMetadataMethod = resourceClass.getMethod("getMetadata"); + if(getMetadataMethod != null){ + try { + obj = getMetadataMethod.invoke(instance); + } catch (InvocationTargetException x) { + Throwable cause = x.getCause(); + } + } + if(obj != null && obj instanceof Metadata){ + metadata = (Metadata)obj; + } else { + metadata = new Metadata(); + Method setMetadataMethod = resourceClass.getMethod("setMetadata", Metadata.class); + if(setMetadataMethod != null){ + try { + setMetadataMethod.invoke(instance, metadata); + } catch (InvocationTargetException x) { + } + } + } + + List<Metadatum> metadatumList = metadata.getMetadatum(); + int i = 0; + while(true){ + String metaNameKey = "metadata.metadatum[" + i + "].metaname"; + String metaValueKey = "metadata.metadatum[" + i + "].metaval"; + if(!params.containsKey(metaNameKey) || !params.containsKey(metaValueKey)) + break; + + Metadatum metadatum = new Metadatum(); + metadatum.setMetaname(params.get(metaNameKey)); + metadatum.setMetaval(params.get(metaValueKey)); + metadatumList.add(metadatum); + + i++; + } + } + + return QueryStatus.SUCCESS; + } + + private Relationship findRelationship(List<Relationship> relationships, String relatedTo) { + if(relatedTo == null) + return null; + + for(Relationship relationship : relationships) { + if(relationship.getRelatedTo().equals(relatedTo)){ + return relationship; + } + } + return null; + } + + + public QueryStatus backup(Map<String, String> params, SvcLogicContext ctx) throws SvcLogicException { + String resource = params.get("resource").toLowerCase(); + String prefix = params.get("data-key"); + + HashMap<String, String> nameValues = new HashMap<>(); + if(AAIRequest.createRequest(resource, nameValues) != null) { + + try { + return newModelBackupRequest(resource, params, prefix, ctx); + } catch (Exception exc) { + getLogger().warn("Failed backup - returning FAILURE", exc); + return QueryStatus.FAILURE; + } + } + + return QueryStatus.NOT_FOUND; + } + + @Override + public QueryStatus restore(Map<String, String> params, SvcLogicContext ctx) throws SvcLogicException { + + QueryStatus retval = QueryStatus.SUCCESS; + String resource = params.get("resource").toLowerCase(); + String prefix = params.get("data-key"); + + HashMap<String, String> nameValues = new HashMap<>(); + if(AAIRequest.createRequest(resource, nameValues) != null) { + + try { + retval = newModelBackupRequest(resource, params, "tmpRestore", ctx); + if(retval == QueryStatus.SUCCESS) { + ctx.setAttribute("tmpRestore", null); + } + } catch (Exception exc) { + getLogger().warn("Failed restore - returning FAILURE", exc); + return QueryStatus.FAILURE; + } + } + + return QueryStatus.NOT_FOUND; + } + + protected Map<String, Object> objectToProperties(Object object) { + ObjectMapper mapper = AAIService.getObjectMapper(); + return mapper.convertValue(object, Map.class); + } + + static <T> T valueOf(Class<T> klazz, String arg) { + Exception cause = null; + T ret = null; + try { + ret = klazz.cast(klazz.getDeclaredMethod("valueOf", String.class).invoke(null, arg)); + } catch (NoSuchMethodException exc) { + LoggerFactory.getLogger(AAIService.class).warn("Wrong data type", exc); + ret = klazz.cast(arg); + } catch (IllegalAccessException e) { + cause = e; + } catch (InvocationTargetException e) { + cause = e; + } + if (cause == null) { + return ret; + } else { + throw new IllegalArgumentException(cause); + } + } + + private QueryStatus processDeleteRelationshipList(String resource, String key, SvcLogicContext ctx, HashMap<String, String> nameValues) { + try { + AAIRequest request = AAIRequest.createRequest(resource.split(":")[0], nameValues); + if(request == null) { + return QueryStatus.FAILURE; + } + + request.processRequestPathValues(nameValues); + URL url = request.getRequestUrl("GET", null); + + Class resourceClass = request.getModelClass(); + Object instance = getResource(url.toString(), resourceClass); + if(instance == null) + return QueryStatus.NOT_FOUND; + + // get resource version + String resourceVersion = null; + Method getResourceVersionMethod = resourceClass.getMethod("getResourceVersion"); + if(getResourceVersionMethod != null){ + try { + Object object = getResourceVersionMethod.invoke(instance); + if(object != null) + resourceVersion = object.toString(); + } catch (InvocationTargetException exc) { + getLogger().warn("Retrieving resource version", exc); + } + } + + RelationshipList relationshipList = null; + Object obj = null; + Method getRelationshipListMethod = null; + try { + getRelationshipListMethod = resourceClass.getMethod("getRelationshipList"); + } catch(Exception exc) { + getLogger().debug(RELATIONSHIP_DATA + exc.getMessage()); + } + if(getRelationshipListMethod != null){ + try { + obj = getRelationshipListMethod.invoke(instance); + } catch (InvocationTargetException x) { + Throwable cause = x.getCause(); + } + } + if(obj != null && obj instanceof RelationshipList){ + relationshipList = (RelationshipList)obj; + } else { + getLogger().debug("No relationships found to process."); + return QueryStatus.NOT_FOUND; + } + + if(relationshipList.getRelationship() == null || relationshipList.getRelationship().isEmpty()) { + return QueryStatus.NOT_FOUND; + } + String relatedTo = nameValues.get("related_to"); + if(relatedTo == null) { + return QueryStatus.FAILURE; + } + + relatedTo = relatedTo.replaceAll("_", "-"); + + String relatedLink = nameValues.get("relationship.related_link"); + if(relatedLink != null) { + relatedLink = URLDecoder.decode(relatedLink, "UTF-8"); + } + + List<Relationship> relationships = relationshipList.getRelationship(); + List<Relationship> relationshipsToDelete = new LinkedList<>(); + + for(Relationship relationship : relationships) { + if(relatedTo.equals(relationship.getRelatedTo())) { + if(relatedLink != null) { + if(relationship.getRelatedLink() != null ) { + String localRelatedLink = relationship.getRelatedLink(); + localRelatedLink = URLDecoder.decode(localRelatedLink, "UTF-8"); + if(localRelatedLink.endsWith(relatedLink)) { + getLogger().debug(String.format("Found relationship of '%s' to keyword '%s'", relationship.getRelatedTo(), relatedTo)); + relationshipsToDelete.add(relationship); + } + } + } else { + getLogger().debug(String.format("Found relationship of '%s' to keyword '%s'", relationship.getRelatedTo(), relatedTo)); + relationshipsToDelete.add(relationship); + } + } + } + if(relationshipsToDelete == null || relationshipsToDelete.isEmpty()) { + getLogger().info(String.format("Relationship has not been found for %s", key)); + return QueryStatus.NOT_FOUND; + } + + String path = url.toString(); + path = path + "/relationship-list/relationship"; + URL deleteUrl = new URL(path); + + ObjectMapper mapper = AAIService.getObjectMapper(); + + boolean cumulativeResponse = true; + + for(Relationship targetRelationship : relationshipsToDelete) { + String json_text = mapper.writeValueAsString(targetRelationship); + boolean response = deleteList(deleteUrl, json_text); + if(!response) + cumulativeResponse = response; + + } + + if(!cumulativeResponse) + return QueryStatus.FAILURE; + + return QueryStatus.SUCCESS; + + } catch(Exception exc) { + getLogger().warn("processDelete", exc); + return QueryStatus.FAILURE; + } + } + + private QueryStatus processDeleteMetadata(String resource, String key, SvcLogicContext ctx, HashMap<String, String> nameValues) { + try { + AAIRequest request = AAIRequest.createRequest(resource, nameValues); + if(request == null) { + return QueryStatus.FAILURE; + } + + request.processRequestPathValues(nameValues); + URL url = request.getRequestUrl("GET", null); + + Class<?> resourceClass = request.getModelClass(); + Object instance = getResource(url.toString(), resourceClass); + + // get resource version + String resourceVersion = null; + Method getResourceVersionMethod = resourceClass.getMethod("getResourceVersion"); + if(getResourceVersionMethod != null){ + try { + resourceVersion = (String) getResourceVersionMethod.invoke(instance); + } catch (InvocationTargetException x) { + } + } + + Metadata metadata = null; + Object obj = null; + Method getMetadataMethod = resourceClass.getMethod("getMetadata"); + if(getMetadataMethod != null){ + try { + obj = getMetadataMethod.invoke(instance); + } catch (InvocationTargetException x) { + Throwable cause = x.getCause(); + } + } + if(obj != null && obj instanceof Metadata){ + metadata = (Metadata)obj; + } else { + getLogger().debug("No metadata found to process."); + return QueryStatus.NOT_FOUND; + } + + if(metadata.getMetadatum() == null || metadata.getMetadatum().isEmpty()) { + return QueryStatus.NOT_FOUND; + } + + List<Metadatum> metadatumList = metadata.getMetadatum(); + Metadatum metadatumToDelete = null; + + final String metaname = nameValues.get("metaname"); + + for(Metadatum metadatum : metadatumList) { + getLogger().debug(String.format("Comparing existing metadatum of '%s' to keyword '%s'", metadatum.getMetaname(), metaname)); + if(metaname.equals(metadatum.getMetaname())) { + metadatumToDelete = metadatum; + break; + } + } + if(metadatumToDelete == null) { + getLogger().info(String.format("Metadatum has not been found for %s", key)); + return QueryStatus.NOT_FOUND; + } + + String path = url.toString(); + path = path + "/metadata/metadatum/" + encodeQuery( metadatumToDelete.getMetaname() ) + + "?resource-version=" + metadatumToDelete.getResourceVersion(); + URL deleteUrl = new URL(path); + boolean response = deleteList(deleteUrl, null); + + if(!response) + return QueryStatus.FAILURE; + + return QueryStatus.SUCCESS; + + } catch(Exception exc) { + getLogger().warn("processDelete", exc); + return QueryStatus.FAILURE; + } + } + + protected String encodeQuery(String param) throws UnsupportedEncodingException { + return URLEncoder.encode(param, "UTF-8").replace("+", "%20"); + } + + static final Map<String, String> ctxGetBeginsWith( SvcLogicContext ctx, String prefix ) { + Map<String, String> tmpPrefixMap = new HashMap<>(); + + if(prefix == null || prefix.isEmpty()){ + return tmpPrefixMap; + } + + for( String key : ctx.getAttributeKeySet() ) { + if( key.startsWith(prefix) ) { + String tmpKey = key.substring(prefix.length() + 1); + tmpPrefixMap.put( tmpKey, ctx.getAttribute(key)); + } + } + + Map<String, String> prefixMap = new HashMap<>(); + Pattern p = Pattern.compile(".*\\[\\d\\]"); + + SortedSet<String> keys = new TreeSet<String>(tmpPrefixMap.keySet () ); + for(String key : keys) { + Matcher m = p.matcher(key); + if(m.matches()) { + continue; + } else if(key.endsWith("_length")) { + String listKey = key.substring(0, key.indexOf("_length")); + int max = Integer.parseInt(tmpPrefixMap.get(key)); + + ArrayList<String> data = new ArrayList<>(); + for(int x = 0; x < max; x++){ + String tmpKey = String.format("%s[%d]", listKey, x); + String tmpValue = tmpPrefixMap.get(tmpKey); + if(tmpValue != null && !tmpValue.isEmpty()) { + data.add(tmpValue); + } + } + if(!data.isEmpty()) { + prefixMap.put(listKey, data.toString()); + } else { + prefixMap.put(key, tmpPrefixMap.get(key)); + } + } else { + prefixMap.put(key, tmpPrefixMap.get(key)); + } + } + + return prefixMap; + } + + public abstract <T> T getResource(String key, Class<T> type) throws AAIServiceException ; + protected abstract boolean deleteList(URL url, String caller) throws AAIServiceException; +} diff --git a/aai-service/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/aai/AAIExecutorInterfaceLighty.java b/aai-service/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/aai/AAIExecutorInterfaceLighty.java new file mode 100755 index 000000000..d2c3812a1 --- /dev/null +++ b/aai-service/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/aai/AAIExecutorInterfaceLighty.java @@ -0,0 +1,36 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : SDN-C + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights + * reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +/** + * @author Rich Tabedzki + * + */ +package org.onap.ccsdk.sli.adaptors.aai; + +/** + * THIS CLASS IS A COPY OF {@link AAIExecutorInterface} WITH REMOVED OSGi DEPENDENCIES + */ +public interface AAIExecutorInterfaceLighty { + public String get(AAIRequestLighty request) throws AAIServiceException; + public String post(AAIRequestLighty request) throws AAIServiceException; + public Boolean delete(AAIRequestLighty request, String resourceVersion) throws AAIServiceException; + public Object query(AAIRequestLighty request, Class clas) throws AAIServiceException; + public Boolean patch(AAIRequestLighty request, String resourceVersion) throws AAIServiceException; +} diff --git a/aai-service/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/aai/AAIRequestLighty.java b/aai-service/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/aai/AAIRequestLighty.java new file mode 100755 index 000000000..81acfca59 --- /dev/null +++ b/aai-service/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/aai/AAIRequestLighty.java @@ -0,0 +1,470 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : SDN-C + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights + * reserved. + * ================================================================================ + * Modifications Copyright (C) 2018 IBM. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +/** + * @author Rich Tabedzki + * + */ +package org.onap.ccsdk.sli.adaptors.aai; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.io.UnsupportedEncodingException; +import java.lang.reflect.Method; +import java.net.MalformedURLException; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLDecoder; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.BitSet; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.TreeSet; +import org.apache.commons.lang.StringUtils; +import org.onap.aai.inventory.v16.GenericVnf; +import org.onap.ccsdk.sli.adaptors.aai.data.AAIDatum; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * THIS CLASS IS A COPY OF {@link AAIRequest} WITH REMOVED OSGi DEPENDENCIES + */ +public abstract class AAIRequestLighty { + protected static final Logger LOG = LoggerFactory.getLogger(AAIRequestLighty.class); + + protected static final String TARGET_URI = "org.onap.ccsdk.sli.adaptors.aai.uri"; + + protected static final String MASTER_REQUEST = "master-request"; + + public static final String RESOURCE_VERSION = "resource-version"; + + public static final String DEPTH = "depth"; + + protected static Properties configProperties; + protected final String targetUri; + protected static AAIServiceLighty aaiService; + + protected AAIDatum requestDatum; + + protected final Properties requestProperties = new Properties(); + + + public static AAIRequestLighty createRequest(String resoourceName, Map<String, String> nameValues){ + + String resoource = resoourceName; + String masterResource = null; + + if(resoource == null) + return null; + + if(resoource.contains(":")) { + String[] tokens = resoource.split(":"); + if(tokens != null && tokens.length == 2) { + resoource = tokens[1]; + masterResource = tokens[0]; + Class<? extends AAIDatum> clazz = getClassFromResource(resoource) ; + + if(clazz == null) { + return null; + } + } + } + + if(nameValues.containsKey("selflink")){ + Class<? extends AAIDatum> clazz = getClassFromResource(resoource) ; + + if(clazz != null) + return new SelfLinkRequestLighty(clazz); + else + return null; + } + + switch(resoource){ + case "generic-query": + return new GenericQueryRequestLighty(); + case "nodes-query": + return new NodesQueryRequestLighty(); + case "custom-query": + case "formatted-query": + return new CustomQueryRequestLighty(); + case "echo": + case "test": + return new EchoRequestLighty(); + + case "linterface": + case "l2-bridge-sbg": + case "l2-bridge-bgf": + { + resoource = "l-interface"; + return getRequestFromResource("l-interface"); + } + case "relationship-list": + return new RelationshipListRequestLighty( + AAIRequestLighty.createRequest(masterResource, nameValues)); + case "relationship": + return new RelationshipRequestLighty( + AAIRequestLighty.createRequest(masterResource, nameValues)); + default: + return getRequestFromResource(resoource); + } + } + + + /** + * Map containing resource tag to its bit position in bitset mapping + */ + private static Map<String, String> tagValues = new LinkedHashMap<>(); + /** + * Map containing bitset value of the path to its path mapping + */ + private static Map<BitSet, String> bitsetPaths = new LinkedHashMap<>(); + + + public static Set<String> getResourceNames() { + return tagValues.keySet(); + } + + + public static void setProperties(Properties props, AAIServiceLighty aaiService) { + AAIRequestLighty.configProperties = props; + AAIRequestLighty.aaiService = aaiService; + + try + { + URL url = aaiService.getClass().getResource("/aai-path.properties"); + + InputStream in = url.openStream(); + Reader reader = new InputStreamReader(in, StandardCharsets.UTF_8); + + Properties properties = new Properties(); + properties.load(reader); + LOG.info("loaded " + properties.size()); + + Set<String> keys = properties.stringPropertyNames(); + + int index = 0; + Set<String> resourceNames = new TreeSet<>(); + + for(String key : keys) { + String[] tags = key.split("\\|"); + for(String tag : tags) { + if(!resourceNames.contains(tag)) { + resourceNames.add(tag); + tagValues.put(tag, Integer.toString(++index)); + } + } + BitSet bs = new BitSet(256); + for(String tag : tags) { + String value = tagValues.get(tag); + Integer bitIndex = Integer.parseInt(value) ; + bs.set(bitIndex); + } + String path = properties.getProperty(key); + LOG.info(String.format("bitset %s\t\t%s", bs.toString(), path)); + bitsetPaths.put(bs, path); + } + LOG.info("loaded " + resourceNames.toString()); + } + catch (Exception e) + { + LOG.error("Caught exception", e); + } + } + + public AAIRequestLighty() { + targetUri = configProperties.getProperty(TARGET_URI); + } + + public void addRequestProperty(String key, String value) { + requestProperties.put(key, value); + } + + public final void setRequestObject(AAIDatum value) { + requestDatum = value; + } + + public final AAIDatum getRequestObject() { + return requestDatum; + } + + public final void addMasterRequest(AAIRequestLighty masterRequest) { + requestProperties.put(MASTER_REQUEST, masterRequest); + } + + protected static String encodeQuery(String param) throws UnsupportedEncodingException { + return URLEncoder.encode(param, "UTF-8").replace("+", "%20"); + } + + protected void handleException(AAIRequestLighty lInterfaceRequest, JsonProcessingException exc) { + aaiService.getLogger().warn("Could not deserialize object of type " + lInterfaceRequest.getClass().getSimpleName(), exc) ; + } + + public URL getRequestUrl(String method, String resourceVersion) throws UnsupportedEncodingException, MalformedURLException, URISyntaxException { + + String request_url = null; + + request_url = targetUri + updatePathDataValues(resourceVersion); + + URL http_req_url = new URL(request_url); + + aaiService.LOGwriteFirstTrace(method, http_req_url.toString()); + + return http_req_url; + } + + public String updatePathDataValues(Object resourceVersion) throws UnsupportedEncodingException, MalformedURLException { + String request_url = getRequestPath(); + + Set<String> uniqueResources = extractUniqueResourceSetFromKeys(requestProperties.stringPropertyNames()); + + for(String resoourceName:uniqueResources) { + AAIRequestLighty + locRequest = AAIRequestLighty.createRequest(resoourceName, new HashMap<String, String>()); + if(locRequest != null) { + Class<?> clazz = locRequest.getClass(); + Method function = null; + try { + function = clazz.getMethod("processPathData", request_url.getClass(), requestProperties.getClass()); + request_url = (String) function.invoke(null, request_url, requestProperties); + } catch (Exception e) { + LOG.error("Caught exception", e); + } + } + } + + if(resourceVersion != null) { + request_url = request_url +"?resource-version="+resourceVersion; + } + + return request_url; + } + + protected String getRequestPath() throws MalformedURLException { + return getRequestPath(null); + } + + protected String getRequestPath(String resource) throws MalformedURLException { + if(requestProperties.containsKey("resource-path")) { + return requestProperties.getProperty("resource-path"); + } + + Set<String> uniqueResources = extractUniqueResourceSetFromKeys(requestProperties.stringPropertyNames()); + if(resource != null) { + // for group search add itself, but remove singular version of itself + if(!uniqueResources.contains(resource)) { + boolean replaced = false; + Set<String> tmpUniqueResources = new HashSet<>(); + tmpUniqueResources.addAll(uniqueResources); + for(String item : tmpUniqueResources){ + String plural = item +"s"; + if(item.endsWith("y")){ + plural = item.substring(0, item.length()-1)+ "ies"; + } + if(plural.equals(resource)) { + uniqueResources.remove(item); + uniqueResources.add(resource); + replaced = true; + break; + } + } + if(!replaced){ + if(!uniqueResources.contains(resource)) { + uniqueResources.add(resource); + } + } + } + } + BitSet bitset = new BitSet(); + for(String key : uniqueResources) { + if(tagValues.containsKey(key)) { + Object tmpValue = tagValues.get(key); + if(tmpValue != null) { + String value = tmpValue.toString(); + int bitIndex = Integer.parseInt(value); + bitset.set(bitIndex); + } + } + } + + String path = bitsetPaths.get(bitset); + if(path == null) { + throw new MalformedURLException("PATH not found for key string containing valies :" +requestProperties.toString()); + } + return path; + } + + public abstract URL getRequestQueryUrl(String method) throws UnsupportedEncodingException, MalformedURLException, URISyntaxException; + + public abstract String toJSONString(); + + public abstract String[] getArgsList(); + + public abstract Class<? extends AAIDatum> getModelClass() ; + + public String getPrimaryResourceName(String resource) { + return resource; + } + + public String formatKey(String argument) { + return argument; + } + + public AAIDatum jsonStringToObject(String jsonData) throws JsonParseException, JsonMappingException, IOException { + if(jsonData == null) { + return null; + } + + AAIDatum response = null; + ObjectMapper mapper = getObjectMapper(); + response = mapper.readValue(jsonData, getModelClass()); + return response; + } + + protected static Set<String> extractUniqueResourceSetFromKeys(Set<String> keySet) { + Set<String> uniqueResources = new TreeSet<>(); + List<String> keys = new ArrayList<>(keySet); + for(String resource : keys) { + if(resource.contains(".")) { + String [] split = resource.split("\\."); + uniqueResources.add(split[0].replaceAll("_", "-")); + } + } + return uniqueResources; + } + + public void processRequestPathValues(Map<String, String> nameValues) { + Set<String> uniqueResources = extractUniqueResourceSetFromKeys(nameValues.keySet()); + + Set<String> tokens = new TreeSet<>(); + tokens.add(DEPTH); + tokens.addAll(Arrays.asList(this.getArgsList())); + + for(String resoourceName:uniqueResources) { + AAIRequestLighty + locRequest = AAIRequestLighty.createRequest(resoourceName, nameValues); + if(locRequest != null) + tokens.addAll(Arrays.asList(locRequest.getArgsList())); + } + + String[] arguments = tokens.toArray(new String[0]); + for(String name : arguments) { + String tmpName = name.replaceAll("-", "_"); + String value = nameValues.get(tmpName); + if(value != null && !value.isEmpty()) { + value = value.trim().replace("'", "").replace("$", "").replace("'", ""); + this.addRequestProperty(name, value); + } + } + } + + public static String processPathData(String request_url, Properties requestProperties) throws UnsupportedEncodingException { + return request_url; + } + + public boolean isDeleteDataRequired() { + return false; + } + + ObjectMapper getObjectMapper() { + return AAIService.getObjectMapper(); + } + + public static Class<? extends AAIDatum> getClassFromResource(String resoourceName) { + String className = GenericVnf.class.getName(); + String[] split = resoourceName.split("-"); + for(int i = 0; i < split.length; i++) { + split[i] = StringUtils.capitalize(split[i]); + } + + String caps = StringUtils.join(split); + className = className.replace("GenericVnf", caps); + try { + return (Class<? extends AAIDatum>)Class.forName(className); + } catch (ClassNotFoundException e) { + LOG.warn("AAIRequestLighty does not support class: " + e.getMessage()); + return null; + } + } + + protected static AAIRequestLighty getRequestFromResource(String resoourceName) { + + Class<? extends AAIDatum> clazz = getClassFromResource(resoourceName); + + if(clazz == null) { + return null; + } + return new GenericRequestLighty(clazz); + } + + public static Map<String, String> splitQuery(String query) throws UnsupportedEncodingException { + Map<String, String> query_pairs = new LinkedHashMap<>(); + + if(query != null && !query.isEmpty()) { + String[] pairs = query.split("&"); + for (String pair : pairs) { + int idx = pair.indexOf('='); + query_pairs.put(URLDecoder.decode(pair.substring(0, idx), "UTF-8"), URLDecoder.decode(pair.substring(idx + 1), "UTF-8")); + } + } + return query_pairs; + } + + public static Map<String, String> splitPath(String path) throws UnsupportedEncodingException { + Map<String, String> query_pairs = new LinkedHashMap<>(); + + if(path != null && !path.isEmpty()) { + String[] pairs = path.split("/"); + for (String pair : pairs) { + int idx = pair.indexOf('='); + query_pairs.put(URLDecoder.decode(pair.substring(0, idx), "UTF-8"), URLDecoder.decode(pair.substring(idx + 1), "UTF-8")); + } + } + return query_pairs; + } + + protected boolean expectsDataFromPUTRequest() { + return false; + } + + + public String getTargetUri() { + return targetUri; + } + + public static final String getSupportedAAIVersion() { + return configProperties.getProperty(AAIDeclarations.AAI_VERSION, "/v16/"); + } +} diff --git a/aai-service/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/aai/AAIServiceLighty.java b/aai-service/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/aai/AAIServiceLighty.java new file mode 100755 index 000000000..bd9115b64 --- /dev/null +++ b/aai-service/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/aai/AAIServiceLighty.java @@ -0,0 +1,1545 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : SDN-C + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights + * reserved. + * ================================================================================ + * Modifications Copyright (C) 2019 IBM. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +/** + * @author Rich Tabedzki + * + */ +package org.onap.ccsdk.sli.adaptors.aai; + +import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.fasterxml.jackson.databind.AnnotationIntrospector; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector; +import com.fasterxml.jackson.databind.type.TypeFactory; +import com.fasterxml.jackson.module.jaxb.JaxbAnnotationIntrospector; +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.io.UnsupportedEncodingException; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.security.KeyManagementException; +import java.security.KeyStore; +import java.security.NoSuchAlgorithmException; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Properties; +import java.util.Set; +import java.util.TimeZone; +import java.util.UUID; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocketFactory; +import javax.ws.rs.HttpMethod; +import javax.xml.bind.annotation.XmlElement; +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.lang3.StringUtils; +import org.onap.aai.inventory.v16.GenericVnf; +import org.onap.aai.inventory.v16.PhysicalLink; +import org.onap.aai.inventory.v16.ResultData; +import org.onap.aai.inventory.v16.SearchResults; +import org.onap.aai.inventory.v16.Vserver; +import org.onap.ccsdk.sli.adaptors.aai.data.AAIDatum; +import org.onap.ccsdk.sli.adaptors.aai.data.ErrorResponse; +import org.onap.ccsdk.sli.adaptors.aai.data.notify.NotifyEvent; +import org.onap.ccsdk.sli.core.sli.ConfigurationException; +import org.onap.ccsdk.sli.core.sli.MetricLogger; +import org.onap.ccsdk.sli.core.sli.SvcLogicContext; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.onap.ccsdk.sli.core.sli.SvcLogicResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.MDC; + +/** + * THIS CLASS IS A COPY OF {@link AAIService} WITH REMOVED OSGi DEPENDENCIES + */ +public class AAIServiceLighty extends AAIDeclarationsLighty implements AAIClientLighty, SvcLogicResource { + + public static final String AAICLIENT_PROPERTIES = "/aaiclient.properties"; + public static final String PATH_PROPERTIES = "/aai-path.properties"; + + private static final Logger LOG = LoggerFactory.getLogger(AAIServiceLighty.class); + + private final String truststorePath; + private final String truststorePassword; + private final String keystorePath; + private final String keystorePassword; + private final Boolean ignoreCertificateHostError; + + private final String targetUri; + private final String networkVserverPath; + + private final String svc_inst_query_path; + + private final String ubb_notify_path; + private final String selflinkAvpn; + private final String selflinkFqdn; + + private final int connectionTimeout; + private final int readTimeout; + + // 1602 + private final String queryNodesPath; + private final String applicationId; + + // authentication credentials + private String userName; + private String userPassword; + + // runtime + private final boolean runtimeOSGI; + + private SSLContext CTX; + + private final MetricLogger ml = new MetricLogger(); + + private AAIExecutorInterfaceLighty executor; + + public AAIServiceLighty(final UtilsProvider configuration) { + this(configuration.getProperties()); + } + + public AAIServiceLighty(final URL url) { + this(getProperties(url)); + } + + public AAIServiceLighty(Properties props) { + LOG.info("Entered AAIService.ctor"); + + String runtime = System.getProperty("aaiclient.runtime"); + if("OSGI".equals(runtime)) { + runtimeOSGI = true; + } else { + runtimeOSGI = false; + } + + try { + AAIRequestLighty.setProperties(props, this); + + } catch(Exception exc){ + LOG.error("AicAAIResource.static", exc); + } + + executor = new AAIClientRESTExecutorLighty(props); + + userName = props.getProperty(CLIENT_NAME); + userPassword = props.getProperty(CLIENT_PWWD); + + if(userName == null || userName.isEmpty()){ + LOG.debug("Basic user name is not set"); + } + if(userPassword == null || userPassword.isEmpty()) { + LOG.debug("Basic password is not set"); + } + + truststorePath = props.getProperty(TRUSTSTORE_PATH); + truststorePassword = props.getProperty(TRUSTSTORE_PSSWD); + keystorePath = props.getProperty(KEYSTORE_PATH); + keystorePassword = props.getProperty(KEYSTORE_PSSWD); + + targetUri = props.getProperty(TARGET_URI); + props.getProperty(QUERY_PATH); + props.getProperty(UPDATE_PATH); + + String tmpApplicationId = props.getProperty(APPLICATION_ID); + if(tmpApplicationId == null || tmpApplicationId.isEmpty()) { + tmpApplicationId = "SDNC"; + } + this.applicationId = tmpApplicationId; + + // connection timeout + int tmpConnectionTimeout = 30000; + int tmpReadTimeout = 30000; + + try { + String tmpValue = null; + tmpValue = props.getProperty(CONNECTION_TIMEOUT, "30000"); + tmpConnectionTimeout = Integer.parseInt(tmpValue); + tmpValue = props.getProperty(READ_TIMEOUT, "30000"); + tmpReadTimeout = Integer.parseInt(tmpValue); + } catch(Exception exc) { + LOG.error("Failed setting connection timeout", exc); + tmpConnectionTimeout = 30000; + tmpReadTimeout = 30000; + } + connectionTimeout = tmpConnectionTimeout; + readTimeout = tmpReadTimeout; + + networkVserverPath =props.getProperty(NETWORK_VSERVER_PATH); + + props.getProperty(SVC_INSTANCE_PATH); + svc_inst_query_path = props.getProperty(SVC_INST_QRY_PATH); + props.getProperty(PARAM_SERVICE_TYPE, "service-type"); + + props.getProperty(VNF_IMAGE_QUERY_PATH); + + ubb_notify_path = props.getProperty(UBB_NOTIFY_PATH); + selflinkAvpn = props.getProperty(SELFLINK_AVPN); + selflinkFqdn = props.getProperty(SELFLINK_FQDN); + + props.getProperty(SERVICE_PATH); + + props.getProperty(SITE_PAIR_SET_PATH); + + queryNodesPath = props.getProperty(QUERY_NODES_PATH); + + String iche = props.getProperty(CERTIFICATE_HOST_ERROR); + boolean host_error = false; + if(iche != null && !iche.isEmpty()) { + host_error = Boolean.valueOf(iche); + } + + ignoreCertificateHostError = host_error; + + HttpsURLConnection.setDefaultHostnameVerifier( new HostnameVerifier(){ + public boolean verify(String string,SSLSession ssls) { + return ignoreCertificateHostError; + } + }); + + if(truststorePath != null && truststorePassword != null && (new File(truststorePath)).exists()) { + System.setProperty("javax.net.ssl.trustStore", truststorePath); + System.setProperty("javax.net.ssl.trustStorePassword", truststorePassword); + } + + if(keystorePath != null && keystorePassword != null && (new File(keystorePath)).exists()) { + //DefaultClientConfig config = new DefaultClientConfig(); + //both jersey and HttpURLConnection can use this + SSLContext ctx = null; + try { + ctx = SSLContext.getInstance("TLS"); + + KeyManagerFactory kmf = null; + try (FileInputStream fin = new FileInputStream(keystorePath)){ + String def = "SunX509"; + String storeType = "PKCS12"; + def = KeyStore.getDefaultType(); + kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + + String extension = keystorePath.substring(keystorePath.lastIndexOf(".") + 1); + if("JKS".equalsIgnoreCase(extension)) { + storeType = "JKS"; + } + KeyStore ks = KeyStore.getInstance(storeType); + + char[] pwd = keystorePassword.toCharArray(); + ks.load(fin, pwd); + kmf.init(ks, pwd); + } catch (Exception ex) { + LOG.error("AAIResource", ex); + } + + if(null!=kmf) { + ctx.init(kmf.getKeyManagers(), null, null); + } + /* + * config.getProperties().put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES, new + * HTTPSProperties( new HostnameVerifier() { + * + * @Override public boolean verify( String s, SSLSession sslSession ) { return + * ignoreCertificateHostError; } }, ctx)); + */ + + CTX = ctx; + LOG.debug("SSLContext created"); + + } catch (KeyManagementException | NoSuchAlgorithmException exc) { + LOG.error("AAIResource", exc); + } + } + + LOG.info("AAIResource.ctor initialized."); + + try { + Field methodsField = HttpURLConnection.class.getDeclaredField("methods"); + methodsField.setAccessible(true); + // get the methods field modifiers + Field modifiersField = Field.class.getDeclaredField("modifiers"); + // bypass the "private" modifier + modifiersField.setAccessible(true); + + // remove the "final" modifier + modifiersField.setInt(methodsField, methodsField.getModifiers() & ~Modifier.FINAL); + + /* valid HTTP methods */ + String[] methods = { + "GET", "POST", "HEAD", "OPTIONS", "PUT", "DELETE", "TRACE", "PATCH" + }; + // set the new methods - including patch + methodsField.set(null, methods); + + } catch (SecurityException | IllegalArgumentException | IllegalAccessException | NoSuchFieldException e) { + LOG.error("Exception occured", e); + } + + } + + private static Properties getProperties(URL url) { + Properties properties = new Properties(); + try { + properties.load(url.openStream()); + } catch (IOException exc) { + LOG.error("getProperties", exc); + } + return properties; + } + + public void setExecutor(AAIExecutorInterfaceLighty executor) { + this.executor = executor; + } + + public void cleanUp() { + + } + + /** + * + * @param http_req_url + * @param method + * @return + * @throws Exception + */ + protected HttpURLConnection getConfiguredConnection(URL http_req_url, String method) throws Exception { + HttpURLConnection con = (HttpURLConnection) http_req_url.openConnection(); + + // Set up the connection properties + con.setRequestProperty( "Connection", "close" ); + con.setDoInput(true); + con.setDoOutput(true); + con.setUseCaches(false); + con.setConnectTimeout( connectionTimeout ); + con.setReadTimeout( readTimeout ); + con.setRequestMethod( method ); + con.setRequestProperty( "Accept", "application/json" ); + con.setRequestProperty( "Content-Type", "PATCH".equalsIgnoreCase(method) ? "application/merge-patch+json" : "application/json" ); + con.setRequestProperty("X-FromAppId", applicationId); + con.setRequestProperty("X-TransactionId", TransactionIdTracker.getNextTransactionId()); + String mlId = ml.getRequestID(); + if(mlId != null && !mlId.isEmpty()) { + LOG.debug(String.format("MetricLogger requestId = %s", mlId)); + con.setRequestProperty(MetricLogger.REQUEST_ID, mlId); + } else { + LOG.debug("MetricLogger requestId is null"); + } + con.setRequestProperty("Transfer-Encoding","chunked"); + + if(userName != null && !userName.isEmpty() && userPassword != null && !userPassword.isEmpty()) { + String basicAuth = "Basic " + new String(Base64.encodeBase64((userName + ":" + userPassword).getBytes())); + con.setRequestProperty ("Authorization", basicAuth); + } + + if(con instanceof HttpsURLConnection && CTX != null) { + SSLSocketFactory sockFact = CTX.getSocketFactory(); + HttpsURLConnection.class.cast(con).setSSLSocketFactory( sockFact ); + } + return con; + } + + + @Override + public GenericVnf requestGenericVnfData(String vnf_id) throws AAIServiceException { + GenericVnf response = null; + + try { + AAIRequestLighty request = AAIRequestLighty.getRequestFromResource("generic-vnf"); + request.addRequestProperty("generic-vnf.vnf-id", vnf_id); + String rv = executor.get(request); + if(rv != null) { + ObjectMapper mapper = getObjectMapper(); + response = mapper.readValue(rv, GenericVnf.class); + } + } catch(AAIServiceException aaiexc) { + throw aaiexc; + } catch (Exception exc) { + LOG.warn(Object.class.getClass().getEnclosingMethod().getName(), exc); + throw new AAIServiceException(exc); + } + + return response; + + } + + @Override + public boolean postGenericVnfData(String vnf_id, GenericVnf data) throws AAIServiceException { + try { + AAIRequestLighty request = AAIRequestLighty.getRequestFromResource("generic-vnf"); + request.addRequestProperty("generic-vnf.vnf-id", vnf_id); + request.setRequestObject(data); + Object response = executor.post(request); + return true; + } catch(AAIServiceException aaiexc) { + throw aaiexc; + } catch (Exception exc) { + LOG.warn("requestGenericVnfData", exc); + throw new AAIServiceException(exc); + } + } + + @Override + public SearchResults requestServiceInstanceURL(String svc_instance_id) throws AAIServiceException { + SearchResults response = null; + InputStream inputStream = null; + + try { + String path = svc_inst_query_path; + path = path.replace("{svc-instance-id}", encodeQuery(svc_instance_id)); + + String request_url = targetUri+path; + URL http_req_url = new URL(request_url); + + HttpURLConnection con = getConfiguredConnection(http_req_url, HttpMethod.GET); + + LOGwriteFirstTrace(HttpMethod.GET, http_req_url.toString()); + LOGwriteDateTrace("svc_instance_id", svc_instance_id); + + // Check for errors + int responseCode = con.getResponseCode(); + if (responseCode == HttpURLConnection.HTTP_OK) { + inputStream = con.getInputStream(); + } else { + inputStream = con.getErrorStream(); + } + + // Process the response + LOG.debug("HttpURLConnection result:" + responseCode); + if(inputStream == null) inputStream = new ByteArrayInputStream("".getBytes(StandardCharsets.UTF_8)); + BufferedReader reader = new BufferedReader( new InputStreamReader( inputStream ) ); + + ObjectMapper mapper = getObjectMapper(); + + if (responseCode == HttpURLConnection.HTTP_OK) { + response = mapper.readValue(reader, SearchResults.class); + LOGwriteEndingTrace(HttpURLConnection.HTTP_OK, "SUCCESS", mapper.writeValueAsString(response)); + } else if(responseCode == HttpURLConnection.HTTP_NOT_FOUND ) { + LOGwriteEndingTrace(responseCode, "HTTP_NOT_FOUND", "Entry does not exist."); + return response; + } else { + ErrorResponse errorresponse = mapper.readValue(reader, ErrorResponse.class); + LOGwriteEndingTrace(responseCode, "FAILURE", mapper.writeValueAsString(errorresponse)); + throw new AAIServiceException(responseCode, errorresponse); + } + + } catch(AAIServiceException aaiexc) { + throw aaiexc; + } catch (Exception exc) { + LOG.warn("requestServiceInstanceURL", exc); + throw new AAIServiceException(exc); + } finally { + if(inputStream != null){ + try { + inputStream.close(); + } catch(Exception exc) { + LOG.warn("Error closing Inputstream", exc); + } + } + } + return response; + } + + + private static Properties initialize(URL url ) throws ConfigurationException { + + if(url == null) { + throw new NullPointerException(); + } + + InputStream is = null; + Properties props = new Properties(); + + try { + if(LOG.isDebugEnabled()) + LOG.info("Property file is: " + url.toString()); + + is = url.openStream(); + + props.load(is); + if(LOG.isDebugEnabled()) { + LOG.info("Properties loaded: " + props.size()); + Enumeration<Object> en = props.keys(); + + while(en.hasMoreElements()) { + String key = (String)en.nextElement(); + String property = props.getProperty(key); + LOG.debug(key + " : " + property); + } + } + } catch (Exception e) { + throw new ConfigurationException("Could not load properties file.", e); + } + return props; + } + + static class TransactionIdTracker { +// protected static AtomicLong tracker = new AtomicLong(); + + public static String getNextTransactionId() { + // Check if RequestId exists as MDC. If not, create new. + String transactionId = MDC.get("RequestId"); + if ("".equals(transactionId) || transactionId == null) { + transactionId = UUID.randomUUID().toString(); + LOG.info("Missing requestID. Assigned " + transactionId); + MDC.put("RequestId", transactionId); + } + return transactionId; + } + + } + + protected void LOGwriteFirstTrace(String method, String url) { + String time = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'").format(System.currentTimeMillis()); + LOG.info("A&AI transaction :"); + LOG.info("Request Time : " + time + ", Method : " + method); + LOG.info("Request URL : "+ url); + } + + protected void LOGwriteDateTrace(String name, String data) { + LOG.info("Input - " + name + " : " + data); + } + + protected void LOGwriteEndingTrace(int response_code, String comment, String data) { + LOG.info("Response code : " + response_code +", " + comment); + LOG.info(String.format("Response data : %s", data)); + } + + protected String encodeQuery(String param) throws UnsupportedEncodingException { + return URLEncoder.encode(param, "UTF-8").replace("+", "%20"); + } + + private String encodeCustomerURL(final String selection) + { + String encrypted_url = selection; + String apnpattern = + "/aai/v11/business/customers/customer/(.+)/service-subscriptions/service-subscription/(.+)/service-instances/service-instance/(.+)/"; + Pattern pattern = Pattern.compile(apnpattern); + + try { + URL url = new URL(selection); + String path = url.getPath(); + + LOG.info("Trying to match apn to <" + path + ">"); + + Matcher matcher = pattern.matcher(path); + + while(matcher.find()) { + String customer = matcher.group(1); + String subscription = matcher.group(2); + String service = matcher.group(3); + + encrypted_url = selection.replace(customer, encodeQuery(customer)); + encrypted_url = encrypted_url.replace(subscription, encodeQuery(subscription)); + encrypted_url = encrypted_url.replace(service, encodeQuery(service)); + } + } catch (Exception e) { + LOG.warn("", e); + } + + return encrypted_url; + } + + + + /* + * (non-Javadoc) + * @see org.onap.sdnct.sli.aai.AAIClient#requestVServersData(java.lang.String, java.lang.String) + */ + @Override + public Vserver requestVServerData(String tenantId, String vserverId, String cloudOwner, String cloudRegionId) throws AAIServiceException { + Vserver response = null; + + try { + AAIRequestLighty request = AAIRequestLighty.getRequestFromResource("vserver"); + request.addRequestProperty("cloud-region.cloud-owner", cloudOwner); + request.addRequestProperty("cloud-region.cloud-region-id", cloudRegionId); + request.addRequestProperty("tenant.tenant-id", tenantId); + request.addRequestProperty("vserver.vserver-id", vserverId); + + String rv = executor.get(request); + if(rv != null) { + ObjectMapper mapper = getObjectMapper(); + response = mapper.readValue(rv, Vserver.class); + } + } catch(AAIServiceException aaiexc) { + throw aaiexc; + } catch (Exception exc) { + LOG.warn(Object.class.getClass().getEnclosingMethod().getName(), exc); + throw new AAIServiceException(exc); + } + return response; + } + + + //================== End of DvsSwitch ================= + //==================== PhysicalLink ====================== + @Override + public PhysicalLink requestPhysicalLinkData(String linkName) throws AAIServiceException { + PhysicalLink response = null; + + try { + AAIRequestLighty request = AAIRequestLighty.getRequestFromResource("physical-link"); + request.addRequestProperty("physical-link.link-name", linkName); + + String rv = executor.get(request); + if(rv != null) { + ObjectMapper mapper = getObjectMapper(); + response = mapper.readValue(rv, PhysicalLink.class); + } + } catch(AAIServiceException aaiexc) { + throw aaiexc; + } catch (Exception exc) { + LOG.warn("requestPhysicalLinkData", exc); + throw new AAIServiceException(exc); + } + return response; + } + + @Override + public boolean postPhysicalLinkData(String linkName, PhysicalLink data) throws AAIServiceException { + try { + AAIRequestLighty request = AAIRequestLighty.getRequestFromResource("physical-link"); + request.addRequestProperty("physical-link.link-name", linkName); + request.setRequestObject(data); + Object response = executor.post(request); + return true; + } catch(AAIServiceException aaiexc) { + throw aaiexc; + } catch (Exception exc) { + LOG.warn(Object.class.getClass().getEnclosingMethod().getName(), exc); + throw new AAIServiceException(exc); + } + } + + @Override + public boolean deletePhysicalLinkData(String linkName, String resourceVersion) throws AAIServiceException { + boolean response = false; + + try { + AAIRequestLighty request = AAIRequestLighty.getRequestFromResource("physical-link"); + request.addRequestProperty("physical-link.link-name", linkName); + response = executor.delete(request, resourceVersion); + } catch(AAIServiceException aaiexc) { + throw aaiexc; + } catch (Exception exc) { + LOG.warn("deletePhysicalLinkData", exc); + throw new AAIServiceException(exc); + } + return response; + } + + public boolean deleteAAIEntity(URL url, String caller) throws AAIServiceException { + + if(url == null) { + throw new NullPointerException(); + } + + boolean response = false; + InputStream inputStream = null; + + try { + URL http_req_url = url; + + HttpURLConnection con = getConfiguredConnection(http_req_url, HttpMethod.DELETE); + + LOGwriteFirstTrace("DELETE", http_req_url.toString()); + + + // Check for errors + int responseCode = con.getResponseCode(); + if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_NO_CONTENT) { + inputStream = con.getInputStream(); + } else { + inputStream = con.getErrorStream(); + } + + // Process the response + LOG.debug("HttpURLConnection result:" + responseCode); + if(inputStream == null) inputStream = new ByteArrayInputStream("".getBytes(StandardCharsets.UTF_8)); + BufferedReader reader = new BufferedReader( new InputStreamReader( inputStream ) ); + String line = null; + + ObjectMapper mapper = getObjectMapper(); + + if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_NO_CONTENT) { + StringBuilder stringBuilder = new StringBuilder(); + + while( ( line = reader.readLine() ) != null ) { + stringBuilder.append( line ); + } + LOGwriteEndingTrace(responseCode, "SUCCESS", stringBuilder.toString()); + response = true; + } else if(responseCode == HttpURLConnection.HTTP_NOT_FOUND ) { + LOGwriteEndingTrace(responseCode, "HTTP_NOT_FOUND", "Entry does not exist."); + response = false; + } else { + ErrorResponse errorresponse = mapper.readValue(reader, ErrorResponse.class); + LOGwriteEndingTrace(responseCode, "FAILURE", mapper.writeValueAsString(errorresponse)); + throw new AAIServiceException(responseCode, errorresponse); + } + + } catch(AAIServiceException aaiexc) { + throw aaiexc; + } catch (Exception exc) { + LOG.warn(caller, exc); + throw new AAIServiceException(exc); + } finally { + if(inputStream != null){ + try { + inputStream.close(); + } catch(Exception exc) { + LOG.warn("Error closing InputStream", exc); + } + } + } + return response; + } + + /** + * Generic method to GET json data from an A&AI callback URL. + * Then convert that json to an Object. + * If successful the Object is attempted to be cast to the type parameter. + * + * @param key + * callback url for A&AI + * @param type + * the class of object that A&AI will return + * @return the object created from json or null if the response code is not 200 + * + * @throws AAIServiceException + * if empty or null key and or type or there's an error with processing + */ + public <T> T dataChangeRequestAaiData(String key, Class<T> type) throws AAIServiceException { + if (StringUtils.isEmpty(key) || type == null) { + throw new AAIServiceException("Key is empty or null and or type is null"); + } + + T response = null; + + SvcLogicContext ctx = new SvcLogicContext(); + if(!key.contains(" = ") && isValidURL(key)) { + key = String.format("selflink = '%s'", key); + } else + if(!key.contains(" = ") && isValidURI(key)) { + key = String.format("resource-path = '%s'", key); + } + + HashMap<String, String> nameValues = AAIServiceUtils.keyToHashMap(key, ctx); + + SelfLinkRequestLighty request = new SelfLinkRequestLighty(type); + request.processRequestPathValues(nameValues); + Object obj = this.getExecutor().query(request, type); + response = type.cast(obj); + + return response != null ? type.cast(response) : response; + } + + + public boolean sendNotify(NotifyEvent event, String serviceInstanceId, String pathCode) throws AAIServiceException { + InputStream inputStream = null; + + try { + + String selfLink = selflinkFqdn; + if(SELFLINK_AVPN != null && SELFLINK_AVPN.equals(pathCode)) { + selfLink = selflinkAvpn; + } + selfLink = selfLink.replace("{service-instance-id}", encodeQuery(serviceInstanceId)); + event.setSelflink(selfLink); + + ObjectMapper mapper = getObjectMapper(); + String json_text = mapper.writeValueAsString(event); + + SSLSocketFactory sockFact = CTX.getSocketFactory(); + + String request_url = targetUri+ubb_notify_path; + URL http_req_url = new URL(request_url); + + HttpURLConnection con = getConfiguredConnection(http_req_url, HttpMethod.PUT); + + if (json_text != null) { + OutputStreamWriter osw = new OutputStreamWriter(con.getOutputStream()); + osw.write(json_text); + osw.flush(); + osw.close(); + } + + LOGwriteFirstTrace("PUT", request_url); + LOGwriteDateTrace("NotifyEvent", json_text); + + // Check for errors + int responseCode = con.getResponseCode(); + if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_CREATED || responseCode == HttpURLConnection.HTTP_ACCEPTED || responseCode == HttpURLConnection.HTTP_NO_CONTENT) { + inputStream = con.getInputStream(); + } else { + inputStream = con.getErrorStream(); + } + + // Process the response + BufferedReader reader; + String line = null; + reader = new BufferedReader( new InputStreamReader( inputStream ) ); + + if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_CREATED || responseCode == HttpURLConnection.HTTP_ACCEPTED || responseCode == HttpURLConnection.HTTP_NO_CONTENT) { + StringBuilder stringBuilder = new StringBuilder(); + + while( ( line = reader.readLine() ) != null ) { + stringBuilder.append( line ); + } + LOGwriteEndingTrace(responseCode, "SUCCESS", (stringBuilder.length() > 0) ? stringBuilder.toString() : + "{no-data}"); + return true; + } else { + ErrorResponse errorresponse = mapper.readValue(reader, ErrorResponse.class); + LOGwriteEndingTrace(responseCode, "FAILURE", mapper.writeValueAsString(errorresponse)); + + throw new AAIServiceException(responseCode, errorresponse); + } + } catch(AAIServiceException aaiexc) { + throw aaiexc; + } catch (Exception exc) { + LOG.warn("sendNotify", exc); + throw new AAIServiceException(exc); + } finally { + try { + if(inputStream != null) + inputStream.close(); + } catch (Exception exc) { + LOG.warn("Error closing Input stream", exc); + } + } + } + + @Override + public SearchResults requestNodeQuery(String node_type, String entityIdentifier, String entityName) throws AAIServiceException { + SearchResults response = null; + InputStream inputStream = null; + + try { + String request_url = targetUri+queryNodesPath; + request_url = request_url.replace("{node-type}", encodeQuery(node_type)) ; + request_url = request_url.replace("{entity-identifier}", entityIdentifier) ; + request_url = request_url.replace("{entity-name}", encodeQuery(entityName)) ; + URL http_req_url = new URL(request_url); + + HttpURLConnection con = getConfiguredConnection(http_req_url, HttpMethod.GET); + + LOGwriteFirstTrace(HttpMethod.GET, http_req_url.toString()); + LOGwriteDateTrace("node_type", node_type); + LOGwriteDateTrace("vnf_name", entityName); + + // Check for errors + int responseCode = con.getResponseCode(); + if (responseCode == HttpURLConnection.HTTP_OK) { + inputStream = con.getInputStream(); + } else { + inputStream = con.getErrorStream(); + } + + // Process the response + LOG.debug("HttpURLConnection result:" + responseCode); + if(inputStream == null) inputStream = new ByteArrayInputStream("".getBytes(StandardCharsets.UTF_8)); + BufferedReader reader = new BufferedReader( new InputStreamReader( inputStream ) ); + + ObjectMapper mapper = getObjectMapper(); + + if (responseCode == HttpURLConnection.HTTP_OK) { + response = mapper.readValue(reader, SearchResults.class); + LOGwriteEndingTrace(HttpURLConnection.HTTP_OK, "SUCCESS", mapper.writeValueAsString(response)); + } else if (responseCode == HttpURLConnection.HTTP_NOT_FOUND) { + LOGwriteEndingTrace(responseCode, "HTTP_NOT_FOUND", "Entry does not exist."); + return response; + } else { + ErrorResponse errorresponse = mapper.readValue(reader, ErrorResponse.class); + LOGwriteEndingTrace(responseCode, "FAILURE", mapper.writeValueAsString(errorresponse)); + throw new AAIServiceException(responseCode, errorresponse); + } + + } catch(AAIServiceException aaiexc) { + throw aaiexc; + } catch (Exception exc) { + LOG.warn("requestNodeQuery", exc); + throw new AAIServiceException(exc); + } finally { + if(inputStream != null){ + try { + inputStream.close(); + } catch(Exception exc) { + LOG.warn("Error closing Input stream", exc); + } + } + } + return response; + + } + + + @Override + public String requestDataByURL(URL url) throws AAIServiceException { + + if(url == null) { + throw new NullPointerException(); + } + + String response = null; + InputStream inputStream = null; + + try { + URL http_req_url = url; + + HttpURLConnection con = getConfiguredConnection(http_req_url, HttpMethod.GET); + + LOGwriteFirstTrace(HttpMethod.GET, http_req_url.toString()); + + // Check for errors + int responseCode = con.getResponseCode(); + if (responseCode == HttpURLConnection.HTTP_OK) { + inputStream = con.getInputStream(); + } else { + inputStream = con.getErrorStream(); + } + + // Process the response + LOG.debug("HttpURLConnection result:" + responseCode); + if(inputStream == null) inputStream = new ByteArrayInputStream("".getBytes(StandardCharsets.UTF_8)); + BufferedReader reader = new BufferedReader( new InputStreamReader( inputStream ) ); + + ObjectMapper mapper = getObjectMapper(); + + if (responseCode == HttpURLConnection.HTTP_OK) { + StringBuilder stringBuilder = new StringBuilder("\n"); + String line = null; + while( ( line = reader.readLine() ) != null ) { + stringBuilder.append( line ); + } + LOG.info(stringBuilder.toString()); +// response = mapper.readValue(reader, String.class); + response = stringBuilder.toString(); + LOGwriteEndingTrace(HttpURLConnection.HTTP_OK, "SUCCESS", mapper.writeValueAsString(response)); + } else if(responseCode == HttpURLConnection.HTTP_NOT_FOUND ) { + LOGwriteEndingTrace(responseCode, "HTTP_NOT_FOUND", "Entry does not exist."); + response = null; + } else { + ErrorResponse errorresponse = mapper.readValue(reader, ErrorResponse.class); + LOGwriteEndingTrace(responseCode, "FAILURE", mapper.writeValueAsString(errorresponse)); + throw new AAIServiceException(responseCode, errorresponse); + } + + } catch(AAIServiceException aaiexc) { + throw aaiexc; + } catch (Exception exc) { + LOG.warn("requestNetworkVceData", exc); + throw new AAIServiceException(exc); + } finally { + if(inputStream != null){ + try { + inputStream.close(); + } catch(Exception exc) { + LOG.warn("Error closing Input stream", exc); + } + } + } + return response; + } + + + @Override + public GenericVnf requestGenericVnfeNodeQuery(String vnf_name) throws AAIServiceException { + + if(vnf_name == null) { + throw new NullPointerException(); + } + + GenericVnf entity = null; + SearchResults resp = this.requestNodeQuery("generic-vnf", "vnf-name", vnf_name); + + List<ResultData> resultDataList = resp.getResultData(); + + try { + for (ResultData datum : resultDataList) { + URI url = new URI(datum.getResourceLink()); + entity = this.getResource(url.toString(), GenericVnf.class); + } + } + catch (Exception e) + { + LOG.error("Caught exception", e); + } + return entity; + } + + @Override + public Vserver requestVServerDataByURL(URL url) throws AAIServiceException { + + if(url == null) { + throw new NullPointerException(); + } + + Vserver entity = null; + + try { + entity = this.getResource(url.toString(), Vserver.class); + } catch (AAIServiceException exc) { + throw exc; + } catch (Exception e) { + throw new AAIServiceException(e); + } + return entity; + } + + @Override + public URL requestVserverURLNodeQuery(String vserver_name) throws AAIServiceException { + + if(vserver_name == null) { + throw new NullPointerException(); + } + + URL entity = null; + SearchResults resp = this.requestNodeQuery("vserver", "vserver-name", vserver_name); + + List<ResultData> resultDataList = resp.getResultData(); + + try { + for (ResultData datum : resultDataList) { + String data_type = datum.getResourceType(); + String resourceLink = datum.getResourceLink(); + if(!resourceLink.isEmpty() && !resourceLink.toLowerCase().startsWith("http")) { + resourceLink = (new EchoRequest()).targetUri + resourceLink; + } + entity = new URL(resourceLink); + } + } catch (Exception e) { + throw new AAIServiceException(e); + } + return entity; + } + + @Override + public String getTenantIdFromVserverUrl(URL url) { + + String path = url.getPath(); + + String[] split = path.split("/tenants/tenant/"); + if(split.length > 1) { + split = split[1].split("/"); + return split[0]; + } else { + return null; + } + } + + @Override + public String getCloudOwnerFromVserverUrl(URL url) { + + String path = url.getPath(); + + String[] split = path.split("/cloud-regions/cloud-region/"); + if(split.length > 1) { + split = split[1].split("/"); + return split[0]; + } else { + return null; + } + } + + @Override + public String getCloudRegionFromVserverUrl(URL url) { + + String path = url.getPath(); + + String[] split = path.split("/cloud-regions/cloud-region/"); + if(split.length > 1) { + split = split[1].split("/"); + return split[1]; + } else { + return null; + } + } + + @Override + public String getVServerIdFromVserverUrl(URL url, String tenantId) { + String pattern = networkVserverPath; + pattern = pattern.replace("{tenant-id}", tenantId); + + int end = pattern.indexOf("{vserver-id}"); + String prefix = pattern.substring(0, end); + + String path = url.getPath(); + + if(path.startsWith(prefix)) { + path = path.substring(prefix.length()); + } + + return path; + } + + protected Logger getLogger(){ + return LOG; + } + + + @Override + public AAIExecutorInterfaceLighty getExecutor() { + return executor; + } + + /** + * Creates a current time stamp in UTC i.e. 2016-03-08T22:15:13.343Z. + * If there are any parameters the values are appended to the time stamp. + * + * @param parameters + * values to be appended to current time stamp + * @param ctx + * used to set an attribute for a DG + * @throws SvcLogicException + */ + public void setStatusMethod(Map<String, String> parameters, SvcLogicContext ctx) throws SvcLogicException { + if (ctx == null) { + throw new SvcLogicException("SvcLogicContext is null."); + } + + StringBuilder sb = new StringBuilder(); + sb.append(String.format("%tFT%<tTZ", Calendar.getInstance(TimeZone.getTimeZone("Z")))).append(" - "); + + for (Entry<String, String> entry : parameters.entrySet()) { + sb.append(entry.getValue()).append(" "); + } + + if (sb.length() > 0) { + sb.setLength(sb.length() - 2); + } + + ctx.setAttribute("aai-summary-status-message", sb.toString()); + LOG.info("aai-summary-status-message: " + sb.toString()); + } + + /** + * Generic method to GET json data from an A&AI using key structure. + * Then convert that json to an Object. + * If successful the Object is attempted to be cast to the type parameter. + * + * @param key + * key identifying the resource to be retrieved from AAI + * @param type + * the class of object that A&AI will return + * @return the object created from json or null if the response code is not 200 + * + * @throws AAIServiceException + * if empty or null key and or type or there's an error with processing + */ + + public <T> T getResource(String key, Class<T> type) throws AAIServiceException { + if (StringUtils.isEmpty(key) || type == null) { + throw new AAIServiceException("Key is empty or null and or type is null"); + } + + T response = null; + + SvcLogicContext ctx = new SvcLogicContext(); + if(!key.contains(" = ")) { + if(isValidURL(key)) { + key = String.format("selflink = '%s'", key); + } else if(isValidURI(key)) { + key = String.format("resource-path = '%s'", key); + } else { + return response; + } + } + + HashMap<String, String> nameValues = AAIServiceUtils.keyToHashMap(key, ctx); + + AAIRequestLighty request = new SelfLinkRequestLighty(type); + if(nameValues.containsKey(PathRequest.RESOURCE_PATH.replaceAll("-", "_"))) { + request = new PathRequestLighty(type); + } + + request.processRequestPathValues(nameValues); + Object obj = this.getExecutor().query(request, type); + response = type.cast(obj); + + return response != null ? type.cast(response) : response; + } + + public boolean isValidURL(String url) { + + URL u = null; + + try { + u = new URL(url); + } catch (MalformedURLException e) { + LOG.warn("MalformedURLException", e); + return false; + } + + try { + u.toURI(); + } catch (URISyntaxException e) { + LOG.warn("URISyntaxException", e); + return false; + } + + return true; + } + + + public boolean isValidURI(String url) { + + URI u = null; + + try { + u = new URI(url); + } catch (URISyntaxException e) { + LOG.warn("URISyntaxException", e); + return false; + } + + return true; + } + + + protected boolean deleteList(URL httpReqUrl, String json_text) throws AAIServiceException { + if(httpReqUrl == null) { + throw new NullPointerException(); + } + + boolean response = false; + InputStream inputStream = null; + + try { + HttpURLConnection con = getConfiguredConnection(httpReqUrl, HttpMethod.DELETE); + +// SSLSocketFactory sockFact = CTX.getSocketFactory(); +// con.setSSLSocketFactory( sockFact ); + if (json_text != null) { + OutputStreamWriter osw = new OutputStreamWriter(con.getOutputStream()); + osw.write(json_text); + osw.flush(); + osw.close(); + } + + LOGwriteFirstTrace("DELETE", httpReqUrl.toString()); + LOGwriteDateTrace("data", json_text); + + // Check for errors + int responseCode = con.getResponseCode(); + if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_NO_CONTENT) { + inputStream = con.getInputStream(); + } else { + inputStream = con.getErrorStream(); + } + + // Process the response + LOG.debug("HttpURLConnection result:" + responseCode); + if(inputStream == null) inputStream = new ByteArrayInputStream("".getBytes(StandardCharsets.UTF_8)); + BufferedReader reader = new BufferedReader( new InputStreamReader( inputStream ) ); + String line = null; + + ObjectMapper mapper = getObjectMapper(); + + if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_NO_CONTENT) { + StringBuilder stringBuilder = new StringBuilder(); + + while( ( line = reader.readLine() ) != null ) { + stringBuilder.append( line ); + } + LOGwriteEndingTrace(responseCode, "SUCCESS", stringBuilder.toString()); + response = true; + } else if(responseCode == HttpURLConnection.HTTP_NOT_FOUND ) { + LOGwriteEndingTrace(responseCode, "HTTP_NOT_FOUND", "Entry does not exist."); + response = false; + } else { + ErrorResponse errorresponse = mapper.readValue(reader, ErrorResponse.class); + LOGwriteEndingTrace(responseCode, "FAILURE", mapper.writeValueAsString(errorresponse)); + throw new AAIServiceException(responseCode, errorresponse); + } + + } catch(AAIServiceException aaiexc) { + throw aaiexc; + } catch (Exception exc) { + LOG.warn("deleteList", exc); + throw new AAIServiceException(exc); + } finally { + if(inputStream != null){ + try { + inputStream.close(); + } catch(Exception exc) { + + } + } + } + return response; + } + + public static ObjectMapper getObjectMapper() { + ObjectMapper mapper = new ObjectMapper(); + AnnotationIntrospector introspector = new JaxbAnnotationIntrospector(TypeFactory.defaultInstance()); + AnnotationIntrospector secondary = new JacksonAnnotationIntrospector(); + mapper.setAnnotationIntrospector(AnnotationIntrospector.pair(introspector, secondary)); + mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); + mapper.setSerializationInclusion(Include.NON_NULL); + mapper.setSerializationInclusion(Include.NON_EMPTY); + return mapper; + } + + public void logMetricRequest(String requestId, String targetServiceName, String msg, String path){ + String svcInstanceId = ""; + String svcName = null; + String partnerName = null; + String targetEntity = "A&AI"; + String targetVirtualEntity = null; + + ml.logRequest(svcInstanceId, svcName, partnerName, targetEntity, targetServiceName, targetVirtualEntity, msg); + } + + public void logMetricResponse(String requestId, int responseCode, String responseDescription){ + ml.logResponse(responseCode < 400 ? "COMPLETE" : "ERROR", Integer.toString(responseCode), responseDescription); + } + + public void logKeyError(String keys){ + LOG.error("Atleast one of the keys [" + keys + "] should have been populated. This will cause a NPE."); + } + + + /** + * Retrofit code + */ + @Override + public QueryStatus save(String resource, boolean force, boolean localOnly, String key, Map<String, String> params, String prefix, SvcLogicContext ctx) + throws SvcLogicException { + String normResource = resource.split(":")[0]; + + switch(normResource){ + case "custom-query": + case "formatted-query": + case "generic-query": + case "nodes-query": + case "linterface": + case "l2-bridge-sbg": + case "l2-bridge-bgf": + case "echo": + case "test": + break; + + default: + if(key.contains("selflink =")) { + break; + } + if(!key.contains(String.format("%s.", normResource))) { + key = rewriteKey(resource, key, ctx); + } + } + return super.save(resource, force, localOnly, key, params, prefix, ctx); + } + + @Override + public QueryStatus query(String resource, boolean localOnly, String select, String key, String prefix, String orderBy, SvcLogicContext ctx) + throws SvcLogicException { + String normResource = resource.split(":")[0]; + + switch(normResource){ + case "custom-query": + case "formatted-query": + case "generic-query": + case "nodes-query": + case "linterface": + case "l2-bridge-sbg": + case "l2-bridge-bgf": + case "echo": + case "test": + break; + + default: + if(key.contains("selflink =")) { + break; + } + if(!key.contains(String.format("%s.", normResource))) { + key = rewriteKey(resource, key, ctx); + } + } + + return super.query(resource, localOnly, select, key, prefix, orderBy, ctx); + } + + @Override + public QueryStatus delete(String resource, String key, SvcLogicContext ctx) throws SvcLogicException { + String normResource = resource.split(":")[0]; + + switch(normResource){ + case "custom-query": + case "formatted-query": + case "generic-query": + case "nodes-query": + case "linterface": + case "l2-bridge-sbg": + case "l2-bridge-bgf": + case "echo": + case "test": + break; + + default: + if(key.contains("selflink =")) { + break; + } + if(!key.contains(String.format("%s.", normResource))) { + key = rewriteKey(resource, key, ctx); + } + } + + return super.delete(resource, key, ctx); + } + + @Override + public QueryStatus update(String resource, String key, Map<String, String> params, String prefix, SvcLogicContext ctx) throws SvcLogicException { + String normResource = resource.split(":")[0]; + + switch(normResource){ + case "custom-query": + case "formatted-query": + case "generic-query": + case "nodes-query": + case "linterface": + case "l2-bridge-sbg": + case "l2-bridge-bgf": + case "echo": + case "test": + break; + + default: + if(key.contains("selflink =")) { + break; + } + if(!key.contains(String.format("%s.", normResource))) { + key = rewriteKey(resource, key, ctx); + } + } + + return super.update(resource, key, params, prefix, ctx); + } + + private String rewriteKey(String resource, String key, SvcLogicContext ctx) { + LOG.info("AAI Deprecation - the format of request key is no longer supported. Please rewrite this key : " + key); + + String normResource = resource.split(":")[0]; + Class<? extends AAIDatum> clazz = AAIRequestLighty.getClassFromResource(normResource) ; + + if(clazz == null) + return key; + + List<String> fieldAnnotatedNames = new LinkedList<>(); + + Field[] fields = clazz.getDeclaredFields(); + for(Field field : fields) { + String fieldName = field.getName(); + XmlElement annotation = field.getAnnotation(XmlElement.class); + if(annotation == null) + continue; + String primaryId = annotation.name(); + if("##default".equals(primaryId)) { + primaryId = fieldName; + } + fieldAnnotatedNames.add(primaryId); + } + + HashMap<String, String> nameValues = AAIServiceUtils.keyToHashMap(key, ctx); + Set<String> keyset = nameValues.keySet(); + for(String keyName : keyset) { + if(keyName.contains(".")) + continue; + else { + String tmpKeyName = keyName.replaceAll("_", "-"); + String valueToSubstitute = String.format("%s =", tmpKeyName); + if(fieldAnnotatedNames.contains(tmpKeyName) && key.contains(valueToSubstitute)) { + key = key.replace(valueToSubstitute, String.format("%s.%s =", normResource, tmpKeyName)); + } + } + } + + + return key; + } + + @Override + public String getPathTemplateForResource(String resoourceName, String keys, SvcLogicContext ctx) throws MalformedURLException { + return AAIServiceUtils.getPathForResource(resoourceName, StringUtils.join(keys, " AND "), ctx); + } + + @Override + public boolean isDeprecatedFormat(String resource, Map<String, String> nameValues) { + return !AAIServiceUtils.isValidFormat(resource, nameValues); + } + + public AAIRequestLighty getRequestFromResource(String resoourceName) { + return AAIRequestLighty.getRequestFromResource(resoourceName); + } + + /* (non-Javadoc) + * @see org.onap.ccsdk.sli.core.sli.aai.haha#query(org.onap.ccsdk.sli.core.sli.aai.AAIRequestLighty) + */ + @Override + public String query(AAIRequestLighty request) throws AAIServiceException { + return executor.get(request); + } + + /* (non-Javadoc) + * @see org.onap.ccsdk.sli.core.sli.aai.haha#save(org.onap.ccsdk.sli.core.sli.aai.AAIRequestLighty) + */ + @Override + public String save(AAIRequestLighty request) throws AAIServiceException { + return executor.post(request); + } + + public boolean update(AAIRequestLighty request, String resourceVersion) throws AAIServiceException { + return executor.patch(request, resourceVersion); + } + + /* (non-Javadoc) + * @see org.onap.ccsdk.sli.core.sli.aai.haha#delete(org.onap.ccsdk.sli.core.sli.aai.AAIRequestLighty, java.lang.String) + */ + @Override + public boolean delete(AAIRequestLighty request, String resourceVersion) throws AAIServiceException { + return executor.delete(request, resourceVersion); + } + +} diff --git a/aai-service/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/aai/AAIServiceProviderLighty.java b/aai-service/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/aai/AAIServiceProviderLighty.java new file mode 100755 index 000000000..c0e825268 --- /dev/null +++ b/aai-service/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/aai/AAIServiceProviderLighty.java @@ -0,0 +1,206 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : SDN-C + * ================================================================================ + * Copyright (C) 2017 - 2018 AT&T Intellectual Property. All rights + * reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +/** + * @author Rich Tabedzki + * + */ +package org.onap.ccsdk.sli.adaptors.aai; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.lang.reflect.Method; +import java.util.Optional; +import java.util.Properties; +import java.util.Vector; +import org.onap.ccsdk.sli.core.utils.KarafRootFileResolver; +import org.onap.ccsdk.sli.core.utils.PropertiesFileResolver; +import org.onap.ccsdk.sli.core.utils.common.BundleContextFileResolver; +import org.onap.ccsdk.sli.core.utils.common.CoreDefaultFileResolver; +import org.onap.ccsdk.sli.core.utils.common.SdncConfigEnvVarFileResolver; +import org.osgi.framework.BundleContext; +import org.osgi.framework.FrameworkUtil; +import org.osgi.framework.ServiceReference; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * THIS CLASS IS A COPY OF {@link AAIServiceProvider} WITH REMOVED OSGi DEPENDENCIES + */ +public class AAIServiceProviderLighty implements UtilsProvider { + + private static final Logger LOG = LoggerFactory.getLogger(AAIServiceProviderLighty.class); + + /** + * The name of the properties file for database configuration + */ + private static final String AAISEERVICE_PROP_FILE_NAME = "aaiclient.properties"; + + /** + * The name of the pwd key + */ + private static final String AAICLIENT_PROPERTY_NAME = "org.onap.ccsdk.sli.adaptors.aai.client.psswd"; + + /** + * A prioritized list of strategies for resolving dblib properties files. + */ + private Vector<PropertiesFileResolver> dblibPropertiesFileResolvers = new Vector<>(); + + /** + * The configuration properties for the db connection. + */ + private Properties properties; + + /** + * Set up the prioritized list of strategies for resolving dblib properties files. + */ + public AAIServiceProviderLighty() { + dblibPropertiesFileResolvers.add(new SdncConfigEnvVarFileResolver( + "Using property file (1) from environment variable" + )); + dblibPropertiesFileResolvers.add(new BundleContextFileResolver( + "Using property file (3) from JRE argument", AAIServiceProviderLighty.class + )); + dblibPropertiesFileResolvers.add(new KarafRootFileResolver( + "Using property file (4) from karaf root", this + )); + dblibPropertiesFileResolvers.add(new CoreDefaultFileResolver( + "Using property file (5) from default directory" + )); + + // determines properties file as according to the priority described in the class header comment + final File propertiesFile = determinePropertiesFile(); + if (propertiesFile != null) { + try(FileInputStream fileInputStream = new FileInputStream(propertiesFile)) { + properties = new Properties(); + properties.load(fileInputStream); + + if(properties.containsKey(AAICLIENT_PROPERTY_NAME)) { + String sensitive = properties.getProperty(AAICLIENT_PROPERTY_NAME); + if(sensitive != null && sensitive.startsWith("ENC:")) { + try { + sensitive = sensitive.substring(4); + String postsense = decrypt(sensitive); + properties.setProperty(AAICLIENT_PROPERTY_NAME, postsense); + } catch(Exception exc) { + LOG.error("Failed to translate property", exc); + } + } + } + } catch (final IOException e) { + LOG.error("Failed to load properties for file: {}", propertiesFile.toString(), + new AAIServiceException("Failed to load properties for file: " + + propertiesFile.toString(), e)); + } + } + } + + /** + * + * @param value + * @return decrypted string if successful or the original value if unsuccessful + */ + private String decrypt(String value) { + try { + BundleContext bctx = FrameworkUtil.getBundle(this.getClass()).getBundleContext(); + + ServiceReference sref = bctx.getServiceReference("org.opendaylight.aaa.encrypt.AAAEncryptionService"); + if(sref == null) { + LOG.warn("Could not acquire service reference for 'org.opendaylight.aaa.encrypt.AAAEncryptionService'"); + return value; + } + Object encrSvc = bctx.getService(sref); + if(encrSvc == null) { + LOG.warn("Could not access service for 'org.opendaylight.aaa.encrypt.AAAEncryptionService'"); + return value; + } + + Method gs2Method = encrSvc.getClass().getMethod("decrypt", new Class[] { "".getClass() }); + Object unmasked = gs2Method.invoke(encrSvc, new Object[] { value }); + return unmasked.toString(); + + } catch (Exception exc) { + LOG.error("Failure", exc); + return value; + } + } + + /** + * Extract db config properties. + * + * @return the db config properties + */ + public Properties getProperties() { + return properties; + } + + /** + * Reports the method chosen for properties resolution to the <code>Logger</code>. + * + * @param message Some user friendly message + * @param fileOptional The file location of the chosen properties file + * @return the file location of the chosen properties file + */ + private static File reportSuccess(final String message, final Optional<File> fileOptional) { + if(fileOptional.isPresent()) { + final File file = fileOptional.get(); + LOG.info("{} {}", message, file.getPath()); + return file; + } + return null; + } + + /** + * Reports fatal errors. This is the case in which no properties file could be found. + * + * @param message An appropriate fatal error message + * @param dblibConfigurationException An exception describing what went wrong during resolution + */ + private static void reportFailure(final String message, + final AAIServiceException dblibConfigurationException) { + + LOG.error("{}", message, dblibConfigurationException); + } + + /** + * Determines the dblib properties file to use based on the following priority: + * <ol> + * <li>A directory identified by the system environment variable <code>SDNC_CONFIG_DIR</code></li> + * <li>The default directory <code>DEFAULT_DBLIB_PROP_DIR</code></li> + * <li>A directory identified by the JRE argument <code>dblib.properties</code></li> + * <li>A <code>dblib.properties</code> file located in the karaf root directory</li> + * </ol> + */ + File determinePropertiesFile() { + + for (final PropertiesFileResolver dblibPropertiesFileResolver : dblibPropertiesFileResolvers) { + final Optional<File> fileOptional = dblibPropertiesFileResolver.resolveFile(AAISEERVICE_PROP_FILE_NAME); + if (fileOptional.isPresent()) { + return reportSuccess(dblibPropertiesFileResolver.getSuccessfulResolutionMessage(), fileOptional); + } + } + + reportFailure("Missing configuration properties resource(3)", + new AAIServiceException("Missing configuration properties resource(3): " + + AAISEERVICE_PROP_FILE_NAME)); + return null; + } +} diff --git a/aai-service/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/aai/CustomQueryRequestLighty.java b/aai-service/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/aai/CustomQueryRequestLighty.java new file mode 100755 index 000000000..fa8dce485 --- /dev/null +++ b/aai-service/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/aai/CustomQueryRequestLighty.java @@ -0,0 +1,136 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : SDN-C + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights + * reserved. + * Modifications Copyright (C) 2018 IBM. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +/** + * @author Rich Tabedzki + * + */ +package org.onap.ccsdk.sli.adaptors.aai; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Properties; +import org.onap.ccsdk.sli.adaptors.aai.data.AAIDatum; +import org.onap.ccsdk.sli.adaptors.aai.query.FormattedQueryRequestData; +import org.onap.ccsdk.sli.adaptors.aai.query.FormattedQueryResultList; + +/** + * THIS CLASS IS A COPY OF {@link CustomQueryRequest} WITH REMOVED OSGi DEPENDENCIES + */ +public class CustomQueryRequestLighty extends AAIRequestLighty { + + public static final String GENERIC_SEARCH_PATH_CONST = "org.onap.ccsdk.sli.adaptors.aai.query.generic"; + + private final String generic_search_path; + + public static final String FORMAT = "format"; + + + public CustomQueryRequestLighty() { + String tmpGenericSearchPath = configProperties.getProperty(GENERIC_SEARCH_PATH_CONST); + tmpGenericSearchPath = tmpGenericSearchPath.split("search")[0]; + generic_search_path = tmpGenericSearchPath +"query"; + } + + + @Override + public URL getRequestUrl(String method, String resourceVersion) throws UnsupportedEncodingException, MalformedURLException { + + String requestUrl = targetUri+generic_search_path; + + requestUrl = processPathData(requestUrl, requestProperties); + + String formatQuery = requestProperties.getProperty(FORMAT); + + if(formatQuery != null) { + requestUrl = requestUrl +"?format="+formatQuery; + } + URL httpReqUrl = new URL(requestUrl); + + aaiService.LOGwriteFirstTrace(method, httpReqUrl.toString()); + + return httpReqUrl; + } + + @Override + public URL getRequestQueryUrl(String method) throws UnsupportedEncodingException, MalformedURLException { + return getRequestUrl(method, null); + } + + + @Override + public String toJSONString() { + ObjectMapper mapper = getObjectMapper(); + FormattedQueryRequestData tenant = (FormattedQueryRequestData)requestDatum; + String jsonText = null; + try { + jsonText = mapper.writeValueAsString(tenant); + } catch (JsonProcessingException exc) { + handleException(this, exc); + return null; + } + return jsonText; + } + + + @Override + public String[] getArgsList() { + String[] args = {FORMAT}; + return args; + } + + + @Override + public Class<? extends AAIDatum> getModelClass() { + return FormattedQueryRequestData.class; + } + + + public static String processPathData(String requestUrl, Properties requestProperties) throws UnsupportedEncodingException { + + String key = FORMAT; + + String encodedVnf = encodeQuery(requestProperties.getProperty(key)); + requestUrl = requestUrl.replace("{identifier}", encodedVnf) ; + aaiService.LOGwriteDateTrace("identifier", requestProperties.getProperty(key)); + + return requestUrl; + } + + public AAIDatum jsonStringToObject(String jsonData) throws IOException { + if(jsonData == null) { + return null; + } + + AAIDatum response = null; + ObjectMapper mapper = getObjectMapper(); + response = mapper.readValue(jsonData, FormattedQueryResultList.class); + return response; + } + + protected boolean expectsDataFromPUTRequest() { + return true; + } +} diff --git a/aai-service/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/aai/EchoRequestLighty.java b/aai-service/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/aai/EchoRequestLighty.java new file mode 100755 index 000000000..46e6aa7af --- /dev/null +++ b/aai-service/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/aai/EchoRequestLighty.java @@ -0,0 +1,98 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : SDN-C + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights + * reserved. + * Modifications Copyright (C) 2018 IBM. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +/** + * @author Rich Tabedzki + * + */ +package org.onap.ccsdk.sli.adaptors.aai; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URL; +import org.onap.ccsdk.sli.adaptors.aai.data.AAIDatum; +import org.onap.ccsdk.sli.adaptors.aai.data.EchoResponse; + +/** + * THIS CLASS IS A COPY OF {@link EchoRequest} WITH REMOVED OSGi DEPENDENCIES + */ +public class EchoRequestLighty extends AAIRequestLighty { + + + + private final String echoPath; + + public EchoRequestLighty() { + echoPath = "/aai/util/echo"; + } + + + @Override + public URL getRequestUrl(String method, String resourceVersion) throws UnsupportedEncodingException, MalformedURLException { + + String requestUrl = targetUri+echoPath; + + if(resourceVersion != null) { + requestUrl = requestUrl +"?resource-version="+resourceVersion; + } + URL httpReqUrl = new URL(requestUrl); + + aaiService.LOGwriteFirstTrace(method, httpReqUrl.toString()); + + return httpReqUrl; + } + + @Override + public URL getRequestQueryUrl(String method) throws UnsupportedEncodingException, MalformedURLException { + return getRequestUrl(method, null); + } + + + @Override + public String toJSONString() { + ObjectMapper mapper = getObjectMapper(); + EchoResponse tenant = (EchoResponse)requestDatum; + String jsonText = null; + try { + jsonText = mapper.writeValueAsString(tenant); + } catch (JsonProcessingException exc) { + handleException(this, exc); + return null; + } + return jsonText; + } + + + @Override + public String[] getArgsList() { + String[] args = {}; + return args; + } + + + @Override + public Class<? extends AAIDatum> getModelClass() { + return EchoResponse.class; + } + +} diff --git a/aai-service/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/aai/GenericQueryRequestLighty.java b/aai-service/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/aai/GenericQueryRequestLighty.java new file mode 100755 index 000000000..65fe0e783 --- /dev/null +++ b/aai-service/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/aai/GenericQueryRequestLighty.java @@ -0,0 +1,129 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : SDN-C + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights + * reserved. + * ================================================================================ + * Modifications Copyright (C) 2018 IBM. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +/** + * @author Rich Tabedzki + * + */ +package org.onap.ccsdk.sli.adaptors.aai; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Properties; +import org.onap.aai.inventory.v16.ResultData; +import org.onap.ccsdk.sli.adaptors.aai.data.AAIDatum; + +/** + * THIS CLASS IS A COPY OF {@link GenericQueryRequest} WITH REMOVED OSGi DEPENDENCIES + */ +public class GenericQueryRequestLighty extends AAIRequestLighty { + + public static final String GENERIC_SEARCH_PATH = "org.onap.ccsdk.sli.adaptors.aai.query.generic"; + + private final String generic_search_path; + + public static final String START_NODE_TYPE = "start-node-type"; + public static final String IDENTIFIER = "identifier"; + public static final String VALUE = "value"; + + + public GenericQueryRequestLighty() { + generic_search_path = configProperties.getProperty(GENERIC_SEARCH_PATH); + } + + @Override + public URL getRequestUrl(String method, String resourceVersion) throws UnsupportedEncodingException, MalformedURLException { + + String request_url = targetUri+generic_search_path; + + request_url = processPathData(request_url, requestProperties); + + if(resourceVersion != null) { + request_url = request_url +"?resource-version="+resourceVersion; + } + URL http_req_url = new URL(request_url); + + aaiService.LOGwriteFirstTrace(method, http_req_url.toString()); + + return http_req_url; + } + + @Override + public URL getRequestQueryUrl(String method) throws UnsupportedEncodingException, MalformedURLException { + return getRequestUrl(method, null); + } + + + @Override + public String toJSONString() { + ObjectMapper mapper = getObjectMapper(); + ResultData tenant = (ResultData)requestDatum; + String json_text = null; + try { + json_text = mapper.writeValueAsString(tenant); + } catch (JsonProcessingException exc) { + handleException(this, exc); + return null; + } + return json_text; + } + + + @Override + public String[] getArgsList() { + String[] args = {START_NODE_TYPE, IDENTIFIER, VALUE}; + return args; + } + + + @Override + public Class<? extends AAIDatum> getModelClass() { + return ResultData.class; + } + + + public static String processPathData(String request_url, Properties requestProperties) throws UnsupportedEncodingException { + + String key = IDENTIFIER; + + String encoded_vnf = encodeQuery(requestProperties.getProperty(key)); + request_url = request_url.replace("{identifier}", encoded_vnf) ; + aaiService.LOGwriteDateTrace(IDENTIFIER, requestProperties.getProperty(key)); + + key = VALUE; + + encoded_vnf = encodeQuery(requestProperties.getProperty(key)); + request_url = request_url.replace("{value}", encoded_vnf) ; + aaiService.LOGwriteDateTrace(VALUE, requestProperties.getProperty(key)); + + key = START_NODE_TYPE; + + encoded_vnf = encodeQuery(requestProperties.getProperty(key)); + request_url = request_url.replace("{start-node-type}", encoded_vnf) ; + aaiService.LOGwriteDateTrace(START_NODE_TYPE, requestProperties.getProperty(key)); + + return request_url; + } +} diff --git a/aai-service/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/aai/GenericRequestLighty.java b/aai-service/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/aai/GenericRequestLighty.java new file mode 100755 index 000000000..96b1e7f19 --- /dev/null +++ b/aai-service/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/aai/GenericRequestLighty.java @@ -0,0 +1,261 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : SDN-C + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights + * reserved. + * ================================================================================ + * Modifications Copyright (C) 2018 IBM. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + /** + * @author Rich Tabedzki + * + */ +package org.onap.ccsdk.sli.adaptors.aai; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.base.Joiner; +import java.io.UnsupportedEncodingException; +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.net.MalformedURLException; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import org.onap.aai.inventory.v16.L3Network; +import org.onap.aai.inventory.v16.L3Networks; +import org.onap.ccsdk.sli.adaptors.aai.data.AAIDatum; + +/** + * THIS CLASS IS A COPY OF {@link GenericRequest} WITH REMOVED OSGi DEPENDENCIES + */ +public class GenericRequestLighty extends AAIRequestLighty { + + + protected Class<? extends AAIDatum> model; + + public GenericRequestLighty(Class<? extends AAIDatum> clazz) { + model = clazz; + } + + @Override + public String updatePathDataValues(Object resourceVersion) throws UnsupportedEncodingException, MalformedURLException { + + String originalPath = null; + String pathSubstitute = null; + String resourceName = null; + + Annotation[] annotations = model.getAnnotations(); + for(Annotation annotation : annotations) { + Class<? extends Annotation> anotationType = annotation.annotationType(); + String annotationName = anotationType.getName(); + if("javax.xml.bind.annotation.XmlRootElement".equals(annotationName)){ + XmlRootElement order = (XmlRootElement)annotation; + resourceName = order.name(); + } + } + + String request_url = getRequestPath(resourceName); + + Map<String, String> queryParams = new HashMap<> (); + if(resourceVersion != null) { + queryParams.put("resource-version", resourceVersion.toString()); + } + + Set<String> uniqueResources = extractUniqueResourceSetFromKeys(requestProperties.stringPropertyNames()); + + String[] keys = requestProperties.keySet().toArray(new String[0]); + for(String key : keys) { + switch(key) { + case "cloud-region.cloud-region-id": + case "entitlement.resource-uuid": + case "license.resource-uuid": + case "route-target.route-target-role": + case "service-capability.vnf-type": + case "ctag-pool.availability-zone-name": + continue; + } + + String value = requestProperties.getProperty(key); + if(key.contains(".")) { + String[] splitKey = key.split("\\."); + if("cloud-region".equals(splitKey[0])){ + String cloudRegionId = requestProperties.getProperty("cloud-region.cloud-region-id"); + aaiService.LOGwriteDateTrace("cloud-region-id", cloudRegionId); + String token = String.format("%s/{%s}/{cloud-region-id}", splitKey[0], splitKey[1] ); + String encoded_owner = encodeQuery(value); + String encoded_region = encodeQuery(cloudRegionId); + request_url = request_url.replace(token, String.format("%s/%s/%s", splitKey[0], encoded_owner, encoded_region)); + } else if("entitlement".equals(splitKey[0])){ + String cloudRegionId = requestProperties.getProperty("entitlement.resource-uuid"); + aaiService.LOGwriteDateTrace("resource-uuid", cloudRegionId); + String token = String.format("%s/{%s}/{resource-uuid}", splitKey[0], splitKey[1] ); + String encoded_owner = encodeQuery(value); + String encoded_region = encodeQuery(cloudRegionId); + request_url = request_url.replace(token, String.format("%s/%s/%s", splitKey[0], encoded_owner, encoded_region)); + } else if("license".equals(splitKey[0])){ + String cloudRegionId = requestProperties.getProperty("license.resource-uuid"); + aaiService.LOGwriteDateTrace("resource-uuid", cloudRegionId); + String token = String.format("%s/{%s}/{resource-uuid}", splitKey[0], splitKey[1] ); + String encoded_owner = encodeQuery(value); + String encoded_region = encodeQuery(cloudRegionId); + request_url = request_url.replace(token, String.format("%s/%s/%s", splitKey[0], encoded_owner, encoded_region)); + } else if("route-target".equals(splitKey[0])){ + String cloudRegionId = requestProperties.getProperty("route-target.route-target-role"); + aaiService.LOGwriteDateTrace("route-target-role", cloudRegionId); + String token = String.format("%s/{%s}/{route-target-role}", splitKey[0], splitKey[1] ); + String encoded_owner = encodeQuery(value); + String encoded_region = encodeQuery(cloudRegionId); + request_url = request_url.replace(token, String.format("%s/%s/%s", splitKey[0], encoded_owner, encoded_region)); + } else if("service-capability".equals(splitKey[0])){ + String vnfType = requestProperties.getProperty("service-capability.vnf-type"); + aaiService.LOGwriteDateTrace("vnf-type", vnfType); + String token = String.format("%s/{%s}/{vnf-type}", splitKey[0], splitKey[1] ); + String encoded_service_type = encodeQuery(value); + String encoded_vnf_type = encodeQuery(vnfType); + if("service-capability".equals(resourceName)) { + request_url = request_url.replace(token, String.format("%s/%s/%s", splitKey[0], encoded_service_type, encoded_vnf_type)); + } else if("service-capabilities".equals(resourceName)) { + queryParams.put("service-type", encoded_service_type); + queryParams.put("vnf-type", encoded_vnf_type); + } + } else if("ctag-pool".equals(splitKey[0])){ + String cloudRegionId = requestProperties.getProperty("ctag-pool.availability-zone-name"); + aaiService.LOGwriteDateTrace("availability-zone-name", cloudRegionId); + String token = String.format("%s/{%s}/{availability-zone-name}", splitKey[0], splitKey[1] ); + String encoded_owner = encodeQuery(value); + String encoded_region = encodeQuery(cloudRegionId); + request_url = request_url.replace(token, String.format("%s/%s/%s", splitKey[0], encoded_owner, encoded_region)); + } else { + Class<? extends AAIDatum> clazz = getClassFromResource(splitKey[0]); + + if(clazz != null) { + if(clazz == this.model) { + Field[] fields = this.model.getDeclaredFields(); + Field field = fields[0]; + String fieldName = field.getName(); + XmlElement annotation = field.getAnnotation(XmlElement.class); + String primaryId = null; + if(annotation != null) { + primaryId = annotation.name(); + if("##default".equals(primaryId)) { + primaryId = fieldName; + } + } else { + primaryId = fieldName; + } + + String token = String.format("%s/{%s}", splitKey[0], primaryId); + + if(splitKey[1].equals(primaryId)) { + String encoded_vnf = encodeQuery(value); + request_url = request_url.replace(token, String.format("%s/%s", splitKey[0], encoded_vnf)); + } else { + queryParams.put(splitKey[1], encodeQuery(value)); + originalPath = token; + pathSubstitute = String.format("%s", splitKey[0]); + } + } else if(L3Networks.class == this.model) { + Field[] fields = L3Network.class.getDeclaredFields(); + Field field = fields[0]; + String fieldName = field.getName(); + XmlElement annotation = field.getAnnotation(XmlElement.class); + String primaryId = annotation.name(); + if("##default".equals(primaryId)) { + primaryId = fieldName; + } + + String token = String.format("%s/{%s}", splitKey[0], primaryId); + originalPath = token; + pathSubstitute = String.format(""); + + queryParams.put(splitKey[1], encodeQuery(value)); + } else { + String token = String.format("%s/{%s}", splitKey[0], splitKey[1]); + String encoded_vnf = encodeQuery(value); + request_url = request_url.replace(token, String.format("%s/%s", splitKey[0], encoded_vnf)); + } + } + + } + aaiService.LOGwriteDateTrace(splitKey[1], value); + } + } + + if(originalPath != null && pathSubstitute != null) + request_url = request_url.replace(originalPath, pathSubstitute); + + if(!queryParams.isEmpty()) { + Joiner.MapJoiner mapJoiner = Joiner.on("&").withKeyValueSeparator("="); + String queryString = mapJoiner.join(queryParams); + request_url = String.format("%s?%s", request_url, queryString); + } + + return request_url; + } + + @Override + public URL getRequestQueryUrl(String method) throws UnsupportedEncodingException, MalformedURLException, URISyntaxException { + return this.getRequestUrl(method, null); + } + + + @Override + public String toJSONString() { + ObjectMapper mapper = getObjectMapper(); + + String json_text = null; + try { + json_text = mapper.writeValueAsString(requestDatum); + } catch (JsonProcessingException exc) { + handleException(this, exc); + return null; + } + return json_text; + } + + @Override + public String[] getArgsList() { + String[] args = {}; + return args; + } + + @Override + public Class<? extends AAIDatum> getModelClass() { + return model; + } + + public void processRequestPathValues(Map<String, String> nameValues) { + // identify unique resources + Set<String> uniqueResources = AAIRequest.extractUniqueResourceSetFromKeys(nameValues.keySet()); + + String[] arguments = nameValues.keySet().toArray(new String[0]); + for(String name : arguments) { + String tmpName = name.replaceAll("-", "_"); + String value = nameValues.get(tmpName); + if(value != null && !value.isEmpty()) { + value = value.trim().replace("'", "").replace("$", "").replace("'", ""); + tmpName = name.replaceAll("_", "-"); + this.addRequestProperty(tmpName, value); + } + } + } +} diff --git a/aai-service/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/aai/NodesQueryRequestLighty.java b/aai-service/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/aai/NodesQueryRequestLighty.java new file mode 100755 index 000000000..ed79b261b --- /dev/null +++ b/aai-service/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/aai/NodesQueryRequestLighty.java @@ -0,0 +1,130 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : SDN-C + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights + * reserved. + * ================================================================================ + * Modifications Copyright (C) 2018 IBM. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +/** + * @author Rich Tabedzki + * + */ +package org.onap.ccsdk.sli.adaptors.aai; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Properties; +import org.onap.aai.inventory.v16.SearchResults; +import org.onap.ccsdk.sli.adaptors.aai.data.AAIDatum; + +/** + * THIS CLASS IS A COPY OF {@link NodesQueryRequest} WITH REMOVED OSGi DEPENDENCIES + */ +public class NodesQueryRequestLighty extends AAIRequestLighty { + + public static final String NODES_SEARCH_PATH = "org.onap.ccsdk.sli.adaptors.aai.query.nodes"; + + private final String nodes_search_path; + + public static final String NODE_TYPE = "node-type"; + public static final String ENTITY_IDENTIFIER = "entity-identifier"; + public static final String ENTITY_VALUE = "entity-value"; + + + public NodesQueryRequestLighty() { + nodes_search_path = configProperties.getProperty(NODES_SEARCH_PATH); + } + + + @Override + public URL getRequestUrl(String method, String resourceVersion) throws UnsupportedEncodingException, MalformedURLException { + + String request_url = targetUri+nodes_search_path; + + request_url = processPathData(request_url, requestProperties); + + if(resourceVersion != null) { + request_url = request_url +"?resource-version="+resourceVersion; + } + URL http_req_url = new URL(request_url); + + aaiService.LOGwriteFirstTrace(method, http_req_url.toString()); + + return http_req_url; + } + + @Override + public URL getRequestQueryUrl(String method) throws UnsupportedEncodingException, MalformedURLException { + return getRequestUrl(method, null); + } + + + @Override + public String toJSONString() { + ObjectMapper mapper = getObjectMapper(); + SearchResults tenant = (SearchResults)requestDatum; + String json_text = null; + try { + json_text = mapper.writeValueAsString(tenant); + } catch (JsonProcessingException exc) { + handleException(this, exc); + return null; + } + return json_text; + } + + + @Override + public String[] getArgsList() { + String[] args = {NODE_TYPE, ENTITY_IDENTIFIER, ENTITY_VALUE}; + return args; + } + + + @Override + public Class<? extends AAIDatum> getModelClass() { + return SearchResults.class; + } + + + public static String processPathData(String request_url, Properties requestProperties) throws UnsupportedEncodingException { + + String key = ENTITY_IDENTIFIER; + + String encoded_vnf = encodeQuery(requestProperties.getProperty(key)); + request_url = request_url.replace("{entity-identifier}", encoded_vnf) ; + aaiService.LOGwriteDateTrace(ENTITY_IDENTIFIER, requestProperties.getProperty(key)); + + key = ENTITY_VALUE; + + encoded_vnf = encodeQuery(requestProperties.getProperty(key)); + request_url = request_url.replace("{entity-name}", encoded_vnf) ; + aaiService.LOGwriteDateTrace("entity-name", requestProperties.getProperty(key)); + + key = NODE_TYPE; + + encoded_vnf = encodeQuery(requestProperties.getProperty(key)); + request_url = request_url.replace("{node-type}", encoded_vnf) ; + aaiService.LOGwriteDateTrace(NODE_TYPE, requestProperties.getProperty(key)); + + return request_url; + } +} diff --git a/aai-service/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/aai/PathRequestLighty.java b/aai-service/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/aai/PathRequestLighty.java new file mode 100755 index 000000000..47543d0b2 --- /dev/null +++ b/aai-service/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/aai/PathRequestLighty.java @@ -0,0 +1,92 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : SDN-C + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights + * reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +/** + * @author Rich Tabedzki + * + */ +package org.onap.ccsdk.sli.adaptors.aai; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URL; +import org.onap.ccsdk.sli.adaptors.aai.data.AAIDatum; + +/** + * THIS CLASS IS A COPY OF {@link PathRequest} WITH REMOVED OSGi DEPENDENCIES + */ +public class PathRequestLighty extends AAIRequestLighty { + + private final Class<? extends AAIDatum> classType; + + public static final String RESOURCE_PATH = "resource-path"; + + public PathRequestLighty(Class<?> type) { + classType = (Class<? extends AAIDatum>)type; + } + + + @Override + public URL getRequestUrl(String method, String resourceVersion) throws UnsupportedEncodingException, MalformedURLException { + + String request_url = targetUri + "{resource-path}"; + + String encoded_vnf = requestProperties.getProperty(RESOURCE_PATH); + request_url = request_url.replace("{resource-path}", encoded_vnf) ; + + URL http_req_url = new URL(request_url); + + aaiService.LOGwriteFirstTrace(method, http_req_url.toString()); + + return http_req_url; + } + + @Override + public URL getRequestQueryUrl(String method) throws UnsupportedEncodingException, MalformedURLException { + return this.getRequestUrl(method, null); + } + + + @Override + public String toJSONString() { + ObjectMapper mapper = getObjectMapper(); + String json_text = null; + try { + json_text = mapper.writeValueAsString(classType); + } catch (JsonProcessingException exc) { + handleException(this, exc); + return null; + } + return json_text; + } + + @Override + public String[] getArgsList() { + String[] args = {RESOURCE_PATH}; + return args; + } + + @Override + public Class<? extends AAIDatum> getModelClass() { + return classType; + } +} diff --git a/aai-service/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/aai/RelationshipListRequestLighty.java b/aai-service/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/aai/RelationshipListRequestLighty.java new file mode 100755 index 000000000..03a22e732 --- /dev/null +++ b/aai-service/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/aai/RelationshipListRequestLighty.java @@ -0,0 +1,67 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : SDN-C + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights + * reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +/** + * @author Rich Tabedzki + * + */ +package org.onap.ccsdk.sli.adaptors.aai; + +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.List; +import org.apache.http.NameValuePair; +import org.apache.http.client.utils.URIBuilder; +import org.apache.http.message.BasicNameValuePair; +import org.onap.aai.inventory.v16.RelationshipList; + +/** + * THIS CLASS IS A COPY OF {@link RelationshipListRequest} WITH REMOVED OSGi DEPENDENCIES + */ +public class RelationshipListRequestLighty extends GenericRequestLighty { + + public static final String SELFLINK = "selflink"; + + public RelationshipListRequestLighty(AAIRequestLighty masterRequest) { + super(RelationshipList.class); + this.addMasterRequest(masterRequest); + } + + + @Override + public URL getRequestUrl(String method, String resourceVersion) throws UnsupportedEncodingException, MalformedURLException, URISyntaxException { + + URL url = super.getRequestUrl(method, null); + URIBuilder builder = new URIBuilder(url.toURI()); + String newPath = builder.getPath() + "/relationship-list"; + builder.setPath(newPath); + if(resourceVersion != null) { + List<NameValuePair> queryList = builder.getQueryParams(); + NameValuePair nvp = new BasicNameValuePair("resourceVersion", resourceVersion); + queryList.add(nvp); + } + + aaiService.LOGwriteFirstTrace(method, builder.toString()); + + return builder.build().toURL(); + } +} diff --git a/aai-service/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/aai/RelationshipRequestLighty.java b/aai-service/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/aai/RelationshipRequestLighty.java new file mode 100755 index 000000000..6e375d5a9 --- /dev/null +++ b/aai-service/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/aai/RelationshipRequestLighty.java @@ -0,0 +1,67 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : SDN-C + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights + * reserved. + * Modifications Copyright (C) 2018 IBM. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +/** + * @author Rich Tabedzki + * + */ +package org.onap.ccsdk.sli.adaptors.aai; + +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.List; +import org.apache.http.NameValuePair; +import org.apache.http.client.utils.URIBuilder; +import org.apache.http.message.BasicNameValuePair; +import org.onap.aai.inventory.v16.Relationship; + +/** + * THIS CLASS IS A COPY OF {@link RelationshipRequest} WITH REMOVED OSGi DEPENDENCIES + */ +public class RelationshipRequestLighty extends GenericRequestLighty { + + public RelationshipRequestLighty(AAIRequestLighty masterRequest) { + super(Relationship.class); + this.addMasterRequest(masterRequest); + } + + + @Override + public URL getRequestUrl(String method, String resourceVersion) throws UnsupportedEncodingException, MalformedURLException, URISyntaxException { + + + URL url = super.getRequestUrl(method, null); + URIBuilder builder = new URIBuilder(url.toURI()); + String newPath = builder.getPath() + "/relationship-list/relationship"; + builder.setPath(newPath); + if(resourceVersion != null) { + List<NameValuePair> queryList = builder.getQueryParams(); + NameValuePair nvp = new BasicNameValuePair("resourceVersion", resourceVersion); + queryList.add(nvp); + } + + aaiService.LOGwriteFirstTrace(method, builder.toString()); + + return builder.build().toURL(); + } +} diff --git a/aai-service/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/aai/SelfLinkRequestLighty.java b/aai-service/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/aai/SelfLinkRequestLighty.java new file mode 100755 index 000000000..aafc993a0 --- /dev/null +++ b/aai-service/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/aai/SelfLinkRequestLighty.java @@ -0,0 +1,110 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : SDN-C + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights + * reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +/** + * @author Rich Tabedzki + * + */ +package org.onap.ccsdk.sli.adaptors.aai; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.base.Joiner; +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URL; +import org.onap.ccsdk.sli.adaptors.aai.data.AAIDatum; + +/** + * THIS CLASS IS A COPY OF {@link SelfLinkRequest} WITH REMOVED OSGi DEPENDENCIES + */ +public class SelfLinkRequestLighty extends AAIRequestLighty { + + private final Class<? extends AAIDatum> classType; + + public static final String SELFLINK = "selflink"; + + public SelfLinkRequestLighty(Class<?> type) { + classType = (Class<? extends AAIDatum>)type; + } + + + @Override + public URL getRequestUrl(String method, String resourceVersion) throws UnsupportedEncodingException, MalformedURLException { + + String request_url = null; + + request_url = requestProperties.getProperty(SELFLINK); + try { + URI uri = new URI(request_url); + if(uri.getHost() == null) { + request_url = targetUri + request_url; + } + } catch(Exception exc) { + LOG.error("SelfLinkRequest.getRequestUrl", exc); + } + String query = null; + + if(request_url.contains("?")) { + query = request_url.substring(request_url.indexOf("?")); + Joiner.MapJoiner mapJoiner = Joiner.on(",").withKeyValueSeparator("="); +// String queryString = mapJoiner.join(query); + } else { + request_url = request_url + "?depth=1"; + } + + URL http_req_url = new URL(request_url); + + aaiService.LOGwriteFirstTrace(method, http_req_url.toString()); + + return http_req_url; + } + + @Override + public URL getRequestQueryUrl(String method) throws UnsupportedEncodingException, MalformedURLException { + return this.getRequestUrl(method, null); + } + + + @Override + public String toJSONString() { + ObjectMapper mapper = getObjectMapper(); + String json_text = null; + try { + json_text = mapper.writeValueAsString(classType); + } catch (JsonProcessingException exc) { + handleException(this, exc); + return null; + } + return json_text; + } + + @Override + public String[] getArgsList() { + String[] args = {SELFLINK}; + return args; + } + + @Override + public Class<? extends AAIDatum> getModelClass() { + return classType; + } +} diff --git a/aai-service/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/aai/UpdateRequestLighty.java b/aai-service/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/aai/UpdateRequestLighty.java new file mode 100755 index 000000000..312215410 --- /dev/null +++ b/aai-service/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/aai/UpdateRequestLighty.java @@ -0,0 +1,153 @@ +/*- + * ============LICENSE_START======================================================= + * openECOMP : SDN-C + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights + * reserved. + * Modifications Copyright (C) 2018 IBM. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +/** + * The UpdateRequest class provides processing related to update transaction. + * @author richtabedzki + */ + +package org.onap.ccsdk.sli.adaptors.aai; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.stream.Collectors; +import org.onap.ccsdk.sli.adaptors.aai.data.AAIDatum; + +/** + * THIS CLASS IS A COPY OF {@link UpdateRequest} WITH REMOVED OSGi DEPENDENCIES + */ +public class UpdateRequestLighty extends AAIRequestLighty { + + private AAIRequestLighty request; + private Map<String, String> params; + + public UpdateRequestLighty(AAIRequestLighty request, Map<String, String> parms) { + this.request = request; + this.params = parms; + } + + @Override + public URL getRequestUrl(String method, String resourceVersion) + throws UnsupportedEncodingException, MalformedURLException, URISyntaxException { + return request.getRequestUrl(method, resourceVersion); + } + + @Override + public URL getRequestQueryUrl(String method) throws UnsupportedEncodingException, MalformedURLException, URISyntaxException { + return request.getRequestQueryUrl(method); + } + + @Override + public String toJSONString() { + updateArrayEntries(params); + ObjectMapper mapper = AAIService.getObjectMapper(); + String json = null; + + try { + json = mapper.writeValueAsString(params); + } catch (JsonProcessingException e) { + LOG.error("Could not convert parameters of " + request.getRequestObject().getClass().getName(), e); + } + + return json; + } + + /** + * + * Update array entries. + * The method converts indexed data entries to an array of values + * + * @param data Map containing String:String values representing input data + */ + private void updateArrayEntries( Map<String, String> data) { + Set<String> set = data.keySet() + .stream() + .filter(s -> s.endsWith("_length")) + .collect(Collectors.toSet()); + + for(String lenghtKey : set) { + String key = lenghtKey.replace("_length", ""); +// String index = data.get(lenghtKey); + List<String> array = new ArrayList<>(); + + Set<String> subset = data.keySet() + .stream() + .filter(s -> s.startsWith(String.format("%s[",key))) + .collect(Collectors.toSet()); + for(String subKey : subset) { + String subValue = data.get(subKey); + array.add(subValue); + LOG.trace("{} : {} ", subKey, subValue); + } + data.put(key, array.toString()); + data.remove(lenghtKey); + for(String subKey : subset) { + data.remove(subKey); + } + } + } + + @Override + public String[] getArgsList() { + return request.getArgsList(); + } + + @Override + public Class<? extends AAIDatum> getModelClass() { + return request.getModelClass(); + } + + @Override + public void addRequestProperty(String key, String value) { + request.requestProperties.put(key, value); + } + + public static String processPathData(String requestUrl, Properties requestProperties) { + +// if(request != null) { +// Class<?> clazz = request.getClass(); +// Method function = null; +// try { +// function = clazz.getMethod("processPathData", request_url.getClass(), requestProperties.getClass()); +// request_url = (String) function.invoke(null, request_url, requestProperties); +// } catch (Exception e) { +// e.printStackTrace(); +// } +// } + +// request.processPathData(request_url, requestProperties); + return requestUrl; + } + + public void processRequestPathValues(Map<String, String> nameValues) { + request.processRequestPathValues(nameValues); + } + +} diff --git a/aai-service/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/aai/lighty/AaaServiceModule.java b/aai-service/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/aai/lighty/AaaServiceModule.java new file mode 100644 index 000000000..d3ae452a0 --- /dev/null +++ b/aai-service/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/aai/lighty/AaaServiceModule.java @@ -0,0 +1,55 @@ +/* + * ============LICENSE_START========================================== + * Copyright (c) 2019 PANTHEON.tech s.r.o. + * =================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS + * OF ANY KIND, either express or implied. See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END============================================ + * + */ +package org.onap.ccsdk.sli.adaptors.aai.lighty; + +import io.lighty.core.controller.api.AbstractLightyModule; +import org.onap.ccsdk.sli.adaptors.aai.AAIClientLighty; +import org.onap.ccsdk.sli.adaptors.aai.AAIServiceLighty; +import org.onap.ccsdk.sli.adaptors.aai.AAIServiceProviderLighty; + +/** + * The implementation of the {@link io.lighty.core.controller.api.LightyModule} that manages and provides services from + * the aai-service-provider artifact. + */ +public class AaaServiceModule extends AbstractLightyModule { + + private AAIServiceProviderLighty aaiServiceProvider; + private AAIServiceLighty aaiService; + + @Override + protected boolean initProcedure() { + this.aaiServiceProvider = new AAIServiceProviderLighty(); + this.aaiService = new AAIServiceLighty(aaiServiceProvider); + return true; + } + + @Override + protected boolean stopProcedure() { + return true; + } + + public AAIServiceLighty getAAIClient() { + return aaiService; + } + + // FIXME original blueprint is exposing AAIClient interface but it contains dependencies on AAIRequest which + // contains dependencies on OSGi - rewrite this AAIRequest into interface or remove the OSGi dependency + public AAIClientLighty getAAIService() { + return aaiService; + } + +} diff --git a/aai-service/pom.xml b/aai-service/pom.xml index 8fe15434d..6ce9992fd 100755 --- a/aai-service/pom.xml +++ b/aai-service/pom.xml @@ -21,5 +21,6 @@ <module>provider</module> <module>features</module> <module>installer</module> + <module>lighty</module> </modules> </project> diff --git a/ansible-adapter/ansible-adapter-lighty/pom.xml b/ansible-adapter/ansible-adapter-lighty/pom.xml new file mode 100755 index 000000000..25603e446 --- /dev/null +++ b/ansible-adapter/ansible-adapter-lighty/pom.xml @@ -0,0 +1,48 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.onap.ccsdk.parent</groupId> + <artifactId>binding-parent</artifactId> + <version>1.4.0-SNAPSHOT</version> + <relativePath/> + </parent> + + <groupId>org.onap.ccsdk.sli.adaptors</groupId> + <artifactId>ansible-adapter-lighty</artifactId> + <version>0.6.0-SNAPSHOT</version> + <packaging>jar</packaging> + + <name>ccsdk-sli-adaptors :: aai-service :: ${project.artifactId}</name> + <url>http://maven.apache.org</url> + + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + </properties> + + <dependencyManagement> + <dependencies> + <dependency> + <groupId>org.onap.ccsdk.sli.core</groupId> + <artifactId>ccsdk-lighty-dependency-versions</artifactId> + <version>${project.version}</version> + <type>pom</type> + <scope>import</scope> + </dependency> + </dependencies> + </dependencyManagement> + + <dependencies> + <dependency> + <groupId>io.lighty.core</groupId> + <artifactId>lighty-controller</artifactId> + </dependency> + <dependency> + <groupId>org.onap.ccsdk.sli.adaptors</groupId> + <artifactId>ansible-adapter-bundle</artifactId> + <version>${project.version}</version> + <scope>compile</scope> + </dependency> + </dependencies> +</project> diff --git a/ansible-adapter/ansible-adapter-lighty/src/main/java/org/onap/ccsdk/sli/adaptors/ansible/impl/AnsibleAdapterPropertiesProviderImplLighty.java b/ansible-adapter/ansible-adapter-lighty/src/main/java/org/onap/ccsdk/sli/adaptors/ansible/impl/AnsibleAdapterPropertiesProviderImplLighty.java new file mode 100755 index 000000000..9690cd61e --- /dev/null +++ b/ansible-adapter/ansible-adapter-lighty/src/main/java/org/onap/ccsdk/sli/adaptors/ansible/impl/AnsibleAdapterPropertiesProviderImplLighty.java @@ -0,0 +1,176 @@ +/*- + * ============LICENSE_START======================================================= + * onap + * ================================================================================ + * Copyright (C) 2016 - 2017 ONAP + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.adaptors.ansible.impl; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Optional; +import java.util.Properties; +import java.util.Vector; +import org.onap.ccsdk.sli.adaptors.ansible.AnsibleAdapterPropertiesProvider; +import org.onap.ccsdk.sli.core.sli.ConfigurationException; +import org.onap.ccsdk.sli.core.utils.KarafRootFileResolver; +import org.onap.ccsdk.sli.core.utils.PropertiesFileResolver; +import org.onap.ccsdk.sli.core.utils.common.CoreDefaultFileResolver; +import org.onap.ccsdk.sli.core.utils.common.SdncConfigEnvVarFileResolver; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * THIS CLASS IS A COPY OF {@link AnsibleAdapterPropertiesProviderImpl} WITH REMOVED OSGi DEPENDENCIES + */ +public class AnsibleAdapterPropertiesProviderImplLighty implements AnsibleAdapterPropertiesProvider { + + private static final Logger LOG = LoggerFactory.getLogger(AnsibleAdapterPropertiesProviderImplLighty.class); + + /** + * The name of the properties file for database configuration + */ + private static final String ANSIBLEADAPTER_PROP_FILE_NAME = "ansible-adapter.properties"; + + /** + * A prioritized list of strategies for resolving sql-resource properties files. + */ + private Vector<PropertiesFileResolver> ansibleAdapterPropertiesFileResolvers = new Vector<>(); + + /** + * The configuration properties for the db connection. + */ + private Properties properties; + + /** + * Set up the prioritized list of strategies for resolving dblib properties + * files. + */ + public AnsibleAdapterPropertiesProviderImplLighty() { + ansibleAdapterPropertiesFileResolvers + .add(new SdncConfigEnvVarFileResolver("Using property file (1) from environment variable")); + ansibleAdapterPropertiesFileResolvers.add(new CoreDefaultFileResolver("Using property file (2) from default directory")); + + ansibleAdapterPropertiesFileResolvers.add(new KarafRootFileResolver("Using property file (4) from karaf root", this)); + + // determines properties file as according to the priority described in the + // class header comment + final File propertiesFile = determinePropertiesFile(this); + if (propertiesFile != null) { + try (FileInputStream fileInputStream = new FileInputStream(propertiesFile)) { + properties = new Properties(); + properties.load(fileInputStream); + } catch (final IOException e) { + LOG.error("Failed to load properties for file: {}", propertiesFile.toString(), + new ConfigurationException("Failed to load properties for file: " + propertiesFile.toString(), + e)); + } + } else { + // Try to read properties as resource + + InputStream propStr = getClass().getResourceAsStream("/" + ANSIBLEADAPTER_PROP_FILE_NAME); + if (propStr != null) { + properties = new Properties(); + try { + properties.load(propStr); + propStr.close(); + } catch (IOException e) { + properties = null; + } + } + + } + + if (properties == null) { + reportFailure("Missing configuration properties resource(3)", new ConfigurationException( + "Missing configuration properties resource(3): " + ANSIBLEADAPTER_PROP_FILE_NAME)); + + LOG.info("Defaulting org.onap.appc.adapter.ansible.clientType to TRUST_ALL"); + + properties = new Properties(); + properties.setProperty("org.onap.appc.adapter.ansible.clientType", "TRUST_ALL"); + } + } + + /** + * Extract svclogic config properties. + * + * @return the svclogic config properties + */ + public Properties getProperties() { + return properties; + } + + /** + * Reports the method chosen for properties resolution to the + * <code>Logger</code>. + * + * @param message + * Some user friendly message + * @param fileOptional + * The file location of the chosen properties file + * @return the file location of the chosen properties file + */ + private static File reportSuccess(final String message, final Optional<File> fileOptional) { + if (fileOptional.isPresent()) { + final File file = fileOptional.get(); + LOG.info("{} {}", message, file.getPath()); + return file; + } + return null; + } + + /** + * Reports fatal errors. This is the case in which no properties file could be + * found. + * + * @param message + * An appropriate fatal error message + * @param configurationException + * An exception describing what went wrong during resolution + */ + private static void reportFailure(final String message, final ConfigurationException configurationException) { + + LOG.error("{}", message, configurationException); + } + + /** + * Determines the sql-resource properties file to use based on the following priority: + * <ol> + * <li>A directory identified by the system environment variable + * <code>SDNC_CONFIG_DIR</code></li> + * <li>The default directory <code>DEFAULT_DBLIB_PROP_DIR</code></li> + * <li>A directory identified by the JRE argument + * <code>sql-resource.properties</code></li> + * <li>A <code>sql-resource.properties</code> file located in the karaf root + * directory</li> + * </ol> + */ + File determinePropertiesFile(final AnsibleAdapterPropertiesProviderImplLighty resourceProvider) { + + for (final PropertiesFileResolver sliPropertiesFileResolver : ansibleAdapterPropertiesFileResolvers) { + final Optional<File> fileOptional = sliPropertiesFileResolver.resolveFile(ANSIBLEADAPTER_PROP_FILE_NAME); + if (fileOptional.isPresent()) { + return reportSuccess(sliPropertiesFileResolver.getSuccessfulResolutionMessage(), fileOptional); + } + } + + return null; + } +} diff --git a/ansible-adapter/ansible-adapter-lighty/src/main/java/org/onap/ccsdk/sli/adaptors/ansible/lighty/AnsibleAdapterModule.java b/ansible-adapter/ansible-adapter-lighty/src/main/java/org/onap/ccsdk/sli/adaptors/ansible/lighty/AnsibleAdapterModule.java new file mode 100644 index 000000000..ae49542b4 --- /dev/null +++ b/ansible-adapter/ansible-adapter-lighty/src/main/java/org/onap/ccsdk/sli/adaptors/ansible/lighty/AnsibleAdapterModule.java @@ -0,0 +1,52 @@ +/* + * ============LICENSE_START========================================== + * Copyright (c) 2019 PANTHEON.tech s.r.o. + * =================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS + * OF ANY KIND, either express or implied. See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END============================================ + * + */ +package org.onap.ccsdk.sli.adaptors.ansible.lighty; + +import io.lighty.core.controller.api.AbstractLightyModule; +import org.onap.ccsdk.sli.adaptors.ansible.AnsibleAdapter; +import org.onap.ccsdk.sli.adaptors.ansible.impl.AnsibleAdapterImpl; +import org.onap.ccsdk.sli.adaptors.ansible.impl.AnsibleAdapterPropertiesProviderImplLighty; + +/** + * The implementation of the {@link io.lighty.core.controller.api.LightyModule} that manages and provides services from + * the ansible-adaptor artifact. + */ +public class AnsibleAdapterModule extends AbstractLightyModule { + + private AnsibleAdapterPropertiesProviderImplLighty ansibleProviderImpl; + private AnsibleAdapterImpl ansibleAdapterImpl; + + @Override + protected boolean initProcedure() { + this.ansibleProviderImpl = new AnsibleAdapterPropertiesProviderImplLighty(); + this.ansibleAdapterImpl = new AnsibleAdapterImpl(ansibleProviderImpl); + return true; + } + + @Override + protected boolean stopProcedure() { + return true; + } + + public AnsibleAdapterPropertiesProviderImplLighty getAnsibleAdapterPropertiesProviderImpl() { + return this.ansibleProviderImpl; + } + + public AnsibleAdapter getAnsibleAdapterImpl() { + return ansibleAdapterImpl; + } +} diff --git a/ansible-adapter/pom.xml b/ansible-adapter/pom.xml index d09afdd97..4cf85e3d7 100644 --- a/ansible-adapter/pom.xml +++ b/ansible-adapter/pom.xml @@ -185,5 +185,6 @@ <module>ansible-adapter-bundle</module> <module>ansible-adapter-features</module> <module>ansible-adapter-installer</module> + <module>ansible-adapter-lighty</module> </modules> </project> diff --git a/ccsdk-adaptors-lighty/pom.xml b/ccsdk-adaptors-lighty/pom.xml new file mode 100755 index 000000000..161375ee6 --- /dev/null +++ b/ccsdk-adaptors-lighty/pom.xml @@ -0,0 +1,59 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.onap.ccsdk.parent</groupId> + <artifactId>odlparent-lite</artifactId> + <version>1.4.0-SNAPSHOT</version> + <relativePath/> + </parent> + + <groupId>org.onap.ccsdk.sli.adaptors</groupId> + <artifactId>ccsdk-adaptors-lighty</artifactId> + <version>0.6.0-SNAPSHOT</version> + <packaging>jar</packaging> + + <dependencies> + <dependency> + <groupId>org.onap.ccsdk.sli.core</groupId> + <artifactId>ccsdk-core-lighty</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.onap.ccsdk.sli.adaptors</groupId> + <artifactId>aai-service-lighty</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.onap.ccsdk.sli.adaptors</groupId> + <artifactId>ansible-adapter-lighty</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.onap.ccsdk.sli.adaptors</groupId> + <artifactId>mdsal-resource-lighty</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.onap.ccsdk.sli.adaptors</groupId> + <artifactId>netbox-client-lighty</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.onap.ccsdk.sli.adaptors</groupId> + <artifactId>resource-assignment-lighty</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.onap.ccsdk.sli.adaptors</groupId> + <artifactId>saltstack-adapter-lighty</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.onap.ccsdk.sli.adaptors</groupId> + <artifactId>sql-resource-lighty</artifactId> + <version>${project.version}</version> + </dependency> + </dependencies> +</project> diff --git a/ccsdk-adaptors-lighty/src/main/java/org/onap/ccsdk/sli/adaptors/lighty/CcsdkAdaptorsLightyModule.java b/ccsdk-adaptors-lighty/src/main/java/org/onap/ccsdk/sli/adaptors/lighty/CcsdkAdaptorsLightyModule.java new file mode 100644 index 000000000..102c01c7f --- /dev/null +++ b/ccsdk-adaptors-lighty/src/main/java/org/onap/ccsdk/sli/adaptors/lighty/CcsdkAdaptorsLightyModule.java @@ -0,0 +1,175 @@ +/* + * ============LICENSE_START========================================== + * Copyright (c) 2019 PANTHEON.tech s.r.o. + * =================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS + * OF ANY KIND, either express or implied. See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END============================================ + * + */ +package org.onap.ccsdk.sli.adaptors.lighty; + +import io.lighty.core.controller.api.AbstractLightyModule; +import org.onap.ccsdk.sli.adaptors.aai.lighty.AaaServiceModule; +import org.onap.ccsdk.sli.adaptors.ansible.lighty.AnsibleAdapterModule; +import org.onap.ccsdk.sli.adaptors.netbox.lighty.NetboxClientModule; +import org.onap.ccsdk.sli.adaptors.resource.lighty.ResourceModule; +import org.onap.ccsdk.sli.adaptors.resource.mdsal.lighty.MdsalResourceModule; +import org.onap.ccsdk.sli.adaptors.resource.sql.lighty.SqlModule; +import org.onap.ccsdk.sli.adaptors.saltstack.lighty.SaltstackAdapterModule; +import org.onap.ccsdk.sli.core.dblib.DbLibService; +import org.onap.ccsdk.sli.core.lighty.common.CcsdkLightyUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The implementation of the {@link io.lighty.core.controller.api.LightyModule} that groups all other LightyModules + * from the ccsdk-sli-adaptors repository so they can be all treated as one component (for example started/stopped + * at once). + * For more information about the lighty.io visit the website https://lighty.io. + */ +public class CcsdkAdaptorsLightyModule extends AbstractLightyModule { + + private static final Logger LOG = LoggerFactory.getLogger(CcsdkAdaptorsLightyModule.class); + + private DbLibService dbLibService; + + private AaaServiceModule aaaServiceModule; + private AnsibleAdapterModule ansibleAdapterModule; + private MdsalResourceModule mdsalResourceModule; + private NetboxClientModule netboxClientModule; + private ResourceModule resourceModule; + private SaltstackAdapterModule saltstackAdapterModule; + private SqlModule sqlModule; + + public CcsdkAdaptorsLightyModule(DbLibService dbLibService) { + this.dbLibService = dbLibService; + } + + @Override + protected boolean initProcedure() { + LOG.debug("Initializing CCSDK Adaptors Lighty module..."); + + this.aaaServiceModule = new AaaServiceModule(); + if (!CcsdkLightyUtils.startLightyModule(aaaServiceModule)) { + LOG.error("Unable to start AaaServiceModule in CCSDK Adaptors Lighty module!"); + return false; + } + + this.ansibleAdapterModule = new AnsibleAdapterModule(); + if (!CcsdkLightyUtils.startLightyModule(ansibleAdapterModule)) { + LOG.error("Unable to start AnsibleAdapterModule in CCSDK Adaptors Lighty module!"); + return false; + } + + this.mdsalResourceModule = new MdsalResourceModule(); + if (!CcsdkLightyUtils.startLightyModule(mdsalResourceModule)) { + LOG.error("Unable to start MdsalResourceModule in CCSDK Adaptors Lighty module!"); + return false; + } + + this.netboxClientModule = new NetboxClientModule(dbLibService); + if (!CcsdkLightyUtils.startLightyModule(netboxClientModule)) { + LOG.error("Unable to start NetboxClientModule in CCSDK Adaptors Lighty module!"); + return false; + } + + this.resourceModule = new ResourceModule(dbLibService); + if (!CcsdkLightyUtils.startLightyModule(resourceModule)) { + LOG.error("Unable to start ResourceModule in CCSDK Adaptors Lighty module!"); + return false; + } + + this.saltstackAdapterModule = new SaltstackAdapterModule(); + if (!CcsdkLightyUtils.startLightyModule(saltstackAdapterModule)) { + LOG.error("Unable to start SaltstackAdapterModule in CCSDK Adaptors Lighty module!"); + return false; + } + + this.sqlModule = new SqlModule(dbLibService); + if (!CcsdkLightyUtils.startLightyModule(sqlModule)) { + LOG.error("Unable to start SqlModule in CCSDK Adaptors Lighty module!"); + return false; + } + + LOG.debug("CCSDK Adaptors Lighty module was initialized successfully"); + return true; + } + + @Override + protected boolean stopProcedure() { + LOG.debug("Stopping CCSDK Adaptors Lighty module..."); + + boolean stopSuccessful = true; + + if (!CcsdkLightyUtils.stopLightyModule(sqlModule)) { + stopSuccessful = false; + } + + if (!CcsdkLightyUtils.stopLightyModule(saltstackAdapterModule)) { + stopSuccessful = false; + } + + if (!CcsdkLightyUtils.stopLightyModule(resourceModule)) { + stopSuccessful = false; + } + + if (!CcsdkLightyUtils.stopLightyModule(netboxClientModule)) { + stopSuccessful = false; + } + + if (!CcsdkLightyUtils.stopLightyModule(mdsalResourceModule)) { + stopSuccessful = false; + } + + if (!CcsdkLightyUtils.stopLightyModule(ansibleAdapterModule)) { + stopSuccessful = false; + } + + if (!CcsdkLightyUtils.stopLightyModule(aaaServiceModule)) { + stopSuccessful = false; + } + + if (stopSuccessful) { + LOG.debug("CCSDK Adaptors Lighty module was stopped successfully"); + } else { + LOG.error("CCSDK Adaptors Lighty module was not stopped successfully!"); + } + return stopSuccessful; + } + + public AaaServiceModule getAaaServiceModule() { + return aaaServiceModule; + } + + public AnsibleAdapterModule getAnsibleAdapterModule() { + return ansibleAdapterModule; + } + + public MdsalResourceModule getMdsalResourceModule() { + return mdsalResourceModule; + } + + public NetboxClientModule getNetboxClientModule() { + return netboxClientModule; + } + + public ResourceModule getResourceModule() { + return resourceModule; + } + + public SaltstackAdapterModule getSaltstackAdapterModule() { + return saltstackAdapterModule; + } + + public SqlModule getSqlModule() { + return sqlModule; + } +} diff --git a/mdsal-resource/lighty/pom.xml b/mdsal-resource/lighty/pom.xml new file mode 100755 index 000000000..08f0a5696 --- /dev/null +++ b/mdsal-resource/lighty/pom.xml @@ -0,0 +1,47 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.onap.ccsdk.parent</groupId> + <artifactId>binding-parent</artifactId> + <version>1.4.0-SNAPSHOT</version> + <relativePath/> + </parent> + + <groupId>org.onap.ccsdk.sli.adaptors</groupId> + <artifactId>mdsal-resource-lighty</artifactId> + <version>0.6.0-SNAPSHOT</version> + <packaging>jar</packaging> + + <name>ccsdk-sli-adaptors :: mdsal-resource :: ${project.artifactId}</name> + <url>http://maven.apache.org</url> + + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + </properties> + + <dependencyManagement> + <dependencies> + <dependency> + <groupId>org.onap.ccsdk.sli.core</groupId> + <artifactId>ccsdk-lighty-dependency-versions</artifactId> + <version>${project.version}</version> + <type>pom</type> + <scope>import</scope> + </dependency> + </dependencies> + </dependencyManagement> + + <dependencies> + <dependency> + <groupId>io.lighty.core</groupId> + <artifactId>lighty-controller</artifactId> + </dependency> + <dependency> + <groupId>org.onap.ccsdk.sli.adaptors</groupId> + <artifactId>mdsal-resource-provider</artifactId> + <version>${project.version}</version> + </dependency> + </dependencies> +</project> diff --git a/mdsal-resource/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/resource/mdsal/lighty/MdsalResourceModule.java b/mdsal-resource/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/resource/mdsal/lighty/MdsalResourceModule.java new file mode 100644 index 000000000..44faa8761 --- /dev/null +++ b/mdsal-resource/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/resource/mdsal/lighty/MdsalResourceModule.java @@ -0,0 +1,58 @@ +/* + * ============LICENSE_START========================================== + * Copyright (c) 2019 PANTHEON.tech s.r.o. + * =================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS + * OF ANY KIND, either express or implied. See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END============================================ + * + */ +package org.onap.ccsdk.sli.adaptors.resource.mdsal.lighty; + +import io.lighty.core.controller.api.AbstractLightyModule; +import org.onap.ccsdk.sli.adaptors.resource.mdsal.ConfigResource; +import org.onap.ccsdk.sli.adaptors.resource.mdsal.MdsalResourcePropertiesProviderImpl; +import org.onap.ccsdk.sli.adaptors.resource.mdsal.OperationalResource; + +/** + * The implementation of the {@link io.lighty.core.controller.api.LightyModule} that manages and provides services from + * the mdsal-resource-provider artifact. + */ +public class MdsalResourceModule extends AbstractLightyModule { + + private MdsalResourcePropertiesProviderImpl mdsalResourcePropertiesProvider; + private ConfigResource configResource; + private OperationalResource operationalResource; + + @Override + protected boolean initProcedure() { + this.mdsalResourcePropertiesProvider = new MdsalResourcePropertiesProviderImpl(); + this.configResource = new ConfigResource(mdsalResourcePropertiesProvider); + this.operationalResource = new OperationalResource(mdsalResourcePropertiesProvider); + return true; + } + + @Override + protected boolean stopProcedure() { + return true; + } + + public MdsalResourcePropertiesProviderImpl getMdsalResourcePropertiesProviderImpl() { + return this.mdsalResourcePropertiesProvider; + } + + public ConfigResource getConfigResource() { + return configResource; + } + + public OperationalResource getOperationalResource() { + return this.operationalResource; + } +} diff --git a/mdsal-resource/pom.xml b/mdsal-resource/pom.xml index 364850f79..468ec98b7 100755 --- a/mdsal-resource/pom.xml +++ b/mdsal-resource/pom.xml @@ -21,6 +21,7 @@ <module>provider</module> <module>features</module> <module>installer</module> + <module>lighty</module> </modules> diff --git a/netbox-client/lighty/pom.xml b/netbox-client/lighty/pom.xml new file mode 100755 index 000000000..18db29466 --- /dev/null +++ b/netbox-client/lighty/pom.xml @@ -0,0 +1,47 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.onap.ccsdk.parent</groupId> + <artifactId>binding-parent</artifactId> + <version>1.4.0-SNAPSHOT</version> + <relativePath/> + </parent> + + <groupId>org.onap.ccsdk.sli.adaptors</groupId> + <artifactId>netbox-client-lighty</artifactId> + <version>0.6.0-SNAPSHOT</version> + <packaging>jar</packaging> + + <name>ccsdk-sli-adaptors :: netbox-client :: ${project.artifactId}</name> + <url>http://maven.apache.org</url> + + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + </properties> + + <dependencyManagement> + <dependencies> + <dependency> + <groupId>org.onap.ccsdk.sli.core</groupId> + <artifactId>ccsdk-lighty-dependency-versions</artifactId> + <version>${project.version}</version> + <type>pom</type> + <scope>import</scope> + </dependency> + </dependencies> + </dependencyManagement> + + <dependencies> + <dependency> + <groupId>io.lighty.core</groupId> + <artifactId>lighty-controller</artifactId> + </dependency> + <dependency> + <groupId>org.onap.ccsdk.sli.adaptors</groupId> + <artifactId>netbox-client-provider</artifactId> + <version>${project.version}</version> + </dependency> + </dependencies> +</project> diff --git a/netbox-client/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxClientImplLighty.java b/netbox-client/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxClientImplLighty.java new file mode 100644 index 000000000..2658c06cc --- /dev/null +++ b/netbox-client/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxClientImplLighty.java @@ -0,0 +1,216 @@ +/* + * Copyright (C) 2018 Bell Canada. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onap.ccsdk.sli.adaptors.netbox.impl; + +import com.google.common.collect.Lists; +import com.google.gson.JsonSyntaxException; +import java.io.IOException; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Map; +import javax.sql.rowset.CachedRowSet; +import org.apache.http.HttpResponse; +import org.apache.http.util.EntityUtils; +import org.onap.ccsdk.sli.adaptors.netbox.api.NetboxClient; +import org.onap.ccsdk.sli.adaptors.netbox.model.IPAddress; +import org.onap.ccsdk.sli.adaptors.netbox.model.IPStatus; +import org.onap.ccsdk.sli.core.dblib.DbLibService; +import org.onap.ccsdk.sli.core.sli.SvcLogicContext; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.onap.ccsdk.sli.core.sli.SvcLogicResource.QueryStatus; +import org.onap.ccsdk.sli.core.slipluginutils.SliPluginUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * THIS CLASS IS A COPY OF {@link NetboxClientImpl} WITH REMOVED OSGi DEPENDENCIES + */ +public class NetboxClientImplLighty implements NetboxClient { + + private static final Logger LOG = LoggerFactory.getLogger(NetboxClientImplLighty.class); + + // Netbox URI + + private static final String NEXT_AVAILABLE_IP_IN_PREFIX_PATH = "/api/ipam/prefixes/%s/available-ips/"; + private static final String IP_ADDRESS_PATH = "/api/ipam/ip-addresses/%s/"; + + // Netbox Payload + + private static final String ASSIGN_IP_ADDRESS_PAYLOAD = "{\n" + + " \"custom_fields\": {\n" + + " \"external-key\": \"%s\",\n" + + " \"resource-name\": \"%s\"\n" + + " }\n" + + "}"; + + // Service Logic Context input variables and exception + + private static final String SERVICE_INSTANCE_ID_PROP = "service_instance_id"; + private static final String VF_MODULE_ID_PROP = "vf_module_id"; + private static final String EXTERNAL_KEY_PROP = "external_key"; + private static final String SQL_EXCEPTION_MESSAGE = "Caught SQL exception"; + + // SQL statement + + private static final String ASSIGN_IP_SQL_STATEMENT = + "INSERT INTO IPAM_IP_ASSIGNEMENT (service_instance_id, vf_module_id, prefix_id, ip_address_id, ip_address, ip_status, ip_response_json, external_key, ip_address_type) \n" + + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"; + private static final String UNASSIGN_IP_SQL_STATEMENT = + "UPDATE IPAM_IP_ASSIGNEMENT SET ip_status = ? WHERE service_instance_id = ? AND external_key = ?"; + private static final String GET_IP_ADDRESS_ID_SQL_STATEMENT = + "SELECT ip_address_id FROM IPAM_IP_ASSIGNEMENT WHERE service_instance_id = ? AND external_key = ?"; + + private final NetboxHttpClientLighty client; + private final DbLibService dbLibService; + + public NetboxClientImplLighty(final NetboxHttpClientLighty client, final DbLibService dbLibService) { + this.client = client; + this.dbLibService = dbLibService; + } + + @Override + public QueryStatus assignIpAddress(final Map<String, String> parameters, final SvcLogicContext ctx) { + + try { + SliPluginUtils + .checkParameters(parameters, + new String[]{SERVICE_INSTANCE_ID_PROP, VF_MODULE_ID_PROP, "prefix_id", "resource_name", + EXTERNAL_KEY_PROP}, LOG); + } catch (SvcLogicException e) { + return QueryStatus.FAILURE; + } + + final String serviceInstanceId = parameters.get(SERVICE_INSTANCE_ID_PROP); + final String vfModuleId = parameters.get(VF_MODULE_ID_PROP); + final String prefixId = parameters.get("prefix_id"); + final String resourceName = parameters.get("resource_name"); + final String externalKey = parameters.get(EXTERNAL_KEY_PROP); + + HttpResponse httpResp; + try { + httpResp = client + .post(String.format(NEXT_AVAILABLE_IP_IN_PREFIX_PATH, prefixId), + String.format(ASSIGN_IP_ADDRESS_PAYLOAD, externalKey, resourceName)); + } catch (IOException e) { + LOG.error("Fail to assign IP for Prefix(id={}). {}", prefixId, e.getMessage(), e.getCause()); + return QueryStatus.FAILURE; + } + + String ipamRespJson; + try { + ipamRespJson = EntityUtils.toString(httpResp.getEntity(), "UTF-8"); + } catch (IOException e) { + LOG.error("Fail to parse IPAM response for assign in Prefix(id={}). Response={}", prefixId, + httpResp.getEntity(), e); + return QueryStatus.FAILURE; + } + + if (httpResp.getStatusLine().getStatusCode() != 201) { + LOG.error("Fail to assign IP for Prefix(id={}). HTTP code 201!={}. Response={}", prefixId, + httpResp.getStatusLine().getStatusCode(), ipamRespJson); + return QueryStatus.FAILURE; + } + + IPAddress ipAddress; + try { + ipAddress = IPAddress.fromJson(ipamRespJson); + } catch (JsonSyntaxException e) { + LOG.error("Fail to parse IPAM JSON reponse to IPAddress POJO. IPAM JSON Response={}", ipamRespJson, e); + return QueryStatus.FAILURE; + } + + ArrayList<String> args = Lists.newArrayList( + serviceInstanceId, + vfModuleId, + String.valueOf(prefixId), + String.valueOf(ipAddress.getId()), + ipAddress.getAddress(), + IPStatus.ASSIGNED.name(), + ipamRespJson, + externalKey, + resourceName); + + try { + dbLibService.writeData(ASSIGN_IP_SQL_STATEMENT, args, null); + } catch (SQLException e) { + LOG.error(SQL_EXCEPTION_MESSAGE, e); + return QueryStatus.FAILURE; + } + + ctx.setAttribute("self_serve_netbox_ip_assignement.ip-address", ipAddress.getAddress()); + + return QueryStatus.SUCCESS; + } + + @Override + public QueryStatus unassignIpAddress(final Map<String, String> parameters, final SvcLogicContext ctx) { + try { + SliPluginUtils + .checkParameters(parameters, new String[]{SERVICE_INSTANCE_ID_PROP, EXTERNAL_KEY_PROP}, + LOG); + } catch (SvcLogicException e) { + return QueryStatus.FAILURE; + } + + final String serviceInstanceId = parameters.get(SERVICE_INSTANCE_ID_PROP); + final String externalKey = parameters.get(EXTERNAL_KEY_PROP); + + String ipAddressId; + ArrayList<String> args = Lists.newArrayList( + serviceInstanceId, + externalKey); + try (CachedRowSet row = dbLibService.getData(GET_IP_ADDRESS_ID_SQL_STATEMENT, args, null)) { + if (row.next()) { + ipAddressId = row.getString("ip_address_id"); + } else { + throw new SQLException("Data not found."); + } + } catch (SQLException e) { + LOG.error(SQL_EXCEPTION_MESSAGE, e); + return QueryStatus.FAILURE; + } + + HttpResponse httpResp; + try { + httpResp = client.delete(String.format(IP_ADDRESS_PATH, ipAddressId)); + } catch (IOException e) { + LOG.error("Fail to unassign IP for IPAddress(id= " + ipAddressId + "). " + e.getMessage(), + e.getCause()); + return QueryStatus.FAILURE; + } + + if (httpResp.getStatusLine().getStatusCode() - 200 >= 100) { + LOG.error("Fail to unassign IP for IPAddress(id={}). HTTP code={}.", ipAddressId, + httpResp.getStatusLine().getStatusCode()); + return QueryStatus.FAILURE; + } + + args.clear(); + args = Lists.newArrayList( + IPStatus.DELETED.name(), + serviceInstanceId, + externalKey); + + try { + dbLibService.writeData(UNASSIGN_IP_SQL_STATEMENT, args, null); + } catch (SQLException e) { + LOG.error(SQL_EXCEPTION_MESSAGE, e); + return QueryStatus.FAILURE; + } + + return QueryStatus.SUCCESS; + } +} diff --git a/netbox-client/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxHttpClientLighty.java b/netbox-client/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxHttpClientLighty.java new file mode 100644 index 000000000..388486c4f --- /dev/null +++ b/netbox-client/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/impl/NetboxHttpClientLighty.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2018 Bell Canada. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onap.ccsdk.sli.adaptors.netbox.impl; + +import static org.apache.http.HttpHeaders.ACCEPT; +import static org.apache.http.HttpHeaders.AUTHORIZATION; +import static org.apache.http.HttpHeaders.CONTENT_TYPE; + +import java.io.IOException; +import java.nio.charset.Charset; +import java.security.KeyManagementException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import javax.net.ssl.SSLContext; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpDelete; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.methods.HttpRequestBase; +import org.apache.http.conn.ssl.NoopHostnameVerifier; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.ssl.SSLContexts; +import org.apache.http.ssl.TrustStrategy; +import org.onap.ccsdk.sli.adaptors.netbox.property.NetboxPropertiesLighty; + +/** + * THIS CLASS IS A COPY OF {@link NetboxHttpClient} WITH REMOVED OSGi DEPENDENCIES + */ +public class NetboxHttpClientLighty implements AutoCloseable { + + private static final String APPLICATION_JSON = "application/json"; + + private final CloseableHttpClient client; + private final String url; + private final String token; + + // Used by the blueprint container + public NetboxHttpClientLighty(NetboxPropertiesLighty properties) { + this(properties.getHost(), properties.getApiKey()); + } + + NetboxHttpClientLighty(final String url, final String token) { + this.url = url; + this.token = token; + + final TrustStrategy acceptingTrustStrategy = (certificate, authType) -> true; + final SSLContext sslContext; + try { + sslContext = SSLContexts.custom() + .loadTrustMaterial(null, acceptingTrustStrategy).build(); + } catch (final NoSuchAlgorithmException | KeyManagementException | KeyStoreException e) { + throw new IllegalStateException("Can't create http client", e); + } + client = HttpClientBuilder.create() + .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE) + .setSSLContext(sslContext) + .build(); + } + + @Override + public void close() throws IOException { + client.close(); + } + + HttpResponse post(final String uri, final String requestBody) throws IOException { + final HttpPost request = new HttpPost(url + uri); + setHeaders(request); + request.setEntity(new StringEntity(requestBody, Charset.forName("UTF-8"))); + return client.execute(request); + } + + HttpResponse delete(final String uri) throws IOException { + final HttpDelete request = new HttpDelete(url + uri); + setHeaders(request); + return client.execute(request); + } + + private void setHeaders(final HttpRequestBase request) { + request.addHeader(ACCEPT, APPLICATION_JSON); + request.addHeader(CONTENT_TYPE, APPLICATION_JSON); + request.addHeader(AUTHORIZATION, "Token " + token); + } +} diff --git a/netbox-client/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/lighty/NetboxClientModule.java b/netbox-client/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/lighty/NetboxClientModule.java new file mode 100644 index 000000000..13f7963bb --- /dev/null +++ b/netbox-client/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/lighty/NetboxClientModule.java @@ -0,0 +1,70 @@ +/* + * ============LICENSE_START========================================== + * Copyright (c) 2019 PANTHEON.tech s.r.o. + * =================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS + * OF ANY KIND, either express or implied. See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END============================================ + * + */ +package org.onap.ccsdk.sli.adaptors.netbox.lighty; + +import io.lighty.core.controller.api.AbstractLightyModule; +import java.io.IOException; +import org.onap.ccsdk.sli.adaptors.netbox.api.NetboxClient; +import org.onap.ccsdk.sli.adaptors.netbox.impl.NetboxClientImplLighty; +import org.onap.ccsdk.sli.adaptors.netbox.impl.NetboxHttpClientLighty; +import org.onap.ccsdk.sli.adaptors.netbox.property.NetboxPropertiesLighty; +import org.onap.ccsdk.sli.core.dblib.DbLibService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The implementation of the {@link io.lighty.core.controller.api.LightyModule} that manages and provides services from + * the netbox-client-provider artifact. + */ +public class NetboxClientModule extends AbstractLightyModule { + + private static final Logger LOG = LoggerFactory.getLogger(NetboxClientModule.class); + + private final DbLibService dbLibService; + + private NetboxPropertiesLighty netboxProperties; + private NetboxHttpClientLighty netboxHttpClient; + private NetboxClientImplLighty netboxClient; + + public NetboxClientModule(DbLibService dbLibService) { + this.dbLibService = dbLibService; + } + + @Override + protected boolean initProcedure() { + this.netboxProperties = new NetboxPropertiesLighty(); + this.netboxHttpClient = new NetboxHttpClientLighty(netboxProperties); + this.netboxClient = new NetboxClientImplLighty(netboxHttpClient, dbLibService); + return true; + } + + @Override + protected boolean stopProcedure() { + try { + netboxHttpClient.close(); + } catch (IOException e) { + LOG.error("Exception thrown while closing {}!", netboxHttpClient.getClass(), e); + return false; + } + return true; + } + + public NetboxClient getNetboxClient() { + return netboxClient; + } + +} diff --git a/netbox-client/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/property/NetboxPropertiesLighty.java b/netbox-client/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/property/NetboxPropertiesLighty.java new file mode 100644 index 000000000..15759c721 --- /dev/null +++ b/netbox-client/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/netbox/property/NetboxPropertiesLighty.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2018 Bell Canada. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onap.ccsdk.sli.adaptors.netbox.property; + +import java.io.FileInputStream; +import java.util.Properties; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * THIS CLASS IS A COPY OF {@link NetboxProperties} WITH REMOVED OSGi DEPENDENCIES + */ +public class NetboxPropertiesLighty { + + private static final Logger LOG = LoggerFactory.getLogger(NetboxPropertiesLighty.class); + + private static final String NETBOX_PROPERTY_FILE_NAME = "netbox.properties"; + private static final String DEFAULT_PROPERTIES_DIR = "/opt/onap/ccsdk/data/properties"; + private static final String PROPERTIES_DIR_KEY = "SDNC_CONFIG_DIR"; + + private static final String NETBOX_URL_PROP = "org.onap.ccsdk.sli.adaptors.netbox.url"; + private static final String NETBOX_API_KEY_PROP = "org.onap.ccsdk.sli.adaptors.netbox.apikey"; + + private Properties properties; + + public NetboxPropertiesLighty() { + loadProps(); + } + + public String getHost() { + return properties.getProperty(NETBOX_URL_PROP); + } + + public String getApiKey() { + return properties.getProperty(NETBOX_API_KEY_PROP); + } + + private void loadProps() { + properties = new Properties(); + // Try to load config from dir + final String ccsdkConfigDir = + System.getProperty(PROPERTIES_DIR_KEY, DEFAULT_PROPERTIES_DIR) + "/" + NETBOX_PROPERTY_FILE_NAME; + LOG.info("Loading properties from file {}", ccsdkConfigDir); + try (FileInputStream in = new FileInputStream(ccsdkConfigDir)) { + properties.load(in); + LOG.info("Loaded {} properties from file {}", properties.size(), ccsdkConfigDir); + } catch (Exception e) { + LOG.error("Failed to load properties for file: {} " + NETBOX_PROPERTY_FILE_NAME, e); + } + } +} diff --git a/netbox-client/pom.xml b/netbox-client/pom.xml index c1b4e3e71..d772ca82c 100644 --- a/netbox-client/pom.xml +++ b/netbox-client/pom.xml @@ -36,5 +36,6 @@ <module>provider</module> <module>features</module> <module>installer</module> + <module>lighty</module> </modules> </project> @@ -99,7 +99,7 @@ <module>aai-service</module> <module>ansible-adapter</module> <module>saltstack-adapter</module> - <module>netbox-client</module> + <module>netbox-client</module> <module>mdsal-resource</module> <module>resource-assignment</module> <module>sql-resource</module> @@ -107,6 +107,7 @@ <module>message-router</module> <module>features</module> <module>artifacts</module> + <module>ccsdk-adaptors-lighty</module> </modules> <organization> <name>ONAP</name> diff --git a/resource-assignment/lighty/pom.xml b/resource-assignment/lighty/pom.xml new file mode 100755 index 000000000..6807c2257 --- /dev/null +++ b/resource-assignment/lighty/pom.xml @@ -0,0 +1,58 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.onap.ccsdk.parent</groupId> + <artifactId>binding-parent</artifactId> + <version>1.4.0-SNAPSHOT</version> + <relativePath/> + </parent> + + <groupId>org.onap.ccsdk.sli.adaptors</groupId> + <artifactId>resource-assignment-lighty</artifactId> + <version>0.6.0-SNAPSHOT</version> + <packaging>jar</packaging> + + <name>ccsdk-sli-adaptors :: resource-assignment :: ${project.artifactId}</name> + <url>http://maven.apache.org</url> + + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + </properties> + + <dependencyManagement> + <dependencies> + <dependency> + <groupId>org.onap.ccsdk.sli.core</groupId> + <artifactId>ccsdk-lighty-dependency-versions</artifactId> + <version>${project.version}</version> + <type>pom</type> + <scope>import</scope> + </dependency> + </dependencies> + </dependencyManagement> + + <dependencies> + <dependency> + <groupId>io.lighty.core</groupId> + <artifactId>lighty-controller</artifactId> + </dependency> + <dependency> + <groupId>org.onap.ccsdk.sli.adaptors</groupId> + <artifactId>resource-assignment-provider</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.onap.ccsdk.sli.core</groupId> + <artifactId>dblib-provider</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.onap.ccsdk.sli.core</groupId> + <artifactId>sli-provider</artifactId> + <version>${project.version}</version> + <scope>provided</scope> + </dependency> + </dependencies> +</project> diff --git a/resource-assignment/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/resource/lighty/ResourceModule.java b/resource-assignment/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/resource/lighty/ResourceModule.java new file mode 100644 index 000000000..b90905995 --- /dev/null +++ b/resource-assignment/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/resource/lighty/ResourceModule.java @@ -0,0 +1,152 @@ +/* + * ============LICENSE_START========================================== + * Copyright (c) 2019 PANTHEON.tech s.r.o. + * =================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS + * OF ANY KIND, either express or implied. See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END============================================ + * + */ +package org.onap.ccsdk.sli.adaptors.resource.lighty; + +import io.lighty.core.controller.api.AbstractLightyModule; +import java.util.Collections; +import org.onap.ccsdk.sli.adaptors.lock.comp.LockHelperImpl; +import org.onap.ccsdk.sli.adaptors.lock.dao.ResourceLockDaoImpl; +import org.onap.ccsdk.sli.adaptors.ra.ResourceAllocator; +import org.onap.ccsdk.sli.adaptors.ra.ResourceLockNode; +import org.onap.ccsdk.sli.adaptors.ra.alloc.DbAllocationRule; +import org.onap.ccsdk.sli.adaptors.ra.comp.EndPointAllocatorImpl; +import org.onap.ccsdk.sli.adaptors.ra.rule.dao.RangeRuleDaoImpl; +import org.onap.ccsdk.sli.adaptors.ra.rule.dao.ResourceRuleDaoImpl; +import org.onap.ccsdk.sli.adaptors.rm.comp.ResourceManagerImpl; +import org.onap.ccsdk.sli.adaptors.rm.dao.jdbc.AllocationItemJdbcDaoImpl; +import org.onap.ccsdk.sli.adaptors.rm.dao.jdbc.ResourceDaoImpl; +import org.onap.ccsdk.sli.adaptors.rm.dao.jdbc.ResourceJdbcDaoImpl; +import org.onap.ccsdk.sli.adaptors.rm.dao.jdbc.ResourceLoadJdbcDaoImpl; +import org.onap.ccsdk.sli.adaptors.util.db.CachedDataSourceWrap; +import org.onap.ccsdk.sli.adaptors.util.db.DataSourceWrap; +import org.onap.ccsdk.sli.adaptors.util.speed.SpeedUtil; +import org.onap.ccsdk.sli.core.dblib.DbLibService; +import org.springframework.jdbc.core.JdbcTemplate; + +/** + * The implementation of the {@link io.lighty.core.controller.api.LightyModule} that manages and provides services from + * the resource-assignment-provider artifact. + */ +public class ResourceModule extends AbstractLightyModule { + + private final DbLibService dbLibService; + + private DataSourceWrap dataSourceWrap; + private CachedDataSourceWrap cachedDataSourceWrap; + private JdbcTemplate rmJdbcTemplate; + private JdbcTemplate lockJdbcTemplate; + private ResourceLockDaoImpl resourceLockDao; + private LockHelperImpl lockHelper; + private ResourceJdbcDaoImpl resourceJdbcDao; + private AllocationItemJdbcDaoImpl allocationItemJdbcDao; + private ResourceLoadJdbcDaoImpl resourceLoadJdbcDao; + private ResourceDaoImpl resourceDao; + private ResourceManagerImpl resourceManager; + private ResourceRuleDaoImpl resourceRuleDao; + private RangeRuleDaoImpl rangeRuleDao; + private ResourceAllocator resourceAllocator; + private ResourceLockNode resourceLockNode; + private SpeedUtil speedUtil; + private EndPointAllocatorImpl endPointAllocator; + private DbAllocationRule dbAllocationRule; + + public ResourceModule(final DbLibService dbLibService) { + this.dbLibService = dbLibService; + } + + @Override + protected boolean initProcedure() { + this.dataSourceWrap = new DataSourceWrap(); + this.dataSourceWrap.setDataSource(dbLibService); + + this.cachedDataSourceWrap = new CachedDataSourceWrap(); + this.cachedDataSourceWrap.setDataSource(dataSourceWrap); + + this.rmJdbcTemplate = new JdbcTemplate(); + this.rmJdbcTemplate.setDataSource(dataSourceWrap); + + this.lockJdbcTemplate = new JdbcTemplate(); + this.lockJdbcTemplate.setDataSource(cachedDataSourceWrap); + + this.resourceLockDao = new ResourceLockDaoImpl(); + this.resourceLockDao.setJdbcTemplate(lockJdbcTemplate); + + this.lockHelper = new LockHelperImpl(); + this.lockHelper.setResourceLockDao(resourceLockDao); + this.lockHelper.setRetryCount(10); + this.lockHelper.setLockWait(5); + + this.resourceJdbcDao = new ResourceJdbcDaoImpl(); + this.resourceJdbcDao.setJdbcTemplate(rmJdbcTemplate); + + this.allocationItemJdbcDao = new AllocationItemJdbcDaoImpl(); + this.allocationItemJdbcDao.setJdbcTemplate(rmJdbcTemplate); + + this.resourceLoadJdbcDao = new ResourceLoadJdbcDaoImpl(); + this.resourceLoadJdbcDao.setJdbcTemplate(rmJdbcTemplate); + + this.resourceDao = new ResourceDaoImpl(); + this.resourceDao.setResourceJdbcDao(resourceJdbcDao); + this.resourceDao.setAllocationItemJdbcDao(allocationItemJdbcDao); + this.resourceDao.setResourceLoadJdbcDao(resourceLoadJdbcDao); + + this.resourceManager = new ResourceManagerImpl(); + this.resourceManager.setLockHelper(lockHelper); + this.resourceManager.setResourceDao(resourceDao); + this.resourceManager.setLockTimeout(600); + + this.resourceRuleDao = new ResourceRuleDaoImpl(); + this.resourceRuleDao.setJdbcTemplate(rmJdbcTemplate); + + this.rangeRuleDao = new RangeRuleDaoImpl(); + this.rangeRuleDao.setJdbcTemplate(rmJdbcTemplate); + + this.resourceLockNode = new ResourceLockNode(); + this.resourceLockNode.setLockHelper(lockHelper); + + this.speedUtil = new SpeedUtil(); + + this.dbAllocationRule = new DbAllocationRule(); + this.dbAllocationRule.setResourceRuleDao(resourceRuleDao); + this.dbAllocationRule.setRangeRuleDao(rangeRuleDao); + + this.endPointAllocator = new EndPointAllocatorImpl(); + this.endPointAllocator.setResourceManager(resourceManager); + this.endPointAllocator.setAllocationRuleMap( + Collections.singletonMap("DEFAULT", Collections.singletonList(dbAllocationRule))); + + this.resourceAllocator = new ResourceAllocator(); + this.resourceAllocator.setResourceManager(resourceManager); + this.resourceAllocator.setEndPointAllocator(endPointAllocator); + this.resourceAllocator.setSpeedUtil(speedUtil); + return true; + } + + @Override + protected boolean stopProcedure() { + return true; + } + + public ResourceAllocator getResourceAllocator() { + return resourceAllocator; + } + + public ResourceLockNode getResourceLockNode() { + return resourceLockNode; + } + +} diff --git a/resource-assignment/pom.xml b/resource-assignment/pom.xml index b17b31aa6..4aa99ad7c 100755 --- a/resource-assignment/pom.xml +++ b/resource-assignment/pom.xml @@ -21,6 +21,7 @@ <module>provider</module> <module>features</module> <module>installer</module> + <module>lighty</module> </modules> diff --git a/saltstack-adapter/pom.xml b/saltstack-adapter/pom.xml index 1d618319f..0700b270c 100644 --- a/saltstack-adapter/pom.xml +++ b/saltstack-adapter/pom.xml @@ -193,5 +193,6 @@ <module>saltstack-adapter-provider</module> <module>saltstack-adapter-features</module> <module>saltstack-adapter-installer</module> + <module>saltstack-adapter-lighty</module> </modules> </project> diff --git a/saltstack-adapter/saltstack-adapter-lighty/pom.xml b/saltstack-adapter/saltstack-adapter-lighty/pom.xml new file mode 100755 index 000000000..54eea24ce --- /dev/null +++ b/saltstack-adapter/saltstack-adapter-lighty/pom.xml @@ -0,0 +1,53 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.onap.ccsdk.parent</groupId> + <artifactId>binding-parent</artifactId> + <version>1.4.0-SNAPSHOT</version> + <relativePath/> + </parent> + + <groupId>org.onap.ccsdk.sli.adaptors</groupId> + <artifactId>saltstack-adapter-lighty</artifactId> + <version>0.6.0-SNAPSHOT</version> + <packaging>jar</packaging> + + <name>ccsdk-sli-adaptors :: netbox-client :: ${project.artifactId}</name> + <url>http://maven.apache.org</url> + + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + </properties> + + <dependencyManagement> + <dependencies> + <dependency> + <groupId>org.onap.ccsdk.sli.core</groupId> + <artifactId>ccsdk-lighty-dependency-versions</artifactId> + <version>${project.version}</version> + <type>pom</type> + <scope>import</scope> + </dependency> + </dependencies> + </dependencyManagement> + + <dependencies> + <dependency> + <groupId>io.lighty.core</groupId> + <artifactId>lighty-controller</artifactId> + </dependency> + <dependency> + <groupId>org.onap.ccsdk.sli.adaptors</groupId> + <artifactId>saltstack-adapter-provider</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.onap.ccsdk.sli.adaptors</groupId> + <artifactId>saltstack-adapter-provider</artifactId> + <version>${project.version}</version> + <scope>compile</scope> + </dependency> + </dependencies> +</project> diff --git a/saltstack-adapter/saltstack-adapter-lighty/src/main/java/org/onap/ccsdk/sli/adaptors/saltstack/impl/SaltstackAdapterPropertiesProviderImplLighty.java b/saltstack-adapter/saltstack-adapter-lighty/src/main/java/org/onap/ccsdk/sli/adaptors/saltstack/impl/SaltstackAdapterPropertiesProviderImplLighty.java new file mode 100755 index 000000000..0ea5a589d --- /dev/null +++ b/saltstack-adapter/saltstack-adapter-lighty/src/main/java/org/onap/ccsdk/sli/adaptors/saltstack/impl/SaltstackAdapterPropertiesProviderImplLighty.java @@ -0,0 +1,175 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : CCSDK + * ================================================================================ + * Copyright (C) 2018 Samsung Electronics. All rights reserved. + * ================================================================================ + * + * ============================================================================= + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + * ============LICENSE_END========================================================= + */ + +package org.onap.ccsdk.sli.adaptors.saltstack.impl; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Optional; +import java.util.Properties; +import java.util.Vector; +import org.onap.ccsdk.sli.adaptors.saltstack.SaltstackAdapterPropertiesProvider; +import org.onap.ccsdk.sli.core.sli.ConfigurationException; +import org.onap.ccsdk.sli.core.utils.KarafRootFileResolver; +import org.onap.ccsdk.sli.core.utils.PropertiesFileResolver; +import org.onap.ccsdk.sli.core.utils.common.CoreDefaultFileResolver; +import org.onap.ccsdk.sli.core.utils.common.SdncConfigEnvVarFileResolver; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * THIS CLASS IS A COPY OF {@link SaltstackAdapterPropertiesProviderImpl} WITH REMOVED OSGi DEPENDENCIES + */ +public class SaltstackAdapterPropertiesProviderImplLighty implements SaltstackAdapterPropertiesProvider { + + private static final Logger LOG = LoggerFactory.getLogger(SaltstackAdapterPropertiesProviderImplLighty.class); + + /** + * The name of the properties file for database configuration + */ + private static final String SALTSTACKADAPTER_PROP_FILE_NAME = "saltstack-adapter.properties"; + + /** + * A prioritized list of strategies for resolving sql-resource properties files. + */ + private Vector<PropertiesFileResolver> saltstackAdapterPropertiesFileResolvers = new Vector<>(); + + /** + * The configuration properties for the db connection. + */ + private Properties properties; + + /** + * Set up the prioritized list of strategies for resolving dblib properties + * files. + */ + public SaltstackAdapterPropertiesProviderImplLighty() { + saltstackAdapterPropertiesFileResolvers + .add(new SdncConfigEnvVarFileResolver("Using property file (1) from environment variable")); + saltstackAdapterPropertiesFileResolvers.add(new CoreDefaultFileResolver("Using property file (2) from default directory")); + saltstackAdapterPropertiesFileResolvers.add(new KarafRootFileResolver("Using property file (4) from karaf root", this)); + + // determines properties file as according to the priority described in the + // class header comment + final File propertiesFile = determinePropertiesFile(this); + if (propertiesFile != null) { + try (FileInputStream fileInputStream = new FileInputStream(propertiesFile)) { + properties = new Properties(); + properties.load(fileInputStream); + } catch (final IOException e) { + LOG.error("Failed to load properties for file: {}", propertiesFile.toString(), + new ConfigurationException("Failed to load properties for file: " + propertiesFile.toString(), + e)); + } + } else { + // Try to read properties as resource + + InputStream propStr = getClass().getResourceAsStream("/" + SALTSTACKADAPTER_PROP_FILE_NAME); + if (propStr != null) { + properties = new Properties(); + try { + properties.load(propStr); + propStr.close(); + } catch (IOException e) { + properties = null; + } + } + + } + + if (properties == null) { + reportFailure("Missing configuration properties resource(3)", new ConfigurationException( + "Missing configuration properties resource(3): " + SALTSTACKADAPTER_PROP_FILE_NAME)); + + LOG.info("Defaulting org.onap.appc.adapter.saltstack.clientType to NONE"); + + properties = new Properties(); + properties.setProperty("org.onap.appc.adapter.saltstack.clientType", "NONE"); + } + } + + /** + * Reports the method chosen for properties resolution to the + * <code>Logger</code>. + * + * @param message Some user friendly message + * @param fileOptional The file location of the chosen properties file + * @return the file location of the chosen properties file + */ + private static File reportSuccess(final String message, final Optional<File> fileOptional) { + if (fileOptional.isPresent()) { + final File file = fileOptional.get(); + LOG.info("{} {}", message, file.getPath()); + return file; + } + return null; + } + + /** + * Reports fatal errors. This is the case in which no properties file could be + * found. + * + * @param message An appropriate fatal error message + * @param configurationException An exception describing what went wrong during resolution + */ + private static void reportFailure(final String message, final ConfigurationException configurationException) { + + LOG.error("{}", message, configurationException); + } + + /** + * Extract svclogic config properties. + * + * @return the svclogic config properties + */ + public Properties getProperties() { + return properties; + } + + /** + * Determines the sql-resource properties file to use based on the following priority: + * <ol> + * <li>A directory identified by the system environment variable + * <code>SDNC_CONFIG_DIR</code></li> + * <li>The default directory <code>DEFAULT_DBLIB_PROP_DIR</code></li> + * <li>A directory identified by the JRE argument + * <code>sql-resource.properties</code></li> + * <li>A <code>sql-resource.properties</code> file located in the karaf root + * directory</li> + * </ol> + */ + File determinePropertiesFile(final SaltstackAdapterPropertiesProviderImplLighty resourceProvider) { + + for (final PropertiesFileResolver sliPropertiesFileResolver : saltstackAdapterPropertiesFileResolvers) { + final Optional<File> fileOptional = sliPropertiesFileResolver.resolveFile(SALTSTACKADAPTER_PROP_FILE_NAME); + if (fileOptional.isPresent()) { + return reportSuccess(sliPropertiesFileResolver.getSuccessfulResolutionMessage(), fileOptional); + } + } + + return null; + } +} diff --git a/saltstack-adapter/saltstack-adapter-lighty/src/main/java/org/onap/ccsdk/sli/adaptors/saltstack/lighty/SaltstackAdapterModule.java b/saltstack-adapter/saltstack-adapter-lighty/src/main/java/org/onap/ccsdk/sli/adaptors/saltstack/lighty/SaltstackAdapterModule.java new file mode 100644 index 000000000..2f58d1f75 --- /dev/null +++ b/saltstack-adapter/saltstack-adapter-lighty/src/main/java/org/onap/ccsdk/sli/adaptors/saltstack/lighty/SaltstackAdapterModule.java @@ -0,0 +1,61 @@ +/* + * ============LICENSE_START========================================== + * Copyright (c) 2019 PANTHEON.tech s.r.o. + * =================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS + * OF ANY KIND, either express or implied. See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END============================================ + * + */ +package org.onap.ccsdk.sli.adaptors.saltstack.lighty; + +import io.lighty.core.controller.api.AbstractLightyModule; +import org.onap.ccsdk.sli.adaptors.saltstack.SaltstackAdapter; +import org.onap.ccsdk.sli.adaptors.saltstack.impl.SaltstackAdapterImpl; +import org.onap.ccsdk.sli.adaptors.saltstack.impl.SaltstackAdapterPropertiesProviderImplLighty; +import org.onap.ccsdk.sli.core.sli.SvcLogicException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The implementation of the {@link io.lighty.core.controller.api.LightyModule} that manages and provides services from + * the saltstack-adapter-provider artifact. + */ +public class SaltstackAdapterModule extends AbstractLightyModule { + + private static final Logger LOG = LoggerFactory.getLogger(SaltstackAdapterModule.class); + + private SaltstackAdapterPropertiesProviderImplLighty salstackPropertiesProvider; + private SaltstackAdapterImpl saltstackAdapter; + + @Override + protected boolean initProcedure() { + this.salstackPropertiesProvider = new SaltstackAdapterPropertiesProviderImplLighty(); + try { + this.saltstackAdapter = new SaltstackAdapterImpl(salstackPropertiesProvider); + } catch (SvcLogicException e) { + LOG.error("Exception thrown while initializing {} in {}!", SaltstackAdapterImpl.class, this.getClass(), e); + } + return true; + } + + @Override + protected boolean stopProcedure() { + return true; + } + + public SaltstackAdapterPropertiesProviderImplLighty getSalstackPropertiesProvider() { + return this.salstackPropertiesProvider; + } + + public SaltstackAdapter getSaltstackAdapter() { + return saltstackAdapter; + } +} diff --git a/sql-resource/lighty/pom.xml b/sql-resource/lighty/pom.xml new file mode 100755 index 000000000..1647e5dbe --- /dev/null +++ b/sql-resource/lighty/pom.xml @@ -0,0 +1,58 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.onap.ccsdk.parent</groupId> + <artifactId>binding-parent</artifactId> + <version>1.4.0-SNAPSHOT</version> + <relativePath/> + </parent> + + <groupId>org.onap.ccsdk.sli.adaptors</groupId> + <artifactId>sql-resource-lighty</artifactId> + <version>0.6.0-SNAPSHOT</version> + <packaging>jar</packaging> + + <name>ccsdk-sli-adaptors :: sql-resource :: ${project.artifactId}</name> + <url>http://maven.apache.org</url> + + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + </properties> + + <dependencyManagement> + <dependencies> + <dependency> + <groupId>org.onap.ccsdk.sli.core</groupId> + <artifactId>ccsdk-lighty-dependency-versions</artifactId> + <version>${project.version}</version> + <type>pom</type> + <scope>import</scope> + </dependency> + </dependencies> + </dependencyManagement> + + <dependencies> + <dependency> + <groupId>io.lighty.core</groupId> + <artifactId>lighty-controller</artifactId> + </dependency> + <dependency> + <groupId>org.onap.ccsdk.sli.adaptors</groupId> + <artifactId>sql-resource-provider</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.onap.ccsdk.sli.core</groupId> + <artifactId>dblib-provider</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.onap.ccsdk.sli.core</groupId> + <artifactId>sli-provider</artifactId> + <version>${project.version}</version> + <scope>provided</scope> + </dependency> + </dependencies> +</project> diff --git a/sql-resource/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/resource/sql/lighty/SqlModule.java b/sql-resource/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/resource/sql/lighty/SqlModule.java new file mode 100644 index 000000000..fc760ba58 --- /dev/null +++ b/sql-resource/lighty/src/main/java/org/onap/ccsdk/sli/adaptors/resource/sql/lighty/SqlModule.java @@ -0,0 +1,54 @@ +/* + * ============LICENSE_START========================================== + * Copyright (c) 2019 PANTHEON.tech s.r.o. + * =================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS + * OF ANY KIND, either express or implied. See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END============================================ + * + */ +package org.onap.ccsdk.sli.adaptors.resource.sql.lighty; + +import io.lighty.core.controller.api.AbstractLightyModule; +import org.onap.ccsdk.sli.adaptors.resource.sql.SqlResource; +import org.onap.ccsdk.sli.adaptors.resource.sql.SqlResourcePropertiesProviderImpl; +import org.onap.ccsdk.sli.core.dblib.DbLibService; + +/** + * The implementation of the {@link io.lighty.core.controller.api.LightyModule} that manages and provides services from + * the sql-resource-provider artifact. + */ +public class SqlModule extends AbstractLightyModule { + + private final DbLibService dbService; + + private SqlResourcePropertiesProviderImpl sqlPropertiesProvider; + private SqlResource sqlResource; + + public SqlModule(DbLibService dbService) { + this.dbService = dbService; + } + + @Override + protected boolean initProcedure() { + this.sqlPropertiesProvider = new SqlResourcePropertiesProviderImpl(); + this.sqlResource = new SqlResource(sqlPropertiesProvider, dbService); + return true; + } + + @Override + protected boolean stopProcedure() { + return true; + } + + public SqlResource getSqlResource() { + return sqlResource; + } +} diff --git a/sql-resource/pom.xml b/sql-resource/pom.xml index 645576e18..2a5c34971 100755 --- a/sql-resource/pom.xml +++ b/sql-resource/pom.xml @@ -21,6 +21,7 @@ <module>provider</module> <module>features</module> <module>installer</module> + <module>lighty</module> </modules> </project> |