diff options
author | Kajur, Harish (vk250x) <vk250x@att.com> | 2020-02-21 14:34:10 -0500 |
---|---|---|
committer | Harish Venkata Kajur <vk250x@att.com> | 2020-02-25 23:59:33 -0500 |
commit | 98749c47bbb5f5ddcc1c4f0690b79c7288f6bdd6 (patch) | |
tree | a472ce2edabd497b643917f44785b775fa16e15e | |
parent | e654645a50a0d028d8e67ea997f84efe8d28a6a0 (diff) |
Enhancements for the aai-common library
Issue-ID: AAI-2806
Change-Id: I2dbb46b897b35136ac1bb802978d3f974af1b307
Signed-off-by: Kajur, Harish (vk250x) <vk250x@att.com>
349 files changed, 21238 insertions, 4625 deletions
@@ -11,4 +11,6 @@ bundleconfig-local/etc/logback.xml **/.idea/ */.idea *.iml -.idea/
\ No newline at end of file +.idea/ +*.log +aai-core/logs/ diff --git a/aai-aaf-auth/pom.xml b/aai-aaf-auth/pom.xml new file mode 100644 index 00000000..87eb9537 --- /dev/null +++ b/aai-aaf-auth/pom.xml @@ -0,0 +1,60 @@ +<?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.aai.aai-common</groupId> + <artifactId>aai-parent</artifactId> + <version>1.6.6-SNAPSHOT</version> + <relativePath>../aai-parent/pom.xml</relativePath> + </parent> + <artifactId>aai-aaf-auth</artifactId> + <name>aai-aaf-auth</name> + <packaging>jar</packaging> + <dependencies> + <dependency> + <groupId>org.onap.aai.aai-common</groupId> + <artifactId>aai-els-onap-logging</artifactId> + </dependency> + <dependency> + <groupId>org.onap.aaf.authz</groupId> + <artifactId>aaf-cadi-core</artifactId> + </dependency> + <dependency> + <groupId>org.onap.aaf.authz</groupId> + <artifactId>aaf-cadi-aaf</artifactId> + </dependency> + <dependency> + <groupId>org.easymock</groupId> + <artifactId>easymock</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-web</artifactId> + </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-context</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-web</artifactId> + <exclusions> + <exclusion> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-tomcat</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>com.google.code.gson</groupId> + <artifactId>gson</artifactId> + </dependency> + <dependency> + <groupId>commons-io</groupId> + <artifactId>commons-io</artifactId> + </dependency> + </dependencies> +</project> diff --git a/aai-core/src/main/java/org/onap/aai/auth/AAIAuthCore.java b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/auth/AAIAuthCore.java index cde2faa3..c64251ad 100644 --- a/aai-core/src/main/java/org/onap/aai/auth/AAIAuthCore.java +++ b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/auth/AAIAuthCore.java @@ -18,15 +18,20 @@ * ============LICENSE_END========================================================= */ -package org.onap.aai.auth; +package org.onap.aai.aaf.auth; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.fasterxml.jackson.core.JsonProcessingException; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; +import org.eclipse.jetty.util.security.Password; +import org.onap.aai.aaf.auth.exceptions.AAIUnrecognizedFunctionException; +import org.onap.aai.logging.ErrorLogHelper; +import org.onap.aai.util.AAIConfig; +import org.onap.aai.util.AAIConstants; import java.io.File; import java.io.FileNotFoundException; @@ -38,22 +43,12 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; -import org.eclipse.jetty.util.security.Password; -import org.eclipse.persistence.internal.oxm.conversion.Base64; -import org.onap.aai.auth.exceptions.AAIUnrecognizedFunctionException; -import org.onap.aai.logging.ErrorLogHelper; -import org.onap.aai.logging.LoggingContext; -import org.onap.aai.logging.LoggingContext.StatusCode; -import org.onap.aai.util.AAIConfig; -import org.onap.aai.util.AAIConstants; -import org.onap.aai.util.FileWatcher; - /** * The Class AAIAuthCore. */ public final class AAIAuthCore { - private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(AAIAuthCore.class); + private static final Logger LOGGER = LoggerFactory.getLogger(AAIAuthCore.class); private static final String ERROR_CODE_AAI_4001 = "AAI_4001"; @@ -71,11 +66,23 @@ public final class AAIAuthCore { * Instantiates a new AAI auth core. */ public AAIAuthCore(String basePath) { + this(basePath, AAIConstants.AAI_AUTH_CONFIG_FILENAME); + } + + public AAIAuthCore(String basePath, String filename){ this.basePath = basePath; + this.globalAuthFileName = filename; AUTH_POLICY_PATTERN = Pattern.compile("^" + this.basePath + "/v\\d+/([\\w\\-]*)"); init(); } + public AAIAuthCore(String basePath, String filename, String pattern){ + this.basePath = basePath; + this.globalAuthFileName = filename; + AUTH_POLICY_PATTERN = Pattern.compile(pattern); + init(); + } + /** * Inits the. */ @@ -90,7 +97,7 @@ public final class AAIAuthCore { * auth config file has been updated and reloads the users if so to get * the most up to date info (that update check logic is within * FileWatcher) - * + * * the timing this method uses is coarser than the frequency of requests * AI&I gets so we're looking at better ways of doing this (TODO) */ @@ -222,7 +229,7 @@ public final class AAIAuthCore { } else if (je.getAsJsonObject().has("user")) { String auth = je.getAsJsonObject().get("user").getAsString() + ":" + Password.deobfuscate(je.getAsJsonObject().get("pass").getAsString()); - String authorizationCode = new String(Base64.base64Encode(auth.getBytes("utf-8"))); + String authorizationCode = new String(Base64.getEncoder().encode(auth.getBytes("utf-8"))); usernames.put(authorizationCode, false); } } @@ -256,7 +263,7 @@ public final class AAIAuthCore { /** * for backwards compatibility - * + * * @param username * @param uri * @param httpMethod @@ -282,7 +289,7 @@ public final class AAIAuthCore { public boolean authorize(String username, String uri, String httpMethod, String haProxyUser, String issuer) throws AAIUnrecognizedFunctionException { String aaiMethod = this.getAuthPolicyFunctName(uri); - if (!this.validFunctions.contains(aaiMethod)) { + if (!this.validFunctions.contains(aaiMethod) && !("info".equalsIgnoreCase(aaiMethod))) { throw new AAIUnrecognizedFunctionException(aaiMethod); } boolean wildcardCheck = isWildcardIssuer(issuer); @@ -328,7 +335,7 @@ public final class AAIAuthCore { /** * returns aai user either matching the username or containing the wildcard. - * + * * @param username * @return */ @@ -357,13 +364,11 @@ public final class AAIAuthCore { * @return true, if successful */ private boolean authorize(AAIUser aaiUser, String aaiMethod, String httpMethod) { - if (aaiUser.hasAccess(aaiMethod, httpMethod)) { - LoggingContext.statusCode(StatusCode.COMPLETE); + if ("info".equalsIgnoreCase(aaiMethod)|| aaiUser.hasAccess(aaiMethod, httpMethod)) { LOGGER.debug("AUTH ACCEPTED: " + aaiUser.getUsername() + " on function " + aaiMethod + " request type " + httpMethod); return true; } else { - LoggingContext.statusCode(StatusCode.ERROR); LOGGER.debug("AUTH FAILED: " + aaiUser.getUsername() + " on function " + aaiMethod + " request type " + httpMethod); return false; diff --git a/aai-core/src/main/java/org/onap/aai/auth/AAIUser.java b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/auth/AAIUser.java index f1e1b084..4512adb0 100644 --- a/aai-core/src/main/java/org/onap/aai/auth/AAIUser.java +++ b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/auth/AAIUser.java @@ -20,7 +20,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.aai.auth; +package org.onap.aai.aaf.auth; import java.util.*; diff --git a/aai-aaf-auth/src/main/java/org/onap/aai/aaf/auth/AafRequestFilter.java b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/auth/AafRequestFilter.java new file mode 100644 index 00000000..9a02fe2c --- /dev/null +++ b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/auth/AafRequestFilter.java @@ -0,0 +1,114 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 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========================================================= + */ + +package org.onap.aai.aaf.auth; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.onap.aaf.cadi.filter.CadiFilter; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Enumeration; +import java.util.List; +import java.util.Properties; + +import static org.onap.aai.aaf.auth.ResponseFormatter.errorResponse; + +/** + * The Class AafRequestFilter provides common auth filter methods + */ +public class AafRequestFilter { + + private static final Logger LOGGER = LoggerFactory.getLogger(AafRequestFilter.class); + + public static void authenticationFilter(HttpServletRequest request, HttpServletResponse response, + FilterChain filterChain, CadiFilter cadiFilter, Properties props, String userChainPattern) + throws IOException, ServletException { + if (!request.getRequestURI().matches("^.*/util/echo$")) { + + List<String> cadiConfiguredIssuers = CertUtil.getCadiCertIssuers(props); + String issuer = CertUtil.getCertIssuer(request); + if (issuer == null || issuer.isEmpty()) { + errorResponse(request, response); + return; + } + issuer = issuer.replaceAll("\\s+", "").toUpperCase(); + + if (cadiConfiguredIssuers.contains(issuer)) { + LOGGER.debug("authenticationFilter CADI issuer " + issuer); + if (CertUtil.isHaProxy(request)) { + // get the end user/client mechid and use it in the user chain header value + String user = CertUtil.getMechId(request); + LOGGER.debug("authenticationFilter haProxy sent end user/mechid " + user); + if (user == null || user.isEmpty()) { + errorResponse(request, response); + return; + } + AafRequestWrapper reqWrapper = new AafRequestWrapper(request); + String userChainHdr = CertUtil.buildUserChainHeader(user, userChainPattern); + LOGGER.debug("User chain header value: " + userChainHdr); + reqWrapper.putHeader(CertUtil.AAF_USER_CHAIN_HDR, userChainHdr); + cadiFilter.doFilter(reqWrapper, response, filterChain); + } else { + cadiFilter.doFilter(request, response, filterChain); + } + if (response.getStatus() == 401 || response.getStatus() == 403) { + LOGGER.debug("authenticationFilter failed CADI authentication"); + errorResponse(request, response); + return; + } + } else { + filterChain.doFilter(request, response); + } + } else { + filterChain.doFilter(request, response); + } + } + + public static void authorizationFilter(HttpServletRequest request, HttpServletResponse response, + FilterChain filterChain, String permission, Properties props) throws IOException, ServletException { + if (request.getRequestURI().matches("^.*/util/echo$")) { + filterChain.doFilter(request, response); + } + List<String> cadiConfiguredIssuers = CertUtil.getCadiCertIssuers(props); + String issuer = CertUtil.getCertIssuer(request); + if (issuer == null || issuer.isEmpty()) { + errorResponse(request, response); + return; + } + issuer = issuer.replaceAll("\\s+", "").toUpperCase(); + Enumeration hdrs = request.getHeaders(CertUtil.AAF_USER_CHAIN_HDR); + while (hdrs.hasMoreElements()) { + String headerValue = (String) hdrs.nextElement(); + LOGGER.debug("authorizationFilter user chain headerValue=" + headerValue); + } + if ((cadiConfiguredIssuers.contains(issuer)) && (!request.isUserInRole(permission))) { + LOGGER.debug( + "authorizationFilter failed CADI authorization issuer=" + issuer + " permission=" + permission); + errorResponse(request, response); + } else { + filterChain.doFilter(request, response); + } + } +} diff --git a/aai-aaf-auth/src/main/java/org/onap/aai/aaf/auth/AafRequestWrapper.java b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/auth/AafRequestWrapper.java new file mode 100644 index 00000000..0ecca679 --- /dev/null +++ b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/auth/AafRequestWrapper.java @@ -0,0 +1,78 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 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========================================================= + */ + +package org.onap.aai.aaf.auth; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; +import java.util.*; + +/** + * The AafRequestWrapper sets the user in the principal name + */ +public class AafRequestWrapper extends HttpServletRequestWrapper { + + private final Map<String, String> customHeaders; + + public AafRequestWrapper(HttpServletRequest request) { + super(request); + this.customHeaders = new HashMap<String, String>(); + } + + public void putHeader(String name, String value) { + this.customHeaders.put(name, value); + } + + @Override + public String getHeader(String name) { + String headerValue = customHeaders.get(name); + if (headerValue != null) { + return headerValue; + } + return (((HttpServletRequest) getRequest()).getHeader(name)); + } + + @Override + public Enumeration<String> getHeaderNames() { + Set<String> nameSet = new HashSet<String>(customHeaders.keySet()); + + Enumeration<String> e = ((HttpServletRequest) getRequest()).getHeaderNames(); + while (e.hasMoreElements()) { + String headerName = e.nextElement(); + nameSet.add(headerName); + } + return Collections.enumeration(nameSet); + } + + @Override + public Enumeration<String> getHeaders(String name) { + String myHeaderValue = customHeaders.get(name); + Set<String> headerValueSet = new HashSet<String>(); + if (myHeaderValue != null) { + headerValueSet.add(myHeaderValue); + } + Enumeration<String> e = ((HttpServletRequest) getRequest()).getHeaders(name); + while (e.hasMoreElements()) { + String headerValue = e.nextElement(); + headerValueSet.add(headerValue); + } + return Collections.enumeration(headerValueSet); + } +} diff --git a/aai-aaf-auth/src/main/java/org/onap/aai/aaf/auth/CertUtil.java b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/auth/CertUtil.java new file mode 100644 index 00000000..334a3060 --- /dev/null +++ b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/auth/CertUtil.java @@ -0,0 +1,157 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 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========================================================= + */ + +package org.onap.aai.aaf.auth; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.servlet.http.HttpServletRequest; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.security.cert.X509Certificate; +import java.util.*; +import java.util.stream.Collectors; + +/** + * The Class CertUtil provides cert related utility methods. + */ +public class CertUtil { + public static final String DEFAULT_CADI_ISSUERS = + "CN=ATT AAF CADI Test Issuing CA 01, OU=CSO, O=ATT, C=US:CN=ATT AAF CADI Test Issuing CA 02, OU=CSO, O=ATT, C=US"; + public static final String CADI_PROP_FILES = "cadi_prop_files"; + public static final String CADI_ISSUERS_PROP_NAME = "cadi_x509_issuers"; + public static final String CADI_ISSUERS_SEPARATOR = ":"; + public static final String AAI_SSL_CLIENT_OU_HDR = "X-AAI-SSL-Client-OU"; + public static final String AAI_SSL_ISSUER_HDR = "X-AAI-SSL-Issuer"; + public static final String AAI_SSL_CLIENT_CN_HDR = "X-AAI-SSL-Client-CN"; + public static final String AAI_SSL_CLIENT_O_HDR = "X-AAI-SSL-Client-O"; + public static final String AAI_SSL_CLIENT_L_HDR = "X-AAI-SSL-Client-L"; + public static final String AAI_SSL_CLIENT_ST_HDR = "X-AAI-SSL-Client-ST"; + public static final String AAI_SSL_CLIENT_C_HDR = "X-AAI-SSL-Client-C"; + public static final String AAF_USER_CHAIN_HDR = "USER_CHAIN"; + public static final String AAF_ID = "<AAF-ID>"; + private static final Logger LOGGER = LoggerFactory.getLogger(CertUtil.class); + + public static String getAaiSslClientOuHeader(HttpServletRequest hsr) { + return (hsr.getHeader(AAI_SSL_CLIENT_OU_HDR)); + } + + public static boolean isHaProxy(HttpServletRequest hsr) { + + String haProxyUser = ""; + if (Objects.isNull(hsr.getHeader(AAI_SSL_CLIENT_CN_HDR)) || Objects.isNull(hsr.getHeader(AAI_SSL_CLIENT_OU_HDR)) + || Objects.isNull(hsr.getHeader(AAI_SSL_CLIENT_O_HDR)) + || Objects.isNull(hsr.getHeader(AAI_SSL_CLIENT_L_HDR)) + || Objects.isNull(hsr.getHeader(AAI_SSL_CLIENT_ST_HDR)) + || Objects.isNull(hsr.getHeader(AAI_SSL_CLIENT_C_HDR))) { + haProxyUser = ""; + } else { + haProxyUser = String.format("CN=%s, OU=%s, O=\"%s\", L=%s, ST=%s, C=%s", + Objects.toString(hsr.getHeader(AAI_SSL_CLIENT_CN_HDR), ""), + Objects.toString(hsr.getHeader(AAI_SSL_CLIENT_OU_HDR), ""), + Objects.toString(hsr.getHeader(AAI_SSL_CLIENT_O_HDR), ""), + Objects.toString(hsr.getHeader(AAI_SSL_CLIENT_L_HDR), ""), + Objects.toString(hsr.getHeader(AAI_SSL_CLIENT_ST_HDR), ""), + Objects.toString(hsr.getHeader(AAI_SSL_CLIENT_C_HDR), "")).toLowerCase(); + } + if (!haProxyUser.isEmpty()) { + LOGGER.debug("isHaProxy haProxyUser=" + haProxyUser); + return true; + } + LOGGER.debug("isHaProxy haProxyUser not found"); + return false; + } + + public static String getMechId(HttpServletRequest hsr) { + String mechId = null; + String ou = getAaiSslClientOuHeader(hsr); + if ((ou != null) && (!ou.isEmpty())) { + String[] parts = ou.split(CADI_ISSUERS_SEPARATOR); + if (parts != null && parts.length >= 1) { + mechId = parts[0]; + } + } + LOGGER.debug("getMechId mechId=" + mechId); + return (mechId); + } + + public static String getCertIssuer(HttpServletRequest hsr) { + String issuer = hsr.getHeader(AAI_SSL_ISSUER_HDR); + if (issuer != null && !issuer.isEmpty()) { + LOGGER.debug("getCertIssuer issuer from header " + AAI_SSL_ISSUER_HDR + " " + issuer); + // the haproxy header replaces the ', ' with '/' and reverses on the '/' need to undo that. + List<String> broken = Arrays.asList(issuer.split("/")); + broken = broken.stream().filter(s -> !s.isEmpty()).collect(Collectors.toList()); + Collections.reverse(broken); + issuer = String.join(", ", broken); + } else { + if (hsr.getAttribute("javax.servlet.request.cipher_suite") != null) { + X509Certificate[] certChain = + (X509Certificate[]) hsr.getAttribute("javax.servlet.request.X509Certificate"); + if (certChain != null && certChain.length > 0) { + X509Certificate clientCert = certChain[0]; + issuer = clientCert.getIssuerX500Principal().getName(); + LOGGER.debug("getCertIssuer issuer from client cert " + issuer); + } + } + } + return issuer; + } + + public static List<String> getCadiCertIssuers(Properties cadiProperties) { + + List<String> defaultList = new ArrayList<String>(); + List<String> resultList = new ArrayList<String>(); + + String[] cIssuers = DEFAULT_CADI_ISSUERS.split(CADI_ISSUERS_SEPARATOR); + for (String issuer : cIssuers) { + defaultList.add(issuer.replaceAll("\\s+", "").toUpperCase()); + } + try { + String certPropFileName = cadiProperties.getProperty(CADI_PROP_FILES); + String configuredIssuers = DEFAULT_CADI_ISSUERS; + Properties certProperties = new Properties(); + if (certPropFileName != null) { + certProperties.load(new FileInputStream(new File(certPropFileName))); + configuredIssuers = certProperties.getProperty(CADI_ISSUERS_PROP_NAME); + } + if ((configuredIssuers != null) && (!configuredIssuers.isEmpty())) { + cIssuers = configuredIssuers.split(CADI_ISSUERS_SEPARATOR); + for (String issuer : cIssuers) { + resultList.add(issuer.replaceAll("\\s+", "").toUpperCase()); + } + } + } catch (IOException ioe) { + return (defaultList); + } + if (resultList.isEmpty()) { + return defaultList; + } + LOGGER.debug("getCadiCertIssuers " + resultList.toString()); + return resultList; + } + + public static String buildUserChainHeader(String user, String userChainPattern) { + // aaf.userchain.pattern=<AAF-ID>:${aaf.userchain.service.reference}:${aaf.userchain.auth.type}:AS + return (userChainPattern.replaceAll(AAF_ID, user)); + } +} diff --git a/aai-core/src/main/java/org/onap/aai/util/FileWatcher.java b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/auth/FileWatcher.java index 07ac2642..45331ed9 100644 --- a/aai-core/src/main/java/org/onap/aai/util/FileWatcher.java +++ b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/auth/FileWatcher.java @@ -18,10 +18,10 @@ * ============LICENSE_END========================================================= */ -package org.onap.aai.util; +package org.onap.aai.aaf.auth; -import java.io.*; -import java.util.*; +import java.io.File; +import java.util.TimerTask; public abstract class FileWatcher extends TimerTask { private long timeStamp; @@ -39,8 +39,8 @@ public abstract class FileWatcher extends TimerTask { /** * runs a timer task - * - * @see TimerTask.run + * + * @see TimerTask#run */ public final void run() { long timeStamp = file.lastModified(); diff --git a/aai-aaf-auth/src/main/java/org/onap/aai/aaf/auth/ResponseFormatter.java b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/auth/ResponseFormatter.java new file mode 100644 index 00000000..d7c88e81 --- /dev/null +++ b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/auth/ResponseFormatter.java @@ -0,0 +1,57 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 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========================================================= + */ + +package org.onap.aai.aaf.auth; + +import org.onap.aai.exceptions.AAIException; +import org.onap.aai.logging.ErrorLogHelper; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.core.MediaType; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; + +public class ResponseFormatter { + + private static final String ACCEPT_HEADER = "accept"; + + public static void errorResponse(HttpServletRequest request, HttpServletResponse response) throws IOException { + errorResponse(new AAIException("AAI_3300"), request, response); + } + + public static void errorResponse(AAIException exception, HttpServletRequest request, HttpServletResponse response) throws IOException { + + if(response.isCommitted()){ + return; + } + + String accept = request.getHeader(ACCEPT_HEADER) == null ? MediaType.APPLICATION_XML : request.getHeader(ACCEPT_HEADER); + + response.setStatus(exception.getErrorObject().getHTTPResponseCode().getStatusCode()); + response.setHeader("Content-Type", accept); + response.resetBuffer(); + + String resp = ErrorLogHelper.getRESTAPIErrorResponse(Collections.singletonList(MediaType.valueOf(accept)), exception, new ArrayList<>()); + response.getOutputStream().print(resp); + response.flushBuffer(); + } +} diff --git a/aai-core/src/main/java/org/onap/aai/auth/exceptions/AAIUnrecognizedFunctionException.java b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/auth/exceptions/AAIUnrecognizedFunctionException.java index 1410b445..c6a97ac5 100644 --- a/aai-core/src/main/java/org/onap/aai/auth/exceptions/AAIUnrecognizedFunctionException.java +++ b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/auth/exceptions/AAIUnrecognizedFunctionException.java @@ -20,7 +20,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.aai.auth.exceptions; +package org.onap.aai.aaf.auth.exceptions; import org.onap.aai.exceptions.AAIException; diff --git a/aai-aaf-auth/src/main/java/org/onap/aai/aaf/filters/AafAuthorizationFilter.java b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/filters/AafAuthorizationFilter.java new file mode 100644 index 00000000..9f2782a4 --- /dev/null +++ b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/filters/AafAuthorizationFilter.java @@ -0,0 +1,119 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 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 + * <p> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p> + * 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.aai.aaf.filters; + +import org.onap.aai.aaf.auth.ResponseFormatter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.web.filter.OrderedRequestContextFilter; +import org.springframework.context.annotation.Profile; +import org.springframework.context.annotation.PropertySource; +import org.springframework.stereotype.Component; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +/** + * AAF authorization filter + */ + +@Component +@Profile(AafProfiles.AAF_AUTHENTICATION) +@PropertySource(value = "file:${CONFIG_HOME}/aaf/permissions.properties", ignoreResourceNotFound = true) +@PropertySource(value = "file:${server.local.startpath}/aaf/permissions.properties", ignoreResourceNotFound = true) +public class AafAuthorizationFilter extends OrderedRequestContextFilter { + + private static final String ADVANCED = "advanced"; + private static final String BASIC = "basic"; + + private final String type; + private final String instance; + + private GremlinFilter gremlinFilter; + + private List<String> advancedKeywordsList; + + @Autowired + public AafAuthorizationFilter( + GremlinFilter gremlinFilter, + @Value("${permission.type}") String type, + @Value("${permission.instance}") String instance, + @Value("${advanced.keywords.list:}") String advancedKeys + ) { + this.gremlinFilter = gremlinFilter; + this.type = type; + this.instance = instance; + if(advancedKeys == null || advancedKeys.isEmpty()){ + this.advancedKeywordsList = new ArrayList<>(); + } else { + this.advancedKeywordsList = Arrays.stream(advancedKeys.split(",")) + .collect(Collectors.toList()); + } + this.setOrder(FilterPriority.AAF_AUTHORIZATION.getPriority()); + } + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException { + if(request.getRequestURI().endsWith("/query")){ + gremlinFilter.doBasicAuthFilter(request, response, filterChain); + } else { + + String permission = null; + + if(advancedKeywordsList == null || advancedKeywordsList.size() == 0) { + permission = String.format("%s|%s|%s", type, instance, request.getMethod().toLowerCase()); + } else { + + boolean isAdvanced = this.containsAdvancedKeywords(request); + + //if the URI contains advanced.keywords it's an advanced query + String queryType = isAdvanced ? ADVANCED : BASIC; + permission = String.format("%s|%s|%s", type, instance, queryType); + } + + boolean isAuthorized = request.isUserInRole(permission); + + if(!isAuthorized){ + ResponseFormatter.errorResponse(request, response); + } else { + filterChain.doFilter(request,response); + } + + } + } + + private boolean containsAdvancedKeywords(HttpServletRequest request) { + String uri = request.getRequestURI(); + for (String keyword: advancedKeywordsList) { + if (uri.contains(keyword)) { + return true; + } + } + return false; + } +} diff --git a/aai-aaf-auth/src/main/java/org/onap/aai/aaf/filters/AafCertAuthorizationFilter.java b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/filters/AafCertAuthorizationFilter.java new file mode 100644 index 00000000..7ec6bb64 --- /dev/null +++ b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/filters/AafCertAuthorizationFilter.java @@ -0,0 +1,107 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 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 + * <p> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p> + * 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.aai.aaf.filters; + +import org.onap.aai.aaf.auth.AafRequestFilter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.web.filter.OrderedRequestContextFilter; +import org.springframework.context.annotation.Profile; +import org.springframework.context.annotation.PropertySource; +import org.springframework.stereotype.Component; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Properties; +import java.util.stream.Collectors; + + +/** + * AAF with client cert authorization filter + */ + +@Component +@Profile(AafProfiles.AAF_CERT_AUTHENTICATION) +@PropertySource(value = "file:${CONFIG_HOME}/aaf/permissions.properties", ignoreResourceNotFound = true) +@PropertySource(value = "file:${server.local.startpath}/aaf/permissions.properties", ignoreResourceNotFound = true) +public class AafCertAuthorizationFilter extends OrderedRequestContextFilter { + + private static final String ADVANCED = "advanced"; + private static final String BASIC = "basic"; + + String type; + + String instance; + + private CadiProps cadiProps; + + private List<String> advancedKeywordsList; + + @Autowired + public AafCertAuthorizationFilter( + @Value("${permission.type}") String type, + @Value("${permission.instance}") String instance, + @Value("${advanced.keywords.list:}") String advancedKeys, + CadiProps cadiProps + ) { + this.type = type; + this.instance = instance; + this.cadiProps = cadiProps; + if(advancedKeys == null || advancedKeys.isEmpty()){ + this.advancedKeywordsList = new ArrayList<>(); + } else { + this.advancedKeywordsList = Arrays.stream(advancedKeys.split(",")) + .collect(Collectors.toList()); + } + this.setOrder(FilterPriority.AAF_CERT_AUTHORIZATION.getPriority()); + } + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException { + if(advancedKeywordsList == null || advancedKeywordsList.size() == 0){ + String permission = String.format("%s|%s|%s", type, instance, request.getMethod().toLowerCase()); + AafRequestFilter.authorizationFilter(request, response, filterChain, permission, cadiProps.getCadiProperties()); + } else { + boolean isAdvanced = this.containsAdvancedKeywords(request); + + //if the URI contains advanced.keywords it's an advanced query + String queryType = isAdvanced ? ADVANCED : BASIC; + String permission = String.format("%s|%s|%s", type, instance, queryType); + AafRequestFilter.authorizationFilter(request, response, filterChain, permission, cadiProps.getCadiProperties()); + } + } + + private boolean containsAdvancedKeywords(HttpServletRequest request) { + String uri = request.getRequestURI(); + for (String keyword: advancedKeywordsList) { + if (uri.contains(keyword)) { + return true; + } + } + return false; + } +} diff --git a/aai-aaf-auth/src/main/java/org/onap/aai/aaf/filters/AafCertFilter.java b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/filters/AafCertFilter.java new file mode 100644 index 00000000..71238cfc --- /dev/null +++ b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/filters/AafCertFilter.java @@ -0,0 +1,111 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 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 + * <p> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p> + * 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.aai.aaf.filters; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.onap.aaf.cadi.PropAccess; +import org.onap.aaf.cadi.filter.CadiFilter; +import org.onap.aai.aaf.auth.AafRequestFilter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.web.filter.OrderedRequestContextFilter; +import org.springframework.context.annotation.Profile; +import org.springframework.context.annotation.PropertySource; +import org.springframework.stereotype.Component; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * AAF with client cert authentication filter + */ + +@Component +@Profile(AafProfiles.AAF_CERT_AUTHENTICATION) +@PropertySource(value = "file:${CONFIG_HOME}/aaf/permissions.properties", ignoreResourceNotFound = true) +@PropertySource(value = "file:${server.local.startpath}/aaf/permissions.properties", ignoreResourceNotFound = true) +public class AafCertFilter extends OrderedRequestContextFilter { + + private static final Logger LOGGER = LoggerFactory.getLogger(AafCertFilter.class); + + String aafUserChainPattern; + + private final CadiFilter cadiFilter; + + private final CadiProps cadiProps; + + @Autowired + public AafCertFilter( @Value("${aaf.userchain.pattern}") String aafUserChainPattern, + CadiProps cadiProps) throws IOException, ServletException { + + this.aafUserChainPattern = aafUserChainPattern; + this.cadiProps = cadiProps; + cadiFilter = new CadiFilter(new PropAccess((level,element)->{ + switch (level) { + case DEBUG: + LOGGER.debug(buildMsg(element)); + break; + case INFO: + case AUDIT: + LOGGER.info(buildMsg(element)); + break; + case WARN: + LOGGER.warn(buildMsg(element)); + break; + case ERROR: + LOGGER.error(buildMsg(element)); + break; + case INIT: + LOGGER.info(buildMsg(element)); + break; + case TRACE: + LOGGER.trace(buildMsg(element)); + break; + case NONE: + break; + } + }, new String[]{"cadi_prop_files=" + cadiProps.getCadiFileName()} )); + this.setOrder(FilterPriority.AAF_CERT_AUTHENTICATION.getPriority()); + } + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException { + AafRequestFilter.authenticationFilter(request, response, filterChain, cadiFilter, cadiProps.getCadiProperties(), aafUserChainPattern); + } + private String buildMsg(Object[] objects) { + StringBuilder sb = new StringBuilder(); + boolean first = true; + for ( Object o: objects ) { + if (first) { + first = false; + } + else { + sb.append(' '); + } + sb.append(o.toString()); + } + return (sb.toString()); + } +} diff --git a/aai-aaf-auth/src/main/java/org/onap/aai/aaf/filters/AafFilter.java b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/filters/AafFilter.java new file mode 100644 index 00000000..16d9afd2 --- /dev/null +++ b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/filters/AafFilter.java @@ -0,0 +1,108 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 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 + * <p> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p> + * 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.aai.aaf.filters; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.onap.aaf.cadi.PropAccess; +import org.onap.aaf.cadi.filter.CadiFilter; +import org.onap.aai.aaf.auth.ResponseFormatter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.web.filter.OrderedRequestContextFilter; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Component; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + + +/** + * AAF authentication filter + */ + +@Component +@Profile(AafProfiles.AAF_AUTHENTICATION) +public class AafFilter extends OrderedRequestContextFilter { + + private static final Logger LOGGER = LoggerFactory.getLogger(AafCertFilter.class); + + private final CadiFilter cadiFilter; + + @Autowired + public AafFilter(CadiProps cadiProps) throws IOException, ServletException { + cadiFilter = new CadiFilter(new PropAccess((level,element)->{ + switch (level) { + case DEBUG: + LOGGER.debug(buildMsg(element)); + break; + case INFO: + case AUDIT: + LOGGER.info(buildMsg(element)); + break; + case WARN: + LOGGER.warn(buildMsg(element)); + break; + case ERROR: + LOGGER.error(buildMsg(element)); + break; + case INIT: + LOGGER.info(buildMsg(element)); + break; + case TRACE: + LOGGER.trace(buildMsg(element)); + break; + case NONE: + break; + } + }, new String[]{"cadi_prop_files=" + cadiProps.getCadiFileName()} )); + this.setOrder(FilterPriority.AAF_AUTHENTICATION.getPriority()); + } + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException { + if (!request.getRequestURI().matches("^.*/util/echo$")) { + cadiFilter.doFilter(request, response, filterChain); + if (response.getStatus() == 401 || response.getStatus() == 403) { + ResponseFormatter.errorResponse(request, response); + } + } else { + filterChain.doFilter(request, response); + } + } + + private String buildMsg(Object[] objects) { + StringBuilder sb = new StringBuilder(); + boolean first = true; + for ( Object o: objects ) { + if (first) { + first = false; + } + else { + sb.append(' '); + } + sb.append(o.toString()); + } + return (sb.toString()); + } +} diff --git a/aai-aaf-auth/src/main/java/org/onap/aai/aaf/filters/AafProfiles.java b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/filters/AafProfiles.java new file mode 100644 index 00000000..b587716e --- /dev/null +++ b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/filters/AafProfiles.java @@ -0,0 +1,33 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2019 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========================================================= + */ +package org.onap.aai.aaf.filters; + +public class AafProfiles { + + // AAF Basic Auth + public static final String AAF_AUTHENTICATION = "aaf-auth"; + + // AAF Auth with Client Certs + public static final String AAF_CERT_AUTHENTICATION = "aaf-cert-auth"; + + public static final String TWO_WAY_SSL = "two-way-ssl"; + + private AafProfiles(){} +} diff --git a/aai-aaf-auth/src/main/java/org/onap/aai/aaf/filters/CadiProps.java b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/filters/CadiProps.java new file mode 100644 index 00000000..35e88f5f --- /dev/null +++ b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/filters/CadiProps.java @@ -0,0 +1,81 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2019 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========================================================= + */ +package org.onap.aai.aaf.filters; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; + +// This component will be created if and only if any of the following profiles are active +@Component +@Profile({ + AafProfiles.AAF_CERT_AUTHENTICATION, + AafProfiles.AAF_AUTHENTICATION, + AafProfiles.TWO_WAY_SSL +}) +public class CadiProps { + + private static final Logger LOGGER = LoggerFactory.getLogger(CadiProps.class); + + private String cadiFileName; + + private Properties cadiProperties; + + @Autowired + public CadiProps(@Value("${aaf.cadi.file:./resources/cadi.properties}") String filename){ + cadiFileName = filename; + cadiProperties = new Properties(); + } + + @PostConstruct + public void init() throws IOException { + + File cadiFile = new File(cadiFileName); + + if(!cadiFile.exists()){ + LOGGER.warn("Unable to find the cadi file in the given path {} so loading cadi.properties from classloader", cadiFileName); + InputStream is = this.getClass().getClassLoader().getResourceAsStream("cadi.properties"); + cadiProperties.load(is); + } else { + LOGGER.info("Successfully found the file {} and started loading the properties from it", cadiFileName); + cadiFileName = cadiFile.getAbsolutePath(); + try (InputStream inputStream = new FileInputStream(cadiFile)) { + cadiProperties.load(inputStream); + } + + } + } + public String getCadiFileName() { + return cadiFileName; + } + public Properties getCadiProperties(){ + return cadiProperties; + } +} diff --git a/aai-core/src/main/java/org/onap/aai/logging/EcompStartTime.java b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/filters/FilterPriority.java index 8f015414..17b9f0e4 100644 --- a/aai-core/src/main/java/org/onap/aai/logging/EcompStartTime.java +++ b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/filters/FilterPriority.java @@ -17,23 +17,23 @@ * limitations under the License. * ============LICENSE_END========================================================= */ +package org.onap.aai.aaf.filters; -package org.onap.aai.logging; +import org.springframework.core.Ordered; -import ch.qos.logback.classic.pattern.ClassicConverter; -import ch.qos.logback.classic.spi.ILoggingEvent; +public enum FilterPriority { -import org.onap.aai.logging.LoggingContext.LoggingField; + AAF_AUTHENTICATION(Ordered.HIGHEST_PRECEDENCE), + AAF_AUTHORIZATION(Ordered.HIGHEST_PRECEDENCE + 1), //higher number = lower priority + AAF_CERT_AUTHENTICATION(Ordered.HIGHEST_PRECEDENCE + 2 ), + AAF_CERT_AUTHORIZATION(Ordered.HIGHEST_PRECEDENCE + 3), + TWO_WAY_SSL_AUTH(Ordered.HIGHEST_PRECEDENCE + 4); -public class EcompStartTime extends ClassicConverter { + private final int priority; - @Override - public String convert(ILoggingEvent event) { - - if (!event.getMDCPropertyMap().containsKey(LoggingField.START_TIME.toString())) { - return LogFormatTools.toDate(event.getTimeStamp()); - } - - return event.getMDCPropertyMap().get(LoggingField.START_TIME.toString()); + FilterPriority(final int p) { + priority = p; } + + public int getPriority() { return priority; } } diff --git a/aai-aaf-auth/src/main/java/org/onap/aai/aaf/filters/GremlinFilter.java b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/filters/GremlinFilter.java new file mode 100644 index 00000000..23ff0c6d --- /dev/null +++ b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/filters/GremlinFilter.java @@ -0,0 +1,99 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2019 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========================================================= + */ +package org.onap.aai.aaf.filters; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.apache.commons.io.IOUtils; +import org.onap.aai.aaf.auth.ResponseFormatter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Component; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.regex.Pattern; + +@Component +@Profile({ + AafProfiles.AAF_CERT_AUTHENTICATION, + AafProfiles.AAF_AUTHENTICATION +}) +public class GremlinFilter { + + private static final Logger LOGGER = LoggerFactory.getLogger(GremlinFilter.class); + + private static final String ADVANCED = "advanced"; + private static final String BASIC = "basic"; + private static final Pattern ECHO_ENDPOINT = Pattern.compile("^.*/util/echo$"); + + String type; + + String instance; + + private CadiProps cadiProps; + + @Autowired + public GremlinFilter( + @Value("${permission.type}") String type, + @Value("${permission.instance}") String instance, + CadiProps cadiProps + ) { + this.type = type; + this.instance = instance; + this.cadiProps = cadiProps; + } + + public void doBasicAuthFilter(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException { + PayloadBufferingRequestWrapper requestBufferWrapper = new PayloadBufferingRequestWrapper(request); + + if(ECHO_ENDPOINT.matcher(request.getRequestURI()).matches()){ + filterChain.doFilter(requestBufferWrapper, response); + } + + String payload = IOUtils.toString(requestBufferWrapper.getInputStream(), StandardCharsets.UTF_8.name()); + boolean containsWordGremlin = payload.contains("\"gremlin\""); + + //if the requestBufferWrapper contains the word "gremlin" it's an "advanced" query needing an "advanced" role + String permissionBasic = String.format("%s|%s|%s", type, instance, BASIC); + String permissionAdvanced = String.format("%s|%s|%s", type, instance, ADVANCED); + + boolean isAuthorized; + + if(containsWordGremlin){ + isAuthorized = requestBufferWrapper.isUserInRole(permissionAdvanced); + }else{ + isAuthorized = requestBufferWrapper.isUserInRole(permissionAdvanced) || requestBufferWrapper.isUserInRole(permissionBasic); + } + + if(!isAuthorized){ + String name = requestBufferWrapper.getUserPrincipal() != null ? requestBufferWrapper.getUserPrincipal().getName() : "unknown"; + LOGGER.info("User " + name + " does not have a role for " + (containsWordGremlin ? "gremlin" : "non-gremlin") + " query" ); + ResponseFormatter.errorResponse(request, response); + } else { + filterChain.doFilter(requestBufferWrapper,response); + } + } +} diff --git a/aai-core/src/main/java/org/onap/aai/logging/EcompErrorCategory.java b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/filters/PayloadBufferingRequestWrapper.java index 452fcd08..eb8a61dd 100644 --- a/aai-core/src/main/java/org/onap/aai/logging/EcompErrorCategory.java +++ b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/filters/PayloadBufferingRequestWrapper.java @@ -17,26 +17,34 @@ * limitations under the License. * ============LICENSE_END========================================================= */ +package org.onap.aai.aaf.filters; -package org.onap.aai.logging; +import org.apache.commons.io.IOUtils; +import org.onap.aaf.cadi.BufferedServletInputStream; -import ch.qos.logback.classic.Level; -import ch.qos.logback.classic.pattern.ClassicConverter; -import ch.qos.logback.classic.spi.ILoggingEvent; +import javax.servlet.ServletInputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; +import java.io.ByteArrayInputStream; +import java.io.IOException; -public class EcompErrorCategory extends ClassicConverter { +/** + * This class buffers the payload of the servlet request. The reason is that we access the payload multiple times, + * which is not supported by the request per se. + */ - @Override - public String convert(ILoggingEvent event) { +class PayloadBufferingRequestWrapper extends HttpServletRequestWrapper { - final Level lev = event.getLevel(); - final String defaultCategory = "WARN"; + private byte[] buffer; - if ((Level.WARN).equals(lev)) { - return (defaultCategory); - } else if ((Level.ERROR).equals(lev)) { - return ("ERROR"); - } - return (defaultCategory); + PayloadBufferingRequestWrapper(HttpServletRequest req) throws IOException { + super(req); + this.buffer = IOUtils.toByteArray(req.getInputStream()); + } + + @Override + public ServletInputStream getInputStream() { + ByteArrayInputStream bais = new ByteArrayInputStream(this.buffer); + return new BufferedServletInputStream(bais); } } diff --git a/aai-aaf-auth/src/main/java/org/onap/aai/aaf/filters/TwoWaySslAuthorization.java b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/filters/TwoWaySslAuthorization.java new file mode 100644 index 00000000..0e206c50 --- /dev/null +++ b/aai-aaf-auth/src/main/java/org/onap/aai/aaf/filters/TwoWaySslAuthorization.java @@ -0,0 +1,186 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2019 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========================================================= + */ +package org.onap.aai.aaf.filters; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.onap.aai.aaf.auth.AAIAuthCore; +import org.onap.aai.aaf.auth.CertUtil; +import org.onap.aai.aaf.auth.ResponseFormatter; +import org.onap.aai.exceptions.AAIException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.web.filter.OrderedRequestContextFilter; +import org.springframework.context.annotation.Profile; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; + +import javax.security.auth.x500.X500Principal; +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.security.cert.X509Certificate; +import java.util.*; + +@Component +@Profile("two-way-ssl") +public class TwoWaySslAuthorization extends OrderedRequestContextFilter { + + private static final Logger LOGGER = LoggerFactory.getLogger(TwoWaySslAuthorization.class); + + public static final String HTTP_METHOD_OVERRIDE = "X-HTTP-Method-Override"; + + public static final String MERGE_PATCH = "MERGE_PATCH"; + + @Autowired + private Environment environment; + + @Autowired + private AAIAuthCore aaiAuthCore; + + @Autowired + private CadiProps cadiProps; + + public TwoWaySslAuthorization(){ + this.setOrder(FilterPriority.TWO_WAY_SSL_AUTH.getPriority()); + } + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException { + + String uri = request.getRequestURI(); + String httpMethod = getHttpMethod(request); + + Optional<String> authUser = getUser(request); + + if (authUser.isPresent()) { + Properties cadiProperties = cadiProps.getCadiProperties(); + + String issuer = CertUtil.getCertIssuer(request); + if (issuer == null || issuer.isEmpty()) { + AAIException aaie = new AAIException("AAI_9107"); + ResponseFormatter.errorResponse(aaie, request, response); + return; + } + issuer = issuer.replaceAll("\\s+","").toUpperCase(); + + List<String> cadiConfiguredIssuers = CertUtil.getCadiCertIssuers(cadiProperties); + boolean isAafAuthProfileActive = this.isAafAuthProfileActive(); + if ((!isAafAuthProfileActive) || (!cadiConfiguredIssuers.contains(issuer)) ) { + try { + this.authorize(uri, httpMethod, authUser.get(), this.getHaProxyUser(request), issuer); + } catch (AAIException e) { + ResponseFormatter.errorResponse(e, request, response); + return; + } + } + } else { + AAIException aaie = new AAIException("AAI_9107"); + ResponseFormatter.errorResponse(aaie, request, response); + return; + } + filterChain.doFilter(request, response); + } + + + private String getHttpMethod(HttpServletRequest request) { + String httpMethod = request.getMethod(); + if ("POST".equalsIgnoreCase(httpMethod) + && "PATCH".equals(request.getHeader(HTTP_METHOD_OVERRIDE))) { + httpMethod = MERGE_PATCH; + } + if (httpMethod.equalsIgnoreCase(MERGE_PATCH) || "patch".equalsIgnoreCase(httpMethod)) { + httpMethod = "PUT"; + } + return httpMethod; + } + + private Optional<String> getUser(HttpServletRequest hsr) { + String authUser = null; + if (hsr.getAttribute("javax.servlet.request.cipher_suite") != null) { + X509Certificate[] certChain = (X509Certificate[]) hsr.getAttribute("javax.servlet.request.X509Certificate"); + + /* + * If the certificate is null or the certificate chain length is zero Then + * retrieve the authorization in the request header Authorization Check that it + * is not null and that it starts with Basic and then strip the basic portion to + * get the base64 credentials Check if this is contained in the AAIBasicAuth + * Singleton class If it is, retrieve the username associated with that + * credentials and set to authUser Otherwise, get the principal from certificate + * and use that authUser + */ + + if (certChain == null || certChain.length == 0) { + + String authorization = hsr.getHeader("Authorization"); + + if (authorization != null && authorization.startsWith("Basic ")) { + authUser = authorization.replace("Basic ", ""); + } + + } else { + X509Certificate clientCert = certChain[0]; + X500Principal subjectDN = clientCert.getSubjectX500Principal(); + authUser = subjectDN.toString().toLowerCase(); + } + } + + return Optional.ofNullable(authUser); + } + + private String getHaProxyUser(HttpServletRequest hsr) { + String haProxyUser; + if (Objects.isNull(hsr.getHeader("X-AAI-SSL-Client-CN")) + || Objects.isNull(hsr.getHeader("X-AAI-SSL-Client-OU")) + || Objects.isNull(hsr.getHeader("X-AAI-SSL-Client-O")) + || Objects.isNull(hsr.getHeader("X-AAI-SSL-Client-L")) + || Objects.isNull(hsr.getHeader("X-AAI-SSL-Client-ST")) + || Objects.isNull(hsr.getHeader("X-AAI-SSL-Client-C"))) { + haProxyUser = ""; + } else { + haProxyUser = String.format("CN=%s, OU=%s, O=\"%s\", L=%s, ST=%s, C=%s", + Objects.toString(hsr.getHeader("X-AAI-SSL-Client-CN"), ""), + Objects.toString(hsr.getHeader("X-AAI-SSL-Client-OU"), ""), + Objects.toString(hsr.getHeader("X-AAI-SSL-Client-O"), ""), + Objects.toString(hsr.getHeader("X-AAI-SSL-Client-L"), ""), + Objects.toString(hsr.getHeader("X-AAI-SSL-Client-ST"), ""), + Objects.toString(hsr.getHeader("X-AAI-SSL-Client-C"), "")).toLowerCase(); + } + return haProxyUser; + } + + private void authorize(String uri, String httpMethod, String authUser, String haProxyUser, String issuer) throws AAIException { + if (!aaiAuthCore.authorize(authUser, uri, httpMethod, haProxyUser, issuer)) { + throw new AAIException("AAI_9101", "Request on " + httpMethod + " " + uri + " status is not OK"); + } + } + + private boolean isAafAuthProfileActive() { + String[] profiles = environment.getActiveProfiles(); + if (profiles != null) { + if (Arrays.stream(profiles).anyMatch( + env -> (env.equalsIgnoreCase(AafProfiles.AAF_CERT_AUTHENTICATION)))) { + return true; + } + } + return false; + } +} diff --git a/aai-core/src/test/java/org/onap/aai/auth/AAIAuthCoreTest.java b/aai-aaf-auth/src/test/java/org/onap/aai/aaf/auth/AAIAuthCoreTest.java index d6075c1f..6fca4fdb 100644 --- a/aai-core/src/test/java/org/onap/aai/auth/AAIAuthCoreTest.java +++ b/aai-aaf-auth/src/test/java/org/onap/aai/aaf/auth/AAIAuthCoreTest.java @@ -18,14 +18,15 @@ * ============LICENSE_END========================================================= */ -package org.onap.aai.auth; - -import static org.junit.Assert.*; +package org.onap.aai.aaf.auth; import org.junit.Before; import org.junit.Test; -import org.onap.aai.AAISetup; -import org.onap.aai.auth.exceptions.AAIUnrecognizedFunctionException; +import org.onap.aai.aaf.auth.exceptions.AAIUnrecognizedFunctionException; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; public class AAIAuthCoreTest extends AAISetup { diff --git a/aai-aaf-auth/src/test/java/org/onap/aai/aaf/auth/AAISetup.java b/aai-aaf-auth/src/test/java/org/onap/aai/aaf/auth/AAISetup.java new file mode 100644 index 00000000..0827782e --- /dev/null +++ b/aai-aaf-auth/src/test/java/org/onap/aai/aaf/auth/AAISetup.java @@ -0,0 +1,31 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2019 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========================================================= + */ +package org.onap.aai.aaf.auth; + +import org.junit.BeforeClass; + +public class AAISetup { + + @BeforeClass + public static void preSetup(){ + System.setProperty("AJSC_HOME", "."); + System.setProperty("BUNDLECONFIG_DIR", "src/test/resources/bundleconfig-local"); + } +} diff --git a/aai-core/src/test/java/org/onap/aai/auth/AAIUserTest.java b/aai-aaf-auth/src/test/java/org/onap/aai/aaf/auth/AAIUserTest.java index cf5eafbd..e3b79cb7 100644 --- a/aai-core/src/test/java/org/onap/aai/auth/AAIUserTest.java +++ b/aai-aaf-auth/src/test/java/org/onap/aai/aaf/auth/AAIUserTest.java @@ -18,12 +18,11 @@ * ============LICENSE_END========================================================= */ -package org.onap.aai.auth; - -import static org.junit.Assert.assertEquals; +package org.onap.aai.aaf.auth; import org.junit.Test; -import org.onap.aai.AAISetup; + +import static org.junit.Assert.assertEquals; public class AAIUserTest extends AAISetup { diff --git a/aai-aaf-auth/src/test/java/org/onap/aai/aaf/auth/CertUtilTest.java b/aai-aaf-auth/src/test/java/org/onap/aai/aaf/auth/CertUtilTest.java new file mode 100644 index 00000000..9f307ac2 --- /dev/null +++ b/aai-aaf-auth/src/test/java/org/onap/aai/aaf/auth/CertUtilTest.java @@ -0,0 +1,87 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 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========================================================= + */ + +package org.onap.aai.aaf.auth; + +import org.junit.BeforeClass; +import org.junit.Test; + +import javax.servlet.http.HttpServletRequest; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.List; +import java.util.Properties; + +import static org.easymock.EasyMock.*; +import static org.junit.Assert.assertTrue; + +/** + * The Class CertUtilTest + */ +public class CertUtilTest extends AAISetup { + + @Test + public void testCadiCertIssuers() throws IOException { + String propFile = System.getProperty("BUNDLECONFIG_DIR") + "/aaf/cadi.properties"; + Properties cadiProperties = new Properties(); + cadiProperties.load(new FileInputStream(new File(propFile))); + + List<String> issuersList = CertUtil.getCadiCertIssuers(cadiProperties); + assertTrue("issuersList isn't populated", !issuersList.isEmpty()); + + int x = issuersList.get(0).indexOf(" "); + assertTrue("issuer contains spaces", x < 0); + } + + @Test + public void testAaiSslClientOuHeader() { + + HttpServletRequest mockRequest = createMock(HttpServletRequest.class); + expect(mockRequest.getHeader(CertUtil.AAI_SSL_CLIENT_OU_HDR)).andReturn("m55555@org.onap.com:TEST").times(1, 4); + expect(mockRequest.getHeader(CertUtil.AAI_SSL_CLIENT_CN_HDR)).andReturn("CN").times(1, 2); + expect(mockRequest.getHeader(CertUtil.AAI_SSL_CLIENT_O_HDR)).andReturn("O").times(1, 2); + expect(mockRequest.getHeader(CertUtil.AAI_SSL_CLIENT_L_HDR)).andReturn("L").times(1, 2); + expect(mockRequest.getHeader(CertUtil.AAI_SSL_CLIENT_ST_HDR)).andReturn("ST").times(1, 2); + expect(mockRequest.getHeader(CertUtil.AAI_SSL_CLIENT_C_HDR)).andReturn("C").times(1, 2); + + replay(mockRequest); + String ou = CertUtil.getAaiSslClientOuHeader(mockRequest); + assertTrue("OU Header value is not as expected", ou.equals("m55555@org.onap.com:TEST")); + + assertTrue("Unexpected isHaProxy() return value", CertUtil.isHaProxy(mockRequest)); + + String mechId = CertUtil.getMechId(mockRequest); + assertTrue("mechid value is not as expected", mechId.equals("m55555@org.onap.com")); + + } + + @Test + public void testBuildUserChain() { + + // aaf.userchain.pattern=<AAF-ID>:${aaf.userchain.service.reference}:${aaf.userchain.auth.type}:AS + String aafUserChainPattern = "<AAF-ID>:org.onap.haproxy:X509:AS"; + String mechid = "m11111@onap.org"; + String result = CertUtil.buildUserChainHeader(mechid, aafUserChainPattern); + + assertTrue("user chain value is not as expected", "m11111@onap.org:org.onap.haproxy:X509:AS".equals(result)); + + } +} diff --git a/aai-aaf-auth/src/test/resources/bundleconfig-local/aaf/cadi.properties b/aai-aaf-auth/src/test/resources/bundleconfig-local/aaf/cadi.properties new file mode 100644 index 00000000..8f7004ff --- /dev/null +++ b/aai-aaf-auth/src/test/resources/bundleconfig-local/aaf/cadi.properties @@ -0,0 +1,14 @@ +## Location properties +## +## Localized Machine Information +## +cadi_loglevel=DEBUG +cadi_latitude=38.0 +cadi_longitude=-72.0 + +# Locate URL (which AAF Env) - Use lower case +aaf_locate_url=https://aafist.test.org:8095 +# AAF URL - Use upper case +aaf_url=https://AAF_LOCATE_URL/service:2.0 +# +cadi_prop_files=src/test/resources/bundleconfig-local/aaf/org.onap.aai.props diff --git a/aai-aaf-auth/src/test/resources/bundleconfig-local/aaf/org.onap.aai.props b/aai-aaf-auth/src/test/resources/bundleconfig-local/aaf/org.onap.aai.props new file mode 100644 index 00000000..3056e5f9 --- /dev/null +++ b/aai-aaf-auth/src/test/resources/bundleconfig-local/aaf/org.onap.aai.props @@ -0,0 +1,4 @@ +cm_url=cm_url +hostname=hostname +aaf_env=IST +cadi_x509_issuers=CN=AAF CADI Test Issuing CA 01, OU=CSO, O=CO, C=US:CN=AAF CADI Test Issuing CA 02, OU=CSO, O=CO, C=US
\ No newline at end of file diff --git a/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/appprops/aaiconfig.properties b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/appprops/aaiconfig.properties new file mode 100644 index 00000000..0239e2ef --- /dev/null +++ b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/appprops/aaiconfig.properties @@ -0,0 +1,58 @@ +# +# ============LICENSE_START======================================================= +# org.onap.aai +# ================================================================================ +# Copyright © 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========================================================= + +aai.config.checktime=1000 + +# this could come from siteconfig.pl? +aai.config.nodename=AutomaticallyOverwritten + +aai.transaction.logging=true +aai.transaction.logging.get=true +aai.transaction.logging.post=true + +aai.server.url.base=https://localhost:8443/aai/ +aai.server.url=https://localhost:8443/aai/v10/ +aai.oldserver.url.base=https://localhost:8443/aai/servers/ +aai.oldserver.url=https://localhost:8443/aai/servers/v2/ +aai.global.callback.url=https://localhost:8443/aai/ + +aai.notification.current.version=v10 +aai.notificationEvent.default.status=UNPROCESSED +aai.notificationEvent.default.eventType=AAI-EVENT +aai.notificationEvent.default.domain=devINT1 +aai.notificationEvent.default.sourceName=aai +aai.notificationEvent.default.sequenceNumber=0 +aai.notificationEvent.default.severity=NORMAL +aai.notificationEvent.default.version=v10 +# This one lets us enable/disable resource-version checking on updates/deletes +aai.resourceversion.enableflag=true +aai.default.api.version=v10 + +aai.example.passwd.x=OBF:1vn21ugu1saj1v9i1v941sar1ugw1vo0 +aai.example.string=hello +aai.example.int=7748 + +aai.realtime.clients=RO,SDNC,SO + +aai.jms.enable=false + +aai.rest.getall.depthparam=someuuid + +aaf.valid.issuer.wildcard=aaf wild card issuer|aafWildCardIssuer|OU=another + diff --git a/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/appprops/error.properties b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/appprops/error.properties new file mode 100644 index 00000000..3a5671c2 --- /dev/null +++ b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/appprops/error.properties @@ -0,0 +1,160 @@ +# Adding comment trying to trigger a build +#------------------------------------------------------------------------------- ---------- +#Key=Disposition:Category:Severity:Error Code:HTTP ResponseCode:RESTError Code:Error Message +#------------------------------------------------------------------------------- ---------- +# testing code, please don't change unless error utility source code changes +AAI_TESTING=5:2:WARN:0000:400:0001:Error code for testing + +# General success +AAI_0000=0:0:INFO:0000:200:0000:Success + +# health check success +AAI_0001=0:0:INFO:0001:200:0001:Success X-FromAppId=%1 X-TransactionId=%2 +AAI_0002=0:0:INFO:0002:200:0001:Successful health check + +# Success with additional info +AAI_0003=0:3:INFO:0003:202:0003:Success with additional info performing %1 on %2. Added %3 with key %4 +AAI_0004=0:3:INFO:0004:202:0003:Added prerequisite object to db + +#--- aairest: 3000-3299 +# svc errors +AAI_3000=5:2:INFO:3000:400:3000:Invalid input performing %1 on %2 +AAI_3001=5:6:INFO:3001:404:3001:Resource not found for %1 using id %2 +AAI_3002=5:1:WARN:3002:400:3002:Error writing output performing %1 on %2 +AAI_3003=5:1:WARN:3003:400:3003:Failed to make edge to missing target node of type %3 with keys %4 performing %1 on %2 +AAI_3005=5:6:WARN:3005:404:3001:Node cannot be directly accessed for read, must be accessed via ancestor(s) +AAI_3006=5:6:WARN:3006:404:3001:Node cannot be directly accessed for write, must be accessed via ancestor(s) +AAI_3007=5:6:INFO:3007:410:3007:This version (%1) of the API is retired, please migrate to %2 +AAI_3008=5:6:ERROR:3008:400:3008:URI is not encoded in UTF-8 +AAI_3009=5:6:ERROR:3009:400:3002:Malformed URL +# pol errors +AAI_3100=5:1:WARN:3100:400:3100:Unsupported operation %1 +AAI_3101=5:1:WARN:3101:403:3101:Attempt by client %1 to execute API %2 +AAI_3102=5:1:WARN:3102:400:3102:Error parsing input performing %1 on %2 +AAI_3300=5:1:WARN:3300:403:3300:Unauthorized +AAI_3301=5:1:WARN:3301:401:3301:Stale credentials +AAI_3302=5:1:WARN:3302:401:3301:Not authenticated +AAI_3303=5:1:ERROR:3303:403:3300:Too many objects would be returned by this request, please refine your request and retry + +#--- aaigen: 4000-4099 +AAI_4000=5:4:ERROR:4000:500:3002:Internal Error +AAI_4001=5:4:FATAL:4001:500:3002:Configuration file not found +AAI_4002=5:4:FATAL:4002:500:3002:Error reading Configuration file +AAI_4003=5:4:ERROR:4003:500:3002:Error writing to log file +AAI_4004=5:4:FATAL:4004:500:3002:Error reading/parsing the error properties file +AAI_4005=5:4:FATAL:4005:500:3002:Missing or invalid configuration parameter +AAI_4006=5:4:FATAL:4006:500:3002:Unexpected error in service +AAI_4007=5:4:ERROR:4007:500:3102:Input parsing error +AAI_4008=5:4:ERROR:4008:500:3002:Output parsing error +AAI_4009=4:0:ERROR:4009:400:3000:Invalid X-FromAppId in header +AAI_4010=4:0:ERROR:4010:400:3000:Invalid X-TransactionId in header +AAI_4011=5:4:ERROR:4011:500:3002:Missing data for REST error response +AAI_4014=4:0:ERROR:4014:400:3000:Invalid Accept header +AAI_4015=4:0:ERROR:4015:400:3000:You must provide at least one indexed property +AAI_4016=4:0:ERROR:4016:400:3000:The depth parameter must be a number or the string "all" +AAI_4017=5:2:INFO:4017:400:3000:Could not set property +AAI_4018=5:2:ERROR:4018:400:3000:Unable to convert the string to integer +#--- aaidbmap: 5102-5199 +AAI_5102=5:4:FATAL:5102:500:3002:Graph database is null after open +AAI_5105=5:4:ERROR:5105:500:3002:Unexpected error reading/updating database +AAI_5106=5:4:WARN:5106:404:3001:Node not found +AAI_5107=5:2:WARN:5107:400:3000:Required information missing +AAI_5108=5:2:WARN:5108:200:0:Unexpected information in request being ignored + +#--- aaidbgen: 6101-6199 +AAI_6101=5:4:ERROR:6101:500:3002:null JanusGraph object passed +AAI_6102=5:4:WARN:6102:400:3000:Passed-in property is not valid for this nodeType +AAI_6103=5:4:WARN:6103:400:3000:Required Node-property not found in input data +AAI_6104=5:4:WARN:6104:400:3000:Required Node-property was passed with no data +AAI_6105=5:4:WARN:6105:400:3000:Node-Key-Property not defined in DbMaps +AAI_6106=5:4:WARN:6106:400:3000:Passed-in property is not valid for this edgeType +AAI_6107=5:4:WARN:6107:400:3000:Required Edge-property not found in input data +AAI_6108=5:4:WARN:6108:400:3000:Required Edge-property was passed with no data +AAI_6109=5:4:WARN:6109:400:3000:Bad dependent Node value +AAI_6110=5:4:ERROR:6110:400:3100:Node cannot be deleted +AAI_6111=5:4:ERROR:6111:400:3000:JSON processing error +AAI_6112=5:4:ERROR:6112:400:3000:More than one node found by getUniqueNode() +AAI_6114=5:4:INFO:6114:404:3001:Node Not Found +AAI_6115=5:4:ERROR:6115:400:3000:Unrecognized NodeType +AAI_6116=5:4:ERROR:6116:400:3000:Unrecognized Property +AAI_6117=5:4:ERROR:6117:400:3000:Uniqueness constraint violated +AAI_6118=5:4:ERROR:6118:400:3000:Required Field not passed. +AAI_6120=5:4:ERROR:6120:400:3000:Bad Parameter Passed +AAI_6121=5:4:ERROR:6121:400:3000:Problem with internal AAI reference data +AAI_6122=5:4:ERROR:6122:400:3000:Data Set not complete in DB for this request +AAI_6123=5:4:ERROR:6123:500:3000:Bad Data found by DataGrooming Tool - Investigate +AAI_6124=5:4:ERROR:6124:500:3000:File read/write error +AAI_6125=5:4:WARN:6125:500:3000:Problem Pulling Data Set +AAI_6126=5:4:ERROR:6126:400:3000:Edge cannot be deleted +AAI_6127=5:4:INFO:6127:404:3001:Edge Not Found +AAI_6128=5:4:INFO:6128:500:3000:Unexpected error +AAI_6129=5:4:INFO:6129:404:3003:Error making edge to target node +AAI_6130=5:4:WARN:6130:412:3000:Precondition Required +AAI_6131=5:4:WARN:6131:412:3000:Precondition Failed +AAI_6132=5:4:WARN:6132:400:3000:Bad Model Definition +AAI_6133=5:4:WARN:6133:400:3000:Bad Named Query Definition +AAI_6134=5:4:ERROR:6134:500:6134:Could not persist transaction to storage back end. Exhausted retry amount +AAI_6135=5:4:WARN:6135:412:3000:Resource version specified on create +AAI_6136=5:4:ERROR:6136:400:3000:Object cannot hold multiple items +AAI_6137=5:4:ERROR:6137:400:3000:Cannot perform writes on multiple vertices +AAI_6138=5:4:ERROR:6138:400:3000:Cannot delete multiple vertices +AAI_6139=5:4:ERROR:6139:404:3000:Attempted to add edge to vertex that does not exist +AAI_6140=5:4:ERROR:6140:400:3000:Edge multiplicity violated +AAI_6141=5:4:WARN:6141:400:3000:Please Refine Query +AAI_6142=5:4:INFO:6142:400:3000:Retrying transaction +AAI_6143=5:4:INFO:6143:400:3000:Ghost vertex found +AAI_6144=5:4:WARN:6144:400:3000:Cycle found in graph +AAI_6145=5:4:ERROR:6145:400:3000:Cannot create a nested/containment edge via relationship +AAI_6146=5:4:ERROR:6146:400:3000:Ambiguous identity map found, use a URI instead + +#--- aaicsvp: 7101-7199 +AAI_7101=5:4:ERROR:7101:500:3002:Unexpected error in CSV file processing +AAI_7102=5:4:ERROR:7102:500:3002:Error in cleanup temporary directory +#AAI_7103=4:2:ERROR:7103:500:3002:Unsupported user +AAI_7104=5:4:ERROR:7104:500:3002:Failed to create directory +AAI_7105=5:4:ERROR:7105:500:3002:Temporary directory exists +AAI_7106=5:4:ERROR:7106:500:3002:Cannot delete +AAI_7107=5:4:ERROR:7107:500:3002:Input file does not exist +AAI_7108=5:4:ERROR:7108:500:3002:Output file does not exist +AAI_7109=5:4:ERROR:7109:500:3002:Error closing file +AAI_7110=5:4:ERROR:7110:500:3002:Error loading/reading properties file +AAI_7111=5:4:ERROR:7111:500:3002:Error executing shell script +AAI_7112=5:4:ERROR:7112:500:3002:Error creating output file +AAI_7113=5:4:ERROR:7113:500:3002:Trailer record error +AAI_7114=5:4:ERROR:7114:500:3002:Input file error +AAI_7115=5:4:ERROR:7115:500:3002:Unexpected error +AAI_7116=5:4:ERROR:7116:500:3002:Request error +AAI_7117=5:4:ERROR:7117:500:3002:Error in get http client object +AAI_7118=5:4:ERROR:7118:500:3002:Script Error +AAI_7119=5:4:ERROR:7119:500:3002:Unknown host + +#--- aaisdnc: 7201-7299 +AAI_7202=5:4:ERROR:7202:500:3002:Error getting connection to odl +AAI_7203=5:4:ERROR:7203:500:3002:Unexpected error calling DataChangeNotification API +AAI_7204=5:4:ERROR:7204:500:3002:Error returned by DataChangeNotification API +AAI_7205=5:4:ERROR:7205:500:3002:Unexpected error running notifySDNCOnUpdate +AAI_7206=5:4:ERROR:7206:500:3002:Invalid data returned from ODL + +#--- NotificationEvent, using UEB space +AAI_7350=5:4:ERROR:7305:500:3002:Notification event creation failed + +#--- aairestctlr: 7401-7499 +AAI_7401=5:4:ERROR:7401:500:3002:Error connecting to AAI REST API +AAI_7402=5:4:ERROR:7402:500:3002:Unexpected error +AAI_7403=5:4:WARN:7403:400:3001:Request error +AAI_7404=5:4:INFO:7404:404:3001:Node not found +AAI_7405=5:4:WARN:7405:200:0:UUID not formatted correctly, generating UUID + +#--- aaiauth: 9101-9199 +AAI_9101=5:0:WARN:9101:403:3300:User is not authorized to perform function +AAI_9102=5:0:WARN:9102:401:3301:Refresh credentials from source +AAI_9103=5:0:WARN:9103:403:3300:User not found +AAI_9104=5:0:WARN:9104:401:3302:Authentication error +AAI_9105=5:0:WARN:9105:403:3300:Authorization error +AAI_9106=5:0:WARN:9106:403:3300:Invalid AppId +#AAI_9107=5:0:WARN:9107:403:3300:No Username in Request +AAI_9107=5:0:WARN:9107:403:3300:SSL is not provided in request, please contact admin + +#--- aaiinstar: 9201-9299 +AAI_9201=5:4:ERROR:9201:500:3002:Unable to send notification +AAI_9202=5:4:ERROR:9202:500:3002:Unable to start a thread diff --git a/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/appprops/janusgraph-cached.properties b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/appprops/janusgraph-cached.properties new file mode 100644 index 00000000..aa3c0631 --- /dev/null +++ b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/appprops/janusgraph-cached.properties @@ -0,0 +1,36 @@ +# +# ============LICENSE_START======================================================= +# org.onap.aai +# ================================================================================ +# Copyright © 2017-18 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========================================================= + +query.fast-property=true +# the following parameters are not reloaded automatically and require a manual bounce +storage.backend=inmemory +storage.hostname=localhost + +#schema.default=none +storage.lock.wait-time=300 +storage.hbase.table=aaigraph-dev1.dev +storage.hbase.ext.zookeeper.znode.parent=/hbase-unsecure +#caching on +cache.db-cache = true +cache.db-cache-clean-wait = 20 +cache.db-cache-time = 180000 +cache.db-cache-size = 0.3 + +#load graphson file on startup +load.snapshot.file=false diff --git a/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/appprops/janusgraph-realtime.properties b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/appprops/janusgraph-realtime.properties new file mode 100644 index 00000000..05394334 --- /dev/null +++ b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/appprops/janusgraph-realtime.properties @@ -0,0 +1,33 @@ +# +# ============LICENSE_START======================================================= +# org.onap.aai +# ================================================================================ +# Copyright © 2017-18 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========================================================= + +query.fast-property=true +# the following parameters are not reloaded automatically and require a manual bounce +storage.backend=inmemory +storage.hostname=localhost + +#schema.default=none +storage.lock.wait-time=300 +storage.hbase.table=aaigraph-dev1.dev +storage.hbase.ext.zookeeper.znode.parent=/hbase-unsecure +# Setting db-cache to false ensure the fastest propagation of changes across servers +cache.db-cache = false + +#load graphson file on startup +load.snapshot.file=false diff --git a/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/auth/aai_policy.json b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/auth/aai_policy.json new file mode 100644 index 00000000..9335a7bb --- /dev/null +++ b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/auth/aai_policy.json @@ -0,0 +1,73 @@ +{ + "roles": [ + { + "name": "testRole", + "functions": [ + { + "name": "testFunction", + "methods": [ + { + "name": "GET" + }, + { + "name": "DELETE" + }, + { + "name": "PUT" + } + ] + } + ], + "users": [ + { + "username": "testUser" + }, + { + "username": "testWildcardId", + "is-wildcard-id": true + } + ] + }, + { + "name": "HAProxy", + "functions": [ + { + "name": "util", + "methods": [ + { + "name": "GET" + } + ] + } + ], + "users": [ + { + "username": "ha-proxy-user" + }, + { + "username": "ha-proxy-wildcard-id", + "is-wildcard-id": true + } + ] + }, + { + "name": "testBasicAuth", + "functions": [ + { + "name": "testBasicAuthFunction", + "methods": [ + { + "name": "GET" + } + ] + } + ], + "users": [ + { + "user": "testBasicAuthUser", + "pass": "OBF:1ytc1vu91v2p1rxf1mqh1v8s1z0d1msn1san1mqf1z0h1v9u1msl1rvf1v1p1vv11yta" + } + ] + } + ] +}
\ No newline at end of file diff --git a/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/queryformarts/graphson/resource.graphson b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/queryformarts/graphson/resource.graphson new file mode 100644 index 00000000..04f48174 --- /dev/null +++ b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/queryformarts/graphson/resource.graphson @@ -0,0 +1,2 @@ +{"id": 386506928,"label": "vertex","properties": {"aai-last-mod-ts": [{"id": "ob632u-6e46nk-5j45","value": 1488308500413}],"aai-uri": [{"id": "ob6712-6e46nk-5lhh","value": "/cloud-infrastructure/cloud-regions/cloud-region/cloud-owner-987654321-9922-as988q/cloud-region-id-987654321-9922-as988q/tenants/tenant/tenant-987654321-9999-as988q/vservers/vserver/vserver-987654321-9999-as988q"}],"prov-status": [{"id": "ob651y-6e46nk-1kw5","value": "example-prov-status-val-7367"}],"aai-created-ts": [{"id": "ob62ae-6e46nk-5gqt","value": 1488308500413}],"source-of-truth": [{"id": "ob61w6-6e46nk-5jwl","value": "FitNesse-Test-as988q"}],"vserver-selflink": [{"id": "ob65g6-6e46nk-3xfp","value": "example-vserver-selflink-val-7367"}],"aai-node-type": [{"id": "ob61hy-6e46nk-5f5x","value": "vserver"}],"in-maint": [{"id": "ob65ue-6e46nk-20p1","value": false}],"resource-version": [{"id": "ob62om-6e46nk-23ut","value": "1488308500413"}],"vserver-name": [{"id": "ob649i-6e46nk-3u9x","value": "example-vserver-name-val-7367vserver-987654321-9999-as988q"}],"vserver-id": [{"id": "ob63va-6e46nk-3sp1","value": "vserver-987654321-9999-as988q"}],"last-mod-source-of-truth": [{"id": "ob63h2-6e46nk-5edh","value": "FitNesse-Test-as988q"}],"vserver-name2": [{"id": "ob64nq-6e46nk-3vut","value": "example-vserver-name2-val-7367"}],"is-closed-loop-disabled": [{"id": "ob668m-6e46nk-229x","value": false}]}} +{"id": 2461872,"label": "vertex","properties": {"aai-last-mod-ts": [{"id": "21hqu-1grlc-5j45","value": 1467901600}],"in-maint": [{"id": "21i52-1grlc-20p1","value": false}],"resource-version": [{"id": "21ija-1grlc-23ut","value": "1467901600"}],"vserver-name": [{"id": "21ixi-1grlc-3u9x","value": "PerfTest_VServerFix0027TenantPez002701611467901587187Name"}],"aai-created-ts": [{"id": "21jbq-1grlc-5gqt","value": 1467901600}],"vserver-id": [{"id": "21jpy-1grlc-3sp1","value": "PerfTest_VServerFix0027TenantPez002701611467901587187"}],"last-mod-source-of-truth": [{"id": "21k46-1grlc-5edh","value": "MSO"}],"vserver-name2": [{"id": "21kie-1grlc-3vut","value": "PerfTest_VServerFix0027TenantPez002701611467901587187-VM Name2 optional"}],"source-of-truth": [{"id": "21kwm-1grlc-5jwl","value": "MSO"}],"vserver-selflink": [{"id": "21lau-1grlc-3xfp","value": "http://testvserverLink.com/.html?vserv=VserverLink"}],"is-closed-loop-disabled": [{"id": "21lp2-1grlc-229x","value": false}],"aai-node-type": [{"id": "21m3a-1grlc-5f5x","value": "vserver"}],"aai-uri": [{"id": "21m3a-1grlc-5a5x","value": "/vservers/vserver/test1"}]}}
\ No newline at end of file diff --git a/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/queryformarts/resource-format.json b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/queryformarts/resource-format.json new file mode 100644 index 00000000..c7e42556 --- /dev/null +++ b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/queryformarts/resource-format.json @@ -0,0 +1,13 @@ +{ + "results": [ + { + "vserver": { + + } + }, + { + "vserver": { + } + } + ] +}
\ No newline at end of file diff --git a/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/queryformarts/resource_and_url-format.json b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/queryformarts/resource_and_url-format.json new file mode 100644 index 00000000..d90a71bc --- /dev/null +++ b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/queryformarts/resource_and_url-format.json @@ -0,0 +1,16 @@ +{ + "results": [ + { + "url" : "/cloud-infrastructure/cloud-regions/cloud-region/cloud-owner-987654321-9922-as988q/cloud-region-id-987654321-9922-as988q/tenants/tenant/tenant-987654321-9999-as988q/vservers/vserver/vserver-987654321-9999-as988q", + "vserver": { + + } + }, + { + "url" : "/vservers/vserver/test1", + "vserver": { + + } + } + ] +}
\ No newline at end of file diff --git a/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/queryformarts/simple-format.json b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/queryformarts/simple-format.json new file mode 100644 index 00000000..dd342615 --- /dev/null +++ b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/queryformarts/simple-format.json @@ -0,0 +1,43 @@ +{ + "results" : [{ + "id" : "0", + "node-type" : "generic-vnf", + "url" : "urimissing", + "properties" : { + "vnf-name" : "myVnf" + }, + "related-to" : [{ + "node-type" : "vserver", + "id" : "1", + "url" : "urimissing" + }] + } , { + "id" : "1", + "node-type" : "vserver", + "url" : "urimissing", + "properties" : { + "vserver-name" : "myVserver" + }, + "related-to" : [{ + "node-type" : "generic-vnf", + "id" : "0", + "url" : "urimissing" + },{ + "node-type" : "pserver", + "id" : "2", + "url" : "/pservers/pserver/key1" + }] + },{ + "id" : "2", + "node-type" : "pserver", + "url" : "/pservers/pserver/key1", + "properties" : { + "hostname" : "myPserver" + }, + "related-to" : [{ + "node-type" : "vserver", + "id" : "1", + "url" : "urimissing" + }] + }] +}
\ No newline at end of file diff --git a/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/relationship/ambiguous-relationship.json b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/relationship/ambiguous-relationship.json new file mode 100644 index 00000000..c6407e2c --- /dev/null +++ b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/relationship/ambiguous-relationship.json @@ -0,0 +1,10 @@ +{ + "related-to": "generic-vnf", + "relationship-data" : [{ + "relationship-key" : "generic-vnf.vnf-id", + "relationship-value":"key1" + },{ + "relationship-key" : "generic-vnf.vnf-id", + "relationship-value":"key2" + }] +}
\ No newline at end of file diff --git a/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/relationship/both-failv10-successv9.json b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/relationship/both-failv10-successv9.json new file mode 100644 index 00000000..5bafc9ff --- /dev/null +++ b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/relationship/both-failv10-successv9.json @@ -0,0 +1,8 @@ +{ + "related-to": "generic-vnf", + "related-link": "/aai/v10/network/generic-vnfs/test-objet/key1", + "relationship-data" : [{ + "relationship-key" : "generic-vnf.vnf-id", + "relationship-value":"key2" + }] +}
\ No newline at end of file diff --git a/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/relationship/both-successv10-failv9.json b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/relationship/both-successv10-failv9.json new file mode 100644 index 00000000..3afe6bb7 --- /dev/null +++ b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/relationship/both-successv10-failv9.json @@ -0,0 +1,8 @@ +{ + "related-to": "generic-vnf", + "related-link": "http://localhost/aai/v10/network/generic-vnfs/generic-vnf/key1", + "relationship-data" : [{ + "relationship-key" : "test-obect.vnf-id", + "relationship-value":"key2" + }] +}
\ No newline at end of file diff --git a/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/relationship/nothing-to-parse.json b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/relationship/nothing-to-parse.json new file mode 100644 index 00000000..b24834af --- /dev/null +++ b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/relationship/nothing-to-parse.json @@ -0,0 +1,4 @@ +{ + "related-to": "generic-vnf", + "relationship-data" : [] +}
\ No newline at end of file diff --git a/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/relationship/only-related-link.json b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/relationship/only-related-link.json new file mode 100644 index 00000000..4cc103e8 --- /dev/null +++ b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/relationship/only-related-link.json @@ -0,0 +1,4 @@ +{ + "related-to": "generic-vnf", + "related-link": "http://localhost/aai/v10/network/generic-vnfs/generic-vnf/key1" +}
\ No newline at end of file diff --git a/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/relationship/only-relationship-data.json b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/relationship/only-relationship-data.json new file mode 100644 index 00000000..b9fccc9c --- /dev/null +++ b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/relationship/only-relationship-data.json @@ -0,0 +1,7 @@ +{ + "related-to": "generic-vnf", + "relationship-data" : [{ + "relationship-key" : "generic-vnf.vnf-id", + "relationship-value":"key1" + }] +}
\ No newline at end of file diff --git a/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/relationship/too-many-items-relationship.json b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/relationship/too-many-items-relationship.json new file mode 100644 index 00000000..97765cfb --- /dev/null +++ b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/relationship/too-many-items-relationship.json @@ -0,0 +1,19 @@ +{ + "related-to": "l-interface", + "relationship-data" : [{ + "relationship-key" : "generic-vnf.vnf-id", + "relationship-value":"key1" + },{ + "relationship-key" : "subnet.subnet-id", + "relationship-value":"key5" + },{ + "relationship-key" : "vlan.vlan-interface", + "relationship-value":"key3" + },{ + "relationship-key" : "l-interface.interface-name", + "relationship-value":"key2" + },{ + "relationship-key" : "l3-interface-ipv4-address-list.l3-interface-ipv4-address", + "relationship-value":"key4" + }] +} diff --git a/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/relationship/top-level-two-keys-relationship.json b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/relationship/top-level-two-keys-relationship.json new file mode 100644 index 00000000..c6dbf557 --- /dev/null +++ b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/relationship/top-level-two-keys-relationship.json @@ -0,0 +1,13 @@ +{ + "related-to" : "availability-zone", + "relationship-data" : [ { + "relationship-key" : "cloud-region.cloud-owner", + "relationship-value" : "key1" + }, { + "relationship-key" : "cloud-region.cloud-region-id", + "relationship-value" : "key2" + }, { + "relationship-key" : "availability-zone.availability-zone-name", + "relationship-value" : "key3" + } ] +}
\ No newline at end of file diff --git a/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/relationship/two-top-level-relationship.json b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/relationship/two-top-level-relationship.json new file mode 100644 index 00000000..54cac2c8 --- /dev/null +++ b/aai-aaf-auth/src/test/resources/bundleconfig-local/etc/relationship/two-top-level-relationship.json @@ -0,0 +1,19 @@ +{ + "related-to": "l-interface", + "relationship-data" : [{ + "relationship-key" : "generic-vnf.vnf-id", + "relationship-value":"key1" + },{ + "relationship-key" : "vlan.vlan-interface", + "relationship-value":"key3" + },{ + "relationship-key" : "l-interface.interface-name", + "relationship-value":"key2" + },{ + "relationship-key" : "zone.zone-id", + "relationship-value":"key5" + },{ + "relationship-key" : "l3-interface-ipv4-address-list.l3-interface-ipv4-address", + "relationship-value":"key4" + }] +} diff --git a/aai-annotations/src/main/java/org/onap/aai/annotations/Metadata.java b/aai-annotations/src/main/java/org/onap/aai/annotations/Metadata.java index eb88230c..142cac98 100644 --- a/aai-annotations/src/main/java/org/onap/aai/annotations/Metadata.java +++ b/aai-annotations/src/main/java/org/onap/aai/annotations/Metadata.java @@ -76,4 +76,6 @@ public @interface Metadata { String sourceOfTruthType() default ""; + String dslStartNodeProps() default ""; + } diff --git a/aai-annotations/src/main/java/org/onap/aai/schema/enums/ObjectMetadata.java b/aai-annotations/src/main/java/org/onap/aai/schema/enums/ObjectMetadata.java index 2ac4538d..1534c8d1 100644 --- a/aai-annotations/src/main/java/org/onap/aai/schema/enums/ObjectMetadata.java +++ b/aai-annotations/src/main/java/org/onap/aai/schema/enums/ObjectMetadata.java @@ -124,7 +124,12 @@ public enum ObjectMetadata { /** * a value of true allows this object to be written directly */ - ALLOW_DIRECT_WRITE("allowDirectWrite"); + ALLOW_DIRECT_WRITE("allowDirectWrite"), + /** + * properties that are allowed to be in start node in a DSL + * <br><b>comma separated list</b> + */ + DSL_START_NODE_PROPS("dslStartNodeProps"); private final String name; diff --git a/aai-core/pom.xml b/aai-core/pom.xml index ec4e7e38..cb0281a6 100644 --- a/aai-core/pom.xml +++ b/aai-core/pom.xml @@ -39,7 +39,7 @@ limitations under the License. <jacoco.line.coverage.limit>0.50</jacoco.line.coverage.limit> <gremlin.version>3.2.2</gremlin.version> - <groovy.version>2.4.15</groovy.version> + <groovy.version>2.4.15</groovy.version> <!-- Start of Default ONAP Schema Properties --> <aai.wiki.link>https://wiki.onap.org/</aai.wiki.link> <gendoc.version>v15</gendoc.version> @@ -98,7 +98,7 @@ limitations under the License. <version>2.8</version> </plugin> <plugin> - <!-- explicitly define maven-deploy-plugin after other to force exec + <!-- explicitly define maven-deploy-plugin after other to force exec order --> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-deploy-plugin</artifactId> @@ -117,6 +117,10 @@ limitations under the License. </dependency> <dependency> <groupId>org.onap.aai.aai-common</groupId> + <artifactId>aai-aaf-auth</artifactId> + </dependency> + <dependency> + <groupId>org.onap.aai.aai-common</groupId> <artifactId>aai-annotations</artifactId> </dependency> <dependency> @@ -132,11 +136,11 @@ limitations under the License. <groupId>com.att.eelf</groupId> <artifactId>eelf-core</artifactId> <exclusions><!-- excluding transitive dependency coming from this artifact, as we would need powermock-api-mockito2--> - <exclusion> - <groupId>org.powermock</groupId> - <artifactId>powermock-api-mockito</artifactId> - </exclusion> - </exclusions> + <exclusion> + <groupId>org.powermock</groupId> + <artifactId>powermock-api-mockito</artifactId> + </exclusion> + </exclusions> </dependency> <dependency> <groupId>org.codehaus.jackson</groupId> @@ -167,20 +171,10 @@ limitations under the License. <scope>test</scope> </dependency> <dependency> - <groupId>org.powermock</groupId> - <artifactId>powermock-module-junit4</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.powermock</groupId> - <artifactId>powermock-api-mockito2</artifactId> + <groupId>org.mockito</groupId> + <artifactId>mockito-core</artifactId> <scope>test</scope> </dependency> - <dependency> - <groupId>org.powermock</groupId> - <artifactId>powermock-core</artifactId> - <scope>test</scope> - </dependency> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> @@ -224,6 +218,11 @@ limitations under the License. <artifactId>json-path</artifactId> </dependency> <dependency> + <groupId>com.jayway.jsonpath</groupId> + <artifactId>json-path-assert</artifactId> + <scope>test</scope> + </dependency> + <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-util</artifactId> </dependency> @@ -244,10 +243,6 @@ limitations under the License. <artifactId>jersey-json</artifactId> </dependency> <dependency> - <groupId>javax.ws.rs</groupId> - <artifactId>javax.ws.rs-api</artifactId> - </dependency> - <dependency> <groupId>org.apache.tinkerpop</groupId> <artifactId>gremlin-core</artifactId> </dependency> @@ -286,10 +281,6 @@ limitations under the License. </dependency> <dependency> - <groupId>javax.servlet</groupId> - <artifactId>javax.servlet-api</artifactId> - </dependency> - <dependency> <groupId>com.bazaarvoice.jolt</groupId> <artifactId>jolt-complete</artifactId> </dependency> diff --git a/aai-core/src/main/java/org/onap/aai/audit/ListEndpoints.java b/aai-core/src/main/java/org/onap/aai/audit/ListEndpoints.java index dcfd58a5..fe2e1ff7 100644 --- a/aai-core/src/main/java/org/onap/aai/audit/ListEndpoints.java +++ b/aai-core/src/main/java/org/onap/aai/audit/ListEndpoints.java @@ -22,8 +22,8 @@ package org.onap.aai.audit; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.google.common.base.CaseFormat; import java.util.ArrayList; @@ -53,7 +53,7 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext */ public class ListEndpoints { - private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(ListEndpoints.class); + private static final Logger LOGGER = LoggerFactory.getLogger(ListEndpoints.class); private static final String START = "inventory"; private static final String[] blacklist = {"search", "aai-internal"}; diff --git a/aai-core/src/main/java/org/onap/aai/concurrent/AaiCallable.java b/aai-core/src/main/java/org/onap/aai/concurrent/AaiCallable.java index 6ea67b90..69560ec1 100644 --- a/aai-core/src/main/java/org/onap/aai/concurrent/AaiCallable.java +++ b/aai-core/src/main/java/org/onap/aai/concurrent/AaiCallable.java @@ -44,7 +44,9 @@ public abstract class AaiCallable<T> implements Callable<T> { * The call method */ public T call() throws Exception { - MDC.setContextMap(mdcCopy); + if ( mdcCopy != null ) { + MDC.setContextMap(mdcCopy); + } return process(); } diff --git a/aai-core/src/main/java/org/onap/aai/config/AuthorizationConfiguration.java b/aai-core/src/main/java/org/onap/aai/config/AuthorizationConfiguration.java index 9f8bbc45..24e7ec5a 100644 --- a/aai-core/src/main/java/org/onap/aai/config/AuthorizationConfiguration.java +++ b/aai-core/src/main/java/org/onap/aai/config/AuthorizationConfiguration.java @@ -20,7 +20,7 @@ package org.onap.aai.config; -import org.onap.aai.auth.AAIAuthCore; +import org.onap.aai.aaf.auth.AAIAuthCore; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/aai-core/src/main/java/org/onap/aai/logging/EcompEncoder.java b/aai-core/src/main/java/org/onap/aai/config/XmlFormatTransformerConfiguration.java index 88587297..0c83c2b3 100644 --- a/aai-core/src/main/java/org/onap/aai/logging/EcompEncoder.java +++ b/aai-core/src/main/java/org/onap/aai/config/XmlFormatTransformerConfiguration.java @@ -17,22 +17,17 @@ * limitations under the License. * ============LICENSE_END========================================================= */ +package org.onap.aai.config; -package org.onap.aai.logging; +import org.onap.aai.transforms.XmlFormatTransformer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; -import ch.qos.logback.classic.PatternLayout; -import ch.qos.logback.classic.encoder.PatternLayoutEncoder; +@Configuration +public class XmlFormatTransformerConfiguration { -public class EcompEncoder extends PatternLayoutEncoder { - - @Override - public void start() { - PatternLayout patternLayout = new EcompPatternLayout(); - patternLayout.setContext(context); - patternLayout.setPattern(getPattern()); - patternLayout.setOutputPatternAsHeader(outputPatternAsHeader); - patternLayout.start(); - this.layout = patternLayout; - super.start(); + @Bean + public XmlFormatTransformer xmlFormatTransformer(){ + return new XmlFormatTransformer(); } } diff --git a/aai-core/src/main/java/org/onap/aai/db/props/AAIProperties.java b/aai-core/src/main/java/org/onap/aai/db/props/AAIProperties.java index a0f6d77e..7dbc3a1d 100644 --- a/aai-core/src/main/java/org/onap/aai/db/props/AAIProperties.java +++ b/aai-core/src/main/java/org/onap/aai/db/props/AAIProperties.java @@ -32,9 +32,15 @@ public class AAIProperties { public static final String RESOURCE_VERSION = "resource-version"; public static final String AAI_URI = "aai-uri"; public static final Integer MAXIMUM_DEPTH = 10000; + public static final Integer MINIMUM_DEPTH = 0; public static final String LINKED = "linked"; public static final String DB_ALIAS_SUFFIX = "-local"; public static final String AAI_UUID = "aai-uuid"; + public static final String START_TS = "start-ts"; + public static final String END_TS = "end-ts"; + public static final String END_SOT = "end-source-of-truth"; + public static final String START_TX_ID = "start-tx-id"; + public static final String END_TX_ID = "end-tx-id"; private AAIProperties() { diff --git a/aai-core/src/main/java/org/onap/aai/dbgen/GraphSONPartialReader.java b/aai-core/src/main/java/org/onap/aai/dbgen/GraphSONPartialReader.java index fdc8e814..d3dfd150 100644 --- a/aai-core/src/main/java/org/onap/aai/dbgen/GraphSONPartialReader.java +++ b/aai-core/src/main/java/org/onap/aai/dbgen/GraphSONPartialReader.java @@ -20,8 +20,8 @@ package org.onap.aai.dbgen; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.BufferedReader; import java.io.ByteArrayInputStream; @@ -77,7 +77,7 @@ public final class GraphSONPartialReader implements GraphReader { private boolean unwrapAdjacencyList = false; private final GraphSONReader reader; - private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(InMemoryGraph.class); + private static final Logger LOGGER = LoggerFactory.getLogger(InMemoryGraph.class); final TypeReference<Map<String, Object>> mapTypeReference = new TypeReference<Map<String, Object>>() {}; diff --git a/aai-core/src/main/java/org/onap/aai/dbgen/SchemaGenerator.java b/aai-core/src/main/java/org/onap/aai/dbgen/SchemaGenerator.java index bfd1f55b..d253f876 100644 --- a/aai-core/src/main/java/org/onap/aai/dbgen/SchemaGenerator.java +++ b/aai-core/src/main/java/org/onap/aai/dbgen/SchemaGenerator.java @@ -20,8 +20,8 @@ package org.onap.aai.dbgen; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.google.common.collect.Multimap; import java.util.HashMap; @@ -49,7 +49,7 @@ import org.onap.aai.util.AAIConfig; public class SchemaGenerator { - private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(SchemaGenerator.class); + private static final Logger LOGGER = LoggerFactory.getLogger(SchemaGenerator.class); /** * Load schema into JanusGraph. diff --git a/aai-core/src/main/java/org/onap/aai/dbgen/SchemaGenerator4Hist.java b/aai-core/src/main/java/org/onap/aai/dbgen/SchemaGenerator4Hist.java new file mode 100644 index 00000000..0f88de24 --- /dev/null +++ b/aai-core/src/main/java/org/onap/aai/dbgen/SchemaGenerator4Hist.java @@ -0,0 +1,238 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 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========================================================= + */ + +package org.onap.aai.dbgen; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import com.google.common.collect.Multimap; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.janusgraph.core.Cardinality; +import org.janusgraph.core.JanusGraph; +import org.janusgraph.core.Multiplicity; +import org.janusgraph.core.PropertyKey; +import org.janusgraph.core.schema.JanusGraphManagement; +import org.onap.aai.config.SpringContextAware; +import org.onap.aai.edges.EdgeIngestor; +import org.onap.aai.edges.EdgeRule; +import org.onap.aai.edges.exceptions.EdgeRuleNotFoundException; +import org.onap.aai.introspection.Introspector; +import org.onap.aai.introspection.Loader; +import org.onap.aai.introspection.LoaderUtil; +import org.onap.aai.logging.LogFormatTools; +import org.onap.aai.schema.enums.PropertyMetadata; +import org.onap.aai.util.AAIConfig; + +import java.util.*; + +import static org.onap.aai.db.props.AAIProperties.*; + +public class SchemaGenerator4Hist { + + private static final Logger LOGGER = LoggerFactory.getLogger(SchemaGenerator4Hist.class); + + /** + * Load schema into JanusGraph. + * + * @param graph + * the graph + * @param graphMgmt + * the graph mgmt + */ + public static void loadSchemaIntoJanusGraph(final JanusGraph graph, final JanusGraphManagement graphMgmt, + String backend) { + + try { + AAIConfig.init(); + } catch (Exception ex) { + LOGGER.error(" ERROR - Could not run AAIConfig.init(). " + LogFormatTools.getStackTop(ex)); + // System.out.println(" ERROR - Could not run AAIConfig.init(). "); + System.exit(1); + } + + // NOTE - JanusGraph 0.5.3 doesn't keep a list of legal node Labels. + // They are only used when a vertex is actually being created. + // JanusGraph 1.1 will keep track (we think). + + // Use EdgeRules to make sure edgeLabels are defined in the db. NOTE: + // the multiplicty used here is + // always "MULTI". This is not the same as our internal "Many2Many", + // "One2One", "One2Many" or "Many2One" + // We use the same edge-label for edges between many different types of + // nodes and our internal + // multiplicty definitions depends on which two types of nodes are being + // connected. + + Multimap<String, EdgeRule> edges = null; + Set<String> labels = new HashSet<>(); + + EdgeIngestor edgeIngestor = SpringContextAware.getBean(EdgeIngestor.class); + + try { + edges = edgeIngestor.getAllCurrentRules(); + } catch (EdgeRuleNotFoundException e) { + LOGGER.error("Unable to find all rules {}", LogFormatTools.getStackTop(e)); + } + + for (EdgeRule rule : edges.values()) { + labels.add(rule.getLabel()); + } + + for (String label : labels) { + if (graphMgmt.containsRelationType(label)) { + String dmsg = " EdgeLabel [" + label + "] already existed. "; + LOGGER.debug(dmsg); + } else { + String dmsg = "Making EdgeLabel: [" + label + "]"; + LOGGER.debug(dmsg); + graphMgmt.makeEdgeLabel(label).multiplicity(Multiplicity.valueOf("MULTI")).make(); + } + } + + Loader loader = LoaderUtil.getLatestVersion(); + + Map<String, Introspector> objs = loader.getAllObjects(); + Map<String, PropertyKey> seenProps = new HashMap<>(); + + for (Introspector obj : objs.values()) { + for (String propName : obj.getProperties()) { + String dbPropName = propName; + Optional<String> alias = obj.getPropertyMetadata(propName, PropertyMetadata.DB_ALIAS); + if (alias.isPresent()) { + dbPropName = alias.get(); + } + if (graphMgmt.containsRelationType(dbPropName)) { + String dmsg = " PropertyKey [" + dbPropName + "] already existed in the DB. "; + LOGGER.debug(dmsg); + } else { + Class<?> type = obj.getClass(propName); + Cardinality cardinality = Cardinality.LIST; + boolean process = false; + if (obj.isListType(propName) && obj.isSimpleGenericType(propName)) { + // NOTE - For history - All properties have cardinality = LIST + // It is assumed that there is special processing in the Resources MS + // for History to turn what used to be SET (referred to as isListType + // above) will be stored in our db as a single String. And that + // single string will have Cardinality = LIST so we can track its + // history. + //cardinality = Cardinality.SET; + type = obj.getGenericTypeClass(propName); + process = true; + } else if (obj.isSimpleType(propName)) { + process = true; + } + + if (process) { + + String imsg = " Creating PropertyKey: [" + dbPropName + "], [" + type.getSimpleName() + "], [" + + cardinality + "]"; + LOGGER.info(imsg); + PropertyKey propK; + if (!seenProps.containsKey(dbPropName)) { + propK = graphMgmt.makePropertyKey(dbPropName).dataType(type).cardinality(cardinality) + .make(); + seenProps.put(dbPropName, propK); + } else { + propK = seenProps.get(dbPropName); + } + if (graphMgmt.containsGraphIndex(dbPropName)) { + String dmsg = " Index [" + dbPropName + "] already existed in the DB. "; + LOGGER.debug(dmsg); + } else { + if (obj.getIndexedProperties().contains(propName)) { + // NOTE - for History we never add a unique index - just a regular index + imsg = "Add index for PropertyKey: [" + dbPropName + "]"; + LOGGER.info(imsg); + graphMgmt.buildIndex(dbPropName, Vertex.class).addKey(propK).buildCompositeIndex(); + } else { + imsg = "No index needed/added for PropertyKey: [" + dbPropName + "]"; + LOGGER.info(imsg); + } + } + } + } + } + }// Done processing all properties defined in the OXM + + // Add the 3 new History properties are in the DB + // They are all Cardinality=Single since instance of a Node, Edge or Property can + // only have one of them. That is, a Property can show up many times in a + // node, but each instance of that property will only have a single start-ts, + // end-ts, end-source-of-truth. Same goes for a node or edge itself. + if (graphMgmt.containsRelationType(END_SOT)) { + String dmsg = "PropertyKey [" + END_SOT + "] already existed in the DB. "; + LOGGER.debug(dmsg); + } else if (!seenProps.containsKey(END_SOT) ) { + String imsg = " Creating PropertyKey: [" + END_SOT + "], [String], [SINGLE]"; + LOGGER.info(imsg); + graphMgmt.makePropertyKey(END_SOT).dataType(String.class) + .cardinality(Cardinality.SINGLE).make(); + } + + if (graphMgmt.containsRelationType(START_TS)) { + String dmsg = " PropertyKey [" + START_TS + "] already existed in the DB. "; + LOGGER.debug(dmsg); + } else if (!seenProps.containsKey(START_TS) ) { + String imsg = " Creating PropertyKey: [" + START_TS + "], [Long], [SINGLE]"; + LOGGER.info(imsg); + graphMgmt.makePropertyKey(START_TS).dataType(Long.class) + .cardinality(Cardinality.SINGLE).make(); + } + + if (graphMgmt.containsRelationType(END_TS)) { + String dmsg = "PropertyKey [" + END_TS + "] already existed in the DB. "; + LOGGER.debug(dmsg); + } else if (!seenProps.containsKey(END_TS) ) { + String imsg = " Creating PropertyKey: [" + END_TS + "], [Long], [SINGLE]"; + LOGGER.info(imsg); + graphMgmt.makePropertyKey(END_TS).dataType(Long.class) + .cardinality(Cardinality.SINGLE).make(); + } + + if (graphMgmt.containsRelationType(START_TX_ID)) { + String dmsg = "PropertyKey [" + START_TX_ID + "] already existed in the DB. "; + LOGGER.debug(dmsg); + } else if (!seenProps.containsKey(START_TX_ID) ) { + String imsg = " Creating PropertyKey: [" + START_TX_ID + "], [String], [SINGLE]"; + LOGGER.info(imsg); + graphMgmt.makePropertyKey(START_TX_ID).dataType(String.class) + .cardinality(Cardinality.SINGLE).make(); + } + + if (graphMgmt.containsRelationType(END_TX_ID)) { + String dmsg = "PropertyKey [" + END_TX_ID + "] already existed in the DB. "; + LOGGER.debug(dmsg); + } else if (!seenProps.containsKey(END_TX_ID) ) { + String imsg = " Creating PropertyKey: [" + END_TX_ID + "], [String], [SINGLE]"; + LOGGER.info(imsg); + graphMgmt.makePropertyKey(END_TX_ID).dataType(String.class) + .cardinality(Cardinality.SINGLE).make(); + } + + String imsg = "-- About to call graphMgmt commit"; + LOGGER.info(imsg); + graphMgmt.commit(); + if (backend != null) { + LOGGER.info("Successfully loaded the schema to " + backend); + } + + } + +} diff --git a/aai-core/src/main/java/org/onap/aai/dbmap/AAIGraph.java b/aai-core/src/main/java/org/onap/aai/dbmap/AAIGraph.java index ca4e02f0..5bb4b656 100644 --- a/aai-core/src/main/java/org/onap/aai/dbmap/AAIGraph.java +++ b/aai-core/src/main/java/org/onap/aai/dbmap/AAIGraph.java @@ -22,13 +22,8 @@ package org.onap.aai.dbmap; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; -import java.io.FileNotFoundException; -import java.util.HashMap; -import java.util.Map; -import java.util.Properties; -import org.apache.commons.configuration.ConfigurationException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.apache.commons.configuration.PropertiesConfiguration; import org.apache.commons.lang.exception.ExceptionUtils; import org.apache.tinkerpop.gremlin.structure.Graph; @@ -36,10 +31,15 @@ import org.apache.tinkerpop.gremlin.structure.io.IoCore; import org.janusgraph.core.JanusGraph; import org.janusgraph.core.JanusGraphFactory; import org.janusgraph.core.schema.JanusGraphManagement; +import org.onap.aai.config.SpringContextAware; import org.onap.aai.dbgen.SchemaGenerator; +import org.onap.aai.dbgen.SchemaGenerator4Hist; import org.onap.aai.exceptions.AAIException; import org.onap.aai.util.AAIConstants; +import java.io.FileNotFoundException; +import java.util.Properties; + /** * Database Mapping class which acts as the middle man between the REST * interface objects and JanusGraph DB objects. This class provides methods to commit @@ -48,16 +48,13 @@ import org.onap.aai.util.AAIConstants; * object to load, commit/rollback and shutdown for each request. The data model * rules such as keys/required properties are handled by calling DBMeth methods * which are driven by a specification file in json. - * - * + * + * */ public class AAIGraph { - private static final EELFLogger logger = EELFManager.getInstance().getLogger(AAIGraph.class); - protected static final String COMPONENT = "aaidbmap"; - protected Map<String, JanusGraph> graphs = new HashMap<>(); - private static final String REALTIME_DB = "realtime"; - private static final String CACHED_DB = "cached"; + private static final Logger logger = LoggerFactory.getLogger(AAIGraph.class); + protected JanusGraph graph; private static boolean isInit = false; /** @@ -67,15 +64,10 @@ public class AAIGraph { try { String serviceName = System.getProperty("aai.service.name", "NA"); String rtConfig = System.getProperty("realtime.db.config"); - String cachedConfig = System.getProperty("cached.db.config"); if (rtConfig == null) { rtConfig = AAIConstants.REALTIME_DB_CONFIG; } - if (cachedConfig == null) { - cachedConfig = AAIConstants.CACHED_DB_CONFIG; - } - this.loadGraph(REALTIME_DB, rtConfig, serviceName); - this.loadGraph(CACHED_DB, cachedConfig, serviceName); + this.loadGraph(rtConfig, serviceName); } catch (Exception e) { throw new RuntimeException("Failed to instantiate graphs", e); } @@ -103,18 +95,17 @@ public class AAIGraph { return isInit; } - private void loadGraph(final String name, final String configPath, final String serviceName) - throws AAIException, ConfigurationException { + private void loadGraph(String configPath, String serviceName) throws Exception { // Graph being opened by JanusGraphFactory is being placed in hashmap to be used later // These graphs shouldn't be closed until the application shutdown try { - final PropertiesConfiguration propertiesConfiguration = - new AAIGraphConfig.Builder(configPath).forService(serviceName).withGraphType(name).buildConfiguration(); - final JanusGraph graph = JanusGraphFactory.open(propertiesConfiguration); + PropertiesConfiguration propertiesConfiguration = new AAIGraphConfig.Builder(configPath) + .forService(serviceName).withGraphType("realtime").buildConfiguration(); + graph = JanusGraphFactory.open(propertiesConfiguration); - final Properties graphProps = new Properties(); + Properties graphProps = new Properties(); propertiesConfiguration.getKeys() - .forEachRemaining(k -> graphProps.setProperty(k, propertiesConfiguration.getString(k))); + .forEachRemaining(k -> graphProps.setProperty(k, propertiesConfiguration.getString(k))); if ("inmemory".equals(graphProps.get("storage.backend"))) { // Load the propertyKeys, indexes and edge-Labels into the DB @@ -126,13 +117,12 @@ public class AAIGraph { throw new AAIException("AAI_5102"); } - graphs.put(name, graph); - } catch (final FileNotFoundException fnfe) { - throw new AAIException("AAI_4001"); + } catch (FileNotFoundException e) { + throw new AAIException("AAI_4001", e); } } - private void loadSnapShotToInMemoryGraph(final JanusGraph graph, final Properties graphProps) { + private void loadSnapShotToInMemoryGraph(JanusGraph graph, Properties graphProps) { if (logger.isDebugEnabled()) { logger.debug("Load Snapshot to InMemory Graph"); } @@ -141,12 +131,12 @@ public class AAIGraph { if ("true".equals(value)) { try (Graph transaction = graph.newTransaction()) { String location = System.getProperty("snapshot.location"); - logAndPrint(logger, "Loading snapshot to inmemory graph."); + logAndPrint("Loading snapshot to inmemory graph."); transaction.io(IoCore.graphson()).readGraph(location); transaction.tx().commit(); - logAndPrint(logger, "Snapshot loaded to inmemory graph."); + logAndPrint("Snapshot loaded to inmemory graph."); } catch (Exception e) { - logAndPrint(logger, "ERROR: Could not load datasnapshot to in memory graph. \n" + logAndPrint("ERROR: Could not load datasnapshot to in memory graph. \n" + ExceptionUtils.getFullStackTrace(e)); throw new RuntimeException(e); } @@ -154,19 +144,25 @@ public class AAIGraph { } } - private void loadSchema(final JanusGraph graph) { + private void loadSchema(JanusGraph graph) { // Load the propertyKeys, indexes and edge-Labels into the DB JanusGraphManagement graphMgt = graph.openManagement(); System.out.println("-- loading schema into JanusGraph"); - SchemaGenerator.loadSchemaIntoJanusGraph(graph, graphMgt, "inmemory"); + if ("true".equals(SpringContextAware.getApplicationContext().getEnvironment().getProperty("history.enabled", "false"))) { + SchemaGenerator4Hist.loadSchemaIntoJanusGraph(graph, graphMgt, "inmemory"); + } else { + SchemaGenerator.loadSchemaIntoJanusGraph(graph, graphMgt, "inmemory"); + } } /** * Close all of the graph connections made in the instance. */ public void graphShutdown() { - graphs.values().stream().filter(JanusGraph::isOpen).forEach(JanusGraph::close); + if (graph != null && graph.isOpen()) { + graph.close(); + } } /** @@ -175,30 +171,10 @@ public class AAIGraph { * @return the graph */ public JanusGraph getGraph() { - return graphs.get(REALTIME_DB); - } - - public void graphShutdown(final DBConnectionType connectionType) { - - graphs.get(this.getGraphName(connectionType)).close(); - } - - public JanusGraph getGraph(final DBConnectionType connectionType) { - return graphs.get(this.getGraphName(connectionType)); - } - - private String getGraphName(final DBConnectionType connectionType) { - String graphName = ""; - if (DBConnectionType.CACHED.equals(connectionType)) { - graphName = this.CACHED_DB; - } else if (DBConnectionType.REALTIME.equals(connectionType)) { - graphName = this.REALTIME_DB; - } - - return graphName; + return graph; } - private void logAndPrint(final EELFLogger logger, final String msg) { + private void logAndPrint(String msg) { System.out.println(msg); logger.info(msg); } diff --git a/aai-core/src/main/java/org/onap/aai/dbmap/AAIGraphConfig.java b/aai-core/src/main/java/org/onap/aai/dbmap/AAIGraphConfig.java index d2f81610..ea939b32 100644 --- a/aai-core/src/main/java/org/onap/aai/dbmap/AAIGraphConfig.java +++ b/aai-core/src/main/java/org/onap/aai/dbmap/AAIGraphConfig.java @@ -22,8 +22,8 @@ package org.onap.aai.dbmap; import static org.janusgraph.graphdb.configuration.GraphDatabaseConfiguration.*; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.google.common.base.Preconditions; import com.google.common.base.Predicate; import com.google.common.collect.Iterators; @@ -46,7 +46,7 @@ import org.janusgraph.diskstorage.configuration.backend.CommonsConfiguration; */ public class AAIGraphConfig { - private static final EELFLogger logger = EELFManager.getInstance().getLogger(AAIGraphConfig.class); + private static final Logger logger = LoggerFactory.getLogger(AAIGraphConfig.class); private AAIGraphConfig() { }; diff --git a/aai-core/src/main/java/org/onap/aai/dbmap/InMemoryGraph.java b/aai-core/src/main/java/org/onap/aai/dbmap/InMemoryGraph.java index 54986f37..d017b7e9 100644 --- a/aai-core/src/main/java/org/onap/aai/dbmap/InMemoryGraph.java +++ b/aai-core/src/main/java/org/onap/aai/dbmap/InMemoryGraph.java @@ -20,12 +20,15 @@ package org.onap.aai.dbmap; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.Properties; + +import org.apache.commons.lang.exception.ExceptionUtils; import org.apache.tinkerpop.gremlin.structure.io.IoCore; import org.janusgraph.core.JanusGraph; import org.janusgraph.core.JanusGraphFactory; @@ -33,52 +36,56 @@ import org.janusgraph.core.JanusGraphTransaction; import org.janusgraph.core.schema.JanusGraphManagement; import org.onap.aai.dbgen.GraphSONPartialIO; import org.onap.aai.dbgen.SchemaGenerator; +import org.onap.aai.logging.LogFormatTools; public class InMemoryGraph { - private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(InMemoryGraph.class); + private static final Logger LOGGER = LoggerFactory.getLogger(InMemoryGraph.class); private JanusGraph graph = null; - public InMemoryGraph(final Builder builder) throws IOException { + public InMemoryGraph(Builder builder) throws IOException { /* * Create a In-memory graph */ - try (final InputStream is = new FileInputStream(builder.propertyFile);) { + InputStream is = new FileInputStream(builder.propertyFile); + try { graph = JanusGraphFactory.open(builder.propertyFile); - final Properties graphProps = new Properties(); + Properties graphProps = new Properties(); graphProps.load(is); - final JanusGraphManagement graphMgt = graph.openManagement(); + JanusGraphManagement graphMgt = graph.openManagement(); if (builder.isSchemaEnabled) { LOGGER.info("Schema Enabled"); SchemaGenerator.loadSchemaIntoJanusGraph(graph, graphMgt, graphProps.getProperty("storage.backend")); } - try (final JanusGraphTransaction transaction = graph.newTransaction();) { - LOGGER.info("Loading snapshot"); - if (builder.isPartialGraph) { - if ((builder.graphsonLocation != null) && (builder.graphsonLocation.length() > 0)) { - transaction.io(GraphSONPartialIO.build()).readGraph(builder.graphsonLocation); - } else { - transaction.io(GraphSONPartialIO.build()).reader().create().readGraph(builder.seqInputStream, + JanusGraphTransaction transaction = graph.newTransaction(); + LOGGER.info("Loading snapshot"); + if (builder.isPartialGraph) { + if ((builder.graphsonLocation != null) && (builder.graphsonLocation.length() > 0)) { + transaction.io(GraphSONPartialIO.build()).readGraph(builder.graphsonLocation); + } else { + transaction.io(GraphSONPartialIO.build()).reader().create().readGraph(builder.seqInputStream, graph); - } + } + } else { + if ((builder.graphsonLocation != null) && (builder.graphsonLocation.length() > 0)) { + transaction.io(IoCore.graphson()).readGraph(builder.graphsonLocation); } else { - if ((builder.graphsonLocation != null) && (builder.graphsonLocation.length() > 0)) { - transaction.io(IoCore.graphson()).readGraph(builder.graphsonLocation); - } else { - transaction.io(IoCore.graphson()).reader().create().readGraph(builder.seqInputStream, graph); - } + transaction.io(IoCore.graphson()).reader().create().readGraph(builder.seqInputStream, graph); } - transaction.commit(); - } catch (final IOException e) { - LOGGER.error("ERROR: Could not load datasnapshot to in memory graph. \n", e); - throw new IllegalStateException("Could not load datasnapshot to in memory graph"); } + transaction.commit(); - } catch (final IOException e) { - LOGGER.error("ERROR: Could not load datasnapshot to in memory graph. \n", e); + } catch (Exception e) { + // TODO : Changesysout to logger + e.printStackTrace(); + LOGGER.error("ERROR: Could not load datasnapshot to in memory graph. \n" + LogFormatTools.getStackTop(e)); throw new IllegalStateException("Could not load datasnapshot to in memory graph"); + + } finally { + is.close(); } + } public static class Builder { diff --git a/aai-core/src/main/java/org/onap/aai/dmaap/AAIDmaapEventJMSConsumer.java b/aai-core/src/main/java/org/onap/aai/dmaap/AAIDmaapEventJMSConsumer.java index 44ff599f..b3a8773e 100644 --- a/aai-core/src/main/java/org/onap/aai/dmaap/AAIDmaapEventJMSConsumer.java +++ b/aai-core/src/main/java/org/onap/aai/dmaap/AAIDmaapEventJMSConsumer.java @@ -22,43 +22,45 @@ package org.onap.aai.dmaap; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; - -import java.util.Objects; -import java.util.UUID; - -import javax.jms.JMSException; -import javax.jms.Message; -import javax.jms.MessageListener; -import javax.jms.TextMessage; - -import org.apache.log4j.MDC; import org.json.JSONException; import org.json.JSONObject; -import org.onap.aai.logging.LogFormatTools; -import org.onap.aai.logging.LoggingContext; -import org.onap.aai.logging.LoggingContext.LoggingField; -import org.onap.aai.logging.LoggingContext.StatusCode; +import org.onap.aai.aailog.logs.AaiDmaapMetricLog; +import org.onap.aai.exceptions.AAIException; +import org.onap.aai.logging.AaiElsErrorCode; +import org.onap.aai.logging.ErrorLogHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.MDC; import org.springframework.core.env.Environment; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.web.client.RestTemplate; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageListener; +import javax.jms.TextMessage; +import java.util.Map; +import java.util.Objects; + public class AAIDmaapEventJMSConsumer implements MessageListener { private static final String EVENT_TOPIC = "event-topic"; - private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(AAIDmaapEventJMSConsumer.class); + private static final Logger LOGGER = LoggerFactory.getLogger(AAIDmaapEventJMSConsumer.class); private RestTemplate restTemplate; private HttpHeaders httpHeaders; private Environment environment; + private Map<String, String> mdcCopy; + public AAIDmaapEventJMSConsumer(Environment environment, RestTemplate restTemplate, HttpHeaders httpHeaders) { + super(); + mdcCopy = MDC.getCopyOfContextMap(); Objects.nonNull(environment); Objects.nonNull(restTemplate); Objects.nonNull(httpHeaders); @@ -76,41 +78,47 @@ public class AAIDmaapEventJMSConsumer implements MessageListener { String jsmMessageTxt = ""; String aaiEvent = ""; + JSONObject aaiEventHeader; + JSONObject joPayload; + String transactionId = ""; + String serviceName = ""; String eventName = ""; - LoggingContext.save(); - LoggingContext.init(); + String aaiElsErrorCode = AaiElsErrorCode.SUCCESS; + String errorDescription = ""; + + if ( mdcCopy != null ) { + MDC.setContextMap(mdcCopy); + } + if (message instanceof TextMessage) { + AaiDmaapMetricLog metricLog = new AaiDmaapMetricLog(); try { jsmMessageTxt = ((TextMessage) message).getText(); JSONObject jo = new JSONObject(jsmMessageTxt); - if (jo.has("aaiEventPayload")) { - aaiEvent = jo.getJSONObject("aaiEventPayload").toString(); + joPayload = jo.getJSONObject("aaiEventPayload"); + aaiEvent = joPayload.toString(); } else { return; } - if (jo.getString("transId") != null) { - LoggingContext.requestId(jo.getString("transId")); - } else { - final UUID generatedRequestUuid = UUID.randomUUID(); - LoggingContext.requestId(generatedRequestUuid.toString()); - } - if (jo.getString("fromAppId") != null) { - LoggingContext.partnerName(jo.getString("fromAppId")); - } - if (jo.getString(EVENT_TOPIC) != null) { - eventName = jo.getString(EVENT_TOPIC); + if (jo.getString("event-topic") != null) { + eventName = jo.getString("event-topic"); } - - LoggingContext.targetEntity("DMAAP"); - if (jo.getString(EVENT_TOPIC) != null) { - eventName = jo.getString(EVENT_TOPIC); - LoggingContext.targetServiceName(eventName); + if (joPayload.has("event-header")) { + try { + aaiEventHeader = joPayload.getJSONObject("event-header"); + if (aaiEventHeader.has("id")) { + transactionId = aaiEventHeader.get("id").toString(); + } + if (aaiEventHeader.has("entity-link")) { + serviceName = aaiEventHeader.get("entity-link").toString(); + } + } + catch (JSONException jexc) { + // ignore, this is just used for logging + } } - LoggingContext.serviceName("AAI"); - LoggingContext.statusCode(StatusCode.COMPLETE); - LoggingContext.responseCode(LoggingContext.SUCCESS); - LOGGER.info(eventName + "|" + aaiEvent); + metricLog.pre(eventName, aaiEvent, transactionId, serviceName); HttpEntity httpEntity = new HttpEntity(aaiEvent, httpHeaders); @@ -121,21 +129,20 @@ public class AAIDmaapEventJMSConsumer implements MessageListener { if ("AAI-EVENT".equals(eventName)) { restTemplate.exchange(baseUrl + endpoint, HttpMethod.POST, httpEntity, String.class); } else { - LoggingContext.statusCode(StatusCode.ERROR); LOGGER.error(eventName + "|Event Topic invalid."); } } catch (JMSException | JSONException e) { - LoggingContext.statusCode(StatusCode.ERROR); - LoggingContext.responseCode(LoggingContext.DATA_ERROR); - LOGGER.error("AAI_7350 Error parsing aaievent jsm message for sending to dmaap. {} {}", jsmMessageTxt, - LogFormatTools.getStackTop(e)); + aaiElsErrorCode = AaiElsErrorCode.DATA_ERROR; + errorDescription = e.getMessage(); + ErrorLogHelper.logException(new AAIException("AAI_7350")); } catch (Exception e) { - LoggingContext.statusCode(StatusCode.ERROR); - LoggingContext.responseCode(LoggingContext.AVAILABILITY_TIMEOUT_ERROR); - LOGGER.error("AAI_7350 Error sending message to dmaap. {} {}", jsmMessageTxt, - LogFormatTools.getStackTop(e)); + aaiElsErrorCode = AaiElsErrorCode.AVAILABILITY_TIMEOUT_ERROR; + errorDescription = e.getMessage(); + ErrorLogHelper.logException(new AAIException("AAI_7304", jsmMessageTxt)); + } + finally { + metricLog.post(aaiElsErrorCode, errorDescription); } } - } } diff --git a/aai-core/src/main/java/org/onap/aai/dmaap/AAIDmaapEventJMSProducer.java b/aai-core/src/main/java/org/onap/aai/dmaap/AAIDmaapEventJMSProducer.java index 4036b907..eb0d1658 100644 --- a/aai-core/src/main/java/org/onap/aai/dmaap/AAIDmaapEventJMSProducer.java +++ b/aai-core/src/main/java/org/onap/aai/dmaap/AAIDmaapEventJMSProducer.java @@ -50,4 +50,12 @@ public class AAIDmaapEventJMSProducer implements MessageProducer { ccf.destroy(); } } + + public void sendMessageToDefaultDestination(String msg) { + if (jmsTemplate != null) { + jmsTemplate.convertAndSend(msg); + CachingConnectionFactory ccf = (CachingConnectionFactory) this.jmsTemplate.getConnectionFactory(); + ccf.destroy(); + } + } } diff --git a/aai-core/src/main/java/org/onap/aai/dmaap/MessageProducer.java b/aai-core/src/main/java/org/onap/aai/dmaap/MessageProducer.java index 9b17d881..1df64b69 100644 --- a/aai-core/src/main/java/org/onap/aai/dmaap/MessageProducer.java +++ b/aai-core/src/main/java/org/onap/aai/dmaap/MessageProducer.java @@ -25,4 +25,5 @@ import org.json.JSONObject; public interface MessageProducer { void sendMessageToDefaultDestination(JSONObject finalJson); + void sendMessageToDefaultDestination(String msg); } diff --git a/aai-core/src/main/java/org/onap/aai/domain/model/AAIResources.java b/aai-core/src/main/java/org/onap/aai/domain/model/AAIResources.java index 4e5f0392..413faf62 100644 --- a/aai-core/src/main/java/org/onap/aai/domain/model/AAIResources.java +++ b/aai-core/src/main/java/org/onap/aai/domain/model/AAIResources.java @@ -20,10 +20,10 @@ package org.onap.aai.domain.model; -import java.util.HashMap; - import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext; +import java.util.HashMap; + public class AAIResources { private DynamicJAXBContext jaxbContext; diff --git a/aai-core/src/main/java/org/onap/aai/domain/notificationEvent/NotificationEvent.java b/aai-core/src/main/java/org/onap/aai/domain/notificationEvent/NotificationEvent.java index d8b9b997..1e6307cc 100644 --- a/aai-core/src/main/java/org/onap/aai/domain/notificationEvent/NotificationEvent.java +++ b/aai-core/src/main/java/org/onap/aai/domain/notificationEvent/NotificationEvent.java @@ -18,30 +18,25 @@ * ============LICENSE_END========================================================= */ // -// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2 -// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> -// Any modifications to this file will be lost upon recompilation of the source schema. -// Generated on: 2016.01.06 at 05:38:00 PM EST +// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2 +// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> +// Any modifications to this file will be lost upon recompilation of the source schema. +// Generated on: 2016.01.06 at 05:38:00 PM EST // package org.onap.aai.domain.notificationEvent; -import javax.xml.bind.annotation.XmlAccessType; -import javax.xml.bind.annotation.XmlAccessorType; -import javax.xml.bind.annotation.XmlAnyElement; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; -import javax.xml.bind.annotation.XmlType; - import org.w3c.dom.Element; +import javax.xml.bind.annotation.*; + /** * <p> * Java class for anonymous complex type. - * + * * <p> * The following schema fragment specifies the expected content contained within this class. - * + * * <pre> * <complexType> * <complexContent> @@ -77,8 +72,8 @@ import org.w3c.dom.Element; * </complexContent> * </complexType> * </pre> - * - * + * + * */ @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "", propOrder = {"cambriaPartition", "eventHeader", "entity"}) @@ -94,11 +89,11 @@ public class NotificationEvent { /** * Gets the value of the eventHeader property. - * + * * @return * possible object is * {@link EventHeader } - * + * */ public EventHeader getEventHeader() { return eventHeader; @@ -106,11 +101,11 @@ public class NotificationEvent { /** * Sets the value of the eventHeader property. - * + * * @param value * allowed object is * {@link EventHeader } - * + * */ public void setEventHeader(EventHeader value) { this.eventHeader = value; @@ -118,12 +113,12 @@ public class NotificationEvent { /** * Gets the value of the any property. - * + * * @return * possible object is * {@link Object } * {@link Element } - * + * */ public Object getEntity() { return entity; @@ -131,12 +126,12 @@ public class NotificationEvent { /** * Sets the value of the any property. - * + * * @param value * allowed object is * {@link Object } * {@link Element } - * + * */ public void setEntity(Object value) { this.entity = value; @@ -144,11 +139,11 @@ public class NotificationEvent { /** * Gets the value of the cambriaPartition property. - * + * * @return * possible object is * {@link String } - * + * */ public String getCambriaPartition() { return cambriaPartition; @@ -156,11 +151,11 @@ public class NotificationEvent { /** * Sets the value of the cambriaPartition property. - * + * * @param value * allowed object is * {@link String } - * + * */ public void setCambriaPartition(String value) { this.cambriaPartition = value; @@ -169,10 +164,10 @@ public class NotificationEvent { /** * <p> * Java class for anonymous complex type. - * + * * <p> * The following schema fragment specifies the expected content contained within this class. - * + * * <pre> * <complexType> * <complexContent> @@ -196,8 +191,8 @@ public class NotificationEvent { * </complexContent> * </complexType> * </pre> - * - * + * + * */ @XmlAccessorType(XmlAccessType.FIELD) @XmlType( @@ -235,11 +230,11 @@ public class NotificationEvent { /** * Gets the value of the id property. - * + * * @return * possible object is * {@link String } - * + * */ public String getId() { return id; @@ -247,11 +242,11 @@ public class NotificationEvent { /** * Sets the value of the id property. - * + * * @param value * allowed object is * {@link String } - * + * */ public void setId(String value) { this.id = value; @@ -259,11 +254,11 @@ public class NotificationEvent { /** * Gets the value of the timestamp property. - * + * * @return * possible object is * {@link String } - * + * */ public String getTimestamp() { return timestamp; @@ -271,11 +266,11 @@ public class NotificationEvent { /** * Sets the value of the timestamp property. - * + * * @param value * allowed object is * {@link String } - * + * */ public void setTimestamp(String value) { this.timestamp = value; @@ -283,11 +278,11 @@ public class NotificationEvent { /** * Gets the value of the sourceName property. - * + * * @return * possible object is * {@link String } - * + * */ public String getSourceName() { return sourceName; @@ -295,11 +290,11 @@ public class NotificationEvent { /** * Sets the value of the sourceName property. - * + * * @param value * allowed object is * {@link String } - * + * */ public void setSourceName(String value) { this.sourceName = value; @@ -307,11 +302,11 @@ public class NotificationEvent { /** * Gets the value of the domain property. - * + * * @return * possible object is * {@link String } - * + * */ public String getDomain() { return domain; @@ -319,11 +314,11 @@ public class NotificationEvent { /** * Sets the value of the domain property. - * + * * @param value * allowed object is * {@link String } - * + * */ public void setDomain(String value) { this.domain = value; @@ -331,11 +326,11 @@ public class NotificationEvent { /** * Gets the value of the sequenceNumber property. - * + * * @return * possible object is * {@link String } - * + * */ public String getSequenceNumber() { return sequenceNumber; @@ -343,11 +338,11 @@ public class NotificationEvent { /** * Sets the value of the sequenceNumber property. - * + * * @param value * allowed object is * {@link String } - * + * */ public void setSequenceNumber(String value) { this.sequenceNumber = value; @@ -355,11 +350,11 @@ public class NotificationEvent { /** * Gets the value of the severity property. - * + * * @return * possible object is * {@link String } - * + * */ public String getSeverity() { return severity; @@ -367,11 +362,11 @@ public class NotificationEvent { /** * Sets the value of the severity property. - * + * * @param value * allowed object is * {@link String } - * + * */ public void setSeverity(String value) { this.severity = value; @@ -379,11 +374,11 @@ public class NotificationEvent { /** * Gets the value of the eventType property. - * + * * @return * possible object is * {@link String } - * + * */ public String getEventType() { return eventType; @@ -391,11 +386,11 @@ public class NotificationEvent { /** * Sets the value of the eventType property. - * + * * @param value * allowed object is * {@link String } - * + * */ public void setEventType(String value) { this.eventType = value; @@ -403,11 +398,11 @@ public class NotificationEvent { /** * Gets the value of the version property. - * + * * @return * possible object is * {@link String } - * + * */ public String getVersion() { return version; @@ -415,11 +410,11 @@ public class NotificationEvent { /** * Sets the value of the version property. - * + * * @param value * allowed object is * {@link String } - * + * */ public void setVersion(String value) { this.version = value; @@ -427,11 +422,11 @@ public class NotificationEvent { /** * Gets the value of the action property. - * + * * @return * possible object is * {@link String } - * + * */ public String getAction() { return action; @@ -439,11 +434,11 @@ public class NotificationEvent { /** * Sets the value of the action property. - * + * * @param value * allowed object is * {@link String } - * + * */ public void setAction(String value) { this.action = value; @@ -451,11 +446,11 @@ public class NotificationEvent { /** * Gets the value of the entityType property. - * + * * @return * possible object is * {@link String } - * + * */ public String getEntityType() { return entityType; @@ -463,11 +458,11 @@ public class NotificationEvent { /** * Sets the value of the entityType property. - * + * * @param value * allowed object is * {@link String } - * + * */ public void setEntityType(String value) { this.entityType = value; @@ -475,11 +470,11 @@ public class NotificationEvent { /** * Gets the value of the topEntityType property. - * + * * @return * possible object is * {@link String } - * + * */ public String getTopEntityType() { return topEntityType; @@ -487,11 +482,11 @@ public class NotificationEvent { /** * Sets the value of the topEntityType property. - * + * * @param value * allowed object is * {@link String } - * + * */ public void setTopEntityType(String value) { this.topEntityType = value; @@ -499,11 +494,11 @@ public class NotificationEvent { /** * Gets the value of the entityLink property. - * + * * @return * possible object is * {@link String } - * + * */ public String getEntityLink() { return entityLink; @@ -511,11 +506,11 @@ public class NotificationEvent { /** * Sets the value of the entityLink property. - * + * * @param value * allowed object is * {@link String } - * + * */ public void setEntityLink(String value) { this.entityLink = value; @@ -523,11 +518,11 @@ public class NotificationEvent { /** * Gets the value of the status property. - * + * * @return * possible object is * {@link String } - * + * */ public String getStatus() { return status; @@ -535,11 +530,11 @@ public class NotificationEvent { /** * Sets the value of the status property. - * + * * @param value * allowed object is * {@link String } - * + * */ public void setStatus(String value) { this.status = value; diff --git a/aai-core/src/main/java/org/onap/aai/domain/responseMessage/AAIResponseMessage.java b/aai-core/src/main/java/org/onap/aai/domain/responseMessage/AAIResponseMessage.java index 6cd82eef..53311990 100644 --- a/aai-core/src/main/java/org/onap/aai/domain/responseMessage/AAIResponseMessage.java +++ b/aai-core/src/main/java/org/onap/aai/domain/responseMessage/AAIResponseMessage.java @@ -20,11 +20,7 @@ package org.onap.aai.domain.responseMessage; -import javax.xml.bind.annotation.XmlAccessType; -import javax.xml.bind.annotation.XmlAccessorType; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; -import javax.xml.bind.annotation.XmlType; +import javax.xml.bind.annotation.*; @XmlAccessorType(XmlAccessType.FIELD) @XmlType( diff --git a/aai-core/src/main/java/org/onap/aai/domain/responseMessage/AAIResponseMessageData.java b/aai-core/src/main/java/org/onap/aai/domain/responseMessage/AAIResponseMessageData.java index 76b73642..c48f1ed8 100644 --- a/aai-core/src/main/java/org/onap/aai/domain/responseMessage/AAIResponseMessageData.java +++ b/aai-core/src/main/java/org/onap/aai/domain/responseMessage/AAIResponseMessageData.java @@ -23,22 +23,16 @@ package org.onap.aai.domain.responseMessage; // -//This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2 -//See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> -//Any modifications to this file will be lost upon recompilation of the source schema. -//Generated on: 2015.09.11 at 11:53:27 AM EDT +//This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2 +//See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> +//Any modifications to this file will be lost upon recompilation of the source schema. +//Generated on: 2015.09.11 at 11:53:27 AM EDT // +import javax.xml.bind.annotation.*; import java.util.ArrayList; import java.util.List; -import javax.xml.bind.annotation.XmlAccessType; -import javax.xml.bind.annotation.XmlAccessorType; -import javax.xml.bind.annotation.XmlAnyElement; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; -import javax.xml.bind.annotation.XmlType; - @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "", propOrder = {"aaiResponseMessageDatum", "any"}) @XmlRootElement(name = "aai-response-message-data", namespace = "http://org.onap.aai.inventory") diff --git a/aai-core/src/main/java/org/onap/aai/domain/responseMessage/AAIResponseMessageDatum.java b/aai-core/src/main/java/org/onap/aai/domain/responseMessage/AAIResponseMessageDatum.java index 90c6e280..a8adffde 100644 --- a/aai-core/src/main/java/org/onap/aai/domain/responseMessage/AAIResponseMessageDatum.java +++ b/aai-core/src/main/java/org/onap/aai/domain/responseMessage/AAIResponseMessageDatum.java @@ -20,11 +20,7 @@ package org.onap.aai.domain.responseMessage; -import javax.xml.bind.annotation.XmlAccessType; -import javax.xml.bind.annotation.XmlAccessorType; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; -import javax.xml.bind.annotation.XmlType; +import javax.xml.bind.annotation.*; @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "", propOrder = {"aaiResponseMessageDatumKey", "aaiResponseMessageDatumValue", diff --git a/aai-core/src/main/java/org/onap/aai/domain/responseMessage/AAIResponseMessages.java b/aai-core/src/main/java/org/onap/aai/domain/responseMessage/AAIResponseMessages.java index 09bf30e3..8263e58d 100644 --- a/aai-core/src/main/java/org/onap/aai/domain/responseMessage/AAIResponseMessages.java +++ b/aai-core/src/main/java/org/onap/aai/domain/responseMessage/AAIResponseMessages.java @@ -21,29 +21,23 @@ package org.onap.aai.domain.responseMessage; // -//This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2 -//See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> -//Any modifications to this file will be lost upon recompilation of the source schema. -//Generated on: 2015.09.11 at 11:53:27 AM EDT +//This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2 +//See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> +//Any modifications to this file will be lost upon recompilation of the source schema. +//Generated on: 2015.09.11 at 11:53:27 AM EDT // +import javax.xml.bind.annotation.*; import java.util.ArrayList; import java.util.List; -import javax.xml.bind.annotation.XmlAccessType; -import javax.xml.bind.annotation.XmlAccessorType; -import javax.xml.bind.annotation.XmlAnyElement; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; -import javax.xml.bind.annotation.XmlType; - /** * <p> * Java class for anonymous complex type. - * + * * <p> * The following schema fragment specifies the expected content contained within this class. - * + * * <pre> * <complexType> * <complexContent> @@ -77,8 +71,8 @@ import javax.xml.bind.annotation.XmlType; * </complexContent> * </complexType> * </pre> - * - * + * + * */ @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "", propOrder = {"aaiResponseMessage", "any"}) diff --git a/aai-core/src/main/java/org/onap/aai/domain/translog/TransactionLogEntries.java b/aai-core/src/main/java/org/onap/aai/domain/translog/TransactionLogEntries.java index 7f02cb53..e81b3e3c 100644 --- a/aai-core/src/main/java/org/onap/aai/domain/translog/TransactionLogEntries.java +++ b/aai-core/src/main/java/org/onap/aai/domain/translog/TransactionLogEntries.java @@ -18,29 +18,28 @@ * ============LICENSE_END========================================================= */ // -// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2 -// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> -// Any modifications to this file will be lost upon recompilation of the source schema. -// Generated on: 2015.03.20 at 09:46:47 AM CDT +// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2 +// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> +// Any modifications to this file will be lost upon recompilation of the source schema. +// Generated on: 2015.03.20 at 09:46:47 AM CDT // package org.onap.aai.domain.translog; -import java.util.ArrayList; -import java.util.List; - import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlType; +import java.util.ArrayList; +import java.util.List; /** * <p> * Java class for anonymous complex type. - * + * * <p> * The following schema fragment specifies the expected content contained within this class. - * + * * <pre> * <complexType> * <complexContent> @@ -102,8 +101,8 @@ import javax.xml.bind.annotation.XmlType; * </complexContent> * </complexType> * </pre> - * - * + * + * */ @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "", propOrder = {"transactionLogEntries"}) diff --git a/aai-core/src/main/java/org/onap/aai/domain/translog/TransactionLogEntry.java b/aai-core/src/main/java/org/onap/aai/domain/translog/TransactionLogEntry.java index 2ce485be..16c773ae 100644 --- a/aai-core/src/main/java/org/onap/aai/domain/translog/TransactionLogEntry.java +++ b/aai-core/src/main/java/org/onap/aai/domain/translog/TransactionLogEntry.java @@ -20,14 +20,10 @@ package org.onap.aai.domain.translog; -import javax.xml.bind.annotation.XmlAccessType; -import javax.xml.bind.annotation.XmlAccessorType; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; -import javax.xml.bind.annotation.XmlType; - import org.eclipse.persistence.oxm.annotations.XmlCDATA; +import javax.xml.bind.annotation.*; + @XmlAccessorType(XmlAccessType.FIELD) @XmlType( name = "", @@ -70,11 +66,11 @@ public class TransactionLogEntry { /** * Gets the value of the transcationLogEntryId property. - * + * * @return * possible object is * {@link String } - * + * */ public String getTransactionLogEntryId() { return transactionLogEntryId; @@ -82,11 +78,11 @@ public class TransactionLogEntry { /** * Sets the value of the transactionLogEntryId property. - * + * * @param value * allowed object is * {@link String } - * + * */ public void setTransactionLogEntryId(String value) { this.transactionLogEntryId = value; @@ -94,11 +90,11 @@ public class TransactionLogEntry { /** * Gets the value of the status property. - * + * * @return * possible object is * {@link String } - * + * */ public String getStatus() { return status; @@ -106,11 +102,11 @@ public class TransactionLogEntry { /** * Sets the value of the status property. - * + * * @param value * allowed object is * {@link String } - * + * */ public void setStatus(String value) { this.status = value; @@ -118,11 +114,11 @@ public class TransactionLogEntry { /** * Gets the value of the rqstDate property. - * + * * @return * possible object is * {@link String } - * + * */ public String getRqstDate() { @@ -131,11 +127,11 @@ public class TransactionLogEntry { /** * Sets the value of the rqstDate property. - * + * * @param value * allowed object is * {@link String } - * + * */ public void setRqstDate(String value) { this.rqstDate = value; @@ -143,11 +139,11 @@ public class TransactionLogEntry { /** * Gets the value of the respDate property. - * + * * @return * possible object is * {@link String } - * + * */ public String getRespDate() { @@ -156,11 +152,11 @@ public class TransactionLogEntry { /** * Sets the value of the respDate property. - * + * * @param value * allowed object is * {@link String } - * + * */ public void setRespDate(String value) { this.respDate = value; @@ -168,11 +164,11 @@ public class TransactionLogEntry { /** * Gets the value of the sourceId property. - * + * * @return * possible object is * {@link String } - * + * */ public String getSourceId() { return sourceId; @@ -180,11 +176,11 @@ public class TransactionLogEntry { /** * Sets the value of the sourceId property. - * + * * @param value * allowed object is * {@link String } - * + * */ public void setSourceId(String value) { this.sourceId = value; @@ -192,11 +188,11 @@ public class TransactionLogEntry { /** * Gets the value of the resourceId property. - * + * * @return * possible object is * {@link String } - * + * */ public String getResourceId() { return resourceId; @@ -204,11 +200,11 @@ public class TransactionLogEntry { /** * Sets the value of the resourceId property. - * + * * @param value * allowed object is * {@link String } - * + * */ public void setResourceId(String value) { this.resourceId = value; @@ -216,11 +212,11 @@ public class TransactionLogEntry { /** * Gets the value of the resourceType property. - * + * * @return * possible object is * {@link String } - * + * */ public String getResourceType() { return resourceType; @@ -228,11 +224,11 @@ public class TransactionLogEntry { /** * Sets the value of the resourceType property. - * + * * @param value * allowed object is * {@link String } - * + * */ public void setResourceType(String value) { this.resourceType = value; @@ -240,11 +236,11 @@ public class TransactionLogEntry { /** * Gets the value of the rqstBuf property. - * + * * @return * possible object is * {@link String } - * + * */ public String getRqstBuf() { return rqstBuf; @@ -252,11 +248,11 @@ public class TransactionLogEntry { /** * Sets the value of the rqstBuf property. - * + * * @param value * allowed object is * {@link String } - * + * */ @XmlCDATA public void setRqstBuf(String value) { @@ -265,11 +261,11 @@ public class TransactionLogEntry { /** * Gets the value of the respBuf property. - * + * * @return * possible object is * {@link String } - * + * */ public String getrespBuf() { return respBuf; @@ -277,11 +273,11 @@ public class TransactionLogEntry { /** * Sets the value of the respBuf property. - * + * * @param value * allowed object is * {@link String } - * + * */ @XmlCDATA public void setrespBuf(String value) { @@ -290,11 +286,11 @@ public class TransactionLogEntry { /** * Gets the value of the notificationPayload property. - * + * * @return * possible object is * {@link String } - * + * */ public String getNotificationPayload() { return notificationPayload; @@ -302,11 +298,11 @@ public class TransactionLogEntry { /** * Sets the value of the notificationPayload property. - * + * * @param value * allowed object is * {@link String } - * + * */ @XmlCDATA public void setNotificationPayload(String value) { @@ -315,11 +311,11 @@ public class TransactionLogEntry { /** * Gets the value of the notificationId property. - * + * * @return * possible object is * {@link String } - * + * */ public String getNotificationId() { return notificationId; @@ -327,11 +323,11 @@ public class TransactionLogEntry { /** * Sets the value of the notificationId property. - * + * * @param value * allowed object is * {@link String } - * + * */ public void setNotificationId(String value) { this.notificationId = value; @@ -339,11 +335,11 @@ public class TransactionLogEntry { /** * Gets the value of the notificationId property. - * + * * @return * possible object is * {@link String } - * + * */ public String getNotificationStatus() { return notificationStatus; @@ -351,11 +347,11 @@ public class TransactionLogEntry { /** * Sets the value of the notificationId property. - * + * * @param value * allowed object is * {@link String } - * + * */ public void setNotificationStatus(String value) { this.notificationStatus = value; @@ -363,11 +359,11 @@ public class TransactionLogEntry { /** * Gets the value of the notificationTopic property. - * + * * @return * possible object is * {@link String } - * + * */ public String getNotificationTopic() { return notificationTopic; @@ -384,11 +380,11 @@ public class TransactionLogEntry { /** * Gets the value of the notificationEntityLink property. - * + * * @return * possible object is * {@link String } - * + * */ public String getNotificationEntityLink() { return notificationEntityLink; diff --git a/aai-core/src/main/java/org/onap/aai/extensions/ExtensionController.java b/aai-core/src/main/java/org/onap/aai/extensions/ExtensionController.java index 13c2de94..ec28858e 100644 --- a/aai-core/src/main/java/org/onap/aai/extensions/ExtensionController.java +++ b/aai-core/src/main/java/org/onap/aai/extensions/ExtensionController.java @@ -20,8 +20,8 @@ package org.onap.aai.extensions; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.lang.reflect.Method; @@ -30,7 +30,7 @@ import org.onap.aai.util.AAIConfig; public class ExtensionController { - private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(ExtensionController.class); + private static final Logger LOGGER = LoggerFactory.getLogger(ExtensionController.class); /** * Run extension. diff --git a/aai-core/src/main/java/org/onap/aai/introspection/Introspector.java b/aai-core/src/main/java/org/onap/aai/introspection/Introspector.java index 11e6233f..53f2a2cd 100644 --- a/aai-core/src/main/java/org/onap/aai/introspection/Introspector.java +++ b/aai-core/src/main/java/org/onap/aai/introspection/Introspector.java @@ -20,15 +20,9 @@ package org.onap.aai.introspection; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.google.common.base.CaseFormat; - -import java.io.UnsupportedEncodingException; -import java.lang.reflect.InvocationTargetException; -import java.util.*; -import java.util.stream.Collectors; - import org.apache.commons.lang.ClassUtils; import org.eclipse.persistence.exceptions.DynamicException; import org.onap.aai.config.SpringContextAware; @@ -43,9 +37,14 @@ import org.onap.aai.schema.enums.PropertyMetadata; import org.onap.aai.setup.SchemaVersion; import org.onap.aai.workarounds.NamingExceptions; +import java.io.UnsupportedEncodingException; +import java.lang.reflect.InvocationTargetException; +import java.util.*; +import java.util.stream.Collectors; + public abstract class Introspector implements Cloneable { - private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(Introspector.class); + private static final Logger LOGGER = LoggerFactory.getLogger(Introspector.class); protected String className; protected String uriChain = ""; @@ -54,6 +53,7 @@ public abstract class Introspector implements Cloneable { private Set<String> uniqueProperties = null; private Set<String> indexedProperties = null; private Set<String> allKeys = null; + private Set<String> dslStartNodeProperties = null; protected CaseFormatStore caseFormatStore = null; protected NodeIngestor nodeIngestor; @@ -177,7 +177,7 @@ public abstract class Introspector implements Cloneable { if (obj != null) { try { - if (!nameClass.isAssignableFrom(obj.getClass())) { + if (!obj.getClass().getName().equals(nameClass.getName())) { if (nameClass.isPrimitive()) { nameClass = ClassUtils.primitiveToWrapper(nameClass); result = nameClass.getConstructor(String.class).newInstance(obj.toString()); @@ -229,15 +229,8 @@ public abstract class Introspector implements Cloneable { public Set<String> getProperties(PropertyPredicate<Introspector, String> p) { final Set<String> temp = new LinkedHashSet<>(); - this.getProperties().stream().filter(item -> { - return p.test(this, item); - }).forEach(item -> { - temp.add(item); - }); - final Set<String> result = Collections.unmodifiableSet(temp); - - return result; - + this.getProperties().stream().filter(item -> p.test(this, item)).forEach(temp::add); + return Collections.unmodifiableSet(temp); } public Set<String> getSimpleProperties(PropertyPredicate<Introspector, String> p) { @@ -301,6 +294,31 @@ public abstract class Introspector implements Cloneable { return result; } + public Set<String> getDslStartNodeProperties() { + Set<String> result = null; + + if (this.dslStartNodeProperties == null) { + /* + * The dslStartNodeProperties will have keys by default + * If dslStartNodeProps exist in the oxm use it + * if not use the indexedProps + */ + result = new LinkedHashSet<>(this.getKeys()); + + String dslKeys = this.getMetadata(ObjectMetadata.DSL_START_NODE_PROPS); + String indexedKeys = this.getMetadata(ObjectMetadata.INDEXED_PROPS); + if (dslKeys != null) { + Arrays.stream(dslKeys.split(",")).forEach(result::add); + } + else if(indexedKeys != null){ + Arrays.stream(indexedKeys.split(",")).forEach(result::add); + } + this.dslStartNodeProperties = Collections.unmodifiableSet(result); + } + result = this.dslStartNodeProperties; + return result; + } + public Set<String> getUniqueProperties() { Set<String> result = null; if (this.uniqueProperties == null) { diff --git a/aai-core/src/main/java/org/onap/aai/introspection/IntrospectorWalker.java b/aai-core/src/main/java/org/onap/aai/introspection/IntrospectorWalker.java index aa5ae156..93a48290 100644 --- a/aai-core/src/main/java/org/onap/aai/introspection/IntrospectorWalker.java +++ b/aai-core/src/main/java/org/onap/aai/introspection/IntrospectorWalker.java @@ -20,8 +20,8 @@ package org.onap.aai.introspection; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.HashSet; import java.util.LinkedHashSet; @@ -34,7 +34,7 @@ import org.onap.aai.logging.LogFormatTools; public class IntrospectorWalker { - private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(IntrospectorWalker.class); + private static final Logger LOGGER = LoggerFactory.getLogger(IntrospectorWalker.class); private Wanderer w = null; private Set<String> blacklist = null; diff --git a/aai-core/src/main/java/org/onap/aai/introspection/JSONStrategy.java b/aai-core/src/main/java/org/onap/aai/introspection/JSONStrategy.java index e628d5a4..55580dc3 100644 --- a/aai-core/src/main/java/org/onap/aai/introspection/JSONStrategy.java +++ b/aai-core/src/main/java/org/onap/aai/introspection/JSONStrategy.java @@ -26,7 +26,6 @@ import java.util.Map; import java.util.Set; import java.util.UUID; -import org.json.simple.JSONArray; import org.json.simple.JSONObject; import org.onap.aai.schema.enums.ObjectMetadata; import org.onap.aai.schema.enums.PropertyMetadata; @@ -150,7 +149,7 @@ public class JSONStrategy extends Introspector { Object resultObject = null; Class<?> resultClass = null; resultObject = this.getValue(name); - if (resultObject instanceof JSONArray) { + if (resultObject.getClass().getName().equals("org.json.simple.JSONArray")) { resultClass = ((List) resultObject).get(0).getClass(); } @@ -274,10 +273,10 @@ public class JSONStrategy extends Introspector { /* * @Override * public String findEdgeName(String parent, String child) { - * + * * // Always has for now * return "has"; - * + * * } */ diff --git a/aai-core/src/main/java/org/onap/aai/introspection/MoxyLoader.java b/aai-core/src/main/java/org/onap/aai/introspection/MoxyLoader.java index 02254a8b..7471c745 100644 --- a/aai-core/src/main/java/org/onap/aai/introspection/MoxyLoader.java +++ b/aai-core/src/main/java/org/onap/aai/introspection/MoxyLoader.java @@ -20,8 +20,8 @@ package org.onap.aai.introspection; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.google.common.base.CaseFormat; import com.google.common.collect.ImmutableMap; @@ -52,7 +52,7 @@ import org.onap.aai.workarounds.NamingExceptions; public class MoxyLoader extends Loader { - private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(MoxyLoader.class); + private static final Logger LOGGER = LoggerFactory.getLogger(MoxyLoader.class); private DynamicJAXBContext jaxbContext = null; private Map<String, Introspector> allObjs = null; diff --git a/aai-core/src/main/java/org/onap/aai/introspection/MoxyStrategy.java b/aai-core/src/main/java/org/onap/aai/introspection/MoxyStrategy.java index 15311638..57e41081 100644 --- a/aai-core/src/main/java/org/onap/aai/introspection/MoxyStrategy.java +++ b/aai-core/src/main/java/org/onap/aai/introspection/MoxyStrategy.java @@ -20,8 +20,8 @@ package org.onap.aai.introspection; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.google.common.base.CaseFormat; import com.google.common.base.Joiner; @@ -54,7 +54,7 @@ import org.springframework.web.util.UriUtils; public class MoxyStrategy extends Introspector { - private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(MoxyStrategy.class); + private static final Logger LOGGER = LoggerFactory.getLogger(MoxyStrategy.class); private DynamicEntity internalObject = null; private DynamicType internalType = null; private DynamicJAXBContext jaxbContext = null; diff --git a/aai-core/src/main/java/org/onap/aai/introspection/generator/CreateExample.java b/aai-core/src/main/java/org/onap/aai/introspection/generator/CreateExample.java index 73f0a346..8288fd68 100644 --- a/aai-core/src/main/java/org/onap/aai/introspection/generator/CreateExample.java +++ b/aai-core/src/main/java/org/onap/aai/introspection/generator/CreateExample.java @@ -20,17 +20,17 @@ package org.onap.aai.introspection.generator; +import org.onap.aai.exceptions.AAIException; +import org.onap.aai.introspection.*; + import java.security.SecureRandom; import java.util.ArrayList; import java.util.List; -import org.onap.aai.exceptions.AAIException; -import org.onap.aai.introspection.*; - public class CreateExample implements Wanderer { private SecureRandom rand = new SecureRandom(); - private final long range = 100000000L; + private static final long range = 100000000L; private Loader loader = null; private Introspector result = null; private String objectName = null; diff --git a/aai-core/src/main/java/org/onap/aai/introspection/sideeffect/DataCopy.java b/aai-core/src/main/java/org/onap/aai/introspection/sideeffect/DataCopy.java index 6a6ee4c1..0994f023 100644 --- a/aai-core/src/main/java/org/onap/aai/introspection/sideeffect/DataCopy.java +++ b/aai-core/src/main/java/org/onap/aai/introspection/sideeffect/DataCopy.java @@ -20,17 +20,6 @@ package org.onap.aai.introspection.sideeffect; -import java.io.UnsupportedEncodingException; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.Collections; -import java.util.List; -import java.util.Map.Entry; -import java.util.Objects; -import java.util.Optional; - -import javax.ws.rs.core.MultivaluedMap; - import org.apache.tinkerpop.gremlin.structure.Vertex; import org.onap.aai.exceptions.AAIException; import org.onap.aai.introspection.Introspector; @@ -42,6 +31,16 @@ import org.onap.aai.schema.enums.PropertyMetadata; import org.onap.aai.serialization.db.DBSerializer; import org.onap.aai.serialization.engines.TransactionalGraphEngine; +import javax.ws.rs.core.MultivaluedMap; +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Collections; +import java.util.List; +import java.util.Map.Entry; +import java.util.Objects; +import java.util.Optional; + public class DataCopy extends SideEffect { public DataCopy(Introspector obj, Vertex self, TransactionalGraphEngine dbEngine, DBSerializer serializer) { @@ -69,14 +68,12 @@ public class DataCopy extends SideEffect { } else { if (results.isEmpty()) { throw new AAIException("AAI_6114", "object located at " + uri + " not found"); - } else if (results.size() > 1) { + } else { throw new AAIMultiplePropertiesException( "multiple values of " + entry.getKey() + " found when searching " + uri); } } - } else { - // skip processing because no required properties were specified - } + } //else skip processing because no required properties were specified } @Override diff --git a/aai-core/src/main/java/org/onap/aai/introspection/sideeffect/PrivateEdge.java b/aai-core/src/main/java/org/onap/aai/introspection/sideeffect/PrivateEdge.java index f4f0bfac..06586317 100644 --- a/aai-core/src/main/java/org/onap/aai/introspection/sideeffect/PrivateEdge.java +++ b/aai-core/src/main/java/org/onap/aai/introspection/sideeffect/PrivateEdge.java @@ -21,15 +21,6 @@ package org.onap.aai.introspection.sideeffect; import com.google.common.collect.Multimap; - -import java.io.UnsupportedEncodingException; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.*; -import java.util.Map.Entry; - -import javax.ws.rs.core.MultivaluedMap; - import org.apache.tinkerpop.gremlin.structure.Edge; import org.apache.tinkerpop.gremlin.structure.Vertex; import org.apache.tinkerpop.gremlin.structure.VertexProperty; @@ -42,7 +33,10 @@ import org.onap.aai.edges.enums.EdgeType; import org.onap.aai.edges.exceptions.AmbiguousRuleChoiceException; import org.onap.aai.edges.exceptions.EdgeRuleNotFoundException; import org.onap.aai.exceptions.AAIException; -import org.onap.aai.introspection.*; +import org.onap.aai.introspection.Introspector; +import org.onap.aai.introspection.Loader; +import org.onap.aai.introspection.LoaderFactory; +import org.onap.aai.introspection.ModelType; import org.onap.aai.introspection.sideeffect.exceptions.AAIMultiplePropertiesException; import org.onap.aai.parsers.query.QueryParser; import org.onap.aai.restcore.util.URITools; @@ -52,6 +46,13 @@ import org.onap.aai.serialization.db.EdgeSerializer; import org.onap.aai.serialization.db.exceptions.EdgeMultiplicityException; import org.onap.aai.serialization.engines.TransactionalGraphEngine; +import javax.ws.rs.core.MultivaluedMap; +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.*; +import java.util.Map.Entry; + public class PrivateEdge extends SideEffect { public PrivateEdge(Introspector obj, Vertex self, TransactionalGraphEngine dbEngine, DBSerializer serializer) { @@ -111,40 +112,38 @@ public class PrivateEdge extends SideEffect { throw new EdgeMultiplicityException(message); } - for (Entry<String, EdgeRule> edgeEntry : edgeRulesMap.entries()) { - EdgeRule edgeRule = edgeIngestor.getRule(edgeQuery); - Iterator<Edge> edges = self.edges(edgeRule.getDirection(), edgeRule.getLabel().toString()); - if (edges.hasNext()) { - Edge edge = edges.next(); - EdgeStatus status = checkStatus(obj, self); - switch (status) { - case CREATED: - edgeSerializer.addPrivateEdge(this.dbEngine.asAdmin().getTraversalSource(), self, - otherVertex, edgeRule.getLabel()); - break; - case MODIFIED: - edge.remove(); - edgeSerializer.addPrivateEdge(this.dbEngine.asAdmin().getTraversalSource(), self, - otherVertex, edgeRule.getLabel()); - break; - case REMOVED: - edge.remove(); - break; - case UNCHANGED: - break; - } - } else { - edgeSerializer.addPrivateEdge(this.dbEngine.asAdmin().getTraversalSource(), self, - otherVertex, edgeRule.getLabel()); + EdgeRule edgeRule = edgeIngestor.getRule(edgeQuery); + Iterator<Edge> edges = self.edges(edgeRule.getDirection(), edgeRule.getLabel()); + if (edges.hasNext()) { + Edge edge = edges.next(); + EdgeStatus status = checkStatus(obj, self); + switch (status) { + case CREATED: + edgeSerializer.addPrivateEdge(this.dbEngine.asAdmin().getTraversalSource(), self, + otherVertex, edgeRule.getLabel()); + break; + case MODIFIED: + edge.remove(); + edgeSerializer.addPrivateEdge(this.dbEngine.asAdmin().getTraversalSource(), self, + otherVertex, edgeRule.getLabel()); + break; + case REMOVED: + edge.remove(); + break; + case UNCHANGED: + break; } + } else { + edgeSerializer.addPrivateEdge(this.dbEngine.asAdmin().getTraversalSource(), self, + otherVertex, edgeRule.getLabel()); } } } else { if (results.isEmpty()) { throw new AAIException("AAI_6114", "object located at " + uri + " not found"); - } else if (results.size() > 1) { + } else { throw new AAIMultiplePropertiesException( - "multiple values of " + entry.getKey() + " found when searching " + uri); + "multiple values of " + entry.getKey() + " found when searching " + uri); } } } @@ -159,7 +158,7 @@ public class PrivateEdge extends SideEffect { for (String key : templateKeys) { String currentObjValue = obj.getValue(key); Map<PropertyMetadata, String> map = obj.getPropertyMetadata(key); - String oldVertexValue = null; + String oldVertexValue; if (map.containsKey(PropertyMetadata.DB_ALIAS)) { oldVertexValue = self.<String>property(key + AAIProperties.DB_ALIAS_SUFFIX).orElse(null); diff --git a/aai-core/src/main/java/org/onap/aai/introspection/sideeffect/SideEffect.java b/aai-core/src/main/java/org/onap/aai/introspection/sideeffect/SideEffect.java index d86c18a0..a71ffa4e 100644 --- a/aai-core/src/main/java/org/onap/aai/introspection/sideeffect/SideEffect.java +++ b/aai-core/src/main/java/org/onap/aai/introspection/sideeffect/SideEffect.java @@ -20,8 +20,8 @@ package org.onap.aai.introspection.sideeffect; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.UnsupportedEncodingException; import java.net.URISyntaxException; @@ -46,7 +46,7 @@ import org.onap.aai.setup.SchemaVersions; public abstract class SideEffect { protected static final Pattern template = Pattern.compile("\\{(.*?)\\}"); - private static final EELFLogger logger = EELFManager.getInstance().getLogger(SideEffect.class); + private static final Logger logger = LoggerFactory.getLogger(SideEffect.class); protected final Introspector obj; protected final TransactionalGraphEngine dbEngine; diff --git a/aai-core/src/main/java/org/onap/aai/introspection/sideeffect/SideEffectRunner.java b/aai-core/src/main/java/org/onap/aai/introspection/sideeffect/SideEffectRunner.java index ffd9a8c8..8bc83156 100644 --- a/aai-core/src/main/java/org/onap/aai/introspection/sideeffect/SideEffectRunner.java +++ b/aai-core/src/main/java/org/onap/aai/introspection/sideeffect/SideEffectRunner.java @@ -20,8 +20,8 @@ package org.onap.aai.introspection.sideeffect; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.UnsupportedEncodingException; import java.lang.reflect.InvocationTargetException; diff --git a/aai-core/src/main/java/org/onap/aai/logging/EcompElapsedTime.java b/aai-core/src/main/java/org/onap/aai/logging/EcompElapsedTime.java deleted file mode 100644 index 66d27868..00000000 --- a/aai-core/src/main/java/org/onap/aai/logging/EcompElapsedTime.java +++ /dev/null @@ -1,66 +0,0 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aai - * ================================================================================ - * Copyright © 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========================================================= - */ - -package org.onap.aai.logging; - -import ch.qos.logback.classic.pattern.ClassicConverter; -import ch.qos.logback.classic.spi.ILoggingEvent; - -import org.onap.aai.logging.LoggingContext.LoggingField; - -public class EcompElapsedTime extends ClassicConverter { - - private static final String DEFAULT_ELAPSED_TIME_FORMAT = "%d"; - - private String ELAPSED_TIME_FORMAT; - - @Override - public void start() { - ELAPSED_TIME_FORMAT = getFirstOption(); - } - - @Override - public String convert(ILoggingEvent event) { - final long end = event.getTimeStamp(); - - if (!event.getMDCPropertyMap().containsKey(LoggingField.START_TIME.toString())) { - return format(0); - } else if (event.getMDCPropertyMap().containsKey(LoggingField.ELAPSED_TIME.toString())) { - return format(Integer.parseInt(event.getMDCPropertyMap().get(LoggingField.ELAPSED_TIME.toString()))); - } - - final long start = - LogFormatTools.toTimestamp(event.getMDCPropertyMap().get(LoggingField.START_TIME.toString())); - - return format(end - start); - } - - private String format(long elapsedTime) { - if (ELAPSED_TIME_FORMAT == null) { - return format(DEFAULT_ELAPSED_TIME_FORMAT, elapsedTime); - } - - return format(ELAPSED_TIME_FORMAT, elapsedTime); - } - - private String format(String format, long elapsedTime) { - return String.format(format, elapsedTime); - } -} diff --git a/aai-core/src/main/java/org/onap/aai/logging/EcompPatternLayout.java b/aai-core/src/main/java/org/onap/aai/logging/EcompPatternLayout.java deleted file mode 100644 index 43c147a0..00000000 --- a/aai-core/src/main/java/org/onap/aai/logging/EcompPatternLayout.java +++ /dev/null @@ -1,36 +0,0 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aai - * ================================================================================ - * Copyright © 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========================================================= - */ - -package org.onap.aai.logging; - -import ch.qos.logback.classic.PatternLayout; - -public class EcompPatternLayout extends PatternLayout { - static { - PatternLayout.defaultConverterMap.put("ecompStartTime", EcompStartTime.class.getName()); - PatternLayout.defaultConverterMap.put("ecompElapsedTime", EcompElapsedTime.class.getName()); - PatternLayout.defaultConverterMap.put("eelfClassOfCaller", EelfClassOfCaller.class.getName()); - PatternLayout.defaultConverterMap.put("ecompErrorCategory", EcompErrorCategory.class.getName()); - PatternLayout.defaultConverterMap.put("ecompResponseCode", EcompResponseCode.class.getName()); - PatternLayout.defaultConverterMap.put("ecompResponseDescription", EcompResponseDescription.class.getName()); - PatternLayout.defaultConverterMap.put("ecompStatusCode", EcompStatusCode.class.getName()); - PatternLayout.defaultConverterMap.put("ecompServiceName", EcompServiceName.class.getName()); - } -} diff --git a/aai-core/src/main/java/org/onap/aai/logging/EcompResponseCode.java b/aai-core/src/main/java/org/onap/aai/logging/EcompResponseCode.java deleted file mode 100644 index 1dc59b4e..00000000 --- a/aai-core/src/main/java/org/onap/aai/logging/EcompResponseCode.java +++ /dev/null @@ -1,39 +0,0 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aai - * ================================================================================ - * Copyright © 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========================================================= - */ - -package org.onap.aai.logging; - -import ch.qos.logback.classic.pattern.ClassicConverter; -import ch.qos.logback.classic.spi.ILoggingEvent; - -import org.onap.aai.logging.LoggingContext.LoggingField; - -public class EcompResponseCode extends ClassicConverter { - - @Override - public String convert(ILoggingEvent event) { - - if (!event.getMDCPropertyMap().containsKey(LoggingField.RESPONSE_CODE.toString())) { - // if response code is not set, return "unknown" (900) - return LoggingContext.UNKNOWN_ERROR; - } - return event.getMDCPropertyMap().get(LoggingField.RESPONSE_CODE.toString()); - } -} diff --git a/aai-core/src/main/java/org/onap/aai/logging/EcompResponseDescription.java b/aai-core/src/main/java/org/onap/aai/logging/EcompResponseDescription.java deleted file mode 100644 index b72cc100..00000000 --- a/aai-core/src/main/java/org/onap/aai/logging/EcompResponseDescription.java +++ /dev/null @@ -1,47 +0,0 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aai - * ================================================================================ - * Copyright © 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========================================================= - */ - -package org.onap.aai.logging; - -import ch.qos.logback.classic.pattern.ClassicConverter; -import ch.qos.logback.classic.spi.ILoggingEvent; -import org.onap.aai.logging.LoggingContext.LoggingField; - -public class EcompResponseDescription extends ClassicConverter { - public static final String DEFAULT_DESCRIPTION = "Unknown response/error description"; - - @Override - public String convert(ILoggingEvent event) { - - if (!event.getMDCPropertyMap().containsKey(LoggingField.RESPONSE_DESCRIPTION.toString())) { - return (DEFAULT_DESCRIPTION); - } - // Replace pipes and new lines - String currentDesc = event.getMDCPropertyMap().get(LoggingField.RESPONSE_DESCRIPTION.toString()); - if ((currentDesc == null) || (currentDesc.length() == 0)) { - return (DEFAULT_DESCRIPTION); - } - currentDesc = currentDesc.replaceAll("\\|", "!"); - currentDesc = currentDesc.replaceAll("[\\r\\n]+", "^"); - return event.getMDCPropertyMap().get(currentDesc); - } -} - - diff --git a/aai-core/src/main/java/org/onap/aai/logging/EcompStatusCode.java b/aai-core/src/main/java/org/onap/aai/logging/EcompStatusCode.java deleted file mode 100644 index 4319bbbd..00000000 --- a/aai-core/src/main/java/org/onap/aai/logging/EcompStatusCode.java +++ /dev/null @@ -1,36 +0,0 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aai - * ================================================================================ - * Copyright © 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========================================================= - */ - -package org.onap.aai.logging; - -import ch.qos.logback.classic.pattern.ClassicConverter; -import ch.qos.logback.classic.spi.ILoggingEvent; - -import org.onap.aai.logging.LoggingContext.LoggingField; - -public class EcompStatusCode extends ClassicConverter { - @Override - public String convert(ILoggingEvent event) { - if (!event.getMDCPropertyMap().containsKey(LoggingField.STATUS_CODE.toString())) { - return LoggingContext.StatusCode.COMPLETE.toString(); - } - return event.getMDCPropertyMap().get(LoggingField.STATUS_CODE.toString()); - } -} diff --git a/aai-core/src/main/java/org/onap/aai/logging/EelfClassOfCaller.java b/aai-core/src/main/java/org/onap/aai/logging/EelfClassOfCaller.java deleted file mode 100644 index dc9bc2c2..00000000 --- a/aai-core/src/main/java/org/onap/aai/logging/EelfClassOfCaller.java +++ /dev/null @@ -1,43 +0,0 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aai - * ================================================================================ - * Copyright © 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========================================================= - */ - -package org.onap.aai.logging; - -import ch.qos.logback.classic.pattern.NamedConverter; -import ch.qos.logback.classic.spi.CallerData; -import ch.qos.logback.classic.spi.ILoggingEvent; - -public class EelfClassOfCaller extends NamedConverter { - protected String getFullyQualifiedName(ILoggingEvent event) { - - StackTraceElement[] cda = event.getCallerData(); - - // If using the EELFLogger, it "hides" the calling class because it wraps the logging calls - // Without this, you'd only ever see "EELF SLF4jWrapper" when using the - // %C pattern converter - if (cda != null && cda.length > 2) { - return cda[2].getClassName(); - } else if (cda != null && cda.length > 0) { - return cda[0].getClassName(); - } else { - return CallerData.NA; - } - } -} diff --git a/aai-core/src/main/java/org/onap/aai/logging/LoggingContext.java b/aai-core/src/main/java/org/onap/aai/logging/LoggingContext.java deleted file mode 100644 index 5630fd10..00000000 --- a/aai-core/src/main/java/org/onap/aai/logging/LoggingContext.java +++ /dev/null @@ -1,417 +0,0 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aai - * ================================================================================ - * Copyright © 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========================================================= - */ - -package org.onap.aai.logging; - -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; - -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.TimeUnit; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; -import org.slf4j.MDC; - -public class LoggingContext { - - public enum StatusCode { - COMPLETE, ERROR - } - - private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(LoggingContext.class); - - private static final String PREVIOUS_CONTEXTS_KEY = "_PREVIOUS_CONTEXTS"; - - // Response codes from Logging Guidelines - public static final String SUCCESS = "0"; - public static final String PERMISSION_ERROR = "100"; - public static final String AVAILABILITY_TIMEOUT_ERROR = "200"; - public static final String DATA_ERROR = "300"; - public static final String SCHEMA_ERROR = "400"; - public static final String BUSINESS_PROCESS_ERROR = "500"; - public static final String UNKNOWN_ERROR = "900"; - - protected static final Map<String, String> responseMap = new HashMap(); - - static { - responseMap.put(SUCCESS, "Success"); - responseMap.put(UNKNOWN_ERROR, "Unknown error"); - } - - // Specific Log Event Fields - public enum LoggingField { - START_TIME("startTime"), REQUEST_ID("requestId"), SERVICE_INSTANCE_ID("serviceInstanceId"), SERVER_NAME( - "serverName"), SERVICE_NAME("serviceName"), PARTNER_NAME("partnerName"), STATUS_CODE( - "statusCode"), RESPONSE_CODE("responseCode"), RESPONSE_DESCRIPTION( - "responseDescription"), INSTANCE_UUID("instanceUUID"), SEVERITY( - "severity"), SERVER_IP_ADDRESS( - "serverIpAddress"), ELAPSED_TIME("elapsedTime"), SERVER( - "server"), CLIENT_IP_ADDRESS("clientIpAddress"), UNUSED( - "unused"), PROCESS_KEY("processKey"), CUSTOM_FIELD_1( - "customField1"), CUSTOM_FIELD_2( - "customField2"), CUSTOM_FIELD_3( - "customField3"), CUSTOM_FIELD_4( - "customField4"), - - // Specific Metric Log Event Fields - TARGET_ENTITY("targetEntity"), TARGET_SERVICE_NAME("targetServiceName"), - // A&AI Specific Log Event Fields - COMPONENT("component"), STOP_WATCH_START("stopWatchStart"); - - private final String text; - - private LoggingField(final String text) { - this.text = text; - } - - @Override - public String toString() { - return text; - } - } - - public static void init() { - LoggingContext.clear(); - LoggingContext.startTime(); - LoggingContext.server(); - LoggingContext.serverIpAddress(); - } - - public static void startTime() { - MDC.put(LoggingField.START_TIME.toString(), LogFormatTools.getCurrentDateTime()); - } - - public static UUID requestId() { - final String sUuid = MDC.get(LoggingField.REQUEST_ID.toString()); - - if (sUuid == null) - return null; - - return UUID.fromString(sUuid); - } - - public static void requestId(UUID requestId) { - MDC.put(LoggingField.REQUEST_ID.toString(), requestId.toString()); - } - - public static void requestId(String requestId) { - try { - if (requestId.contains(":")) { - String[] uuidParts = requestId.split(":"); - requestId = uuidParts[0]; - } - MDC.put(LoggingField.REQUEST_ID.toString(), UUID.fromString(requestId).toString()); - } catch (IllegalArgumentException e) { - final UUID generatedRequestUuid = UUID.randomUUID(); - MDC.put(LoggingField.REQUEST_ID.toString(), generatedRequestUuid.toString()); - LoggingContext.save(); - // set response code to 0 since we don't know what the outcome of this request is yet - String responseCode = LoggingContext.DATA_ERROR; - LoggingContext.responseCode(responseCode); - LoggingContext.responseDescription("Unable to use UUID " + requestId + " (Not formatted properly) "); - LoggingContext.statusCode(StatusCode.ERROR); - - LOGGER.warn("Using generated UUID=" + generatedRequestUuid); - LoggingContext.restore(); - - } - } - - public static void serviceInstanceId(String serviceInstanceId) { - MDC.put(LoggingField.SERVICE_INSTANCE_ID.toString(), serviceInstanceId); - } - - public static void serverName(String serverName) { - MDC.put(LoggingField.SERVER_NAME.toString(), serverName); - } - - public static void serviceName(String serviceName) { - MDC.put(LoggingField.SERVICE_NAME.toString(), serviceName); - } - - public static void partnerName(String partnerName) { - MDC.put(LoggingField.PARTNER_NAME.toString(), partnerName); - } - - public static void statusCode(StatusCode statusCode) { - MDC.put(LoggingField.STATUS_CODE.toString(), statusCode.toString()); - } - - public static String responseCode() { - return MDC.get(LoggingField.RESPONSE_CODE.toString()); - } - - public static void responseCode(String responseCode) { - MDC.put(LoggingField.RESPONSE_CODE.toString(), responseCode); - } - - public static void responseDescription(String responseDescription) { - MDC.put(LoggingField.RESPONSE_DESCRIPTION.toString(), responseDescription); - } - - public static Object instanceUuid() { - return UUID.fromString(MDC.get(LoggingField.INSTANCE_UUID.toString())); - } - - public static void instanceUuid(UUID instanceUuid) { - MDC.put(LoggingField.INSTANCE_UUID.toString(), instanceUuid.toString()); - } - - public static void severity(int severity) { - MDC.put(LoggingField.SEVERITY.toString(), String.valueOf(severity)); - } - - public static void successStatusFields() { - responseCode(SUCCESS); - statusCode(StatusCode.COMPLETE); - responseDescription("Success"); - } - - private static void serverIpAddress() { - try { - MDC.put(LoggingField.SERVER_IP_ADDRESS.toString(), InetAddress.getLocalHost().getHostAddress()); - } catch (UnknownHostException e) { - LOGGER.warn("Unable to resolve server IP address - will not be displayed in logged events"); - } - } - - public static void elapsedTime(long elapsedTime, TimeUnit timeUnit) { - MDC.put(LoggingField.ELAPSED_TIME.toString(), - String.valueOf(TimeUnit.MILLISECONDS.convert(elapsedTime, timeUnit))); - } - - private static void server() { - try { - MDC.put(LoggingField.SERVER.toString(), InetAddress.getLocalHost().getCanonicalHostName()); - } catch (UnknownHostException e) { - LOGGER.warn("Unable to resolve server IP address - hostname will not be displayed in logged events"); - } - } - - public static void clientIpAddress(InetAddress clientIpAddress) { - MDC.put(LoggingField.CLIENT_IP_ADDRESS.toString(), clientIpAddress.getHostAddress()); - } - - public static void clientIpAddress(String clientIpAddress) { - try { - MDC.put(LoggingField.CLIENT_IP_ADDRESS.toString(), InetAddress.getByName(clientIpAddress).getHostAddress()); - } catch (UnknownHostException e) { - // Ignore, will not be thrown since InetAddress.getByName(String) only - // checks the validity of the passed in string - } - } - - public static void unused(String unused) { - LOGGER.warn("Using field '" + LoggingField.UNUSED + "' (seems like this should go unused...)"); - MDC.put(LoggingField.UNUSED.toString(), unused); - } - - public static void processKey(String processKey) { - MDC.put(LoggingField.PROCESS_KEY.toString(), processKey); - } - - public static String customField1() { - return MDC.get(LoggingField.CUSTOM_FIELD_1.toString()); - } - - public static void customField1(String customField1) { - MDC.put(LoggingField.CUSTOM_FIELD_1.toString(), customField1); - } - - public static void customField2(String customField2) { - MDC.put(LoggingField.CUSTOM_FIELD_2.toString(), customField2); - } - - public static void customField3(String customField3) { - MDC.put(LoggingField.CUSTOM_FIELD_3.toString(), customField3); - } - - public static void customField4(String customField4) { - MDC.put(LoggingField.CUSTOM_FIELD_4.toString(), customField4); - } - - public static void component(String component) { - MDC.put(LoggingField.COMPONENT.toString(), component); - } - - public static void targetEntity(String targetEntity) { - MDC.put(LoggingField.TARGET_ENTITY.toString(), targetEntity); - } - - public static void targetServiceName(String targetServiceName) { - MDC.put(LoggingField.TARGET_SERVICE_NAME.toString(), targetServiceName); - } - - public static boolean isStopWatchStarted() { - final String rawStopWatchStart = MDC.get(LoggingField.STOP_WATCH_START.toString()); - return rawStopWatchStart != null; - } - - public static void stopWatchStart() { - MDC.put(LoggingField.STOP_WATCH_START.toString(), String.valueOf(System.nanoTime())); - } - - public static double stopWatchStop() { - final long stopWatchEnd = System.nanoTime(); - final String rawStopWatchStart = MDC.get(LoggingField.STOP_WATCH_START.toString()); - - if (rawStopWatchStart == null) - throw new StopWatchNotStartedException(); - - final Long stopWatchStart = Long.valueOf(rawStopWatchStart); - - MDC.remove(LoggingField.STOP_WATCH_START.toString()); - - final double elapsedTimeMillis = (stopWatchEnd - stopWatchStart) / 1000.0 / 1000.0; - - LoggingContext.elapsedTime((long) elapsedTimeMillis, TimeUnit.MILLISECONDS); - - return elapsedTimeMillis; - } - - public static void put(String key, String value) { - MDC.put(key, value); - } - - public static void clear() { - MDC.clear(); - } - - public static void remove(String key) { - MDC.remove(key); - } - - public static void save() { - final JSONObject context = new JSONObject(); - - for (LoggingField field : LoggingField.values()) { - if (field == LoggingField.ELAPSED_TIME) - continue; - - try { - context.put(field.toString(), MDC.get(field.toString())); - } catch (JSONException e) { - // Ignore - only occurs when the key is null (which can't happen) - // or the value is invalid (everything is converted to a string - // before it get put() to the MDC) - } - } - - final String rawJsonArray = MDC.get(PREVIOUS_CONTEXTS_KEY); - - if (rawJsonArray == null) { - final JSONArray stack = new JSONArray().put(context); - - MDC.put(PREVIOUS_CONTEXTS_KEY, stack.toString()); - } else { - try { - final JSONArray stack = new JSONArray(rawJsonArray).put(context); - - MDC.put(PREVIOUS_CONTEXTS_KEY, stack.toString()); - } catch (JSONException e) { - // Ignore - } - } - } - - public static void restore() { - - final String rawPreviousContexts = MDC.get(PREVIOUS_CONTEXTS_KEY); - - if (rawPreviousContexts == null) { - throw new LoggingContextNotExistsException(); - } - - try { - final JSONArray previousContexts = new JSONArray(rawPreviousContexts); - final JSONObject previousContext = previousContexts.getJSONObject(previousContexts.length() - 1); - - @SuppressWarnings("unchecked") - final Iterator<String> keys = previousContext.keys(); - boolean foundElapsedTime = false; - while (keys.hasNext()) { - final String key = keys.next(); - if (LoggingField.ELAPSED_TIME.toString().equals(key)) { - foundElapsedTime = true; - } - try { - MDC.put(key, previousContext.getString(key)); - } catch (JSONException e) { - // Ignore, only occurs when the key is null (cannot happen) - // or the value is invalid (they are all strings) - } - } - if (!foundElapsedTime) { - MDC.remove(LoggingField.ELAPSED_TIME.toString()); - } - MDC.put(PREVIOUS_CONTEXTS_KEY, removeLast(previousContexts).toString()); - } catch (JSONException e) { - // Ignore, the previousContext is serialized from a JSONObject - } - } - - public static void restoreIfPossible() { - try { - restore(); - } catch (LoggingContextNotExistsException e) { - // Ignore - } - } - - /** - * AJSC declares an ancient version of org.json:json in one of the parent POMs of this project. - * I tried to update our version of that library in our POM, but it's ignored because of the way - * AJSC has organized their <dependencies>. Had they put it into the <dependencyManagement> section, - * this method would not be necessary. - */ - private static JSONArray removeLast(JSONArray previousContexts) { - final JSONArray result = new JSONArray(); - - for (int i = 0; i < previousContexts.length() - 1; i++) { - try { - result.put(previousContexts.getJSONObject(i)); - } catch (JSONException e) { - // Ignore - not possible - } - } - - return result; - } - - public static Map<String, String> getCopy() { - final Map<String, String> copy = new HashMap<>(); - - for (LoggingField field : LoggingField.values()) { - final String value = MDC.get(field.toString()); - - if (value != null) - copy.put(field.toString(), value); - } - - return copy; - } -} diff --git a/aai-core/src/main/java/org/onap/aai/parsers/query/LegacyQueryParser.java b/aai-core/src/main/java/org/onap/aai/parsers/query/LegacyQueryParser.java index c9412733..ca735357 100644 --- a/aai-core/src/main/java/org/onap/aai/parsers/query/LegacyQueryParser.java +++ b/aai-core/src/main/java/org/onap/aai/parsers/query/LegacyQueryParser.java @@ -20,8 +20,8 @@ package org.onap.aai.parsers.query; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.UnsupportedEncodingException; import java.net.URI; @@ -49,7 +49,7 @@ import org.onap.aai.schema.enums.PropertyMetadata; */ public class LegacyQueryParser extends QueryParser implements Parsable { - private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(LegacyQueryParser.class); + private static final Logger LOGGER = LoggerFactory.getLogger(LegacyQueryParser.class); private Introspector previous = null; diff --git a/aai-core/src/main/java/org/onap/aai/parsers/query/RelationshipQueryParser.java b/aai-core/src/main/java/org/onap/aai/parsers/query/RelationshipQueryParser.java index 0958a81e..e1319802 100644 --- a/aai-core/src/main/java/org/onap/aai/parsers/query/RelationshipQueryParser.java +++ b/aai-core/src/main/java/org/onap/aai/parsers/query/RelationshipQueryParser.java @@ -20,8 +20,8 @@ package org.onap.aai.parsers.query; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.UnsupportedEncodingException; @@ -41,7 +41,7 @@ import org.springframework.context.ApplicationContext; */ public class RelationshipQueryParser extends LegacyQueryParser { - private static final EELFLogger logger = EELFManager.getInstance().getLogger(RelationshipQueryParser.class); + private static final Logger logger = LoggerFactory.getLogger(RelationshipQueryParser.class); private Introspector relationship = null; diff --git a/aai-core/src/main/java/org/onap/aai/parsers/relationship/RelationshipToURI.java b/aai-core/src/main/java/org/onap/aai/parsers/relationship/RelationshipToURI.java index 0b072b88..0ee22f50 100644 --- a/aai-core/src/main/java/org/onap/aai/parsers/relationship/RelationshipToURI.java +++ b/aai-core/src/main/java/org/onap/aai/parsers/relationship/RelationshipToURI.java @@ -20,8 +20,8 @@ package org.onap.aai.parsers.relationship; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.UnsupportedEncodingException; import java.net.URI; @@ -57,7 +57,7 @@ import org.springframework.context.ApplicationContext; */ public class RelationshipToURI { - private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(RelationshipToURI.class); + private static final Logger LOGGER = LoggerFactory.getLogger(RelationshipToURI.class); private Introspector relationship = null; diff --git a/aai-core/src/main/java/org/onap/aai/prevalidation/Validation.java b/aai-core/src/main/java/org/onap/aai/prevalidation/Validation.java new file mode 100644 index 00000000..d420c558 --- /dev/null +++ b/aai-core/src/main/java/org/onap/aai/prevalidation/Validation.java @@ -0,0 +1,92 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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========================================================= + */ +package org.onap.aai.prevalidation; + +import com.google.gson.annotations.SerializedName; + +import java.util.List; +import java.util.Objects; + +public class Validation { + + @SerializedName("validationId") + private String validationId; + + @SerializedName("action") + private String action; + + @SerializedName("violations") + private List<Violation> violations; + + public String getValidationId() { + return validationId; + } + + public void setValidationId(String validationId) { + this.validationId = validationId; + } + + public List<Violation> getViolations() { + return violations; + } + + public void setViolations(List<Violation> violations) { + this.violations = violations; + } + + public String getAction() { + return action; + } + + public void setAction(String action) { + this.action = action; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Validation that = (Validation) o; + return Objects.equals(validationId, that.validationId) && + Objects.equals(action, that.action) && + Objects.equals(violations, that.violations); + } + + @Override + public int hashCode() { + return Objects.hash(validationId, action, violations); + } + + @Override + public String toString() { + return "Validation{" + + "validationId='" + validationId + '\'' + + ", action='" + action + '\'' + + ", violations=" + violations + + '}'; + } + +} diff --git a/aai-core/src/main/java/org/onap/aai/prevalidation/ValidationConfiguration.java b/aai-core/src/main/java/org/onap/aai/prevalidation/ValidationConfiguration.java new file mode 100644 index 00000000..36569dd0 --- /dev/null +++ b/aai-core/src/main/java/org/onap/aai/prevalidation/ValidationConfiguration.java @@ -0,0 +1,51 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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========================================================= + */ +package org.onap.aai.prevalidation; + +import org.onap.aai.restclient.RestClient; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; + +@Profile("pre-validation") +@Configuration +public class ValidationConfiguration { + + @Bean(name = "validationRestClient") + @ConditionalOnProperty(name = "validation.service.client", havingValue = "two-way-ssl", matchIfMissing = true) + public RestClient validationRestClientTwoWaySSL() { + return new ValidationServiceRestClient(); + } + + @Bean(name = "validationRestClient") + @ConditionalOnProperty(name = "validation.service.client", havingValue = "no-auth") + public RestClient validationRestClientNoAuth() { + return new ValidationServiceNoAuthClient(); + } + + @Bean(name = "validationRestClient") + @ConditionalOnProperty(name = "validation.service.client", havingValue = "one-way-ssl") + public RestClient validationRestClientOneWaySSL() { + return new ValidationServiceOneWayClient(); + } +} diff --git a/aai-core/src/main/java/org/onap/aai/prevalidation/ValidationService.java b/aai-core/src/main/java/org/onap/aai/prevalidation/ValidationService.java new file mode 100644 index 00000000..78083ecb --- /dev/null +++ b/aai-core/src/main/java/org/onap/aai/prevalidation/ValidationService.java @@ -0,0 +1,299 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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========================================================= + */ +package org.onap.aai.prevalidation; + +import com.google.gson.Gson; +import com.google.gson.JsonSyntaxException; +import org.apache.http.conn.ConnectTimeoutException; +import org.onap.aai.exceptions.AAIException; +import org.onap.aai.introspection.Introspector; +import org.onap.aai.rest.ueb.NotificationEvent; +import org.onap.aai.restclient.RestClient; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Profile; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +import javax.annotation.PostConstruct; +import java.net.ConnectException; +import java.net.SocketTimeoutException; +import java.util.*; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +/** + * <b>ValidationService</b> routes all the writes to the database + * excluding deletes for now to the validation service to verify + * that the request is an valid one before committing to the database + */ +@Service +@Profile("pre-validation") +public class ValidationService { + + /** + * Error indicating that the service trying to connect is down + */ + static final String CONNECTION_REFUSED_STRING = + "Connection refused to the validation microservice due to service unreachable"; + + /** + * Error indicating that the server is unable to reach the port + * Could be server related connectivity issue + */ + static final String CONNECTION_TIMEOUT_STRING = + "Connection timeout to the validation microservice as this could " + + "indicate the server is unable to reach port, " + + "please check on server by running: nc -w10 -z -v ${VALIDATION_HOST} ${VALIDATION_PORT}"; + + /** + * Error indicating that the request exceeded the allowed time + * + * Note: This means that the service could be active its + * just taking some time to process our request + */ + static final String REQUEST_TIMEOUT_STRING = + "Request to validation service took longer than the currently set timeout"; + + static final String VALIDATION_ENDPOINT = "/v1/app/validate"; + static final String VALIDATION_HEALTH_ENDPOINT = "/v1/core/core-service/info"; + + private static final String ENTITY_TYPE = "entity-type"; + private static final String ACTION = "action"; + private static final String SOURCE_NAME = "source-name"; + + private static final String DELETE = "DELETE"; + + private static final Logger LOGGER = LoggerFactory.getLogger(ValidationService.class); + + private final RestClient validationRestClient; + + private final String appName; + + private final Set<String> validationNodeTypes; + + private List<Pattern> exclusionList; + + private final Gson gson; + + @Autowired + public ValidationService( + @Qualifier("validationRestClient") RestClient validationRestClient, + @Value("${spring.application.name}") String appName, + @Value("${validation.service.node-types}") String validationNodes, + @Value("${validation.service.exclusion-regexes}") String exclusionRegexes + ){ + this.validationRestClient = validationRestClient; + this.appName = appName; + + this.validationNodeTypes = Arrays + .stream(validationNodes.split(",")) + .collect(Collectors.toSet()); + + if(exclusionRegexes == null || exclusionRegexes.isEmpty()){ + this.exclusionList = new ArrayList<>(); + } else { + this.exclusionList = Arrays + .stream(exclusionRegexes.split(",")) + .map(Pattern::compile) + .collect(Collectors.toList()); + } + this.gson = new Gson(); + LOGGER.info("Successfully initialized the pre validation service"); + } + + @PostConstruct + public void initialize() throws AAIException { + + Map<String, String> httpHeaders = new HashMap<>(); + + httpHeaders.put("X-FromAppId", appName); + httpHeaders.put("X-TransactionID", UUID.randomUUID().toString()); + httpHeaders.put("Content-Type", "application/json"); + + ResponseEntity<String> healthCheckResponse = null; + + try { + + healthCheckResponse = validationRestClient.execute( + VALIDATION_HEALTH_ENDPOINT, + HttpMethod.GET, + httpHeaders, + null + ); + + } catch(Exception ex){ + AAIException validationException = new AAIException("AAI_4021", ex); + throw validationException; + } + + if(!isSuccess(healthCheckResponse)){ + throw new AAIException("AAI_4021"); + } + + LOGGER.info("Successfully connected to the validation service endpoint"); + } + + public boolean shouldValidate(String nodeType){ + return this.validationNodeTypes.contains(nodeType); + } + + public void validate(List<NotificationEvent> notificationEvents) throws AAIException { + + if(notificationEvents == null || notificationEvents.isEmpty()){ + return; + } + + { + // Get the first notification and if the source of that notification + // is in one of the regexes then we skip sending it to validation + NotificationEvent notification = notificationEvents.get(0); + Introspector eventHeader = notification.getEventHeader(); + if(eventHeader != null){ + String source = eventHeader.getValue(SOURCE_NAME); + for(Pattern pattern: exclusionList){ + if(pattern.matcher(source).matches()){ + return; + } + } + } + + } + + for (NotificationEvent event : notificationEvents) { + + Introspector eventHeader = event.getEventHeader(); + + if(eventHeader == null){ + // Should I skip processing the request and let it continue + // or fail the request and cause client impact + continue; + } + + String entityType = eventHeader.getValue(ENTITY_TYPE); + String action = eventHeader.getValue(ACTION); + + /** + * Skipping the delete events for now + * Note: Might revisit this later when validation supports DELETE events + */ + if(DELETE.equalsIgnoreCase(action)){ + continue; + } + + if (this.shouldValidate(entityType)) { + List<String> violations = this.preValidate(event.getNotificationEvent()); + if(!violations.isEmpty()){ + AAIException aaiException = new AAIException("AAI_4019"); + aaiException.getTemplateVars().addAll(violations); + throw aaiException; + } + } + } + } + + List<String> preValidate(String body) throws AAIException { + + Map<String, String> httpHeaders = new HashMap<>(); + + httpHeaders.put("X-FromAppId", appName); + httpHeaders.put("X-TransactionID", UUID.randomUUID().toString()); + httpHeaders.put("Content-Type", "application/json"); + + List<String> violations = new ArrayList<>(); + ResponseEntity responseEntity; + try { + + responseEntity = validationRestClient.execute( + VALIDATION_ENDPOINT, + HttpMethod.POST, + httpHeaders, + body + ); + + if(isSuccess(responseEntity)){ + LOGGER.debug("Validation Service returned following response status code {} and body {}", responseEntity.getStatusCodeValue(), responseEntity.getBody()); + } else { + Validation validation = null; + try { + validation = gson.fromJson(responseEntity.getBody().toString(), Validation.class); + } catch(JsonSyntaxException jsonException){ + LOGGER.warn("Unable to convert the response body {}", jsonException.getMessage()); + } + + if(validation == null){ + LOGGER.debug( + "Validation Service following status code {} with body {}", + responseEntity.getStatusCodeValue(), + responseEntity.getBody() + ); + } else { + violations.addAll(extractViolations(validation)); + } + } + } catch(Exception e){ + // If the exception cause is client side timeout + // then proceed as if it passed validation + // resources microservice shouldn't be blocked because of validation service + // is taking too long or if the validation service is down + // Any other exception it should block the request from passing? + if(e.getCause() instanceof SocketTimeoutException){ + LOGGER.error(REQUEST_TIMEOUT_STRING, e.getCause()); + } else if(e.getCause() instanceof ConnectException){ + LOGGER.error(CONNECTION_REFUSED_STRING, e.getCause()); + } else if(e.getCause() instanceof ConnectTimeoutException){ + LOGGER.error(CONNECTION_TIMEOUT_STRING, e.getCause()); + } else { + LOGGER.error("Unknown exception thrown please investigate", e.getCause()); + } + } + return violations; + } + + boolean isSuccess(ResponseEntity responseEntity){ + return responseEntity != null && responseEntity.getStatusCode().is2xxSuccessful(); + } + + List<String> extractViolations(Validation validation) { + + List<String> errorMessages = new ArrayList<>(); + + if(validation == null){ + return errorMessages; + } + + List<Violation> violations = validation.getViolations(); + + if (violations != null && !violations.isEmpty()) { + for (Violation violation : validation.getViolations()) { + LOGGER.info(violation.getErrorMessage()); + errorMessages.add(violation.getErrorMessage()); + } + } + + return errorMessages; + } +} diff --git a/aai-core/src/main/java/org/onap/aai/prevalidation/ValidationServiceNoAuthClient.java b/aai-core/src/main/java/org/onap/aai/prevalidation/ValidationServiceNoAuthClient.java new file mode 100644 index 00000000..d373ae78 --- /dev/null +++ b/aai-core/src/main/java/org/onap/aai/prevalidation/ValidationServiceNoAuthClient.java @@ -0,0 +1,79 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2018-19 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========================================================= + */ + +package org.onap.aai.prevalidation; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.onap.aai.restclient.NoAuthRestClient; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.util.MultiValueMap; + +import java.util.Collections; +import java.util.Map; +import java.util.UUID; + +public class ValidationServiceNoAuthClient extends NoAuthRestClient { + + private static Logger logger = LoggerFactory.getLogger(ValidationServiceNoAuthClient.class); + + @Value("${validation.service.base.url}") + private String baseUrl; + + @Value("${validation.service.timeout-in-milliseconds}") + private Integer timeout; + + @Override + protected HttpComponentsClientHttpRequestFactory getHttpRequestFactory() throws Exception { + HttpComponentsClientHttpRequestFactory requestFactory = super.getHttpRequestFactory(); + requestFactory.setConnectionRequestTimeout(timeout); + requestFactory.setReadTimeout(timeout); + requestFactory.setConnectTimeout(timeout); + return requestFactory; + } + + @Override + public String getBaseUrl() { + return baseUrl; + } + + @Override + public MultiValueMap<String, String> getHeaders(Map<String, String> headers) { + HttpHeaders httpHeaders = new HttpHeaders(); + + String defaultAccept = headers.getOrDefault(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON.toString()); + String defaultContentType = + headers.getOrDefault(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON.toString()); + + if (headers.isEmpty()) { + httpHeaders.setAccept(Collections.singletonList(MediaType.parseMediaType(defaultAccept))); + httpHeaders.setContentType(MediaType.parseMediaType(defaultContentType)); + } + + httpHeaders.add("X-FromAppId", appName); + httpHeaders.add("X-TransactionId", UUID.randomUUID().toString()); + headers.forEach(httpHeaders::add); + return httpHeaders; + } + +} diff --git a/aai-core/src/main/java/org/onap/aai/prevalidation/ValidationServiceOneWayClient.java b/aai-core/src/main/java/org/onap/aai/prevalidation/ValidationServiceOneWayClient.java new file mode 100644 index 00000000..40efd469 --- /dev/null +++ b/aai-core/src/main/java/org/onap/aai/prevalidation/ValidationServiceOneWayClient.java @@ -0,0 +1,92 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2018-19 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========================================================= + */ + +package org.onap.aai.prevalidation; + +import org.onap.aai.restclient.OneWaySSLRestClient; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.util.MultiValueMap; + +import java.util.Collections; +import java.util.Map; +import java.util.UUID; + +public class ValidationServiceOneWayClient extends OneWaySSLRestClient { + + @Value("${validation.service.base.url}") + private String baseUrl; + + @Value("${validation.service.ssl.trust-store}") + private String truststorePath; + + @Value("${validation.service.ssl.trust-store-password}") + private String truststorePassword; + + @Value("${validation.service.timeout-in-milliseconds}") + private Integer timeout; + + @Override + public String getBaseUrl() { + return baseUrl; + } + + @Override + protected String getTruststorePath() { + return truststorePath; + } + + @Override + protected char[] getTruststorePassword() { + return truststorePassword.toCharArray(); + } + + @Override + protected HttpComponentsClientHttpRequestFactory getHttpRequestFactory() throws Exception { + HttpComponentsClientHttpRequestFactory requestFactory = super.getHttpRequestFactory(); + requestFactory.setConnectionRequestTimeout(timeout); + requestFactory.setReadTimeout(timeout); + requestFactory.setConnectTimeout(timeout); + return requestFactory; + } + + @Override + public MultiValueMap<String, String> getHeaders(Map<String, String> headers) { + HttpHeaders httpHeaders = new HttpHeaders(); + + String defaultAccept = headers.getOrDefault(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON.toString()); + String defaultContentType = + headers.getOrDefault(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON.toString()); + + if (headers.isEmpty()) { + httpHeaders.setAccept(Collections.singletonList(MediaType.parseMediaType(defaultAccept))); + httpHeaders.setContentType(MediaType.parseMediaType(defaultContentType)); + } + + httpHeaders.add("X-FromAppId", appName); + httpHeaders.add("X-TransactionId", UUID.randomUUID().toString()); + httpHeaders.add("X-TransactionId", appName); + headers.forEach(httpHeaders::add); + return httpHeaders; + } + +} diff --git a/aai-core/src/main/java/org/onap/aai/prevalidation/ValidationServiceRestClient.java b/aai-core/src/main/java/org/onap/aai/prevalidation/ValidationServiceRestClient.java new file mode 100644 index 00000000..8674272e --- /dev/null +++ b/aai-core/src/main/java/org/onap/aai/prevalidation/ValidationServiceRestClient.java @@ -0,0 +1,108 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 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========================================================= + */ + +package org.onap.aai.prevalidation; + +import org.onap.aai.restclient.TwoWaySSLRestClient; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.util.MultiValueMap; + +import java.util.Collections; +import java.util.Map; +import java.util.UUID; + +public class ValidationServiceRestClient extends TwoWaySSLRestClient { + + @Value("${validation.service.base.url}") + private String baseUrl; + + @Value("${validation.service.ssl.key-store}") + private String keystorePath; + + @Value("${validation.service.ssl.trust-store}") + private String truststorePath; + + @Value("${validation.service.ssl.key-store-password}") + private String keystorePassword; + + @Value("${validation.service.ssl.trust-store-password}") + private String truststorePassword; + + @Value("${validation.service.timeout-in-milliseconds}") + private Integer timeout; + + @Override + public String getBaseUrl() { + return baseUrl; + } + + @Override + protected String getKeystorePath() { + return keystorePath; + } + + @Override + protected String getTruststorePath() { + return truststorePath; + } + + @Override + protected char[] getKeystorePassword() { + return keystorePassword.toCharArray(); + } + + @Override + protected char[] getTruststorePassword() { + return truststorePassword.toCharArray(); + } + + protected HttpComponentsClientHttpRequestFactory getHttpRequestFactory() throws Exception { + HttpComponentsClientHttpRequestFactory requestFactory = super.getHttpRequestFactory(); + requestFactory.setConnectionRequestTimeout(timeout); + requestFactory.setReadTimeout(timeout); + requestFactory.setConnectTimeout(timeout); + return requestFactory; + } + + @Override + public MultiValueMap<String, String> getHeaders(Map<String, String> headers) { + HttpHeaders httpHeaders = new HttpHeaders(); + + String defaultAccept = headers.getOrDefault(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON.toString()); + String defaultContentType = + headers.getOrDefault(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON.toString()); + + if (headers.isEmpty()) { + httpHeaders.setAccept(Collections.singletonList(MediaType.parseMediaType(defaultAccept))); + httpHeaders.setContentType(MediaType.parseMediaType(defaultContentType)); + } + + httpHeaders.add("X-FromAppId", appName); + httpHeaders.add("X-TransactionId", UUID.randomUUID().toString()); + headers.forEach(httpHeaders::add); + return httpHeaders; + } + +} diff --git a/aai-core/src/main/java/org/onap/aai/prevalidation/Violation.java b/aai-core/src/main/java/org/onap/aai/prevalidation/Violation.java new file mode 100644 index 00000000..e5472a7c --- /dev/null +++ b/aai-core/src/main/java/org/onap/aai/prevalidation/Violation.java @@ -0,0 +1,128 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2018-19 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========================================================= + */ + +package org.onap.aai.prevalidation; + +import com.google.gson.annotations.SerializedName; + +import java.util.Objects; + +public class Violation { + + @SerializedName("violationId") + private String violationId; + + @SerializedName("modelName") + private String modelName; + + @SerializedName("category") + private String category; + + @SerializedName("severity") + private String severity; + + @SerializedName("violationType") + private String violationType; + + @SerializedName("errorMessage") + private String errorMessage; + + public String getViolationId() { + return violationId; + } + + public void setViolationId(String violationId) { + this.violationId = violationId; + } + + public String getModelName() { + return modelName; + } + + public void setModelName(String modelName) { + this.modelName = modelName; + } + + public String getCategory() { + return category; + } + + public void setCategory(String category) { + this.category = category; + } + + public String getSeverity() { + return severity; + } + + public void setSeverity(String severity) { + this.severity = severity; + } + + public String getViolationType() { + return violationType; + } + + public void setViolationType(String violationType) { + this.violationType = violationType; + } + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + + @Override + public String toString() { + return "Violation{" + + "violationId='" + violationId + '\'' + + ", modelName='" + modelName + '\'' + + ", category='" + category + '\'' + + ", severity='" + severity + '\'' + + ", violationType='" + violationType + '\'' + + ", errorMessage='" + errorMessage + '\'' + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Violation violation = (Violation) o; + return Objects.equals(violationId, violation.violationId) && + Objects.equals(modelName, violation.modelName) && + Objects.equals(category, violation.category) && + Objects.equals(severity, violation.severity) && + Objects.equals(violationType, violation.violationType) && + Objects.equals(errorMessage, violation.errorMessage); + } + + @Override + public int hashCode() { + return Objects.hash(violationId, modelName, category, severity, violationType, errorMessage); + } +} diff --git a/aai-core/src/main/java/org/onap/aai/query/builder/GraphTraversalBuilder.java b/aai-core/src/main/java/org/onap/aai/query/builder/GraphTraversalBuilder.java index 272a2c21..1dc3f1d6 100644 --- a/aai-core/src/main/java/org/onap/aai/query/builder/GraphTraversalBuilder.java +++ b/aai-core/src/main/java/org/onap/aai/query/builder/GraphTraversalBuilder.java @@ -64,7 +64,6 @@ public abstract class GraphTraversalBuilder<E> extends QueryBuilder<E> { */ public GraphTraversalBuilder(Loader loader, GraphTraversalSource source) { super(loader, source); - traversal = (GraphTraversal<Vertex, E>) __.<E>start(); } @@ -73,7 +72,7 @@ public abstract class GraphTraversalBuilder<E> extends QueryBuilder<E> { * Instantiates a new graph traversal builder. * * @param loader the loader - * @param start the start + * @param start the start */ public GraphTraversalBuilder(Loader loader, GraphTraversalSource source, Vertex start) { super(loader, source, start); @@ -89,12 +88,33 @@ public abstract class GraphTraversalBuilder<E> extends QueryBuilder<E> { public QueryBuilder<Vertex> getVerticesByProperty(String key, Object value) { // correct value call because the index is registered as an Integer - traversal.has(key, this.correctObjectType(value)); - + this.vertexHas(key, this.correctObjectType(value)); stepIndex++; return (QueryBuilder<Vertex>) this; } + @Override + protected void vertexHas(String key, Object value) { + traversal.has(key, value); + } + + @Override + protected void vertexHasNot(String key) { + traversal.hasNot(key); + } + + @Override + protected void vertexHas(String key) { + traversal.has(key); + } + + //TODO: Remove this once we test this - at this point i dont thib this is required + //because predicare is an object + /*@Override + protected void vertexHas(final String key, final P<?> predicate) { + traversal.has(key, predicate); + }*/ + /** * @{inheritDoc} */ @@ -107,7 +127,21 @@ public abstract class GraphTraversalBuilder<E> extends QueryBuilder<E> { correctedValues.add(this.correctObjectType(item)); } - traversal.has(key, P.within(correctedValues)); + this.vertexHas(key, P.within(correctedValues)); + stepIndex++; + return (QueryBuilder<Vertex>) this; + } + + /** + * @{inheritDoc} + */ + public QueryBuilder<Vertex> getVerticesByCommaSeperatedValue(String key, String value) { + ArrayList<String> values = new ArrayList<>(Arrays.asList(value.split(","))); + int size = values.size(); + for (int i = 0; i < size; i++) { + values.set(i, values.get(i).trim()); + } + this.vertexHas(key, P.within(values)); stepIndex++; return (QueryBuilder<Vertex>) this; @@ -120,7 +154,8 @@ public abstract class GraphTraversalBuilder<E> extends QueryBuilder<E> { public QueryBuilder<Vertex> getVerticesStartsWithProperty(String key, Object value) { // correct value call because the index is registered as an Integer - traversal.has(key, org.janusgraph.core.attribute.Text.textPrefix(value)); + //TODO Check if this needs to be in QB and add these as internal + this.vertexHas(key, org.janusgraph.core.attribute.Text.textPrefix(value)); stepIndex++; return (QueryBuilder<Vertex>) this; @@ -131,8 +166,7 @@ public abstract class GraphTraversalBuilder<E> extends QueryBuilder<E> { */ @Override public QueryBuilder<Vertex> getVerticesByProperty(String key) { - - traversal.has(key); + this.vertexHas(key); stepIndex++; return (QueryBuilder<Vertex>) this; } @@ -142,8 +176,7 @@ public abstract class GraphTraversalBuilder<E> extends QueryBuilder<E> { */ @Override public QueryBuilder<Vertex> getVerticesExcludeByProperty(String key) { - - traversal.hasNot(key); + this.vertexHasNot(key); stepIndex++; return (QueryBuilder<Vertex>) this; } @@ -155,8 +188,7 @@ public abstract class GraphTraversalBuilder<E> extends QueryBuilder<E> { public QueryBuilder<Vertex> getVerticesExcludeByProperty(String key, Object value) { // correct value call because the index is registered as an Integer - traversal.has(key, P.neq(this.correctObjectType(value))); - + this.vertexHas(key, P.neq(this.correctObjectType(value))); stepIndex++; return (QueryBuilder<Vertex>) this; } @@ -173,16 +205,14 @@ public abstract class GraphTraversalBuilder<E> extends QueryBuilder<E> { correctedValues.add(this.correctObjectType(item)); } - traversal.has(key, P.without(correctedValues)); - + this.vertexHas(key, P.without(correctedValues)); stepIndex++; return (QueryBuilder<Vertex>) this; } @Override public QueryBuilder<Vertex> getVerticesGreaterThanProperty(final String key, Object value) { - - traversal.has(key, P.gte(this.correctObjectType(value))); + this.vertexHas(key, P.gte(this.correctObjectType(value))); stepIndex++; return (QueryBuilder<Vertex>) this; @@ -190,8 +220,7 @@ public abstract class GraphTraversalBuilder<E> extends QueryBuilder<E> { @Override public QueryBuilder<Vertex> getVerticesLessThanProperty(final String key, Object value) { - - traversal.has(key, P.lte(this.correctObjectType(value))); + this.vertexHas(key, P.lte(this.correctObjectType(value))); stepIndex++; return (QueryBuilder<Vertex>) this; @@ -214,7 +243,7 @@ public abstract class GraphTraversalBuilder<E> extends QueryBuilder<E> { public QueryBuilder<Vertex> getTypedVerticesByMap(String type, Map<String, String> map) { for (Map.Entry<String, String> es : map.entrySet()) { - traversal.has(es.getKey(), es.getValue()); + this.vertexHas(es.getKey(), es.getValue()); stepIndex++; } traversal.has(AAIProperties.NODE_TYPE, type); @@ -234,7 +263,7 @@ public abstract class GraphTraversalBuilder<E> extends QueryBuilder<E> { bValue = (Boolean) value; } - traversal.has(key, bValue); + this.vertexHas(key, bValue); stepIndex++; } return (QueryBuilder<Vertex>) this; @@ -257,9 +286,9 @@ public abstract class GraphTraversalBuilder<E> extends QueryBuilder<E> { if (val != null) { // this is because the index is registered as an Integer if (val.getClass().equals(Long.class)) { - traversal.has(key, new Integer(val.toString())); + this.vertexHas(key, new Integer(val.toString())); } else { - traversal.has(key, val); + this.vertexHas(key, val); } stepIndex++; } @@ -290,9 +319,9 @@ public abstract class GraphTraversalBuilder<E> extends QueryBuilder<E> { } // this is because the index is registered as an Integer if (val.getClass().equals(Long.class)) { - traversal.has(prop, new Integer(val.toString())); + this.vertexHas(prop, new Integer(val.toString())); } else { - traversal.has(prop, val); + this.vertexHas(prop, val); } stepIndex++; } @@ -326,7 +355,7 @@ public abstract class GraphTraversalBuilder<E> extends QueryBuilder<E> { */ @Override public QueryBuilder<Vertex> createEdgeTraversal(EdgeType type, Introspector parent, Introspector child) - throws AAIException { + throws AAIException { createTraversal(type, parent, child, false); return (QueryBuilder<Vertex>) this; @@ -334,13 +363,13 @@ public abstract class GraphTraversalBuilder<E> extends QueryBuilder<E> { @Override public QueryBuilder<Vertex> createPrivateEdgeTraversal(EdgeType type, Introspector parent, Introspector child) - throws AAIException { + throws AAIException { this.createTraversal(type, parent, child, true); return (QueryBuilder<Vertex>) this; } private void createTraversal(EdgeType type, Introspector parent, Introspector child, boolean isPrivateEdge) - throws AAIException { + throws AAIException { String isAbstractType = parent.getMetadata(ObjectMetadata.ABSTRACT); if ("true".equals(isAbstractType)) { markParentBoundary(); @@ -352,18 +381,17 @@ public abstract class GraphTraversalBuilder<E> extends QueryBuilder<E> { } /** - * * @{inheritDoc} */ @Override public QueryBuilder<Vertex> createEdgeTraversalWithLabels(EdgeType type, Introspector out, Introspector in, - List<String> labels) throws AAIException { + List<String> labels) throws AAIException { this.edgeQueryToVertex(type, out, in, labels); return (QueryBuilder<Vertex>) this; } private Traversal<Vertex, Vertex>[] handleAbstractEdge(EdgeType type, Introspector abstractParent, - Introspector child, boolean isPrivateEdge) throws AAIException { + Introspector child, boolean isPrivateEdge) throws AAIException { String childName = child.getDbName(); String inheritorMetadata = abstractParent.getMetadata(ObjectMetadata.INHERITORS); String[] inheritors = inheritorMetadata.split(","); @@ -399,7 +427,7 @@ public abstract class GraphTraversalBuilder<E> extends QueryBuilder<E> { innerTraversal.in(inLabels.toArray(new String[inLabels.size()])); } else { innerTraversal.union(__.out(outLabels.toArray(new String[outLabels.size()])), - __.in(inLabels.toArray(new String[inLabels.size()]))); + __.in(inLabels.toArray(new String[inLabels.size()]))); } innerTraversal.has(AAIProperties.NODE_TYPE, childName); @@ -411,7 +439,7 @@ public abstract class GraphTraversalBuilder<E> extends QueryBuilder<E> { } public QueryBuilder<Edge> getEdgesBetweenWithLabels(EdgeType type, String outNodeType, String inNodeType, - List<String> labels) throws AAIException { + List<String> labels) throws AAIException { Introspector outObj = loader.introspectorFromName(outNodeType); Introspector inObj = loader.introspectorFromName(inNodeType); this.edgeQuery(type, outObj, inObj, labels); @@ -556,6 +584,23 @@ public abstract class GraphTraversalBuilder<E> extends QueryBuilder<E> { return this; } + @Override + public QueryBuilder<E> valueMap() { + this.traversal.valueMap(); + stepIndex++; + + return this; + } + + @Override + public QueryBuilder<E> valueMap(String... names) { + this.traversal.valueMap(names); + stepIndex++; + + return this; + } + + /** * {@inheritDoc} */ @@ -649,12 +694,12 @@ public abstract class GraphTraversalBuilder<E> extends QueryBuilder<E> { * Edge query. * * @param outObj the out type - * @param inObj the in type + * @param inObj the in type * @throws NoEdgeRuleFoundException * @throws AAIException */ private void edgeQueryToVertex(EdgeType type, Introspector outObj, Introspector inObj, List<String> labels) - throws AAIException { + throws AAIException { String outType = outObj.getDbName(); String inType = inObj.getDbName(); @@ -686,7 +731,7 @@ public abstract class GraphTraversalBuilder<E> extends QueryBuilder<E> { } if (rules.isEmpty()) { throw new NoEdgeRuleFoundException( - "No edge rules found for " + outType + " and " + inType + " of type " + type.toString()); + "No edge rules found for " + outType + " and " + inType + " of type " + type.toString()); } } @@ -711,7 +756,7 @@ public abstract class GraphTraversalBuilder<E> extends QueryBuilder<E> { traversal.in(inLabels.toArray(new String[inLabels.size()])); } else { traversal.union(__.out(outLabels.toArray(new String[outLabels.size()])), - __.in(inLabels.toArray(new String[inLabels.size()]))); + __.in(inLabels.toArray(new String[inLabels.size()]))); } stepIndex++; @@ -724,12 +769,12 @@ public abstract class GraphTraversalBuilder<E> extends QueryBuilder<E> { * Edge query. * * @param outObj the out type - * @param inObj the in type + * @param inObj the in type * @throws NoEdgeRuleFoundException * @throws AAIException */ private void edgeQuery(EdgeType type, Introspector outObj, Introspector inObj, List<String> labels) - throws AAIException { + throws AAIException { String outType = outObj.getDbName(); String inType = inObj.getDbName(); @@ -777,7 +822,7 @@ public abstract class GraphTraversalBuilder<E> extends QueryBuilder<E> { traversal.inE(inLabels.toArray(new String[inLabels.size()])); } else { traversal.union(__.outE(outLabels.toArray(new String[outLabels.size()])), - __.inE(inLabels.toArray(new String[inLabels.size()]))); + __.inE(inLabels.toArray(new String[inLabels.size()]))); } } @@ -902,4 +947,5 @@ public abstract class GraphTraversalBuilder<E> extends QueryBuilder<E> { return (QueryBuilder<Edge>) this; } + } diff --git a/aai-core/src/main/java/org/onap/aai/query/builder/GremlinQueryBuilder.java b/aai-core/src/main/java/org/onap/aai/query/builder/GremlinQueryBuilder.java index 98da0766..fcfeb268 100644 --- a/aai-core/src/main/java/org/onap/aai/query/builder/GremlinQueryBuilder.java +++ b/aai-core/src/main/java/org/onap/aai/query/builder/GremlinQueryBuilder.java @@ -22,6 +22,8 @@ package org.onap.aai.query.builder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.google.common.base.Joiner; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Multimap; @@ -54,10 +56,14 @@ public abstract class GremlinQueryBuilder<E> extends QueryBuilder<E> { private static final String ARGUMENT2 = "#!#argument#!#"; private static final String HAS = ".has('"; + private static final String SINGLE_QUOTE = "'"; + private static final String ESCAPE_SINGLE_QUOTE = "\\'"; private GremlinGroovyShell gremlinGroovy = new GremlinGroovyShell(); private GraphTraversal<?, ?> completeTraversal = null; protected List<String> list = null; + private static final Logger LOGGER = LoggerFactory.getLogger(QueryBuilder.class); + /** * Instantiates a new gremlin query builder. * @@ -79,6 +85,7 @@ public abstract class GremlinQueryBuilder<E> extends QueryBuilder<E> { list = new ArrayList<>(); } + @Override public QueryBuilder<Vertex> exactMatchQuery(Introspector obj) { // TODO not implemented because this is implementation is no longer used @@ -87,6 +94,22 @@ public abstract class GremlinQueryBuilder<E> extends QueryBuilder<E> { return (QueryBuilder<Vertex>) this; } + @Override + protected void vertexHas(String key, Object value) { + list.add(HAS + key + "', " + value + ")"); + } + + @Override + protected void vertexHasNot(String key) { + list.add(".hasNot('" + key + "')"); + + } + + @Override + protected void vertexHas(String key) { + list.add(HAS + key + "')"); + } + /** * @{inheritDoc} */ @@ -95,11 +118,16 @@ public abstract class GremlinQueryBuilder<E> extends QueryBuilder<E> { String term = ""; if (value != null && !(value instanceof String)) { + String valueString = value.toString(); + if (valueString.indexOf('\'') != -1) { + value = valueString.replace(SINGLE_QUOTE, ESCAPE_SINGLE_QUOTE); + } + LOGGER.trace("Inside getVerticesByProperty(): key = {}, value = {}", key, value); term = value.toString(); } else { term = "'" + value + "'"; } - list.add(HAS + key + "', " + term + ")"); + this.vertexHas(key, term); stepIndex++; return (QueryBuilder<Vertex>) this; } @@ -109,7 +137,7 @@ public abstract class GremlinQueryBuilder<E> extends QueryBuilder<E> { */ @Override public QueryBuilder<Vertex> getVerticesByNumberProperty(String key, Object value) { - list.add(HAS + key + "', " + value + ")"); + this.vertexHas(key, value); stepIndex++; return (QueryBuilder<Vertex>) this; } @@ -125,7 +153,7 @@ public abstract class GremlinQueryBuilder<E> extends QueryBuilder<E> { bValue = (Boolean) value; } - list.add(HAS + key + "', " + bValue + ")"); + this.vertexHas(key, bValue); stepIndex++; } return (QueryBuilder<Vertex>) this; @@ -148,7 +176,31 @@ public abstract class GremlinQueryBuilder<E> extends QueryBuilder<E> { } String argument = Joiner.on(",").join(arguments); predicate = predicate.replace(ARGUMENT2, argument); - list.add(HAS + key + "', " + predicate + ")"); + this.vertexHas(key, predicate); + stepIndex++; + return (QueryBuilder<Vertex>) this; + } + + /** + * @{inheritDoc} + */ + @Override + public QueryBuilder<Vertex> getVerticesByCommaSeperatedValue(String key, String value) { + ArrayList<String> arguments = new ArrayList<>(Arrays.asList(value.split(","))); + //add the single quotes + for (int i = 0; i < arguments.size(); i++) { + if(arguments.get(i) != null && !arguments.get(i).startsWith("'") + && !arguments.get(i).endsWith("'")) { + arguments.set(i,"'" + arguments.get(i).trim() + "'"); + } + else { + arguments.set(i, arguments.get(i).trim()); + } + } + String predicate = "P.within(#!#argument#!#)"; + String argument = Joiner.on(",").join(arguments); + predicate = predicate.replace(ARGUMENT2, argument); + this.vertexHas(key, predicate); stepIndex++; return (QueryBuilder<Vertex>) this; } @@ -158,8 +210,7 @@ public abstract class GremlinQueryBuilder<E> extends QueryBuilder<E> { */ @Override public QueryBuilder<Vertex> getVerticesByProperty(String key) { - - list.add(HAS + key + "')"); + this.vertexHas(key); stepIndex++; return (QueryBuilder<Vertex>) this; } @@ -169,8 +220,7 @@ public abstract class GremlinQueryBuilder<E> extends QueryBuilder<E> { */ @Override public QueryBuilder<Vertex> getVerticesExcludeByProperty(String key) { - - list.add(".hasNot('" + key + "')"); + this.vertexHasNot(key); stepIndex++; return (QueryBuilder<Vertex>) this; } @@ -180,7 +230,6 @@ public abstract class GremlinQueryBuilder<E> extends QueryBuilder<E> { */ @Override public QueryBuilder<Vertex> getVerticesStartsWithProperty(String key, Object value) { - String term = ""; String predicate = "org.janusgraph.core.attribute.Text.textPrefix(#!#argument#!#)"; if (value != null && !(value instanceof String)) { @@ -189,7 +238,7 @@ public abstract class GremlinQueryBuilder<E> extends QueryBuilder<E> { term = "'" + value + "'"; } predicate = predicate.replace(ARGUMENT2, term); - list.add(HAS + key + "', " + predicate + ")"); + this.vertexHas(key, predicate); stepIndex++; return (QueryBuilder<Vertex>) this; } @@ -208,7 +257,7 @@ public abstract class GremlinQueryBuilder<E> extends QueryBuilder<E> { term = "'" + value + "'"; } predicate = predicate.replace(ARGUMENT2, term); - list.add(HAS + key + "', " + predicate + ")"); + this.vertexHas(key, predicate); stepIndex++; return (QueryBuilder<Vertex>) this; } @@ -230,7 +279,7 @@ public abstract class GremlinQueryBuilder<E> extends QueryBuilder<E> { } String argument = Joiner.on(",").join(arguments); predicate = predicate.replace(ARGUMENT2, argument); - list.add(HAS + key + "', " + predicate + ")"); + this.vertexHas(key, predicate); stepIndex++; return (QueryBuilder<Vertex>) this; } @@ -245,7 +294,7 @@ public abstract class GremlinQueryBuilder<E> extends QueryBuilder<E> { term = "'" + value + "'"; } predicate = predicate.replace("#!#argument1#!#", term); - list.add(HAS + key + "', " + predicate + ")"); + this.vertexHas(key, predicate); stepIndex++; return (QueryBuilder<Vertex>) this; } @@ -260,7 +309,7 @@ public abstract class GremlinQueryBuilder<E> extends QueryBuilder<E> { term = "'" + value + "'"; } predicate = predicate.replace("#!#argument1#!#", term); - list.add(HAS + key + "', " + predicate + ")"); + this.vertexHas(key, predicate); stepIndex++; return (QueryBuilder<Vertex>) this; } @@ -281,6 +330,7 @@ public abstract class GremlinQueryBuilder<E> extends QueryBuilder<E> { public QueryBuilder<Vertex> getTypedVerticesByMap(String type, Map<String, String> map) { for (Map.Entry<String, String> es : map.entrySet()) { + //TODO what is this and where is it used - need to check list.add(HAS + es.getKey() + "', '" + es.getValue() + "')"); stepIndex++; } @@ -594,6 +644,20 @@ public abstract class GremlinQueryBuilder<E> extends QueryBuilder<E> { } @Override + public QueryBuilder<E> fold() { + this.list.add(".fold()"); + stepIndex++; + return this; + } + + @Override + public QueryBuilder<E> id() { + this.list.add(".id()"); + stepIndex++; + return this; + } + + @Override public QueryBuilder<E> dedup() { this.list.add(".dedup()"); stepIndex++; @@ -656,6 +720,31 @@ public abstract class GremlinQueryBuilder<E> extends QueryBuilder<E> { return this; } + + @Override + public QueryBuilder<E> valueMap() { + this.list.add(".valueMap()"); + stepIndex++; + + return this; + } + + @Override + public QueryBuilder<E> valueMap(String... names) { + String stepString = ".valueMap('"; + for (int i = 0; i < names.length; i++) { + stepString = stepString + names[i] + "'"; + if (i != (names.length - 1)) { + stepString = stepString + ",'"; + } + } + stepString = stepString + ")"; + this.list.add(stepString); + stepIndex++; + + return this; + } + /** * {@inheritDoc} @@ -853,4 +942,9 @@ public abstract class GremlinQueryBuilder<E> extends QueryBuilder<E> { return (QueryBuilder<Edge>) this; } + /* + * This is required for the subgraphstrategies to work + */ + + } diff --git a/aai-core/src/main/java/org/onap/aai/query/builder/GremlinTraversal.java b/aai-core/src/main/java/org/onap/aai/query/builder/GremlinTraversal.java index 710db480..9cd35ab9 100644 --- a/aai-core/src/main/java/org/onap/aai/query/builder/GremlinTraversal.java +++ b/aai-core/src/main/java/org/onap/aai/query/builder/GremlinTraversal.java @@ -61,6 +61,7 @@ public class GremlinTraversal<E> extends GremlinQueryBuilder<E> { this.factory = new TraversalStrategy(this.loader, this); } + protected GremlinTraversal(List<String> traversal, Loader loader, GraphTraversalSource source, GremlinQueryBuilder<E> gtb) { super(loader, source); diff --git a/aai-core/src/main/java/org/onap/aai/query/builder/HistoryGremlinTraversal.java b/aai-core/src/main/java/org/onap/aai/query/builder/HistoryGremlinTraversal.java new file mode 100644 index 00000000..5b14995c --- /dev/null +++ b/aai-core/src/main/java/org/onap/aai/query/builder/HistoryGremlinTraversal.java @@ -0,0 +1,170 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 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========================================================= + */ + +package org.onap.aai.query.builder; + +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.onap.aai.db.props.AAIProperties; +import org.onap.aai.exceptions.AAIException; +import org.onap.aai.introspection.Introspector; +import org.onap.aai.introspection.Loader; +import org.onap.aai.parsers.query.QueryParser; +import org.onap.aai.parsers.query.TraversalStrategy; + +import javax.ws.rs.core.MultivaluedMap; +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.util.ArrayList; +import java.util.List; + +/** + * The Class GremlinTraversal. + */ +public class HistoryGremlinTraversal<E> extends GremlinTraversal<E> { + + /** + * Instantiates a new gremlin traversal. + * + * @param loader the loader + */ + public HistoryGremlinTraversal(Loader loader, GraphTraversalSource source) { + super(loader, source); + } + + /** + * Instantiates a new gremlin traversal. + * + * @param loader the loader + * @param start the start + */ + public HistoryGremlinTraversal(Loader loader, GraphTraversalSource source, Vertex start) { + super(loader, source, start); + } + + + protected HistoryGremlinTraversal(List<String> traversal, Loader loader, GraphTraversalSource source, + GremlinQueryBuilder<E> gtb) { + super(traversal, loader, source, gtb); + } + + /** + * @{inheritDoc} + */ + @Override + public QueryParser createQueryFromURI(URI uri) throws UnsupportedEncodingException, AAIException { + return factory.buildURIParser(uri); + } + + /** + * @{inheritDoc} + */ + @Override + public QueryParser createQueryFromRelationship(Introspector relationship) + throws UnsupportedEncodingException, AAIException { + return factory.buildRelationshipParser(relationship); + } + + /** + * @{inheritDoc} + */ + @Override + public QueryParser createQueryFromURI(URI uri, MultivaluedMap<String, String> queryParams) + throws UnsupportedEncodingException, AAIException { + return factory.buildURIParser(uri, queryParams); + } + + /** + * @{inheritDoc} + */ + @Override + public QueryParser createQueryFromObjectName(String objName) { + return factory.buildObjectNameParser(objName); + } + + /** + * @{inheritDoc} + */ + @Override + public QueryBuilder<E> newInstance(Vertex start) { + return new HistoryGremlinTraversal<>(loader, source, start); + } + + /** + * @{inheritDoc} + */ + @Override + public QueryBuilder<E> newInstance() { + return new HistoryGremlinTraversal<>(loader, source); + } + + @Override + protected QueryBuilder<E> cloneQueryAtStep(int index) { + + int idx = index; + + if (idx == 0) { + idx = stepIndex; + } + + List<String> newList = new ArrayList<>(); + for (int i = 0; i < idx; i++) { + newList.add(this.list.get(i)); + } + + return new HistoryGremlinTraversal<>(newList, loader, source, this); + } + + @Override + protected void vertexHas(String key, Object value) { + super.vertexHas(key, value); + touchHistoryProperties(key, value); + } + + @Override + protected void vertexHasNot(String key) { + super.vertexHasNot(key); + touchHistoryProperties(key); + + } + + @Override + protected void vertexHas(String key) { + super.vertexHas(key); + touchHistoryProperties(key); + } + + /* + * This is required for the subgraphstrategies to work + */ + private void touchHistoryProperties(String key){ + if(key != null && !key.isEmpty() && !key.equals(AAIProperties.NODE_TYPE)) { + list.add(".where(__.properties('" + key + "'))"); + } + + } + + private void touchHistoryProperties(String key, Object value) { + if(key != null && !key.isEmpty() && !key.equals(AAIProperties.NODE_TYPE)) { + list.add(".where(__.properties('" + key + "').hasValue(" + value + "))"); + } + } +} diff --git a/aai-core/src/main/java/org/onap/aai/query/builder/HistoryTraversalURIOptimizedQuery.java b/aai-core/src/main/java/org/onap/aai/query/builder/HistoryTraversalURIOptimizedQuery.java new file mode 100644 index 00000000..aeb5cd19 --- /dev/null +++ b/aai-core/src/main/java/org/onap/aai/query/builder/HistoryTraversalURIOptimizedQuery.java @@ -0,0 +1,93 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 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========================================================= + */ + +package org.onap.aai.query.builder; + +import org.apache.tinkerpop.gremlin.process.traversal.P; +import org.apache.tinkerpop.gremlin.process.traversal.Step; +import org.apache.tinkerpop.gremlin.process.traversal.Traversal; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__; +import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.onap.aai.db.props.AAIProperties; +import org.onap.aai.introspection.Introspector; +import org.onap.aai.introspection.Loader; +import org.onap.aai.schema.enums.ObjectMetadata; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +public class HistoryTraversalURIOptimizedQuery<E> extends TraversalURIOptimizedQuery { + + protected Map<Integer, String> stepToAaiUri = new HashMap<>(); + + public HistoryTraversalURIOptimizedQuery(Loader loader, GraphTraversalSource source) { + super(loader, source); + } + + public HistoryTraversalURIOptimizedQuery(Loader loader, GraphTraversalSource source, Vertex start) { + super(loader, source, start); + } + + protected HistoryTraversalURIOptimizedQuery(GraphTraversal traversal, Loader loader, GraphTraversalSource source, + GraphTraversalBuilder gtb) { + super(traversal, loader, source, gtb); + } + + protected HistoryTraversalURIOptimizedQuery(GraphTraversal traversal, Loader loader, GraphTraversalSource source, + GraphTraversalBuilder gtb, Map<Integer, String> stepToAaiUri) { + super(traversal, loader, source, gtb, stepToAaiUri); + } + + @Override + protected void vertexHas(String key, Object value) { + super.vertexHas(key, value); + touchHistoryProperties(key, value); + } + + @Override + protected void vertexHasNot(String key) { + super.vertexHasNot(key); + touchHistoryProperties(key); + } + + @Override + protected void vertexHas(String key) { + super.vertexHas(key); + touchHistoryProperties(key); + } + + private void touchHistoryProperties(String key){ + if(key != null && !key.isEmpty() && !key.equals(AAIProperties.NODE_TYPE)) { + traversal.where(__.properties(key)); + } + } + + private void touchHistoryProperties(String key, Object value){ + if(key != null && !key.isEmpty() && !key.equals(AAIProperties.NODE_TYPE)) { + traversal.where(__.properties(key).hasValue(value)); + } + } +} diff --git a/aai-core/src/main/java/org/onap/aai/query/builder/QueryBuilder.java b/aai-core/src/main/java/org/onap/aai/query/builder/QueryBuilder.java index a214811c..007f9798 100644 --- a/aai-core/src/main/java/org/onap/aai/query/builder/QueryBuilder.java +++ b/aai-core/src/main/java/org/onap/aai/query/builder/QueryBuilder.java @@ -20,14 +20,6 @@ package org.onap.aai.query.builder; -import java.io.UnsupportedEncodingException; -import java.net.URI; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -import javax.ws.rs.core.MultivaluedMap; - import org.apache.tinkerpop.gremlin.process.traversal.Path; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree; @@ -42,11 +34,17 @@ import org.onap.aai.edges.enums.EdgeType; import org.onap.aai.exceptions.AAIException; import org.onap.aai.introspection.Introspector; import org.onap.aai.introspection.Loader; -import org.onap.aai.introspection.exceptions.AAIUnknownObjectException; import org.onap.aai.parsers.query.QueryParser; import org.onap.aai.parsers.query.QueryParserStrategy; import org.springframework.context.ApplicationContext; +import javax.ws.rs.core.MultivaluedMap; +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + /** * The Class QueryBuilder. */ @@ -113,9 +111,21 @@ public abstract class QueryBuilder<E> implements Iterator<E> { */ public abstract QueryBuilder<Vertex> getVerticesByProperty(String key, Object value); + + /** + * Gets the edges by property. + * + * @param key the key + * @param value the value + * @return the vertices by property + */ + public QueryBuilder<Edge> getEdgesByProperty(String key, Object value) { + return this.has(key, value.toString()); + } + /** * filters by all the values for this property - * + * * @param key * @param values * @return vertices that match these values @@ -126,7 +136,7 @@ public abstract class QueryBuilder<E> implements Iterator<E> { /** * filters by all the values for this property - * + * * @param key * @param values * @return vertices that match these values @@ -134,10 +144,18 @@ public abstract class QueryBuilder<E> implements Iterator<E> { public abstract QueryBuilder<Vertex> getVerticesByProperty(String key, List<?> values); /** + * filters by all the values for this property + * + * @param key + * @param value in comma delimited string format + * @return vertices that match these values + */ + public abstract QueryBuilder<Vertex> getVerticesByCommaSeperatedValue(String key, String value); + + /** * Gets the vertices that have this property key. * * @param key the key - * @param value the value * @return the vertices by property */ public abstract QueryBuilder<Vertex> getVerticesByProperty(String key); @@ -146,14 +164,13 @@ public abstract class QueryBuilder<E> implements Iterator<E> { * Gets the vertices that do not have this property key. * * @param key the key - * @param value the value * @return the vertices by property */ public abstract QueryBuilder<Vertex> getVerticesExcludeByProperty(String key); /** * filters by elements that start with the value for this property - * + * * @param key * @param value * @return vertices that match these values @@ -171,7 +188,7 @@ public abstract class QueryBuilder<E> implements Iterator<E> { /** * filters by all the values for this property and excludes the vertices - * + * * @param key * @param values * @return vertices that match these values @@ -182,7 +199,7 @@ public abstract class QueryBuilder<E> implements Iterator<E> { /** * filters by all the values for this property and excludes the vertices - * + * * @param key * @param values * @return vertices that match these values @@ -191,18 +208,18 @@ public abstract class QueryBuilder<E> implements Iterator<E> { /** * filters by all the values greater than for this property - * + * * @param key - * @param values + * @param value * @return vertices that match these values */ public abstract QueryBuilder<Vertex> getVerticesGreaterThanProperty(String key, Object value); /** * filters by all the values less than for this property - * + * * @param key - * @param values + * @param value * @return vertices that match these values */ @@ -334,7 +351,7 @@ public abstract class QueryBuilder<E> implements Iterator<E> { /** * - * @param MissingOptionalParameter + * @param edgeType * @param outNodeType * @param inNodeType * @return @@ -348,6 +365,22 @@ public abstract class QueryBuilder<E> implements Iterator<E> { return this.createEdgeTraversal(outNodeType, inNodeType); } + /** + * + * @param edgeType + * @param outNodeType + * @param inNodeType + * @return + * @throws AAIException + */ + public QueryBuilder<Vertex> createEdgeTraversalWithLabels(MissingOptionalParameter edgeType, String outNodeType, + String inNodeType, List<String> labels) throws AAIException { + /* + * When no optional parameter edgetype is sent get all edges between the 2 nodetypes + */ + return this.createEdgeTraversalWithLabels(outNodeType, inNodeType, labels); + } + public QueryBuilder<Vertex> createEdgeTraversal(String outNodeType, String inNodeType) throws AAIException { Introspector out = loader.introspectorFromName(outNodeType); @@ -380,6 +413,38 @@ public abstract class QueryBuilder<E> implements Iterator<E> { return queryBuilder; } + public QueryBuilder<Vertex> createEdgeTraversalWithLabels(String outNodeType, String inNodeType, List<String> labels) throws AAIException { + + Introspector out = loader.introspectorFromName(outNodeType); + Introspector in = loader.introspectorFromName(inNodeType); + + QueryBuilder<Vertex> cousinBuilder = null; + QueryBuilder<Vertex> treeBuilder = null; + QueryBuilder<Vertex> queryBuilder = null; + + try { + cousinBuilder = this.newInstance().createEdgeTraversalWithLabels(EdgeType.COUSIN, out, in, labels); + } catch (AAIException e) { + } + + if (cousinBuilder != null) { + try { + treeBuilder = this.newInstance().createEdgeTraversalWithLabels(EdgeType.TREE, out, in, labels); + } catch (AAIException e) { + } + if (treeBuilder != null) { + queryBuilder = this.union(new QueryBuilder[] {cousinBuilder, treeBuilder}); + } else { + queryBuilder = this.union(new QueryBuilder[] {cousinBuilder}); + } + } else { + treeBuilder = this.newInstance().createEdgeTraversalWithLabels(EdgeType.TREE, out, in, labels); + queryBuilder = this.union(new QueryBuilder[] {treeBuilder}); + } + + return queryBuilder; + } + public QueryBuilder<Vertex> createPrivateEdgeTraversal(EdgeType type, String outNodeType, String inNodeType) throws AAIException { Introspector out = loader.introspectorFromName(outNodeType); @@ -415,6 +480,43 @@ public abstract class QueryBuilder<E> implements Iterator<E> { public abstract QueryBuilder<Vertex> createEdgeTraversalWithLabels(EdgeType type, Introspector out, Introspector in, List<String> labels) throws AAIException; + + /** + * This method and it's overloaded counterpart are conditional statements. + * This method creates an edge traversal step if an optional property is present + * This is necessary in cases such as "if the Optional Property 1 is sent, + * find all Nodes of type A with edges to Nodes of type B with property 1, + * otherwise, simply find all nodes of type A". + * @param type + * @param outNodeType + * @param inNodeType + * @param value + * @return + * @throws AAIException + */ + public QueryBuilder<Vertex> createEdgeTraversalIfParameterIsPresent(EdgeType type, String outNodeType, String inNodeType, + Object value) throws AAIException { + return this.createEdgeTraversal(type, outNodeType, inNodeType); + } + + /** + * This method and it's overloaded counterpart are conditional statements. + * This method skips an edge traversal step if there is an optional property missing. + * This is necessary in cases such as "if the Optional Property 1 is sent, + * find all Nodes of type A with edges to Nodes of type B with property 1, + * otherwise, simply find all nodes of type A". + * @param type + * @param outNodeType + * @param inNodeType + * @param value + * @return + * @throws AAIException + */ + public QueryBuilder<Vertex> createEdgeTraversalIfParameterIsPresent(EdgeType type, String outNodeType, String inNodeType, + MissingOptionalParameter value) throws AAIException { + return (QueryBuilder<Vertex>) this; + } + /** * * @param type @@ -467,7 +569,7 @@ public abstract class QueryBuilder<E> implements Iterator<E> { /** * Creates a queryparser from a given object name. - * + * * @param objName - name of the object type as it appears in the database * @return */ @@ -538,7 +640,7 @@ public abstract class QueryBuilder<E> implements Iterator<E> { /** * uses all fields in the introspector to create a query - * + * * @param obj * @return */ @@ -547,7 +649,7 @@ public abstract class QueryBuilder<E> implements Iterator<E> { /** * lets you join any number of QueryBuilders * <b>be careful about starting with a union it will not use indexes</b> - * + * * @param builder * @return */ @@ -563,6 +665,10 @@ public abstract class QueryBuilder<E> implements Iterator<E> { public abstract QueryBuilder<E> unfold(); + public abstract QueryBuilder<E> fold(); + + public abstract QueryBuilder<E> id(); + public abstract QueryBuilder<E> dedup(); public abstract QueryBuilder<E> emit(); @@ -591,6 +697,10 @@ public abstract class QueryBuilder<E> implements Iterator<E> { public abstract QueryBuilder<E> by(String name); + public abstract QueryBuilder<E> valueMap(); + + public abstract QueryBuilder<E> valueMap(String... names); + public abstract QueryBuilder<E> both(); public abstract QueryBuilder<Tree> tree(); @@ -598,7 +708,7 @@ public abstract class QueryBuilder<E> implements Iterator<E> { /** * Used to prevent the traversal from repeating its path through the graph. * See http://tinkerpop.apache.org/docs/3.0.1-incubating/#simplepath-step for more info. - * + * * @return a QueryBuilder with the simplePath step appended to its traversal */ public abstract QueryBuilder<E> simplePath(); @@ -617,7 +727,7 @@ public abstract class QueryBuilder<E> implements Iterator<E> { /** * Used to skip step if there is an optional property missing. - * + * * @param key * @param value * @return @@ -629,7 +739,7 @@ public abstract class QueryBuilder<E> implements Iterator<E> { /** * TODO the edge direction is hardcoded here, make it more generic * Returns the parent edge of the vertex - * + * * @return */ public QueryBuilder<Edge> getParentEdge() { @@ -640,7 +750,7 @@ public abstract class QueryBuilder<E> implements Iterator<E> { /** * TODO the edge direction is hardcoded here, make it more generic * Returns the parent vertex of the vertex - * + * * @return */ public QueryBuilder<Vertex> getParentVertex() { @@ -672,4 +782,13 @@ public abstract class QueryBuilder<E> implements Iterator<E> { public QueryBuilder<Vertex> getVerticesByNumberProperty(String key, MissingOptionalParameter value) { return getVerticesByProperty(key, value); } + + protected abstract void vertexHas(String key, Object value) ; + + protected abstract void vertexHasNot(String key); + + protected abstract void vertexHas(String key); + + //TODO: This probably is not required but need to test + // protected abstract void vertexHas(final String key, final P<?> predicate); } diff --git a/aai-core/src/main/java/org/onap/aai/query/builder/TraversalQuery.java b/aai-core/src/main/java/org/onap/aai/query/builder/TraversalQuery.java index cf99fd10..579c3571 100644 --- a/aai-core/src/main/java/org/onap/aai/query/builder/TraversalQuery.java +++ b/aai-core/src/main/java/org/onap/aai/query/builder/TraversalQuery.java @@ -30,7 +30,6 @@ import org.apache.tinkerpop.gremlin.process.traversal.Step; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; import org.apache.tinkerpop.gremlin.structure.Vertex; -import org.onap.aai.edges.enums.EdgeType; import org.onap.aai.exceptions.AAIException; import org.onap.aai.introspection.Introspector; import org.onap.aai.introspection.Loader; @@ -47,6 +46,7 @@ public class TraversalQuery<E> extends GraphTraversalBuilder<E> { * * @param loader the loader */ + public TraversalQuery(Loader loader, GraphTraversalSource source) { super(loader, source); this.factory = new TraversalStrategy(this.loader, this); @@ -125,6 +125,16 @@ public class TraversalQuery<E> extends GraphTraversalBuilder<E> { } @Override + public QueryBuilder<E> fold() { + return this; + } + + @Override + public QueryBuilder<E> id() { + return this; + } + + @Override protected QueryBuilder<E> cloneQueryAtStep(int index) { GraphTraversal.Admin<Vertex, E> cloneAdmin = getCloneAdmin(index); return new TraversalQuery<>(cloneAdmin, loader, source, this); diff --git a/aai-core/src/main/java/org/onap/aai/query/builder/TraversalURIOptimizedQuery.java b/aai-core/src/main/java/org/onap/aai/query/builder/TraversalURIOptimizedQuery.java index 91d2d084..0e2a9cad 100644 --- a/aai-core/src/main/java/org/onap/aai/query/builder/TraversalURIOptimizedQuery.java +++ b/aai-core/src/main/java/org/onap/aai/query/builder/TraversalURIOptimizedQuery.java @@ -145,7 +145,6 @@ public class TraversalURIOptimizedQuery<E> extends TraversalQuery { } return shouldOptimize; - } private Optional<String> getStepUriFromIntrospector(Introspector obj) { @@ -166,7 +165,7 @@ public class TraversalURIOptimizedQuery<E> extends TraversalQuery { return Optional.of(uri); } - private int getLastURIStepKey() { + protected int getLastURIStepKey() { return stepToAaiUri.keySet().stream().mapToInt(Integer::intValue).max().getAsInt(); } diff --git a/aai-core/src/main/java/org/onap/aai/rest/db/DBRequest.java b/aai-core/src/main/java/org/onap/aai/rest/db/DBRequest.java index 1f94fbe2..e25a9062 100644 --- a/aai-core/src/main/java/org/onap/aai/rest/db/DBRequest.java +++ b/aai-core/src/main/java/org/onap/aai/rest/db/DBRequest.java @@ -26,6 +26,7 @@ import java.util.Optional; import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.UriInfo; +import org.onap.aai.aailog.logs.DBRequestWrapper; import org.onap.aai.introspection.Introspector; import org.onap.aai.introspection.MarshallerProperties; import org.onap.aai.parsers.query.QueryParser; @@ -34,7 +35,7 @@ import org.onap.aai.restcore.HttpMethod; /** * The Class DBRequest. */ -public class DBRequest { +public class DBRequest implements DBRequestWrapper { private final QueryParser parser; diff --git a/aai-core/src/main/java/org/onap/aai/rest/db/HttpEntry.java b/aai-core/src/main/java/org/onap/aai/rest/db/HttpEntry.java index 61fc33a4..86d7e1b7 100644 --- a/aai-core/src/main/java/org/onap/aai/rest/db/HttpEntry.java +++ b/aai-core/src/main/java/org/onap/aai/rest/db/HttpEntry.java @@ -20,57 +20,24 @@ package org.onap.aai.rest.db; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.github.fge.jsonpatch.JsonPatchException; import com.github.fge.jsonpatch.mergepatch.JsonMergePatch; - -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.lang.reflect.InvocationTargetException; -import java.net.MalformedURLException; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; - -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.MultivaluedMap; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.Response.Status; -import javax.ws.rs.core.UriBuilder; - -import org.apache.commons.lang.StringUtils; -import org.apache.tinkerpop.gremlin.structure.Graph; import org.apache.tinkerpop.gremlin.structure.Vertex; -import org.apache.tinkerpop.gremlin.structure.VertexProperty; import org.janusgraph.core.JanusGraphException; import org.javatuples.Pair; -import org.json.JSONException; -import org.json.JSONObject; +import org.onap.aai.aailog.logs.AaiDBMetricLog; import org.onap.aai.db.props.AAIProperties; -import org.onap.aai.dbmap.DBConnectionType; -import org.onap.aai.domain.responseMessage.AAIResponseMessage; -import org.onap.aai.domain.responseMessage.AAIResponseMessageDatum; import org.onap.aai.exceptions.AAIException; -import org.onap.aai.extensions.AAIExtensionMap; -import org.onap.aai.extensions.ExtensionController; import org.onap.aai.introspection.*; import org.onap.aai.introspection.exceptions.AAIUnknownObjectException; import org.onap.aai.logging.ErrorLogHelper; -import org.onap.aai.logging.LoggingContext; import org.onap.aai.nodes.NodeIngestor; import org.onap.aai.parsers.query.QueryParser; -import org.onap.aai.parsers.uri.URIToExtensionInformation; -import org.onap.aai.parsers.uri.URIToObject; +import org.onap.aai.prevalidation.ValidationService; import org.onap.aai.rest.ueb.UEBNotification; import org.onap.aai.restcore.HttpMethod; import org.onap.aai.schema.enums.ObjectMetadata; @@ -84,17 +51,31 @@ import org.onap.aai.serialization.queryformats.FormatFactory; import org.onap.aai.serialization.queryformats.Formatter; import org.onap.aai.setup.SchemaVersion; import org.onap.aai.setup.SchemaVersions; +import org.onap.aai.transforms.XmlFormatTransformer; import org.onap.aai.util.AAIConfig; +import org.onap.aai.util.AAIConstants; +import org.onap.aai.util.delta.DeltaEvents; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.ResponseEntity; + +import javax.ws.rs.core.*; +import javax.ws.rs.core.Response.Status; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.lang.reflect.InvocationTargetException; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.*; +import java.util.stream.Collectors; /** * The Class HttpEntry. */ public class HttpEntry { - private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(HttpEntry.class); - private static final String TARGET_ENTITY = "DB"; + private static final Logger LOGGER = LoggerFactory.getLogger(HttpEntry.class); private ModelType introspectorFactoryType; @@ -125,8 +106,24 @@ public class HttpEntry { @Value("${schema.uri.base.path}") private String basePath; + @Value("${delta.events.enabled:false}") + private boolean isDeltaEventsEnabled; + + @Autowired + private XmlFormatTransformer xmlFormatTransformer; + + /** + * Inject the validation service if the profile pre-valiation is enabled, + * Otherwise this variable will be set to null and thats why required=false + * so that it can continue even if pre validation isn't enabled + */ + @Autowired(required = false) + private ValidationService validationService; + private UEBNotification notification; + private int notificationDepth; + /** * Instantiates a new http entry. * @@ -138,23 +135,45 @@ public class HttpEntry { this.queryStyle = queryStyle; } - public HttpEntry setHttpEntryProperties(SchemaVersion version, DBConnectionType connectionType) { + public HttpEntry setHttpEntryProperties(SchemaVersion version) { this.version = version; this.loader = loaderFactory.createLoaderForVersion(introspectorFactoryType, version); - this.dbEngine = new JanusGraphDBEngine(queryStyle, connectionType, loader); + this.dbEngine = new JanusGraphDBEngine(queryStyle, loader); getDbEngine().startTransaction(); this.notification = new UEBNotification(loader, loaderFactory, schemaVersions); + if("true".equals(AAIConfig.get("aai.notification.depth.all.enabled", "true"))){ + this.notificationDepth = AAIProperties.MAXIMUM_DEPTH; + } else { + this.notificationDepth = AAIProperties.MINIMUM_DEPTH; + } return this; } - public HttpEntry setHttpEntryProperties(SchemaVersion version, DBConnectionType connectionType, - UEBNotification notification) { + public HttpEntry setHttpEntryProperties(SchemaVersion version, UEBNotification notification) { this.version = version; this.loader = loaderFactory.createLoaderForVersion(introspectorFactoryType, version); - this.dbEngine = new JanusGraphDBEngine(queryStyle, connectionType, loader); + this.dbEngine = new JanusGraphDBEngine(queryStyle, loader); this.notification = notification; + + if("true".equals(AAIConfig.get("aai.notification.depth.all.enabled", "true"))){ + this.notificationDepth = AAIProperties.MAXIMUM_DEPTH; + } else { + this.notificationDepth = AAIProperties.MINIMUM_DEPTH; + } + // start transaction on creation + getDbEngine().startTransaction(); + return this; + } + + public HttpEntry setHttpEntryProperties(SchemaVersion version, UEBNotification notification, int notificationDepth) { + this.version = version; + this.loader = loaderFactory.createLoaderForVersion(introspectorFactoryType, version); + this.dbEngine = new JanusGraphDBEngine(queryStyle, loader); + + this.notification = notification; + this.notificationDepth = notificationDepth; // start transaction on creation getDbEngine().startTransaction(); return this; @@ -222,7 +241,7 @@ public class HttpEntry { /** * Returns the pagination size - * + * * @return integer of the size of results to be returned when paginated */ public int getPaginationBucket() { @@ -231,7 +250,7 @@ public class HttpEntry { /** * Setter for the pagination bucket variable which stores in this object the size of results to return - * + * * @param pb */ public void setPaginationBucket(int pb) { @@ -240,7 +259,7 @@ public class HttpEntry { /** * Getter to return the pagination index requested by the user when requesting paginated results - * + * * @return */ public int getPaginationIndex() { @@ -250,7 +269,7 @@ public class HttpEntry { /** * Sets the pagination index that was passed in by the user, to determine which index or results to retrieve when * paginated - * + * * @param pi */ public void setPaginationIndex(int pi) { @@ -262,7 +281,7 @@ public class HttpEntry { /** * Sets the total vertices variables and calculates the amount of pages based on size and total vertices - * + * * @param totalVertices * @param paginationBucketSize */ @@ -293,7 +312,7 @@ public class HttpEntry { /** * Process. - * + * * @param requests the requests * @param sourceOfTruth the source of truth * @@ -303,41 +322,44 @@ public class HttpEntry { public Pair<Boolean, List<Pair<URI, Response>>> process(List<DBRequest> requests, String sourceOfTruth, boolean enableResourceVersion) throws AAIException { - DBSerializer serializer = new DBSerializer(version, dbEngine, introspectorFactoryType, sourceOfTruth); - String methodName = "process"; + DBSerializer serializer = new DBSerializer(version, dbEngine, introspectorFactoryType, sourceOfTruth, notificationDepth); Response response; - Introspector obj = null; - QueryParser query = null; - URI uri = null; + Introspector obj; + QueryParser query; + URI uri; String transactionId = null; - int depth = AAIProperties.MAXIMUM_DEPTH; + int depth; Format format = null; List<Pair<URI, Response>> responses = new ArrayList<>(); - MultivaluedMap<String, String> params = null; - HttpMethod method = null; - String uriTemp = ""; - Boolean success = true; + MultivaluedMap<String, String> params; + HttpMethod method; + String uriTemp; + boolean success = true; QueryEngine queryEngine = dbEngine.getQueryEngine(); - int maxRetries = 10; - int retry = 0; + Set<Vertex> mainVertexesToNotifyOn = new LinkedHashSet<>(); + + AaiDBMetricLog metricLog = new AaiDBMetricLog(AAIConstants.AAI_RESOURCES_MS); + + String outputMediaType = null; + + if(requests != null && !requests.isEmpty()){ + HttpHeaders headers = requests.get(0).getHeaders(); + outputMediaType = getMediaType(headers.getAcceptableMediaTypes()); + } - LoggingContext.save(); for (DBRequest request : requests) { response = null; Status status = Status.NOT_FOUND; method = request.getMethod(); + metricLog.pre(request); try { try { - LoggingContext.targetEntity(TARGET_ENTITY); - LoggingContext.targetServiceName(methodName + " " + method); - obj = request.getIntrospector(); query = request.getParser(); transactionId = request.getTransactionId(); uriTemp = request.getUri().getRawPath().replaceFirst("^v\\d+/", ""); uri = UriBuilder.fromPath(uriTemp).build(); - LoggingContext.startTime(); List<Vertex> vertTemp; List<Vertex> vertices; if (this.isPaginated()) { @@ -348,8 +370,9 @@ public class HttpEntry { } else { vertices = query.getQueryBuilder().toList(); } - boolean isNewVertex = false; - String outputMediaType = getMediaType(request.getHeaders().getAcceptableMediaTypes()); + boolean isNewVertex; + HttpHeaders headers = request.getHeaders(); + outputMediaType = getMediaType(headers.getAcceptableMediaTypes()); String result = null; params = request.getInfo().getQueryParameters(false); depth = setDepth(obj, params.getFirst("depth")); @@ -369,15 +392,14 @@ public class HttpEntry { if (vertices.size() > 1 && processSingle && !(method.equals(HttpMethod.GET) || method.equals(HttpMethod.GET_RELATIONSHIP))) { if (method.equals(HttpMethod.DELETE)) { - LoggingContext.restoreIfPossible(); + throw new AAIException("AAI_6138"); } else { - LoggingContext.restoreIfPossible(); throw new AAIException("AAI_6137"); } } if (method.equals(HttpMethod.PUT)) { - String resourceVersion = (String) obj.getValue("resource-version"); + String resourceVersion = obj.getValue(AAIProperties.RESOURCE_VERSION); if (vertices.isEmpty()) { if (enableResourceVersion) { serializer.verifyResourceVersion("create", query.getResultType(), "", @@ -387,7 +409,7 @@ public class HttpEntry { } else { if (enableResourceVersion) { serializer.verifyResourceVersion("update", query.getResultType(), - vertices.get(0).<String>property("resource-version").orElse(null), + vertices.get(0).<String>property(AAIProperties.RESOURCE_VERSION).orElse(null), resourceVersion, obj.getURI()); } isNewVertex = false; @@ -404,6 +426,22 @@ public class HttpEntry { if (!isNewVertex) { v = vertices.get(0); } + + /* + * This skip-related-to query parameter is used to determine if the relationships object will omit the related-to-property + * If a GET is sent to resources without a format, if format=resource, or if format=resource_and_url with this param set to false + * then behavior will be keep the related-to properties. By default, set to true. + * Otherwise, for any other case, when the skip-related-to parameter exists, has value=true, or some unfamiliar input (e.g. skip-related-to=bogusvalue), the value is true. + */ + boolean isSkipRelatedTo = true; + if (params.containsKey("skip-related-to")) { + String skipRelatedTo = params.getFirst("skip-related-to"); + isSkipRelatedTo = !(skipRelatedTo != null && skipRelatedTo.equals("false")); + } else { + // if skip-related-to param is missing, then default it to false; + isSkipRelatedTo = false; + } + HashMap<String, Introspector> relatedObjects = new HashMap<>(); String nodeOnly = params.getFirst("nodes-only"); boolean isNodeOnly = nodeOnly != null; @@ -412,12 +450,7 @@ public class HttpEntry { if (format == null) { obj = this.getObjectFromDb(vertices, serializer, query, obj, request.getUri(), - depth, isNodeOnly, cleanUp); - - LoggingContext.elapsedTime((long) serializer.getDBTimeMsecs(), - TimeUnit.MILLISECONDS); - LOGGER.info("Completed"); - LoggingContext.restoreIfPossible(); + depth, isNodeOnly, cleanUp, isSkipRelatedTo); if (obj != null) { status = Status.OK; @@ -436,6 +469,14 @@ public class HttpEntry { Formatter formatter = ff.get(format, params); result = formatter.output(vertices.stream().map(vertex -> (Object) vertex) .collect(Collectors.toList())).toString(); + + if(outputMediaType == null){ + outputMediaType = MediaType.APPLICATION_JSON; + } + + if(MediaType.APPLICATION_XML_TYPE.isCompatible(MediaType.valueOf(outputMediaType))){ + result = xmlFormatTransformer.transform(result); + } status = Status.OK; } @@ -443,12 +484,7 @@ public class HttpEntry { case GET_RELATIONSHIP: if (format == null) { obj = this.getRelationshipObjectFromDb(vertices, serializer, query, - request.getInfo().getRequestUri()); - - LoggingContext.elapsedTime((long) serializer.getDBTimeMsecs(), - TimeUnit.MILLISECONDS); - LOGGER.info("Completed"); - LoggingContext.restoreIfPossible(); + request.getInfo().getRequestUri(), isSkipRelatedTo); if (obj != null) { status = Status.OK; @@ -471,49 +507,50 @@ public class HttpEntry { Formatter formatter = ff.get(format, params); result = formatter.output(vertices.stream().map(vertex -> (Object) vertex) .collect(Collectors.toList())).toString(); + + if(outputMediaType == null){ + outputMediaType = MediaType.APPLICATION_JSON; + } + + if(MediaType.APPLICATION_XML_TYPE.isCompatible(MediaType.valueOf(outputMediaType))){ + result = xmlFormatTransformer.transform(result); + } status = Status.OK; } break; case PUT: - response = this.invokeExtension(dbEngine, this.dbEngine.tx(), method, request, - sourceOfTruth, version, loader, obj, uri, true); if (isNewVertex) { v = serializer.createNewVertex(obj); } serializer.serializeToDb(obj, v, query, uri.getRawPath(), requestContext); - this.invokeExtension(dbEngine, this.dbEngine.tx(), HttpMethod.PUT, request, - sourceOfTruth, version, loader, obj, uri, false); status = Status.OK; if (isNewVertex) { status = Status.CREATED; } - obj = serializer.getLatestVersionView(v); - if (query.isDependent()) { - relatedObjects = - this.getRelatedObjects(serializer, queryEngine, v, obj, this.loader); + + mainVertexesToNotifyOn.add(v); + if (notificationDepth == AAIProperties.MINIMUM_DEPTH) { + Map<String, Pair<Introspector, LinkedHashMap<String,Introspector>>> allImpliedDeleteObjs = serializer.getImpliedDeleteUriObjectPair(); + + for(Map.Entry<String, Pair<Introspector, LinkedHashMap<String,Introspector>>> entry: allImpliedDeleteObjs.entrySet()){ + // The format is purposefully %s/%s%s due to the fact + // that every aai-uri will have a slash at the beginning + // If that assumption isn't true, then its best to change this code + String curUri = String.format("%s/%s%s", basePath , version , entry.getKey()); + Introspector curObj = entry.getValue().getValue0(); + HashMap<String, Introspector> curObjRelated = entry.getValue().getValue1(); + notification.createNotificationEvent(transactionId, sourceOfTruth, Status.NO_CONTENT, URI.create(curUri), curObj, curObjRelated, basePath); + } } - LoggingContext.elapsedTime( - (long) serializer.getDBTimeMsecs() + (long) queryEngine.getDBTimeMsecs(), - TimeUnit.MILLISECONDS); - LOGGER.info("Completed "); - LoggingContext.restoreIfPossible(); - notification.createNotificationEvent(transactionId, sourceOfTruth, status, uri, obj, - relatedObjects, basePath); break; case PUT_EDGE: serializer.touchStandardVertexProperties(v, false); - this.invokeExtension(dbEngine, this.dbEngine.tx(), method, request, sourceOfTruth, - version, loader, obj, uri, true); - serializer.createEdge(obj, v); - - LoggingContext.elapsedTime((long) serializer.getDBTimeMsecs(), TimeUnit.MILLISECONDS); - LOGGER.info("Completed"); - LoggingContext.restoreIfPossible(); + Vertex relatedVertex = serializer.createEdge(obj, v); status = Status.OK; - notification.createNotificationEvent(transactionId, sourceOfTruth, status, - new URI(uri.toString().replace("/relationship-list/relationship", "")), - serializer.getLatestVersionView(v), relatedObjects, basePath); + + mainVertexesToNotifyOn.add(v); + serializer.addVertexToEdgeVertexes(relatedVertex); break; case MERGE_PATCH: Introspector existingObj = loader.introspectorFromName(obj.getDbName()); @@ -536,37 +573,23 @@ public class HttpEntry { JsonNode completed = patch.apply(existingNode); String patched = mapper.writeValueAsString(completed); Introspector patchedObj = loader.unmarshal(existingObj.getName(), patched); - if (relationshipList == null) { + if (relationshipList == null && patchedObj.hasProperty("relationship-list")) { // if the caller didn't touch the relationship-list, we shouldn't either patchedObj.setValue("relationship-list", null); } serializer.serializeToDb(patchedObj, v, query, uri.getRawPath(), requestContext); status = Status.OK; - patchedObj = serializer.getLatestVersionView(v); - if (query.isDependent()) { - relatedObjects = this.getRelatedObjects(serializer, queryEngine, v, patchedObj, - this.loader); - } - LoggingContext.elapsedTime( - (long) serializer.getDBTimeMsecs() + (long) queryEngine.getDBTimeMsecs(), - TimeUnit.MILLISECONDS); - LOGGER.info("Completed"); - LoggingContext.restoreIfPossible(); - notification.createNotificationEvent(transactionId, sourceOfTruth, status, uri, - patchedObj, relatedObjects, basePath); + mainVertexesToNotifyOn.add(v); } catch (IOException | JsonPatchException e) { - - LOGGER.info("Caught exception: " + e.getMessage()); - LoggingContext.restoreIfPossible(); throw new AAIException("AAI_3000", "could not perform patch operation"); } break; case DELETE: - String resourceVersion = params.getFirst("resource-version"); - obj = serializer.getLatestVersionView(v); + String resourceVersion = params.getFirst(AAIProperties.RESOURCE_VERSION); + obj = serializer.getLatestVersionView(v, notificationDepth); if (query.isDependent()) { relatedObjects = - this.getRelatedObjects(serializer, queryEngine, v, obj, this.loader); + serializer.getRelatedObjects(queryEngine, v, obj, this.loader); } /* * Find all Delete-other-vertex vertices and create structure for notify @@ -576,7 +599,7 @@ public class HttpEntry { */ List<Vertex> deletableVertices = dbEngine.getQueryEngine().findDeletable(v); - Long vId = (Long) v.id(); + Object vId = v.id(); /* * I am assuming vertexId cant be null @@ -595,17 +618,7 @@ public class HttpEntry { this.buildRelatedObjects(serializer, queryEngine, deleteObjects); } - this.invokeExtension(dbEngine, this.dbEngine.tx(), method, request, sourceOfTruth, - version, loader, obj, uri, true); serializer.delete(v, deletableVertices, resourceVersion, enableResourceVersion); - this.invokeExtension(dbEngine, this.dbEngine.tx(), method, request, sourceOfTruth, - version, loader, obj, uri, false); - - LoggingContext.elapsedTime( - (long) serializer.getDBTimeMsecs() + (long) queryEngine.getDBTimeMsecs(), - TimeUnit.MILLISECONDS); - LOGGER.info("Completed"); - LoggingContext.restoreIfPossible(); status = Status.NO_CONTENT; notification.createNotificationEvent(transactionId, sourceOfTruth, status, uri, obj, relatedObjects, basePath); @@ -618,19 +631,16 @@ public class HttpEntry { this.buildNotificationEvent(sourceOfTruth, status, transactionId, notification, deleteObjects, uriMap, deleteRelatedObjects, basePath); } - break; case DELETE_EDGE: serializer.touchStandardVertexProperties(v, false); - serializer.deleteEdge(obj, v); + Optional<Vertex> otherV = serializer.deleteEdge(obj, v); - LoggingContext.elapsedTime((long) serializer.getDBTimeMsecs(), TimeUnit.MILLISECONDS); - LOGGER.info("Completed"); - LoggingContext.restoreIfPossible(); status = Status.NO_CONTENT; - notification.createNotificationEvent(transactionId, sourceOfTruth, Status.OK, - new URI(uri.toString().replace("/relationship-list/relationship", "")), - serializer.getLatestVersionView(v), relatedObjects, basePath); + if (otherV.isPresent()) { + mainVertexesToNotifyOn.add(v); + serializer.addVertexToEdgeVertexes(otherV.get()); + } break; default: break; @@ -659,21 +669,14 @@ public class HttpEntry { } } else if (response == null) { response = Response.status(status).type(outputMediaType).build(); - } else { - // response already set to something - } + } // else, response already set to something + Pair<URI, Response> pairedResp = Pair.with(request.getUri(), response); responses.add(pairedResp); } catch (JanusGraphException e) { this.dbEngine.rollback(); - - LOGGER.info("Caught exception: " + e.getMessage()); - LoggingContext.restoreIfPossible(); throw new AAIException("AAI_6134", e); } - if (retry == maxRetries) { - throw new AAIException("AAI_6134"); - } } catch (AAIException e) { success = false; ArrayList<String> templateVars = new ArrayList<>(); @@ -683,31 +686,123 @@ public class HttpEntry { ErrorLogHelper.logException(e); response = Response.status(e.getErrorObject().getHTTPResponseCode()).entity(ErrorLogHelper .getRESTAPIErrorResponse(request.getHeaders().getAcceptableMediaTypes(), e, templateVars)) + .type(outputMediaType) .build(); Pair<URI, Response> pairedResp = Pair.with(request.getUri(), response); responses.add(pairedResp); - continue; } catch (Exception e) { success = false; - e.printStackTrace(); AAIException ex = new AAIException("AAI_4000", e); - ArrayList<String> templateVars = new ArrayList<String>(); + ArrayList<String> templateVars = new ArrayList<>(); templateVars.add(request.getMethod().toString()); // GET, PUT, etc - templateVars.add(request.getUri().getPath().toString()); + templateVars.add(request.getUri().getPath()); ErrorLogHelper.logException(ex); response = Response.status(ex.getErrorObject().getHTTPResponseCode()).entity(ErrorLogHelper .getRESTAPIErrorResponse(request.getHeaders().getAcceptableMediaTypes(), ex, templateVars)) + .type(outputMediaType) .build(); Pair<URI, Response> pairedResp = Pair.with(request.getUri(), response); responses.add(pairedResp); - continue; + } + finally { + if (response != null) { + metricLog.post(request, response); + } } } - notification.triggerEvents(); + + if (success) { + generateEvents(sourceOfTruth, serializer, transactionId, queryEngine, mainVertexesToNotifyOn); + } else { + notification.clearEvents(); + } + return Pair.with(success, responses); } /** + * Generate notification events for the resulting db requests. + */ + private void generateEvents(String sourceOfTruth, DBSerializer serializer, String transactionId, QueryEngine queryEngine, Set<Vertex> mainVertexesToNotifyOn) throws AAIException { + if (notificationDepth == AAIProperties.MINIMUM_DEPTH) { + serializer.getUpdatedVertexes().entrySet().stream().filter(Map.Entry::getValue).map(Map.Entry::getKey).forEach(mainVertexesToNotifyOn::add); + } + Set<Vertex> edgeVertexes = serializer.touchStandardVertexPropertiesForEdges().stream() + .filter(v -> !mainVertexesToNotifyOn.contains(v)).collect(Collectors.toSet()); + try { + createNotificationEvents(mainVertexesToNotifyOn, sourceOfTruth, serializer, transactionId, queryEngine, notificationDepth); + if("true".equals(AAIConfig.get("aai.notification.both.sides.enabled", "true"))){ + createNotificationEvents(edgeVertexes, sourceOfTruth, serializer, transactionId, queryEngine, AAIProperties.MINIMUM_DEPTH); + } + } catch (UnsupportedEncodingException e) { + LOGGER.warn("Encountered exception generating events", e); + } + + // Since @Autowired required is set to false, we need to do a null check + // for the existence of the validationService since its only enabled if profile is enabled + if(validationService != null){ + validationService.validate(notification.getEvents()); + } + notification.triggerEvents(); + if (isDeltaEventsEnabled) { + try { + DeltaEvents deltaEvents = new DeltaEvents(transactionId, sourceOfTruth, version.toString(), serializer.getObjectDeltas()); + deltaEvents.triggerEvents(); + } catch (Exception e) { + LOGGER.error("Error sending Delta Events", e); + } + } + } + + /** + * Generate notification events for provided set of vertexes at the specified depth + */ + private void createNotificationEvents(Set<Vertex> vertexesToNotifyOn, String sourceOfTruth, DBSerializer serializer, + String transactionId, QueryEngine queryEngine, int eventDepth) throws AAIException, UnsupportedEncodingException { + for(Vertex vertex : vertexesToNotifyOn){ + if (canGenerateEvent(vertex)) { + boolean isCurVertexNew = vertex.value(AAIProperties.CREATED_TS).equals(vertex.value(AAIProperties.LAST_MOD_TS)); + Status curObjStatus = (isCurVertexNew) ? Status.CREATED : Status.OK; + + Introspector curObj = serializer.getLatestVersionView(vertex, eventDepth); + String aaiUri = vertex.<String>property(AAIProperties.AAI_URI).value(); + String uri = String.format("%s/%s%s", basePath, version, aaiUri); + HashMap<String, Introspector> curRelatedObjs = new HashMap<>(); + if (!curObj.isTopLevel()) { + curRelatedObjs = serializer.getRelatedObjects(queryEngine, vertex, curObj, this.loader); + } + notification.createNotificationEvent(transactionId, sourceOfTruth, curObjStatus, URI.create(uri), curObj, curRelatedObjs, basePath); + } + } + } + + /** + * Verifies that vertex has needed properties to generate on + * @param vertex Vertex to be verified + * @return <code>true</code> if vertex has necessary properties and exists + */ + private boolean canGenerateEvent(Vertex vertex) { + boolean canGenerate = true; + try { + if(!vertex.property(AAIProperties.AAI_URI).isPresent()){ + LOGGER.debug("Encountered an vertex {} with missing aai-uri", vertex.id()); + canGenerate = false; + } else if(!vertex.property(AAIProperties.CREATED_TS).isPresent() || !vertex.property(AAIProperties.LAST_MOD_TS).isPresent()){ + LOGGER.debug("Encountered an vertex {} with missing timestamp", vertex.id()); + canGenerate = false; + } + } catch (IllegalStateException e) { + if (e.getMessage().contains(" was removed")) { + LOGGER.warn("Attempted to generate event for non existent vertex", e); + } else { + LOGGER.warn("Encountered exception generating events", e); + } + canGenerate = false; + } + return canGenerate; + } + + /** * Gets the media type. * * @param mediaTypeList the media type list @@ -760,7 +855,6 @@ public class HttpEntry { return serializer.dbToObject(results, obj, depth, nodeOnly, cleanUp); } - /** * Gets the object from db. * @@ -770,6 +864,7 @@ public class HttpEntry { * @param uri the uri * @param depth the depth * @param cleanUp the clean up + * @param isSkipRelatedTo include related to flag * @return the object from db * @throws AAIException the AAI exception * @throws IllegalAccessException the illegal access exception @@ -783,9 +878,11 @@ public class HttpEntry { * @throws AAIUnknownObjectException * @throws URISyntaxException */ - private Introspector getRelationshipObjectFromDb(List<Vertex> results, DBSerializer serializer, QueryParser query, - URI uri) throws AAIException, IllegalArgumentException, SecurityException, UnsupportedEncodingException, - AAIUnknownObjectException { + private Introspector getObjectFromDb(List<Vertex> results, DBSerializer serializer, QueryParser query, + Introspector obj, URI uri, int depth, boolean nodeOnly, String cleanUp, boolean isSkipRelatedTo) + throws AAIException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, + SecurityException, InstantiationException, NoSuchMethodException, UnsupportedEncodingException, + AAIUnknownObjectException, URISyntaxException { // nothing found if (results.isEmpty()) { @@ -793,104 +890,45 @@ public class HttpEntry { throw new AAIException("AAI_6114", msg); } - if (results.size() > 1) { - throw new AAIException("AAI_6148", uri.getPath()); - } + return serializer.dbToObject(results, obj, depth, nodeOnly, cleanUp, isSkipRelatedTo); - Vertex v = results.get(0); - return serializer.dbToRelationshipObject(v); } /** - * Invoke extension. + * Gets the object from db. * - * @param dbEngine the db engine - * @param g the g - * @param httpMethod the http method - * @param fromAppId the from app id - * @param apiVersion the api version - * @param loader the loader - * @param obj the obj + * @param serializer the serializer + * @param query the query * @param uri the uri - * @param isPreprocess the is preprocess - * @return the response + * @return the object from db + * @throws AAIException the AAI exception + * @throws IllegalAccessException the illegal access exception * @throws IllegalArgumentException the illegal argument exception + * @throws InvocationTargetException the invocation target exception + * @throws SecurityException the security exception + * @throws InstantiationException the instantiation exception + * @throws NoSuchMethodException the no such method exception * @throws UnsupportedEncodingException the unsupported encoding exception - * @throws AAIException the AAI exception - */ - private Response invokeExtension(TransactionalGraphEngine dbEngine, Graph g, HttpMethod httpMethod, - DBRequest request, String fromAppId, SchemaVersion apiVersion, Loader loader, Introspector obj, URI uri, - boolean isPreprocess) throws IllegalArgumentException, UnsupportedEncodingException, AAIException { - AAIExtensionMap aaiExtMap = new AAIExtensionMap(); - // ModelInjestor injestor = ModelInjestor.getInstance(); - Response response = null; - URIToExtensionInformation extensionInformation = new URIToExtensionInformation(loader, uri); - aaiExtMap.setHttpEntry(this); - aaiExtMap.setDbRequest(request); - aaiExtMap.setTransId(request.getTransactionId()); - aaiExtMap.setFromAppId(fromAppId); - aaiExtMap.setGraph(g); - aaiExtMap.setApiVersion(apiVersion.toString()); - aaiExtMap.setObjectFromRequest(obj); - aaiExtMap.setObjectFromRequestType(obj.getJavaClassName()); - aaiExtMap.setObjectFromResponse(obj); - aaiExtMap.setObjectFromResponseType(obj.getJavaClassName()); - aaiExtMap.setJaxbContext(nodeIngestor.getContextForVersion(apiVersion)); - aaiExtMap.setUri(uri.getRawPath()); - aaiExtMap.setTransactionalGraphEngine(dbEngine); - aaiExtMap.setLoader(loader); - aaiExtMap.setNamespace(extensionInformation.getNamespace()); - - ExtensionController ext = new ExtensionController(); - ext.runExtension(aaiExtMap.getApiVersion(), extensionInformation.getNamespace(), - extensionInformation.getTopObject(), extensionInformation.getMethodName(httpMethod, isPreprocess), - aaiExtMap, isPreprocess); - - if (aaiExtMap.getPrecheckAddedList().size() > 0) { - response = notifyOnSkeletonCreation(aaiExtMap, obj, request.getHeaders()); - } - - return response; - } - - /** - * Notify on skeleton creation. - * - * @param aaiExtMap the aai ext map - * @param input the input - * @param headers the headers - * @return the response + * @throws MalformedURLException the malformed URL exception + * @throws AAIUnknownObjectException + * @throws URISyntaxException */ - // Legacy support - private Response notifyOnSkeletonCreation(AAIExtensionMap aaiExtMap, Introspector input, HttpHeaders headers) { - Response response = null; - HashMap<AAIException, ArrayList<String>> exceptionList = new HashMap<AAIException, ArrayList<String>>(); - - StringBuilder keyString = new StringBuilder(); + private Introspector getRelationshipObjectFromDb(List<Vertex> results, DBSerializer serializer, QueryParser query, + URI uri, boolean isSkipRelatedTo) throws AAIException, IllegalArgumentException, SecurityException, UnsupportedEncodingException, + AAIUnknownObjectException { - Set<String> resourceKeys = input.getKeys(); - for (String key : resourceKeys) { - keyString.append(key).append("=").append(input.getValue(key).toString()).append(" "); + // nothing found + if (results.isEmpty()) { + String msg = createNotFoundMessage(query.getResultType(), uri); + throw new AAIException("AAI_6114", msg); } - for (AAIResponseMessage msg : aaiExtMap.getPrecheckResponseMessages().getAAIResponseMessage()) { - ArrayList<String> templateVars = new ArrayList<>(); - - templateVars.add("PUT " + input.getDbName()); - templateVars.add(keyString.toString()); - List<String> keys = new ArrayList<>(); - templateVars.add(msg.getAaiResponseMessageResourceType()); - for (AAIResponseMessageDatum dat : msg.getAaiResponseMessageData().getAAIResponseMessageDatum()) { - keys.add(dat.getAaiResponseMessageDatumKey() + "=" + dat.getAaiResponseMessageDatumValue()); - } - templateVars.add(StringUtils.join(keys, ", ")); - exceptionList.put(new AAIException("AAI_0004", msg.getAaiResponseMessageResourceType()), templateVars); + if (results.size() > 1) { + throw new AAIException("AAI_6148", uri.getPath()); } - response = Response.status(Status.ACCEPTED) - .entity(ErrorLogHelper.getRESTAPIInfoResponse(headers.getAcceptableMediaTypes(), exceptionList)) - .build(); - return response; + Vertex v = results.get(0); + return serializer.dbToRelationshipObject(v, isSkipRelatedTo); } /** @@ -901,10 +939,7 @@ public class HttpEntry { * @return the string */ private String createNotFoundMessage(String resultType, URI uri) { - - String msg = "No Node of type " + resultType + " found at: " + uri.getPath(); - - return msg; + return "No Node of type " + resultType + " found at: " + uri.getPath(); } /** @@ -915,11 +950,8 @@ public class HttpEntry { * @return the string */ private String createRelationshipNotFoundMessage(String resultType, URI uri) { - - String msg = "No relationship found of type " + resultType + " at the given URI: " + uri.getPath() + return "No relationship found of type " + resultType + " at the given URI: " + uri.getPath() + "/relationship-list"; - - return msg; } /** @@ -933,16 +965,13 @@ public class HttpEntry { int depth = AAIProperties.MAXIMUM_DEPTH; String getAllRandomStr = AAIConfig.get("aai.rest.getall.depthparam", ""); - if (depthParam != null && getAllRandomStr != null && !getAllRandomStr.isEmpty() - && getAllRandomStr.equals(depthParam)) { + if (getAllRandomStr != null && !getAllRandomStr.isEmpty() && getAllRandomStr.equals(depthParam)) { return depth; } if (depthParam == null) { if (this.version.compareTo(schemaVersions.getDepthVersion()) >= 0) { depth = 0; - } else { - depth = AAIProperties.MAXIMUM_DEPTH; } } else { if (!depthParam.isEmpty() && !"all".equals(depthParam)) { @@ -973,184 +1002,14 @@ public class HttpEntry { return depth; } - /** - * Checks if is modification method. - * - * @param method the method - * @return true, if is modification method - */ - private boolean isModificationMethod(HttpMethod method) { - boolean result = false; - - if (method.equals(HttpMethod.PUT) || method.equals(HttpMethod.PUT_EDGE) || method.equals(HttpMethod.DELETE_EDGE) - || method.equals(HttpMethod.MERGE_PATCH)) { - result = true; - } - - return result; - - } - - /** - * Given an uri, introspector object and loader object - * it will check if the obj is top level object if it is, - * it will return immediately returning the uri passed in - * If it isn't, it will go through, get the uriTemplate - * from the introspector object and get the count of "/"s - * and remove that part of the uri using substring - * and keep doing that until the current object is top level - * Also added the max depth just so worst case scenario - * Then keep adding aai-uri to the list include the aai-uri passed in - * Convert that list into an array and return it - * <p> - * - * Example: - * - * <blockquote> - * aai-uri -> - * /cloud-infrastructure/cloud-regions/cloud-region/cloud-owner/cloud-region-id/tenants/tenant/tenant1/vservers/vserver/v1 - * - * Given the uriTemplate vserver -> /vservers/vserver/{vserver-id} - * it converts to /vservers/vserver - * - * lastIndexOf /vservers/vserver in - * /cloud-infrastructure/cloud-regions/cloud-region/cloud-owner/cloud-region-id/tenants/tenant/tenant1/vservers/vserver/v1 - * ^ - * | - * | - * lastIndexOf - * Use substring to get the string from 0 to that lastIndexOf - * aai-uri -> /cloud-infrastructure/cloud-regions/cloud-region/cloud-owner/cloud-region-id/tenants/tenant/tenant1 - * - * From this new aai-uri, generate a introspector from the URITOObject class - * and keep doing this until you - * - * </blockquote> - * - * @param aaiUri - aai-uri of the vertex representating the unique id of a given vertex - * @param obj - introspector object of the given starting vertex - * @param loader - Type of loader which will always be MoxyLoader to support model driven - * @return an array of strings which can be used to get the vertexes of parent and grand parents from a given vertex - * @throws UnsupportedEncodingException - * @throws AAIException - */ - String[] convertIntrospectorToUriList(String aaiUri, Introspector obj, Loader loader) - throws UnsupportedEncodingException, AAIException { - - List<String> uriList = new ArrayList<>(); - String template = StringUtils.EMPTY; - String truncatedUri = aaiUri; - int depth = AAIProperties.MAXIMUM_DEPTH; - uriList.add(truncatedUri); - - while (depth >= 0 && !obj.isTopLevel()) { - template = obj.getMetadata(ObjectMetadata.URI_TEMPLATE); - - if (template == null) { - LOGGER.warn("Unable to find the uriTemplate for the object {}", obj.getDbName()); - return null; - } - - int templateCount = StringUtils.countMatches(template, "/"); - int truncatedUriCount = StringUtils.countMatches(truncatedUri, "/"); - - if (templateCount > truncatedUriCount) { - LOGGER.warn("Template uri {} contains more slashes than truncatedUri {}", template, truncatedUri); - return null; - } - - int cutIndex = StringUtils.ordinalIndexOf(truncatedUri, "/", truncatedUriCount - templateCount + 1); - truncatedUri = StringUtils.substring(truncatedUri, 0, cutIndex); - uriList.add(truncatedUri); - obj = new URIToObject(loader, UriBuilder.fromPath(truncatedUri).build()).getEntity(); - depth--; - } - - return uriList.toArray(new String[uriList.size()]); - } - - /** - * - * @param serializer - * @param queryEngine - * @param v - * @param obj - * @param loader - * @return - * @throws IllegalAccessException - * @throws IllegalArgumentException - * @throws InvocationTargetException - * @throws SecurityException - * @throws InstantiationException - * @throws NoSuchMethodException - * @throws UnsupportedEncodingException - * @throws AAIException - * @throws URISyntaxException - */ - private HashMap<String, Introspector> getRelatedObjects(DBSerializer serializer, QueryEngine queryEngine, Vertex v, - Introspector obj, Loader loader) throws IllegalAccessException, IllegalArgumentException, - InvocationTargetException, SecurityException, InstantiationException, NoSuchMethodException, - UnsupportedEncodingException, AAIException, URISyntaxException { - - HashMap<String, Introspector> relatedVertices = new HashMap<>(); - VertexProperty aaiUriProperty = v.property(AAIProperties.AAI_URI); - - if (!aaiUriProperty.isPresent()) { - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("For the given vertex {}, it seems aai-uri is not present so not getting related objects", - v.id().toString()); - } else { - LOGGER.info( - "It seems aai-uri is not present in vertex, so not getting related objects, for more info enable debug log"); - } - return relatedVertices; - } - - String aaiUri = aaiUriProperty.value().toString(); - - if (!obj.isTopLevel()) { - String[] uriList = convertIntrospectorToUriList(aaiUri, obj, loader); - List<Vertex> vertexChain = null; - // If the uriList is null then there is something wrong with converting the uri - // into a list of aai-uris so falling back to the old mechanism for finding parents - if (uriList == null) { - LOGGER.info( - "Falling back to the old mechanism due to unable to convert aai-uri to list of uris but this is not optimal"); - vertexChain = queryEngine.findParents(v); - } else { - vertexChain = queryEngine.findParents(uriList); - } - for (Vertex vertex : vertexChain) { - try { - final Introspector vertexObj = serializer.getVertexProperties(vertex); - relatedVertices.put(vertexObj.getObjectId(), vertexObj); - } catch (AAIUnknownObjectException e) { - LOGGER.warn("Unable to get vertex properties, partial list of related vertices returned"); - } - } - } else { - try { - final Introspector vertexObj = serializer.getVertexProperties(v); - relatedVertices.put(vertexObj.getObjectId(), vertexObj); - } catch (AAIUnknownObjectException e) { - LOGGER.warn("Unable to get vertex properties, partial list of related vertices returned"); - } - } - - return relatedVertices; - } - private Map<Vertex, Introspector> buildIntrospectorObjects(DBSerializer serializer, Iterable<Vertex> vertices) { Map<Vertex, Introspector> deleteObjectMap = new HashMap<>(); for (Vertex vertex : vertices) { try { - // deleteObjectMap.computeIfAbsent(vertex, s -> - // serializer.getLatestVersionView(vertex)); - Introspector deleteObj = serializer.getLatestVersionView(vertex); + Introspector deleteObj = serializer.getLatestVersionView(vertex, notificationDepth); deleteObjectMap.put(vertex, deleteObj); } catch (UnsupportedEncodingException | AAIException e) { LOGGER.warn("Unable to get Introspctor Objects, Just continue"); - continue; } } @@ -1170,7 +1029,6 @@ public class HttpEntry { } } catch (UnsupportedEncodingException e) { LOGGER.warn("Unable to get URIs, Just continue"); - continue; } } @@ -1186,15 +1044,13 @@ public class HttpEntry { for (Map.Entry<Vertex, Introspector> entry : introSpector.entrySet()) { try { HashMap<String, Introspector> relatedObjects = - this.getRelatedObjects(serializer, queryEngine, entry.getKey(), entry.getValue(), this.loader); + serializer.getRelatedObjects(queryEngine, entry.getKey(), entry.getValue(), this.loader); if (null != entry.getValue()) { relatedObjectsMap.put(entry.getValue().getObjectId(), relatedObjects); } - } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | SecurityException - | InstantiationException | NoSuchMethodException | UnsupportedEncodingException | AAIException - | URISyntaxException e) { + } catch (IllegalArgumentException | SecurityException + | UnsupportedEncodingException | AAIException e) { LOGGER.warn("Unable to get realted Objects, Just continue"); - continue; } } @@ -1208,10 +1064,8 @@ public class HttpEntry { Map<String, HashMap<String, Introspector>> deleteRelatedObjects, String basePath) { for (Map.Entry<Vertex, Introspector> entry : deleteObjects.entrySet()) { try { - String vertexObjectId = ""; - if (null != entry.getValue()) { - vertexObjectId = entry.getValue().getObjectId(); + String vertexObjectId = entry.getValue().getObjectId(); if (uriMap.containsKey(vertexObjectId) && deleteRelatedObjects.containsKey(vertexObjectId)) { notification.createNotificationEvent(transactionId, sourceOfTruth, status, @@ -1227,12 +1081,38 @@ public class HttpEntry { } public void setPaginationParameters(String resultIndex, String resultSize) { - if (resultIndex != null && resultIndex != "-1" && resultSize != null && resultSize != "-1") { + if (resultIndex != null && !"-1".equals(resultIndex) && resultSize != null && !"-1".equals(resultSize)) { this.setPaginationIndex(Integer.parseInt(resultIndex)); this.setPaginationBucket(Integer.parseInt(resultSize)); } } + public List<Object> getPaginatedVertexListForAggregateFormat(List<Object> aggregateVertexList) throws AAIException { + List<Object> finalList = new Vector<>(); + if (this.isPaginated()) { + if (aggregateVertexList != null && !aggregateVertexList.isEmpty()) { + int listSize = aggregateVertexList.size(); + if (listSize == 1) { + List<Object> vertexList = (List<Object>) aggregateVertexList.get(0); + this.setTotalsForPaging(vertexList.size(), this.getPaginationBucket()); + int startIndex = (this.getPaginationIndex() - 1) * this.getPaginationBucket(); + int endIndex = Math.min((this.getPaginationBucket() * this.getPaginationIndex()), vertexList.size()); + if (startIndex > endIndex) { + throw new AAIException("AAI_6150", + " ResultIndex is not appropriate for the result set, Needs to be <= " + endIndex); + } + finalList.add(new ArrayList<Object>()); + for (int i = startIndex; i < endIndex; i++) { + ((ArrayList<Object>) finalList.get(0)).add(((ArrayList<Object>) aggregateVertexList.get(0)).get(i)); + } + return finalList; + } + } + } + // If the list size is greater than 1 or if pagination is not needed, return the original list. + return aggregateVertexList; + } + public List<Object> getPaginatedVertexList(List<Object> vertexList) throws AAIException { List<Object> vertices; if (this.isPaginated()) { diff --git a/aai-core/src/main/java/org/onap/aai/rest/ueb/NotificationEvent.java b/aai-core/src/main/java/org/onap/aai/rest/ueb/NotificationEvent.java index 61beb8d0..14e554cd 100644 --- a/aai-core/src/main/java/org/onap/aai/rest/ueb/NotificationEvent.java +++ b/aai-core/src/main/java/org/onap/aai/rest/ueb/NotificationEvent.java @@ -63,10 +63,13 @@ public class NotificationEvent { StoreNotificationEvent sne = new StoreNotificationEvent(transactionId, sourceOfTruth); - sne.storeEvent(loader, eventHeader, obj); + sne.storeEventAndSendToJms(loader, eventHeader, obj); } + public String getNotificationEvent() throws AAIException { + return new StoreNotificationEvent(transactionId, sourceOfTruth).storeEventOnly(loader, eventHeader, obj); + } /** * Gets the notification version. * diff --git a/aai-core/src/main/java/org/onap/aai/rest/ueb/UEBNotification.java b/aai-core/src/main/java/org/onap/aai/rest/ueb/UEBNotification.java index b189c050..28a644a9 100644 --- a/aai-core/src/main/java/org/onap/aai/rest/ueb/UEBNotification.java +++ b/aai-core/src/main/java/org/onap/aai/rest/ueb/UEBNotification.java @@ -20,22 +20,13 @@ package org.onap.aai.rest.ueb; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; - -import java.io.UnsupportedEncodingException; -import java.net.URI; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; - -import javax.ws.rs.core.Response.Status; - -import org.onap.aai.config.SpringContextAware; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.onap.aai.exceptions.AAIException; import org.onap.aai.introspection.Introspector; import org.onap.aai.introspection.Loader; import org.onap.aai.introspection.LoaderFactory; +import org.onap.aai.introspection.ModelType; import org.onap.aai.introspection.exceptions.AAIUnknownObjectException; import org.onap.aai.introspection.exceptions.AAIUnmarshallingException; import org.onap.aai.logging.LogFormatTools; @@ -43,15 +34,20 @@ import org.onap.aai.parsers.uri.URIToObject; import org.onap.aai.setup.SchemaVersion; import org.onap.aai.setup.SchemaVersions; +import javax.ws.rs.core.Response.Status; +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.util.*; + /** * The Class UEBNotification. */ public class UEBNotification { - private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(UEBNotification.class); + private static final Logger LOGGER = LoggerFactory.getLogger(UEBNotification.class); private Loader currentVersionLoader = null; - protected List<NotificationEvent> events = null; + protected Map<String, NotificationEvent> events = null; private SchemaVersion notificationVersion = null; /** @@ -60,13 +56,27 @@ public class UEBNotification { * @param loader the loader */ public UEBNotification(Loader loader, LoaderFactory loaderFactory, SchemaVersions schemaVersions) { - events = new ArrayList<>(); + events = new LinkedHashMap<>(); SchemaVersion defaultVersion = schemaVersions.getDefaultVersion(); currentVersionLoader = loaderFactory.createLoaderForVersion(loader.getModelType(), defaultVersion); notificationVersion = defaultVersion; } /** + * Instantiates a new UEB notification. + * + * @param modelType - Model type + * @param loaderFactory - the loader factory + * @param schemaVersions the schema versions bean + */ + public UEBNotification(ModelType modelType, LoaderFactory loaderFactory, SchemaVersions schemaVersions) { + events = new LinkedHashMap<>(); + SchemaVersion defaultVersion = schemaVersions.getDefaultVersion(); + currentVersionLoader = loaderFactory.createLoaderForVersion(modelType, defaultVersion); + notificationVersion = defaultVersion; + } + + /** * Creates the notification event. * * @param transactionId the X-TransactionId @@ -97,7 +107,6 @@ public class UEBNotification { Introspector eventHeader = currentVersionLoader.introspectorFromName("notification-event-header"); URIToObject parser = new URIToObject(currentVersionLoader, uri, relatedObjects); - String entityLink = ""; if ((basePath != null) && (!basePath.isEmpty())) { if (!(basePath.startsWith("/"))) { basePath = "/" + basePath; @@ -113,10 +122,12 @@ public class UEBNotification { } } - if (uri.toString().startsWith("/")) { - entityLink = basePath + notificationVersion + uri; + String uriStr = getUri(uri.toString(), basePath); + String entityLink; + if (uriStr.startsWith("/")) { + entityLink = basePath + notificationVersion + uriStr; } else { - entityLink = basePath + notificationVersion + "/" + uri; + entityLink = basePath + notificationVersion + "/" + uriStr; } eventHeader.setValue("entity-link", entityLink); @@ -166,7 +177,7 @@ public class UEBNotification { } final NotificationEvent event = new NotificationEvent(currentVersionLoader, eventHeader, eventObject, transactionId, sourceOfTruth); - events.add(event); + events.put(uri.toString(), event); } catch (AAIUnknownObjectException e) { throw new RuntimeException("Fatal error - notification-event-header object not found!"); } catch (AAIUnmarshallingException e) { @@ -181,14 +192,41 @@ public class UEBNotification { * @throws AAIException the AAI exception */ public void triggerEvents() throws AAIException { - for (NotificationEvent event : events) { + for (NotificationEvent event : events.values()) { event.trigger(); } - events.clear(); + clearEvents(); } public List<NotificationEvent> getEvents() { + return new ArrayList<>(this.events.values()); + } + public Map<String, NotificationEvent> getEventsMap() { return this.events; } + private String getUri(String uri, String basePath) { + if (uri == null || uri.isEmpty()) { + return uri; + } else if (uri.charAt(0) != '/') { + uri = '/' + uri; + } + + if ((basePath != null) && (!basePath.isEmpty())) { + if (!(basePath.startsWith("/"))) { + basePath = "/" + basePath; + } + if (!(basePath.endsWith("/"))) { + basePath = basePath + "/"; + } + } + + LOGGER.trace("Notification header uri base path:'{}', uri:'{}'", basePath, uri); + + return uri.replaceAll("^" + basePath + "v\\d+", ""); + } + + public void clearEvents() { + events.clear(); + } } diff --git a/aai-core/src/main/java/org/onap/aai/restcore/RESTAPI.java b/aai-core/src/main/java/org/onap/aai/restcore/RESTAPI.java index ae102a83..2b1256ba 100644 --- a/aai-core/src/main/java/org/onap/aai/restcore/RESTAPI.java +++ b/aai-core/src/main/java/org/onap/aai/restcore/RESTAPI.java @@ -20,64 +20,47 @@ package org.onap.aai.restcore; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; -import com.google.common.base.Joiner; - -import java.io.UnsupportedEncodingException; -import java.net.URI; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; - -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.UriInfo; - +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.onap.aai.db.props.AAIProperties; -import org.onap.aai.dbmap.DBConnectionType; import org.onap.aai.exceptions.AAIException; import org.onap.aai.introspection.Introspector; import org.onap.aai.introspection.Loader; -import org.onap.aai.introspection.tools.CreateUUID; -import org.onap.aai.introspection.tools.DefaultFields; -import org.onap.aai.introspection.tools.InjectKeysFromURI; -import org.onap.aai.introspection.tools.IntrospectorValidator; -import org.onap.aai.introspection.tools.Issue; -import org.onap.aai.introspection.tools.RemoveNonVisibleProperty; +import org.onap.aai.introspection.tools.*; import org.onap.aai.logging.ErrorLogHelper; -import org.onap.aai.logging.LoggingContext; import org.onap.aai.util.AAIConfig; import org.onap.aai.util.FormatDate; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.*; + /** * Base class for AAI REST API classes. * Provides method to validate header information * TODO should authenticate caller and authorize them for the API they are calling * TODO should store the transaction * - * + * */ public class RESTAPI { - private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(RESTAPI.class); - - protected final String COMPONENT = "aairest"; + private static final Logger LOGGER = LoggerFactory.getLogger(RESTAPI.class); /** * The Enum Action. */ public enum Action { GET, PUT, POST, DELETE - }; + } /** * Gets the from app id. @@ -101,8 +84,6 @@ public class RESTAPI { throw new AAIException("AAI_4009"); } - LoggingContext.partnerName(fromAppId); - return fromAppId; } @@ -128,8 +109,6 @@ public class RESTAPI { throw new AAIException("AAI_4010"); } - LoggingContext.requestId(transId); - return transId; } @@ -173,7 +152,7 @@ public class RESTAPI { int depth = AAIProperties.MAXIMUM_DEPTH; // default if (depthParam != null && depthParam.length() > 0 && !depthParam.equals("all")) { try { - depth = Integer.valueOf(depthParam); + depth = Integer.parseInt(depthParam); } catch (Exception e) { throw new AAIException("AAI_4016"); } @@ -192,9 +171,9 @@ public class RESTAPI { */ protected Response consumerExceptionResponseGenerator(HttpHeaders headers, UriInfo info, HttpMethod templateAction, AAIException e) { - ArrayList<String> templateVars = new ArrayList<String>(); + ArrayList<String> templateVars = new ArrayList<>(); templateVars.add(templateAction.toString()); // GET, PUT, etc - templateVars.add(info.getPath().toString()); + templateVars.add(info.getPath()); templateVars.addAll(e.getTemplateVars()); ErrorLogHelper.logException(e); @@ -236,7 +215,7 @@ public class RESTAPI { messages.add(issue.getDetail()); } } - String errors = Joiner.on(",").join(messages); + String errors = String.join(",", messages); throw new AAIException("AAI_3000", errors); } // check that key in payload and key in request uri are the same @@ -249,22 +228,6 @@ public class RESTAPI { } } - protected DBConnectionType determineConnectionType(String fromAppId, String realTime) throws AAIException { - if (fromAppId == null) { - throw new AAIException("AAI_4009", "X-FromAppId is not set"); - } - - DBConnectionType type = DBConnectionType.REALTIME; - boolean isRealTimeClient = AAIConfig.get("aai.realtime.clients", "").contains(fromAppId); - if (isRealTimeClient || realTime != null) { - type = DBConnectionType.REALTIME; - } else { - type = DBConnectionType.CACHED; - } - - return type; - } - /** * Gets the input media type. * @@ -272,10 +235,7 @@ public class RESTAPI { * @return the input media type */ protected String getInputMediaType(MediaType mediaType) { - String result = mediaType.getType() + "/" + mediaType.getSubtype(); - - return result; - + return mediaType.getType() + "/" + mediaType.getSubtype(); } /** @@ -288,25 +248,23 @@ public class RESTAPI { * @throws AAIException */ - public int getTimeoutLimit(String sot, String appTimeouts, String defaultTimeout) throws AAIException { + public int getTimeoutLimit(String sot, String appTimeouts, String defaultTimeout) { String[] ignoreAppIds = (appTimeouts).split("\\|"); int appLimit = Integer.parseInt(defaultTimeout); - final Map<String, Integer> m = new HashMap<String, Integer>(); - if (ignoreAppIds != null) { - for (int i = 0; i < ignoreAppIds.length; i++) { - String[] vals = ignoreAppIds[i].split(","); - m.put(vals[0], Integer.parseInt(vals[1])); - } - if (m.get(sot) != null) { - appLimit = m.get(sot); - } + final Map<String, Integer> m = new HashMap<>(); + for (int i = 0; i < ignoreAppIds.length; i++) { + String[] vals = ignoreAppIds[i].split(","); + m.put(vals[0], Integer.parseInt(vals[1])); + } + if (m.get(sot) != null) { + appLimit = m.get(sot); } return appLimit; } /** * Returns whether time out is enabled - * + * * @param sot * @param isEnabled * @param appTimeouts @@ -314,9 +272,8 @@ public class RESTAPI { * @return boolean of whether the timeout is enabled * @throws AAIException */ - public boolean isTimeoutEnabled(String sot, String isEnabled, String appTimeouts, String defaultTimeout) - throws AAIException { - Boolean isTimeoutEnabled = Boolean.parseBoolean(isEnabled); + public boolean isTimeoutEnabled(String sot, String isEnabled, String appTimeouts, String defaultTimeout) { + boolean isTimeoutEnabled = Boolean.parseBoolean(isEnabled); int ata = -1; if (isTimeoutEnabled) { ata = getTimeoutLimit(sot, appTimeouts, defaultTimeout); @@ -326,7 +283,7 @@ public class RESTAPI { /** * Executes the process thread and watches the future for the timeout - * + * * @param handler * @param sourceOfTruth * @param appTimeoutLimit @@ -358,7 +315,7 @@ public class RESTAPI { /** * runner sets up the timer logic and invokes it - * + * * @param toe * @param tba * @param tdl diff --git a/aai-core/src/main/java/org/onap/aai/restcore/search/AAIAbstractGroovyShell.java b/aai-core/src/main/java/org/onap/aai/restcore/search/AAIAbstractGroovyShell.java index b521a617..13f3f05e 100644 --- a/aai-core/src/main/java/org/onap/aai/restcore/search/AAIAbstractGroovyShell.java +++ b/aai-core/src/main/java/org/onap/aai/restcore/search/AAIAbstractGroovyShell.java @@ -28,13 +28,20 @@ import java.util.Map; import java.util.concurrent.TimeUnit; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; import org.codehaus.groovy.ast.ClassHelper; import org.codehaus.groovy.ast.expr.ClassExpression; import org.codehaus.groovy.ast.expr.PropertyExpression; import org.codehaus.groovy.control.CompilerConfiguration; import org.codehaus.groovy.control.customizers.ASTTransformationCustomizer; import org.codehaus.groovy.control.customizers.ImportCustomizer; +import org.onap.aai.config.SpringContextAware; +import org.onap.aai.introspection.Loader; +import org.onap.aai.introspection.LoaderFactory; +import org.onap.aai.introspection.ModelType; +import org.onap.aai.serialization.engines.QueryStyle; import org.onap.aai.serialization.engines.TransactionalGraphEngine; +import org.onap.aai.setup.SchemaVersions; public abstract class AAIAbstractGroovyShell { @@ -76,4 +83,20 @@ public abstract class AAIAbstractGroovyShell { * @return result of graph traversal */ public abstract GraphTraversal<?, ?> executeTraversal(String traversal, Map<String, Object> params); + + /** + * + * @param engine + * @param traversal + * @param params + * @return result of graph traversal + */ + public abstract String executeTraversal(TransactionalGraphEngine engine, String traversal, + Map<String, Object> params, QueryStyle style, GraphTraversalSource source); + + protected Loader getLoader(){ + SchemaVersions schemaVersions = (SchemaVersions) SpringContextAware.getBean("schemaVersions"); + return SpringContextAware.getBean(LoaderFactory.class).createLoaderForVersion(ModelType.MOXY, + schemaVersions.getDefaultVersion()); + } } diff --git a/aai-core/src/main/java/org/onap/aai/restcore/search/GremlinGroovyShell.java b/aai-core/src/main/java/org/onap/aai/restcore/search/GremlinGroovyShell.java index 2b39af43..85e47223 100644 --- a/aai-core/src/main/java/org/onap/aai/restcore/search/GremlinGroovyShell.java +++ b/aai-core/src/main/java/org/onap/aai/restcore/search/GremlinGroovyShell.java @@ -26,6 +26,8 @@ import groovy.lang.Script; import java.util.Map; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; +import org.onap.aai.serialization.engines.QueryStyle; import org.onap.aai.serialization.engines.TransactionalGraphEngine; /** @@ -57,4 +59,9 @@ public class GremlinGroovyShell extends AAIAbstractGroovyShell { public String executeTraversal(TransactionalGraphEngine engine, String traversal, Map<String, Object> params) { throw new UnsupportedOperationException(); } + + @Override + public String executeTraversal(TransactionalGraphEngine engine, String traversal, Map<String, Object> params, QueryStyle style, GraphTraversalSource source) { + throw new UnsupportedOperationException(); + } } diff --git a/aai-core/src/main/java/org/onap/aai/restcore/search/GroovyQueryBuilder.java b/aai-core/src/main/java/org/onap/aai/restcore/search/GroovyQueryBuilder.java index ba6acb66..fbaa7465 100644 --- a/aai-core/src/main/java/org/onap/aai/restcore/search/GroovyQueryBuilder.java +++ b/aai-core/src/main/java/org/onap/aai/restcore/search/GroovyQueryBuilder.java @@ -26,6 +26,7 @@ import groovy.lang.Script; import java.util.Map; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; import org.apache.tinkerpop.gremlin.structure.Vertex; import org.onap.aai.config.SpringContextAware; import org.onap.aai.introspection.Loader; @@ -53,11 +54,8 @@ public class GroovyQueryBuilder extends AAIAbstractGroovyShell { @Override public String executeTraversal(TransactionalGraphEngine engine, String traversal, Map<String, Object> params) { QueryBuilder<Vertex> builder = engine.getQueryBuilder(QueryStyle.GREMLIN_TRAVERSAL); - SchemaVersions schemaVersions = (SchemaVersions) SpringContextAware.getBean("schemaVersions"); - Loader loader = SpringContextAware.getBean(LoaderFactory.class).createLoaderForVersion(ModelType.MOXY, - schemaVersions.getDefaultVersion()); - builder.changeLoader(loader); + builder.changeLoader(getLoader()); Binding binding = new Binding(params); binding.setVariable("builder", builder); Script script = shell.parse(traversal); @@ -74,4 +72,17 @@ public class GroovyQueryBuilder extends AAIAbstractGroovyShell { public GraphTraversal<?, ?> executeTraversal(String traversal, Map<String, Object> params) { throw new UnsupportedOperationException(); } + + @Override + public String executeTraversal(TransactionalGraphEngine engine, String traversal, Map<String, Object> params, QueryStyle style, GraphTraversalSource traversalSource) { + QueryBuilder<Vertex> builder = engine.getQueryBuilder(style, traversalSource); + builder.changeLoader(getLoader()); + Binding binding = new Binding(params); + binding.setVariable("builder", builder); + Script script = shell.parse(traversal); + script.setBinding(binding); + script.run(); + + return builder.getQuery(); + } } diff --git a/aai-core/src/main/java/org/onap/aai/restcore/util/URITools.java b/aai-core/src/main/java/org/onap/aai/restcore/util/URITools.java index c3211fbe..a757d3db 100644 --- a/aai-core/src/main/java/org/onap/aai/restcore/util/URITools.java +++ b/aai-core/src/main/java/org/onap/aai/restcore/util/URITools.java @@ -47,22 +47,26 @@ public class URITools { MultivaluedMap<String, String> result = new MultivaluedHashMap<>(); String queryParams = uri.getRawQuery(); if (queryParams != null) { - String[] sections = queryParams.split("&"); - String[] query = null; - String key, value = ""; - for (String section : sections) { - query = section.split("="); - key = UriUtils.decode(query[0], "UTF-8"); - if (query[1] != null) { - query[1] = query[1].replaceAll("\\+", "%20"); + try { + String[] sections = queryParams.split("&"); + String[] query = null; + String key, value = ""; + for (String section : sections) { + query = section.split("="); + key = UriUtils.decode(query[0], "UTF-8"); + if (query[1] != null) { + query[1] = query[1].replaceAll("\\+", "%20"); + } + value = UriUtils.decode(query[1], "UTF-8"); + if (result.containsKey(key)) { + result.add(key, value); + } else { + result.putSingle(key, value); + } } - value = UriUtils.decode(query[1], "UTF-8"); - if (result.containsKey(key)) { - result.add(key, value); - } else { - result.putSingle(key, value); - } - } + } catch (UnsupportedEncodingException e) { + + } } return result; diff --git a/aai-core/src/main/java/org/onap/aai/serialization/db/DBSerializer.java b/aai-core/src/main/java/org/onap/aai/serialization/db/DBSerializer.java index 3996c07d..14fb8cb5 100644 --- a/aai-core/src/main/java/org/onap/aai/serialization/db/DBSerializer.java +++ b/aai-core/src/main/java/org/onap/aai/serialization/db/DBSerializer.java @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * org.onap.aai * ================================================================================ - * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017-2019 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. @@ -17,29 +17,13 @@ * limitations under the License. * ============LICENSE_END========================================================= */ - package org.onap.aai.serialization.db; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.google.common.base.CaseFormat; - -import java.io.UnsupportedEncodingException; -import java.lang.reflect.Array; -import java.lang.reflect.InvocationTargetException; -import java.net.MalformedURLException; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.*; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Future; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import javax.ws.rs.core.UriBuilder; - -import org.apache.commons.collections.IteratorUtils; +import org.apache.commons.lang.StringUtils; +import org.apache.tinkerpop.gremlin.process.traversal.Path; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__; import org.apache.tinkerpop.gremlin.structure.Direction; @@ -47,14 +31,13 @@ import org.apache.tinkerpop.gremlin.structure.Edge; import org.apache.tinkerpop.gremlin.structure.Vertex; import org.apache.tinkerpop.gremlin.structure.VertexProperty; import org.janusgraph.core.SchemaViolationException; -import org.javatuples.Triplet; +import org.javatuples.Pair; import org.onap.aai.concurrent.AaiCallable; import org.onap.aai.config.SpringContextAware; import org.onap.aai.db.props.AAIProperties; import org.onap.aai.edges.EdgeIngestor; import org.onap.aai.edges.EdgeRule; import org.onap.aai.edges.EdgeRuleQuery; -import org.onap.aai.edges.TypeAlphabetizer; import org.onap.aai.edges.enums.AAIDirection; import org.onap.aai.edges.enums.EdgeField; import org.onap.aai.edges.enums.EdgeProperty; @@ -67,10 +50,11 @@ import org.onap.aai.introspection.exceptions.AAIUnknownObjectException; import org.onap.aai.introspection.sideeffect.*; import org.onap.aai.logging.ErrorLogHelper; import org.onap.aai.logging.LogFormatTools; -import org.onap.aai.logging.LoggingContext; import org.onap.aai.logging.StopWatch; import org.onap.aai.parsers.query.QueryParser; +import org.onap.aai.parsers.relationship.RelationshipToURI; import org.onap.aai.parsers.uri.URIParser; +import org.onap.aai.parsers.uri.URIToObject; import org.onap.aai.parsers.uri.URIToRelationshipObject; import org.onap.aai.query.builder.QueryBuilder; import org.onap.aai.schema.enums.ObjectMetadata; @@ -83,16 +67,32 @@ import org.onap.aai.setup.SchemaVersion; import org.onap.aai.setup.SchemaVersions; import org.onap.aai.util.AAIConfig; import org.onap.aai.util.AAIConstants; +import org.onap.aai.util.delta.*; import org.onap.aai.workarounds.NamingExceptions; import org.springframework.context.ApplicationContext; -public class DBSerializer { - - private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(DBSerializer.class); +import javax.ws.rs.core.UriBuilder; +import java.io.UnsupportedEncodingException; +import java.lang.reflect.Array; +import java.lang.reflect.InvocationTargetException; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.*; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.regex.Matcher; +import java.util.regex.Pattern; - private static final String IMPLICIT_DELETE = "Implicit DELETE"; +public class DBSerializer { - private static final String MISSING_REQUIRED_NODE_PROPERTY = "Vertex missing required aai-node-type property"; + private static final Logger LOGGER = LoggerFactory.getLogger(DBSerializer.class); + private static final String RELATIONSHIP_LABEL = "relationship-label"; + private static final String RELATIONSHIP = "relationship"; + public static final String FALSE = "false"; + public static final String AAI_6145 = "AAI_6145"; + public static final String AAI_6129 = "AAI_6129"; private final TransactionalGraphEngine engine; private final String sourceOfTruth; @@ -108,6 +108,12 @@ public class DBSerializer { private SchemaVersions schemaVersions; private Set<String> namedPropNodes; + private Map<String, ObjectDelta> objectDeltas = new LinkedHashMap<>(); + private Map<Vertex, Boolean> updatedVertexes = new LinkedHashMap<>(); + private Set<Vertex> edgeVertexes = new LinkedHashSet<>(); + private Map<String, Pair<Introspector, LinkedHashMap<String, Introspector>>> impliedDeleteUriObjectPair = new LinkedHashMap<>(); + private int notificationDepth; + private boolean isDeltaEventsEnabled; /** * Instantiates a new DB serializer. @@ -124,15 +130,39 @@ public class DBSerializer { this.sourceOfTruth = sourceOfTruth; this.introspectionType = introspectionType; this.schemaVersions = (SchemaVersions) SpringContextAware.getBean("schemaVersions"); - SchemaVersion LATEST = schemaVersions.getDefaultVersion(); + SchemaVersion latestVersion = schemaVersions.getDefaultVersion(); this.latestLoader = - SpringContextAware.getBean(LoaderFactory.class).createLoaderForVersion(introspectionType, LATEST); + SpringContextAware.getBean(LoaderFactory.class).createLoaderForVersion(introspectionType, latestVersion); this.version = version; this.loader = SpringContextAware.getBean(LoaderFactory.class).createLoaderForVersion(introspectionType, version); this.namedPropNodes = this.latestLoader.getNamedPropNodes(); this.baseURL = AAIConfig.get(AAIConstants.AAI_SERVER_URL_BASE); this.currentTimeMillis = System.currentTimeMillis(); + // If creating the DBSerializer the old way then set the notification depth to maximum + this.notificationDepth = AAIProperties.MAXIMUM_DEPTH; + initBeans(); + } + + public DBSerializer(SchemaVersion version, + TransactionalGraphEngine engine, + ModelType introspectionType, + String sourceOfTruth, + int notificationDepth) throws AAIException { + this.engine = engine; + this.sourceOfTruth = sourceOfTruth; + this.introspectionType = introspectionType; + this.schemaVersions = (SchemaVersions) SpringContextAware.getBean("schemaVersions"); + SchemaVersion latestVersion = schemaVersions.getDefaultVersion(); + this.latestLoader = + SpringContextAware.getBean(LoaderFactory.class).createLoaderForVersion(introspectionType, latestVersion); + this.version = version; + this.loader = + SpringContextAware.getBean(LoaderFactory.class).createLoaderForVersion(introspectionType, version); + this.namedPropNodes = this.latestLoader.getNamedPropNodes(); + this.baseURL = AAIConfig.get(AAIConstants.AAI_SERVER_URL_BASE); + this.currentTimeMillis = System.currentTimeMillis(); + this.notificationDepth = notificationDepth; initBeans(); } @@ -143,10 +173,7 @@ public class DBSerializer { setEdgeIngestor(ei); EdgeSerializer es = ctx.getBean(EdgeSerializer.class); setEdgeSerializer(es); - } - - private void backupESInit() { - setEdgeSerializer(new EdgeSerializer(this.edgeRules)); + isDeltaEventsEnabled = Boolean.parseBoolean(SpringContextAware.getApplicationContext().getEnvironment().getProperty("delta.events.enabled", FALSE)); } public void setEdgeSerializer(EdgeSerializer edgeSer) { @@ -165,31 +192,95 @@ public class DBSerializer { return this.edgeRules; } + public Map<Vertex, Boolean> getUpdatedVertexes() { + return updatedVertexes; + } + + public Map<String, Pair<Introspector, LinkedHashMap<String, Introspector>>> getImpliedDeleteUriObjectPair(){ + return impliedDeleteUriObjectPair; + } + /** * Touch standard vertex properties. - * - * @param v the v + * @param v the v * @param isNewVertex the is new vertex */ public void touchStandardVertexProperties(Vertex v, boolean isNewVertex) { String timeNowInSec = Long.toString(currentTimeMillis); - if (isNewVertex) { + String uuid = UUID.randomUUID().toString(); v.property(AAIProperties.SOURCE_OF_TRUTH, this.sourceOfTruth); - v.property(AAIProperties.CREATED_TS, timeNowInSec); - v.property(AAIProperties.AAI_UUID, UUID.randomUUID().toString()); + v.property(AAIProperties.CREATED_TS, currentTimeMillis); + v.property(AAIProperties.AAI_UUID, uuid); + v.property(AAIProperties.RESOURCE_VERSION, timeNowInSec); + v.property(AAIProperties.LAST_MOD_TS, currentTimeMillis); + v.property(AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, this.sourceOfTruth); + } else { + if(isDeltaEventsEnabled) { + standardVertexPropsDeltas(v, timeNowInSec); + } + v.property(AAIProperties.RESOURCE_VERSION, timeNowInSec); + v.property(AAIProperties.LAST_MOD_TS, currentTimeMillis); + v.property(AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, this.sourceOfTruth); } - v.property(AAIProperties.RESOURCE_VERSION, timeNowInSec); - v.property(AAIProperties.LAST_MOD_TS, timeNowInSec); - v.property(AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, this.sourceOfTruth); + } + private void standardVertexPropsDeltas(Vertex v, String timeNowInSec) { + String uri = v.property(AAIProperties.AAI_URI).value().toString(); + long createdTs = (Long) v.property(AAIProperties.CREATED_TS).value(); + DeltaAction objDeltaAction = createdTs == currentTimeMillis ? DeltaAction.CREATE : DeltaAction.UPDATE; + if (getObjectDeltas().containsKey(uri)) { + getObjectDeltas().get(uri).setAction(objDeltaAction); + } + + addPropDelta(uri, AAIProperties.AAI_UUID, PropertyDeltaFactory.getDelta(DeltaAction.STATIC, v.property(AAIProperties.AAI_UUID).value()), objDeltaAction); + addPropDelta(uri, AAIProperties.NODE_TYPE, PropertyDeltaFactory.getDelta(DeltaAction.STATIC, v.property(AAIProperties.NODE_TYPE).value()), objDeltaAction); + addPropDelta(uri, AAIProperties.SOURCE_OF_TRUTH, PropertyDeltaFactory.getDelta(DeltaAction.STATIC, v.property(AAIProperties.SOURCE_OF_TRUTH).value()), objDeltaAction); + addPropDelta(uri, AAIProperties.CREATED_TS, PropertyDeltaFactory.getDelta(DeltaAction.STATIC, v.property(AAIProperties.CREATED_TS).value()), objDeltaAction); + + if (objDeltaAction.equals(DeltaAction.UPDATE)) { + addPropDelta( + uri, + AAIProperties.RESOURCE_VERSION, + PropertyDeltaFactory.getDelta(objDeltaAction, timeNowInSec, v.property(AAIProperties.RESOURCE_VERSION).value()), + objDeltaAction + ); + addPropDelta( + uri, + AAIProperties.LAST_MOD_TS, + PropertyDeltaFactory.getDelta(objDeltaAction, currentTimeMillis, v.property(AAIProperties.LAST_MOD_TS).value()), + objDeltaAction + ); + addPropDelta( + uri, + AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, + PropertyDeltaFactory.getDelta(objDeltaAction, this.sourceOfTruth, v.property(AAIProperties.LAST_MOD_SOURCE_OF_TRUTH).value()), + objDeltaAction + ); + } else { + addPropDelta(uri, AAIProperties.RESOURCE_VERSION, PropertyDeltaFactory.getDelta(objDeltaAction, v.property(AAIProperties.RESOURCE_VERSION).value()), objDeltaAction); + addPropDelta(uri, AAIProperties.LAST_MOD_TS, PropertyDeltaFactory.getDelta(objDeltaAction, v.property(AAIProperties.LAST_MOD_TS).value()), objDeltaAction); + addPropDelta(uri, AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, PropertyDeltaFactory.getDelta(objDeltaAction, v.property(AAIProperties.LAST_MOD_SOURCE_OF_TRUTH).value()), objDeltaAction); + } } - private void touchStandardVertexProperties(String nodeType, Vertex v, boolean isNewVertex) { + public Map<String, ObjectDelta> getObjectDeltas() {return objectDeltas;} + + private void addPropDelta(String uri, String prop, PropertyDelta delta, DeltaAction objDeltaAction) { + ObjectDelta objectDelta = this.objectDeltas.getOrDefault(uri, new ObjectDelta(uri, objDeltaAction, this.sourceOfTruth, this.currentTimeMillis)); + objectDelta.addPropertyDelta(prop, delta); + objectDeltas.put(uri, objectDelta); + } + private void addRelationshipDelta(String uri, RelationshipDelta delta, DeltaAction objDeltaAction) { + ObjectDelta objectDelta = this.objectDeltas.getOrDefault(uri, new ObjectDelta(uri, objDeltaAction, this.sourceOfTruth, this.currentTimeMillis)); + objectDelta.addRelationshipDelta(delta); + objectDeltas.put(uri, objectDelta); + } + + private void touchStandardVertexProperties(String nodeType, Vertex v, boolean isNewVertex) { v.property(AAIProperties.NODE_TYPE, nodeType); touchStandardVertexProperties(v, isNewVertex); - } /** @@ -197,14 +288,12 @@ public class DBSerializer { * * @param wrappedObject the wrapped object * @return the vertex - * @throws UnsupportedEncodingException the unsupported encoding exception - * @throws AAIException the AAI exception */ public Vertex createNewVertex(Introspector wrappedObject) { Vertex v; try { StopWatch.conditionalStart(); - v = this.engine.tx().addVertex(); + v = this.engine.tx().addVertex(wrappedObject.getDbName()); touchStandardVertexProperties(wrappedObject.getDbName(), v, true); } finally { dbTimeMsecs += StopWatch.stopIfStarted(); @@ -227,7 +316,7 @@ public class DBSerializer { if (className.lastIndexOf('.') == -1) { return className; } - returnValue = className.substring(className.lastIndexOf('.') + 1, className.length()); + returnValue = className.substring(className.lastIndexOf('.') + 1); return returnValue; } @@ -240,15 +329,9 @@ public class DBSerializer { * @param uriQuery the uri query * @param identifier the identifier * @throws SecurityException the security exception - * @throws IllegalAccessException the illegal access exception * @throws IllegalArgumentException the illegal argument exception - * @throws InvocationTargetException the invocation target exception - * @throws InstantiationException the instantiation exception - * @throws InterruptedException the interrupted exception - * @throws NoSuchMethodException the no such method exception * @throws AAIException the AAI exception * @throws UnsupportedEncodingException the unsupported encoding exception - * @throws AAIUnknownObjectException */ public void serializeToDb(Introspector obj, Vertex v, QueryParser uriQuery, String identifier, String requestContext) throws AAIException, UnsupportedEncodingException { @@ -284,8 +367,6 @@ public class DBSerializer { if (isTopLevel) { addUriIfNeeded(v, obj.getURI()); } - - processObject(obj, v, requestContext); if (!isTopLevel) { URI uri = this.getURIForVertex(v); URIParser parser = new URIParser(this.loader, uri); @@ -293,6 +374,7 @@ public class DBSerializer { addUriIfNeeded(v, uri.toString()); } } + processObject(obj, v, requestContext); } catch (SchemaViolationException e) { throw new AAIException("AAI_6117", e); } finally { @@ -302,7 +384,7 @@ public class DBSerializer { private void addUriIfNeeded(Vertex v, String uri) { VertexProperty<String> uriProp = v.property(AAIProperties.AAI_URI); - if (!uriProp.isPresent() || (uriProp.isPresent() && !uriProp.value().equals(uri))) { + if (!uriProp.isPresent() || !uriProp.value().equals(uri)) { v.property(AAIProperties.AAI_URI, uri); } } @@ -310,43 +392,42 @@ public class DBSerializer { /** * Process object. * - * @param <T> the generic type * @param obj the obj * @param v the v * @return the list - * @throws IllegalAccessException the illegal access exception * @throws IllegalArgumentException the illegal argument exception - * @throws InvocationTargetException the invocation target exception - * @throws InstantiationException the instantiation exception - * @throws NoSuchMethodException the no such method exception * @throws SecurityException the security exception * @throws AAIException the AAI exception * @throws UnsupportedEncodingException the unsupported encoding exception - * @throws AAIUnknownObjectException */ /* * Helper method for reflectToDb * Handles all the property setting */ - private <T> List<Vertex> processObject(Introspector obj, Vertex v, String requestContext) + private List<Vertex> processObject(Introspector obj, Vertex v, String requestContext) throws UnsupportedEncodingException, AAIException { Set<String> properties = new LinkedHashSet<>(obj.getProperties()); properties.remove(AAIProperties.RESOURCE_VERSION); List<Vertex> dependentVertexes = new ArrayList<>(); List<Vertex> processedVertexes = new ArrayList<>(); - boolean isComplexType = false; - boolean isListType = false; - if (!obj.isContainer()) { - this.touchStandardVertexProperties(v, false); + + boolean isComplexType ; + boolean isListType; + + // If the notification depth is set to maximum + // this is the behavior of the expected clients + if(notificationDepth == AAIProperties.MAXIMUM_DEPTH) { + if (!obj.isContainer()) { + this.touchStandardVertexProperties(v, false); + } } this.executePreSideEffects(obj, v); for (String property : properties) { - Object value = null; final String propertyType; propertyType = obj.getType(property); isComplexType = obj.isComplexType(property); isListType = obj.isListType(property); - value = obj.getValue(property); + Object value = obj.getValue(property); if (!(isComplexType || isListType)) { boolean canModify = this.canModify(obj, property, requestContext); @@ -362,16 +443,28 @@ public class DBSerializer { // they are populated dynamically on GETs continue; } + Object oldValue = v.property(dbProperty).orElse(null); + String uri = getURIForVertex(v).toString(); if (value != null) { - if (!value.equals(v.property(dbProperty).orElse(null))) { + if (!value.equals(oldValue)) { if (propertyType.toLowerCase().contains(".long")) { v.property(dbProperty, new Integer(((Long) value).toString())); } else { v.property(dbProperty, value); } + if (isDeltaEventsEnabled) { + createDeltaProperty(uri, value, dbProperty, oldValue); + } + this.updatedVertexes.putIfAbsent(v, false); } } else { - v.property(dbProperty).remove(); + if (oldValue != null) { + v.property(dbProperty).remove(); + if (isDeltaEventsEnabled) { + addPropDelta(uri, dbProperty, PropertyDeltaFactory.getDelta(DeltaAction.DELETE, oldValue), DeltaAction.UPDATE); + } + this.updatedVertexes.putIfAbsent(v, false); + } } } } else if (isListType) { @@ -386,7 +479,21 @@ public class DBSerializer { } } else { // simple list case - engine.setListProperty(v, property, list); + if (isDeltaEventsEnabled) { + String uri = getURIForVertex(v).toString(); + List<Object> oldVal = engine.getListProperty(v, property); + engine.setListProperty(v, property, list); + if (list == null || list.isEmpty()) { // property delete scenario, there is no new value + if (oldVal != null && !oldVal.isEmpty()) { // and there is an old value + addPropDelta(uri, property, PropertyDeltaFactory.getDelta(DeltaAction.DELETE, oldVal), DeltaAction.UPDATE); + } + } else { // is either a create or update and is handled by the called method + createDeltaProperty(uri, list, property, oldVal); + } + } else { + engine.setListProperty(v, property, list); + } + this.updatedVertexes.putIfAbsent(v, false); } } else { // method.getReturnType() is not 'simple' then create a vertex and edge recursively returning an edge @@ -427,62 +534,192 @@ public class DBSerializer { } this.writeThroughDefaults(v, obj); /* handle those vertexes not touched */ - for (Vertex toBeRemoved : processedVertexes) { - dependentVertexes.remove(toBeRemoved); + for (Vertex toBeKept : processedVertexes) { + dependentVertexes.remove(toBeKept); } - // If the dependent vertices are not empty, then with - // the current behaviour, it should remove the vertices implicitly - // We are updating the code to properly log which call - // is doing this so the SE can work with the clients making the call to - // tell them not to call this API and can hopefully deprecate this - // functionality in the future releases - if (!dependentVertexes.isEmpty()) { + ImpliedDelete impliedDelete = new ImpliedDelete(engine, this); + List<Vertex> impliedDeleteVertices = impliedDelete.execute(v.id(), sourceOfTruth, obj.getName(), dependentVertexes); + + if(notificationDepth == AAIProperties.MINIMUM_DEPTH){ + for(Vertex curVertex : impliedDeleteVertices){ + if(!curVertex.property("aai-uri").isPresent()){ + LOGGER.debug("Encountered an vertex {} with missing aai-uri", curVertex.id()); + continue; + } + String curAaiUri = curVertex.<String>property(AAIProperties.AAI_URI).value(); + Introspector curObj = this.getLatestVersionView(curVertex, notificationDepth); - LoggingContext.responseDescription(IMPLICIT_DELETE); + LinkedHashMap<String, Introspector> curObjRelated = new LinkedHashMap<>(); - // Find all the deletable vertices from the dependent vertices that should be deleted - // So for each of the following dependent vertices, - // we will use the edge properties and do the cascade delete - List<Vertex> impliedDeleteVertices = this.engine.getQueryEngine().findDeletable(dependentVertexes); - int impliedDeleteCount = impliedDeleteVertices.size(); + if(!curObj.isTopLevel()){ + curObjRelated.putAll(this.getRelatedObjects(engine.getQueryEngine(), curVertex, curObj, this.loader)); + } - LOGGER.warn( - "For the vertex with id {}, doing an implicit delete on update will delete total of {} vertexes", - v.id(), impliedDeleteCount); + if(!impliedDeleteUriObjectPair.containsKey(curAaiUri)){ + impliedDeleteUriObjectPair.put(curAaiUri, new Pair<>(curObj, curObjRelated)); + } + } + } - String impliedDeleteLogEnabled = AAIConfig.get(AAIConstants.AAI_IMPLIED_DELETE_LOG_ENABLED, "true"); + impliedDelete.delete(impliedDeleteVertices); - int impliedDeleteLogLimit = AAIConfig.getInt(AAIConstants.AAI_IMPLIED_DELETE_LOG_LIMIT, "-1"); + // touch svp using vertex list for what changed + // if the notification depth is zero + if(notificationDepth == AAIProperties.MINIMUM_DEPTH){ + this.updatedVertexes.entrySet().stream() + .filter(e -> !e.getValue()) + .filter(e -> !edgeVertexes.contains(e.getKey())) + .forEach(e -> { + this.touchStandardVertexProperties(e.getKey(), false); + e.setValue(true); + }); + } + this.executePostSideEffects(obj, v); + return processedVertexes; + } - if (impliedDeleteLogLimit == -1) { - impliedDeleteLogLimit = Integer.MAX_VALUE; - } + private void createDeltaProperty(String uri, Object value, String dbProperty, Object oldValue) { + if (oldValue == null) { + addPropDelta(uri, dbProperty, PropertyDeltaFactory.getDelta(DeltaAction.CREATE, value), DeltaAction.UPDATE); + } else { + addPropDelta(uri, dbProperty, PropertyDeltaFactory.getDelta(DeltaAction.UPDATE, value, oldValue), DeltaAction.UPDATE); + } + } - // If the logging is enabled for implied delete - // then log the payload in the latest format - if ("true".equals(impliedDeleteLogEnabled) && impliedDeleteCount <= impliedDeleteLogLimit) { - for (Vertex vertex : impliedDeleteVertices) { - Introspector introspector = null; - try { - introspector = getLatestVersionView(vertex); - if (LOGGER.isInfoEnabled()) { - LOGGER.info("Implied delete object in json format {}", introspector.marshal(false)); - } - } catch (Exception ex) { - LOGGER.warn( - "Encountered an exception during retrieval of vertex properties with vertex-id {} -> {}", - v.id(), LogFormatTools.getStackTop(ex)); - } + public HashMap<String, Introspector> getRelatedObjects(QueryEngine queryEngine, Vertex v, + Introspector obj, Loader loader) throws IllegalArgumentException, SecurityException, UnsupportedEncodingException, AAIException { + + HashMap<String, Introspector> relatedVertices = new HashMap<>(); + VertexProperty aaiUriProperty = v.property(AAIProperties.AAI_URI); + + if (!aaiUriProperty.isPresent()) { + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("For the given vertex {}, it seems aai-uri is not present so not getting related objects", + v.id().toString()); + } else { + LOGGER.info( + "It seems aai-uri is not present in vertex, so not getting related objects, for more info enable debug log"); + } + return relatedVertices; + } + + String aaiUri = aaiUriProperty.value().toString(); + + if (!obj.isTopLevel()) { + String[] uriList = convertIntrospectorToUriList(aaiUri, obj, loader); + List<Vertex> vertexChain; + // If the uriList is null then there is something wrong with converting the uri + // into a list of aai-uris so falling back to the old mechanism for finding parents + if (uriList == null) { + LOGGER.info( + "Falling back to the old mechanism due to unable to convert aai-uri to list of uris but this is not optimal"); + vertexChain = queryEngine.findParents(v); + } else if (uriList.length == 1) { + // If the uri list is size 1 the only uri in the list is the one represented by v thus no need to query + vertexChain = Collections.singletonList(v); + } else { + // the uriList at element 0 is the node in question and should not be included in the vertex chain lookup. + vertexChain = queryEngine.findParents(Arrays.copyOfRange(uriList, 1, uriList.length)); + // inject v into start of vertexChain + vertexChain.add(0, v); + } + for (Vertex vertex : vertexChain) { + try { + final Introspector vertexObj = this.getVertexProperties(vertex); + relatedVertices.put(vertexObj.getObjectId(), vertexObj); + } catch (AAIUnknownObjectException e) { + LOGGER.warn("Unable to get vertex properties, partial list of related vertices returned"); } } + } else { + try { + final Introspector vertexObj = this.getVertexProperties(v); + relatedVertices.put(vertexObj.getObjectId(), vertexObj); + } catch (AAIUnknownObjectException e) { + LOGGER.warn("Unable to get vertex properties, partial list of related vertices returned"); + } + } + + return relatedVertices; + } + + /** + * Given an uri, introspector object and loader object + * it will check if the obj is top level object if it is, + * it will return immediately returning the uri passed in + * If it isn't, it will go through, get the uriTemplate + * from the introspector object and get the count of "/"s + * and remove that part of the uri using substring + * and keep doing that until the current object is top level + * Also added the max depth just so worst case scenario + * Then keep adding aai-uri to the list include the aai-uri passed in + * Convert that list into an array and return it + * <p> + * + * Example: + * + * <blockquote> + * aai-uri -> + * /cloud-infrastructure/cloud-regions/cloud-region/cloud-owner/cloud-region-id/tenants/tenant/tenant1/vservers/vserver/v1 + * + * Given the uriTemplate vserver -> /vservers/vserver/{vserver-id} + * it converts to /vservers/vserver + * + * lastIndexOf /vservers/vserver in + * /cloud-infrastructure/cloud-regions/cloud-region/cloud-owner/cloud-region-id/tenants/tenant/tenant1/vservers/vserver/v1 + * ^ + * | + * | + * lastIndexOf + * Use substring to get the string from 0 to that lastIndexOf + * aai-uri -> /cloud-infrastructure/cloud-regions/cloud-region/cloud-owner/cloud-region-id/tenants/tenant/tenant1 + * + * From this new aai-uri, generate a introspector from the URITOObject class + * and keep doing this until you + * + * </blockquote> + * + * @param aaiUri - aai-uri of the vertex representating the unique id of a given vertex + * @param obj - introspector object of the given starting vertex + * @param loader - Type of loader which will always be MoxyLoader to support model driven + * @return an array of strings which can be used to get the vertexes of parent and grand parents from a given vertex + * @throws UnsupportedEncodingException + * @throws AAIException + */ + String[] convertIntrospectorToUriList(String aaiUri, Introspector obj, Loader loader) + throws UnsupportedEncodingException, AAIException { + + List<String> uriList = new ArrayList<>(); + String template; + String truncatedUri = aaiUri; + int depth = AAIProperties.MAXIMUM_DEPTH; + uriList.add(truncatedUri); + + while (depth >= 0 && !obj.isTopLevel()) { + template = obj.getMetadata(ObjectMetadata.URI_TEMPLATE); + + if (template == null) { + LOGGER.warn("Unable to find the uriTemplate for the object {}", obj.getDbName()); + return null; + } - // After all the appropriate logging, calling the delete to delete the affected vertices - this.delete(impliedDeleteVertices); + int templateCount = StringUtils.countMatches(template, "/"); + int truncatedUriCount = StringUtils.countMatches(truncatedUri, "/"); + + if (templateCount > truncatedUriCount) { + LOGGER.warn("Template uri {} contains more slashes than truncatedUri {}", template, truncatedUri); + return null; + } + + int cutIndex = StringUtils.ordinalIndexOf(truncatedUri, "/", truncatedUriCount - templateCount + 1); + truncatedUri = StringUtils.substring(truncatedUri, 0, cutIndex); + uriList.add(truncatedUri); + obj = new URIToObject(loader, UriBuilder.fromPath(truncatedUri).build()).getEntity(); + depth--; } - this.executePostSideEffects(obj, v); - return processedVertexes; + return uriList.toArray(new String[0]); } /** @@ -491,9 +728,7 @@ public class DBSerializer { * @param obj the obj * @param vertex the vertex * @throws SecurityException the security exception - * @throws IllegalAccessException the illegal access exception * @throws IllegalArgumentException the illegal argument exception - * @throws InvocationTargetException the invocation target exception * @throws UnsupportedEncodingException the unsupported encoding exception * @throws AAIException the AAI exception */ @@ -517,28 +752,141 @@ public class DBSerializer { * @throws AAIException the AAI exception */ private void processRelationshipList(Introspector wrapped, Vertex v) - throws UnsupportedEncodingException, AAIException { + throws UnsupportedEncodingException, AAIException { + + List<Object> relationships = wrapped.getValue("relationship"); + String mainUri = getURIForVertex(v).toString(); + String aNodeType = v.property(AAIProperties.NODE_TYPE).value().toString(); + EdgeRuleQuery.Builder cousinQueryBuilder = new EdgeRuleQuery.Builder(aNodeType) + .edgeType(EdgeType.COUSIN) + .version(wrapped.getVersion()); + EdgeRuleQuery.Builder treeQueryBuilder = new EdgeRuleQuery.Builder(aNodeType) + .edgeType(EdgeType.TREE) + .version(wrapped.getVersion()); - List<Object> relationships = (List<Object>) wrapped.getValue("relationship"); - - List<Triplet<Vertex, Vertex, String>> addEdges = new ArrayList<>(); - List<Edge> existingEdges = this.engine.getQueryEngine().findEdgesForVersion(v, wrapped.getLoader()); + EdgeIngestor edgeIngestor = SpringContextAware.getBean(EdgeIngestor.class); + Set<Pair<String, String>> cousinUriAndLabels = new LinkedHashSet<>(); for (Object relationship : relationships) { - Edge e = null; - Vertex cousinVertex = null; - String label = null; + + String label; Introspector wrappedRel = IntrospectorFactory.newInstance(this.introspectionType, relationship); - QueryParser parser = engine.getQueryBuilder().createQueryFromRelationship(wrappedRel); + String relUri = urlToUri(new RelationshipToURI(loader, wrappedRel).getUri().toString()); + + if (relUri.startsWith("/vnf/")) { + QueryParser parser = engine.getQueryBuilder().createQueryFromRelationship(wrappedRel); + List<Vertex> results = parser.getQueryBuilder().toList(); + if (results.isEmpty()) { + final AAIException ex = new AAIException(AAI_6129, + String.format("Node of type %s. Could not find object at: %s", parser.getResultType(), parser.getUri())); + ex.getTemplateVars().add(parser.getResultType()); + ex.getTemplateVars().add(parser.getUri().toString()); + throw ex; + } else { + // still an issue if there's more than one + if (results.get(0).property(AAIProperties.AAI_URI).isPresent()) { + relUri = results.get(0).value(AAIProperties.AAI_URI); + } else { + LOGGER.warn("Not processing the vertex {} because its missing required property aai-uri", results.get(0).id()); + continue; + } + } + } - if (wrappedRel.hasProperty("relationship-label")) { - label = wrappedRel.getValue("relationship-label"); + if (wrappedRel.getValue(RELATIONSHIP_LABEL) != null) { + label = wrappedRel.getValue(RELATIONSHIP_LABEL); + } else { + URIToObject uriToObject = new URIToObject(loader, URI.create(relUri)); + String bNodeType = uriToObject.getEntityName(); + EdgeRuleQuery ruleQuery = cousinQueryBuilder.to(bNodeType).build(); + if (!edgeIngestor.hasRule(ruleQuery)) { + EdgeRuleQuery treeQuery = treeQueryBuilder.to(bNodeType).build(); + if (edgeIngestor.hasRule(treeQuery)) { + throw new AAIException(AAI_6145); //attempted to create cousin edge for a parent-child edge rule + } + throw new AAIException("AAI_6120", String.format( + "No EdgeRule found for passed nodeTypes: %s, %s.", + aNodeType, bNodeType)); + } else { + try { + final List<EdgeRule> rules = new ArrayList<>(edgeIngestor.getRules(ruleQuery).values()); + if (rules.size() == 1) { + label = rules.get(0).getLabel(); + } else { + Optional<EdgeRule> defaultRule = rules.stream().filter(EdgeRule::isDefault).findFirst(); + if (defaultRule.isPresent()) { + label = defaultRule.get().getLabel(); + } else { + throw new AAIException(AAI_6145); + } + } + } catch (EdgeRuleNotFoundException ea) { + throw new AAIException(AAI_6145, ea); + } + } } + cousinUriAndLabels.add(Pair.with(relUri, label)); + } + + List<Path> paths = this.engine.getQueryEngine().findCousinsAsPath(v); + Set<Path> toRemove = new HashSet<>(); + + + // for each path 3 things can happen: + // 1. The edge rule that created it is not in this version no action is to be taken on that edge + // 2. The edge rule exits in this version it's included in the request the edge is left alone + // 3. The edge rule exits in this version and is not included in the request it is marked for removal + for (Path path : paths) { + if (path.size() < 3) { + continue; + } + + // Path represents + // v ----related-to--> otherV + // In the above case, + // path objects get(0) returns vertex v + // path objects.get(1) returns edge related-to + // path objects.get(2) returns vertex otherV + Vertex otherV = path.get(2); + + String bUri; + if (otherV.property(AAIProperties.AAI_URI).isPresent()) { + bUri = otherV.value(AAIProperties.AAI_URI); + } else { + continue; + } + String edgeLabel = path.<Edge>get(1).label(); + + Pair<String, String> key = Pair.with(bUri, edgeLabel); + if (cousinUriAndLabels.contains(key)) { + cousinUriAndLabels.remove(key); + } else { + String bNodeType; + if (otherV.property(AAIProperties.NODE_TYPE).isPresent()) { + bNodeType = otherV.property(AAIProperties.NODE_TYPE).value().toString(); + } else { + continue; + } + EdgeRuleQuery ruleQuery = cousinQueryBuilder.to(bNodeType).label(edgeLabel).build(); + if (edgeIngestor.hasRule(ruleQuery)) { + toRemove.add(path); + } + } + + } + + Set<Pair<Vertex, String>> toBeCreated = new HashSet<>(); + for (Pair<String, String> cousinUriAndLabel : cousinUriAndLabels) { + Edge e; + Vertex cousinVertex; + String label = cousinUriAndLabel.getValue1(); + String cousinUri = cousinUriAndLabel.getValue0(); + QueryParser parser = engine.getQueryBuilder().createQueryFromURI(URI.create(cousinUri)); List<Vertex> results = parser.getQueryBuilder().toList(); if (results.isEmpty()) { - final AAIException ex = new AAIException("AAI_6129", - "Node of type " + parser.getResultType() + ". Could not find object at: " + parser.getUri()); + final AAIException ex = new AAIException(AAI_6129, + "Node of type " + parser.getResultType() + ". Could not find object at: " + parser.getUri()); ex.getTemplateVars().add(parser.getResultType()); ex.getTemplateVars().add(parser.getUri().toString()); throw ex; @@ -553,38 +901,56 @@ public class DBSerializer { EdgeRuleQuery.Builder baseQ = new EdgeRuleQuery.Builder(vType, cousinType).label(label); if (!edgeRules.hasRule(baseQ.build())) { - throw new AAIException("AAI_6120", - "No EdgeRule found for passed nodeTypes: " - + v.property(AAIProperties.NODE_TYPE).value().toString() + ", " - + cousinVertex.property(AAIProperties.NODE_TYPE).value().toString() - + (label != null ? (" with label " + label) : "") + "."); + throw new AAIException("AAI_6120", String.format( + "No EdgeRule found for passed nodeTypes: %s, %s%s.", + aNodeType, cousinType, label != null ? (" with label " + label) : "")); } else if (edgeRules.hasRule(baseQ.edgeType(EdgeType.TREE).build()) - && !edgeRules.hasRule(baseQ.edgeType(EdgeType.COUSIN).build())) { - throw new AAIException("AAI_6145"); + && !edgeRules.hasRule(baseQ.edgeType(EdgeType.COUSIN).build())) { + throw new AAIException(AAI_6145); } e = this.getEdgeBetween(EdgeType.COUSIN, v, cousinVertex, label); if (e == null) { - addEdges.add(new Triplet<>(v, cousinVertex, label)); - } else { - existingEdges.remove(e); + toBeCreated.add(Pair.with(cousinVertex, label)); } } } - for (Edge edge : existingEdges) { - edge.remove(); + for (Path path : toRemove) { + if(isDeltaEventsEnabled) { + deltaForEdge(mainUri, path.get(1), DeltaAction.DELETE_REL, DeltaAction.UPDATE); + } + this.updatedVertexes.putIfAbsent(v, false); + this.edgeVertexes.add(path.get(2)); + path.<Edge>get(1).remove(); } - for (Triplet<Vertex, Vertex, String> triplet : addEdges) { + + for (Pair<Vertex, String> create : toBeCreated) { try { - edgeSer.addEdge(this.engine.asAdmin().getTraversalSource(), triplet.getValue0(), triplet.getValue1(), - triplet.getValue2()); - } catch (NoEdgeRuleFoundException e) { - throw new AAIException("AAI_6129", e); + Edge e = edgeSer.addEdge(this.engine.asAdmin().getTraversalSource(), v, create.getValue0(), create.getValue1()); + if (isDeltaEventsEnabled) { + deltaForEdge(mainUri, e, DeltaAction.CREATE_REL, DeltaAction.UPDATE); + } + this.updatedVertexes.putIfAbsent(v, false); + this.edgeVertexes.add(create.getValue0()); + } catch (NoEdgeRuleFoundException ex) { + throw new AAIException(AAI_6129, ex); } } + } + + private void deltaForEdge(String mainUri, Edge edge, DeltaAction edgeAction, DeltaAction mainAction) { + RelationshipDelta relationshipDelta = new RelationshipDelta( + edgeAction, + edge.inVertex().property(AAIProperties.AAI_UUID).value().toString(), + edge.outVertex().property(AAIProperties.AAI_UUID).value().toString(), + edge.inVertex().property(AAIProperties.AAI_URI).value().toString(), + edge.outVertex().property(AAIProperties.AAI_URI).value().toString(), + edge.label()); + edge.properties().forEachRemaining(p -> relationshipDelta.addProp(p.key(), p.value().toString())); + addRelationshipDelta(mainUri, relationshipDelta, mainAction); } /** @@ -600,11 +966,9 @@ public class DBSerializer { Set<String> required = latest.getRequiredProperties(); for (String field : required) { - String defaultValue = null; - Object vertexProp = null; - defaultValue = latest.getPropertyMetadata(field).get(PropertyMetadata.DEFAULT_VALUE); + String defaultValue = latest.getPropertyMetadata(field).get(PropertyMetadata.DEFAULT_VALUE); if (defaultValue != null) { - vertexProp = v.<Object>property(field).orElse(null); + Object vertexProp = v.property(field).orElse(null); if (vertexProp == null) { v.property(field, defaultValue); } @@ -620,11 +984,7 @@ public class DBSerializer { * @param v the v * @param dependentObj the dependent obj * @return the vertex - * @throws IllegalAccessException the illegal access exception * @throws IllegalArgumentException the illegal argument exception - * @throws InvocationTargetException the invocation target exception - * @throws InstantiationException the instantiation exception - * @throws NoSuchMethodException the no such method exception * @throws SecurityException the security exception * @throws AAIException the AAI exception * @throws UnsupportedEncodingException the unsupported encoding exception @@ -633,23 +993,21 @@ public class DBSerializer { private Vertex reflectDependentVertex(Vertex v, Introspector dependentObj, String requestContext) throws AAIException, UnsupportedEncodingException { - // QueryParser p = this.engine.getQueryBuilder().createQueryFromURI(obj.getURI()); - // List<Vertex> items = p.getQuery().toList(); QueryBuilder<Vertex> query = this.engine.getQueryBuilder(v); query.createEdgeTraversal(EdgeType.TREE, v, dependentObj); query.createKeyQuery(dependentObj); List<Vertex> items = query.toList(); - Vertex dependentVertex = null; + Vertex dependentVertex; if (items.size() == 1) { dependentVertex = items.get(0); this.verifyResourceVersion("update", dependentObj.getDbName(), dependentVertex.<String>property(AAIProperties.RESOURCE_VERSION).orElse(null), - (String) dependentObj.getValue(AAIProperties.RESOURCE_VERSION), (String) dependentObj.getURI()); + dependentObj.getValue(AAIProperties.RESOURCE_VERSION), dependentObj.getURI()); } else { this.verifyResourceVersion("create", dependentObj.getDbName(), "", - (String) dependentObj.getValue(AAIProperties.RESOURCE_VERSION), (String) dependentObj.getURI()); + dependentObj.getValue(AAIProperties.RESOURCE_VERSION), dependentObj.getURI()); dependentVertex = createNewVertex(dependentObj); } @@ -664,11 +1022,7 @@ public class DBSerializer { * @param child the child * @param obj the obj * @return the vertex - * @throws IllegalAccessException the illegal access exception * @throws IllegalArgumentException the illegal argument exception - * @throws InvocationTargetException the invocation target exception - * @throws InstantiationException the instantiation exception - * @throws NoSuchMethodException the no such method exception * @throws SecurityException the security exception * @throws AAIException the AAI exception * @throws UnsupportedEncodingException the unsupported encoding exception @@ -699,7 +1053,10 @@ public class DBSerializer { child.property(AAIProperties.LINKED, true); } } - edgeSer.addTreeEdge(this.engine.asAdmin().getTraversalSource(), parent, child); + e = edgeSer.addTreeEdge(this.engine.asAdmin().getTraversalSource(), parent, child); + if(isDeltaEventsEnabled) { + deltaForEdge(child.property(AAIProperties.AAI_URI).value().toString(), e, DeltaAction.CREATE_REL, DeltaAction.CREATE); + } } return child; @@ -724,19 +1081,14 @@ public class DBSerializer { * @param cleanUp the clean up * @return the introspector * @throws AAIException the AAI exception - * @throws IllegalAccessException the illegal access exception * @throws IllegalArgumentException the illegal argument exception - * @throws InvocationTargetException the invocation target exception * @throws SecurityException the security exception - * @throws InstantiationException the instantiation exception - * @throws NoSuchMethodException the no such method exception * @throws UnsupportedEncodingException the unsupported encoding exception - * @throws MalformedURLException the malformed URL exception * @throws AAIUnknownObjectException * @throws URISyntaxException */ public Introspector dbToObject(List<Vertex> vertices, final Introspector obj, int depth, boolean nodeOnly, - String cleanUp) throws UnsupportedEncodingException, AAIException { + String cleanUp, boolean isSkipRelatedTo) throws UnsupportedEncodingException, AAIException { final int internalDepth; if (depth == Integer.MAX_VALUE) { internalDepth = depth--; @@ -747,7 +1099,7 @@ public class DBSerializer { if (vertices.size() > 1 && !obj.isContainer()) { dbTimeMsecs += StopWatch.stopIfStarted(); throw new AAIException("AAI_6136", - "query object mismatch: this object cannot hold multiple items." + obj.getDbName()); + "query object mismatch: this object cannot hold multiple items." + obj.getDbName()); } else if (obj.isContainer()) { final List getList; String listProperty = null; @@ -758,7 +1110,7 @@ public class DBSerializer { } } final String propertyName = listProperty; - getList = (List) obj.getValue(listProperty); + getList = obj.getValue(listProperty); /* * This is an experimental multithreading experiment @@ -768,28 +1120,15 @@ public class DBSerializer { List<Future<Object>> futures = new ArrayList<>(); - QueryEngine tgEngine = this.engine.getQueryEngine(); for (Vertex v : vertices) { - AaiCallable<Object> task = new AaiCallable<Object>() { @Override public Object process() throws UnsupportedEncodingException, AAIException { Set<Vertex> seen = new HashSet<>(); Introspector childObject; - try { - childObject = obj.newIntrospectorInstanceOfNestedProperty(propertyName); - } catch (AAIUnknownObjectException e) { - throw e; - } - try { - dbToObject(childObject, v, seen, internalDepth, nodeOnly, cleanUp); - } catch (UnsupportedEncodingException e) { - throw e; - } catch (AAIException e) { - throw e; - } + childObject = obj.newIntrospectorInstanceOfNestedProperty(propertyName); + dbToObject(childObject, v, seen, internalDepth, nodeOnly, cleanUp, isSkipRelatedTo); return childObject.getUnderlyingObject(); - // getList.add(childObject.getUnderlyingObject()); } }; futures.add(pool.submit(task)); @@ -798,17 +1137,14 @@ public class DBSerializer { for (Future<Object> future : futures) { try { getList.add(future.get()); - } catch (ExecutionException e) { - dbTimeMsecs += StopWatch.stopIfStarted(); - throw new AAIException("AAI_4000", e); - } catch (InterruptedException e) { + } catch (ExecutionException | InterruptedException e) { dbTimeMsecs += StopWatch.stopIfStarted(); throw new AAIException("AAI_4000", e); } } } else if (vertices.size() == 1) { Set<Vertex> seen = new HashSet<>(); - dbToObject(obj, vertices.get(0), seen, depth, nodeOnly, cleanUp); + dbToObject(obj, vertices.get(0), seen, depth, nodeOnly, cleanUp, isSkipRelatedTo); } else { // obj = null; } @@ -820,26 +1156,62 @@ public class DBSerializer { /** * Db to object. * + * @param vertices the vertices + * @param obj the obj + * @param depth the depth + * @param cleanUp the clean up + * @return the introspector + * @throws AAIException the AAI exception + * @throws IllegalArgumentException the illegal argument exception + * @throws SecurityException the security exception + * @throws UnsupportedEncodingException the unsupported encoding exception + * @throws AAIUnknownObjectException + * @throws URISyntaxException + */ + public Introspector dbToObject(List<Vertex> vertices, final Introspector obj, int depth, boolean nodeOnly, + String cleanUp) throws UnsupportedEncodingException, AAIException { + return dbToObject(vertices, obj, depth, nodeOnly, cleanUp, false); + } + + /** + * Db to object. + * * @param obj the obj * @param v the v * @param seen the seen * @param depth the depth * @param cleanUp the clean up * @return the introspector - * @throws IllegalAccessException the illegal access exception * @throws IllegalArgumentException the illegal argument exception - * @throws InvocationTargetException the invocation target exception * @throws SecurityException the security exception - * @throws InstantiationException the instantiation exception - * @throws NoSuchMethodException the no such method exception * @throws UnsupportedEncodingException the unsupported encoding exception * @throws AAIException the AAI exception - * @throws MalformedURLException the malformed URL exception * @throws AAIUnknownObjectException * @throws URISyntaxException */ private Introspector dbToObject(Introspector obj, Vertex v, Set<Vertex> seen, int depth, boolean nodeOnly, String cleanUp) throws AAIException, UnsupportedEncodingException { + return dbToObject(obj, v, seen, depth, nodeOnly, cleanUp, false); + } + + /** + * Db to object. + * + * @param obj the obj + * @param v the v + * @param seen the seen + * @param depth the depth + * @param cleanUp the clean up + * @return the introspector + * @throws IllegalArgumentException the illegal argument exception + * @throws SecurityException the security exception + * @throws UnsupportedEncodingException the unsupported encoding exception + * @throws AAIException the AAI exception + * @throws AAIUnknownObjectException + * @throws URISyntaxException + */ + private Introspector dbToObject(Introspector obj, Vertex v, Set<Vertex> seen, int depth, boolean nodeOnly, + String cleanUp, boolean isSkipRelatedTo) throws AAIException, UnsupportedEncodingException { if (depth < 0) { return null; @@ -850,7 +1222,6 @@ public class DBSerializer { boolean modified = false; for (String property : obj.getProperties(PropertyPredicates.isVisible())) { List<Object> getList = null; - Vertex[] vertices = null; if (!(obj.isComplexType(property) || obj.isListType(property))) { this.copySimpleProperty(property, obj, v); @@ -869,9 +1240,8 @@ public class DBSerializer { } else if (property.equals("relationship-list") && !nodeOnly) { /* relationships need to be handled correctly */ Introspector relationshipList = obj.newIntrospectorInstanceOfProperty(property); - relationshipList = createRelationshipList(v, relationshipList, cleanUp); + relationshipList = createRelationshipList(v, relationshipList, cleanUp, isSkipRelatedTo); if (relationshipList != null) { - modified = true; obj.setValue(property, relationshipList.getUnderlyingObject()); modified = true; } @@ -890,42 +1260,39 @@ public class DBSerializer { try { rule = edgeRules.getRule( - new EdgeRuleQuery.Builder(vType, childDbName).edgeType(EdgeType.TREE).build()); + new EdgeRuleQuery.Builder(vType, childDbName).edgeType(EdgeType.TREE).build()); } catch (EdgeRuleNotFoundException e) { throw new NoEdgeRuleFoundException(e); } catch (AmbiguousRuleChoiceException e) { throw new MultipleEdgeRuleFoundException(e); } if (!rule.getContains().equals(AAIDirection.NONE.toString())) { - // vertices = this.queryEngine.findRelatedVertices(v, Direction.OUT, rule.getLabel(), - // childDbName); + Direction ruleDirection = rule.getDirection(); - Iterator<Vertex> itr = v.vertices(ruleDirection, rule.getLabel()); - List<Vertex> verticesList = (List<Vertex>) IteratorUtils.toList(itr); - itr = verticesList.stream().filter(item -> { - return item.property(AAIProperties.NODE_TYPE).orElse("").equals(childDbName); - }).iterator(); - if (itr.hasNext()) { - getList = (List<Object>) obj.getValue(property); + List<Vertex> verticesList = new ArrayList<>(); + v.vertices(ruleDirection, rule.getLabel()).forEachRemaining(vertex -> { + if (vertex.property(AAIProperties.NODE_TYPE).orElse("").equals(childDbName)) { + verticesList.add(vertex); + } + }); + if (!verticesList.isEmpty()) { + getList = obj.getValue(property); } int processed = 0; - int removed = 0; - while (itr.hasNext()) { - Vertex childVertex = itr.next(); + for (Vertex childVertex : verticesList) { if (!seen.contains(childVertex)) { Introspector argumentObject = obj.newIntrospectorInstanceOfNestedProperty(property); Object result = - dbToObject(argumentObject, childVertex, seen, depth, nodeOnly, cleanUp); + dbToObject(argumentObject, childVertex, seen, depth, nodeOnly, cleanUp, isSkipRelatedTo); if (result != null) { getList.add(argumentObject.getUnderlyingObject()); } processed++; } else { - removed++; LOGGER.warn("Cycle found while serializing vertex id={}", - childVertex.id().toString()); + childVertex.id().toString()); } } if (processed == 0) { @@ -943,11 +1310,8 @@ public class DBSerializer { getList.addAll(temp); modified = true; } - } - } - } } @@ -969,27 +1333,26 @@ public class DBSerializer { Introspector obj = this.latestLoader.introspectorFromName(nodeType); Set<Vertex> seen = new HashSet<>(); int depth = 0; - String cleanUp = "false"; - boolean nodeOnly = true; StopWatch.conditionalStart(); - this.dbToObject(obj, v, seen, depth, nodeOnly, cleanUp); + this.dbToObject(obj, v, seen, depth, false, FALSE); dbTimeMsecs += StopWatch.stopIfStarted(); return obj; } public Introspector getLatestVersionView(Vertex v) throws AAIException, UnsupportedEncodingException { + return getLatestVersionView(v, AAIProperties.MAXIMUM_DEPTH); + } + + public Introspector getLatestVersionView(Vertex v, int depth) throws AAIException, UnsupportedEncodingException { String nodeType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null); if (nodeType == null) { throw new AAIException("AAI_6143"); } Introspector obj = this.latestLoader.introspectorFromName(nodeType); Set<Vertex> seen = new HashSet<>(); - int depth = AAIProperties.MAXIMUM_DEPTH; - String cleanUp = "false"; - boolean nodeOnly = false; StopWatch.conditionalStart(); - this.dbToObject(obj, v, seen, depth, nodeOnly, cleanUp); + this.dbToObject(obj, v, seen, depth, false, FALSE); dbTimeMsecs += StopWatch.stopIfStarted(); return obj; } @@ -1000,11 +1363,7 @@ public class DBSerializer { * @param property the property * @param obj the obj * @param v the v - * @throws InstantiationException the instantiation exception - * @throws IllegalAccessException the illegal access exception * @throws IllegalArgumentException the illegal argument exception - * @throws InvocationTargetException the invocation target exception - * @throws NoSuchMethodException the no such method exception * @throws SecurityException the security exception */ private void copySimpleProperty(String property, Introspector obj, Vertex v) { @@ -1014,65 +1373,22 @@ public class DBSerializer { } } - /** - * Load the introspector from the hashmap for the given property key - * - * @param property - vertex property - * @param obj - introspector object representing the vertex - * @param hashMap - Containing a list of pre-fetched properties for a given vertex - */ - private void copySimplePropertyFromHashMap(String property, Introspector obj, Map<String, Object> hashMap) { - - final Map<PropertyMetadata, String> metadata = obj.getPropertyMetadata(property); - String dbPropertyName = property; - - if (metadata.containsKey(PropertyMetadata.DB_ALIAS)) { - dbPropertyName = metadata.get(PropertyMetadata.DB_ALIAS); - } - - final Object temp = hashMap.getOrDefault(dbPropertyName, null); - - if (temp != null) { - obj.setValue(property, temp); - } - } - - /** - * Simple db to object. - * - * @param obj the obj - * @param v the v - * @throws InstantiationException the instantiation exception - * @throws IllegalAccessException the illegal access exception - * @throws IllegalArgumentException the illegal argument exception - * @throws InvocationTargetException the invocation target exception - * @throws NoSuchMethodException the no such method exception - * @throws SecurityException the security exception - */ - private void simpleDbToObject(Introspector obj, Vertex v) { - for (String key : obj.getProperties()) { - this.copySimpleProperty(key, obj, v); - } - } - public Map<String, Object> convertVertexToHashMap(Introspector obj, Vertex v) { - long startTime = System.currentTimeMillis(); - Set<String> simpleProperties = obj.getSimpleProperties(PropertyPredicates.isVisible()); String[] simplePropsArray = new String[simpleProperties.size()]; simplePropsArray = simpleProperties.toArray(simplePropsArray); Map<String, Object> simplePropsHashMap = new HashMap<>(simplePropsArray.length * 2); - v.properties(simplePropsArray).forEachRemaining((vp) -> simplePropsHashMap.put(vp.key(), vp.value())); + v.properties(simplePropsArray).forEachRemaining(vp -> simplePropsHashMap.put(vp.key(), vp.value())); return simplePropsHashMap; } - public Introspector dbToRelationshipObject(Vertex v) throws UnsupportedEncodingException, AAIException { + public Introspector dbToRelationshipObject(Vertex v, boolean isSkipRelatedTo) throws UnsupportedEncodingException, AAIException { Introspector relationshipList = this.latestLoader.introspectorFromName("relationship-list"); - relationshipList = createRelationshipList(v, relationshipList, "false"); + relationshipList = createRelationshipList(v, relationshipList, FALSE, isSkipRelatedTo); return relationshipList; } @@ -1083,136 +1399,96 @@ public class DBSerializer { * @param obj the obj * @param cleanUp the clean up * @return the object - * @throws InstantiationException the instantiation exception - * @throws IllegalAccessException the illegal access exception * @throws IllegalArgumentException the illegal argument exception - * @throws InvocationTargetException the invocation target exception - * @throws NoSuchMethodException the no such method exception * @throws SecurityException the security exception * @throws UnsupportedEncodingException the unsupported encoding exception * @throws AAIException the AAI exception - * @throws MalformedURLException the malformed URL exception * @throws URISyntaxException */ private Introspector createRelationshipList(Vertex v, Introspector obj, String cleanUp) throws UnsupportedEncodingException, AAIException { + // default boolean value for isSkipRelatedTo is false + return createRelationshipList(v, obj, cleanUp, false); + } - String[] cousinRules = new String[0]; - - try { - cousinRules = edgeRules.retrieveCachedCousinLabels(obj.getDbName()); - } catch (ExecutionException e) { - LOGGER.warn("Encountered an execution exception while retrieving labels for the node type {} using cached", - obj.getDbName(), e); - } - - List<Vertex> cousins = null; - if (cousinRules != null && cousinRules.length != 0) { - cousins = this.engine.getQueryEngine().findCousinVertices(v, cousinRules); - } else { - cousins = this.engine.getQueryEngine().findCousinVertices(v); - } + /** + * Creates the relationship list. + * + * @param v the v + * @param obj the obj + * @param cleanUp the clean up + * @param isSkipRelatedTo to determine adding related-to-property in response + * @return the object + * @throws IllegalArgumentException the illegal argument exception + * @throws SecurityException the security exception + * @throws UnsupportedEncodingException the unsupported encoding exception + * @throws AAIException the AAI exception + * @throws URISyntaxException + */ + private Introspector createRelationshipList(Vertex v, Introspector obj, String cleanUp, boolean isSkipRelatedTo) + throws UnsupportedEncodingException, AAIException { - List<Object> relationshipObjList = obj.getValue("relationship"); + List<Object> relationshipObjList = obj.getValue(RELATIONSHIP); VertexProperty nodeTypeProperty = v.property(AAIProperties.NODE_TYPE); if (!nodeTypeProperty.isPresent()) { - LoggingContext.responseDescription(MISSING_REQUIRED_NODE_PROPERTY); LOGGER.warn("Not processing the vertex {} because its missing required property aai-node-type", v.id()); - LoggingContext.remove(LoggingContext.LoggingField.RESPONSE_DESCRIPTION.toString()); return null; } - String aNodeType = nodeTypeProperty.value().toString(); + List<Path> paths = this.engine.getQueryEngine().findCousinsAsPath(v); - TypeAlphabetizer alphabetizer = new TypeAlphabetizer(); + String aNodeType = v.property(AAIProperties.NODE_TYPE).value().toString(); EdgeIngestor edgeIngestor = SpringContextAware.getBean(EdgeIngestor.class); - Set<String> keysWithMultipleLabels = edgeIngestor.getMultipleLabelKeys(); - - // For the given vertex, find all the cousins - // For each cousin retrieve the node type and then - // check if the version is greater than the edge label version - // meaning is the current version equal to greater than the version - // where we introduced the edge labels into the relationship payload - // If it is, then we check if the edge key there are multiple labels - // If there are multiple labels, then we need to go to the database - // to retrieve the labels between itself and cousin vertex - // If there is only single label between the edge a and b, then - // we can retrieve what that is without going to the database - // from using the edge rules json and get the edge rule out of it - EdgeRuleQuery.Builder queryBuilder = new EdgeRuleQuery.Builder(aNodeType); - for (Vertex cousin : cousins) { - VertexProperty vertexProperty = cousin.property(AAIProperties.NODE_TYPE); - String bNodeType = null; - if (vertexProperty.isPresent()) { - bNodeType = cousin.property(AAIProperties.NODE_TYPE).value().toString(); - } else { - // If the vertex is missing the aai-node-type - // Then its either a bad vertex or its in the process - // of getting deleted so we should ignore these vertexes - LoggingContext.responseDescription(MISSING_REQUIRED_NODE_PROPERTY); - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("For the vertex {}, unable to retrieve the aai-node-type", v.id().toString()); - } else { - LOGGER.info("Unable to retrieve the aai-node-type for vertex, for more info enable debug log"); - } - LoggingContext.remove(LoggingContext.LoggingField.RESPONSE_DESCRIPTION.toString()); + + EdgeRuleQuery.Builder queryBuilder = new EdgeRuleQuery.Builder(aNodeType) + .edgeType(EdgeType.COUSIN) + .version(obj.getVersion()); + + for (Path path : paths){ + if(path.size() < 3){ continue; } - if (obj.getVersion().compareTo(schemaVersions.getEdgeLabelVersion()) >= 0) { - String edgeKey = alphabetizer.buildAlphabetizedKey(aNodeType, bNodeType); - if (keysWithMultipleLabels.contains(edgeKey)) { - List<String> edgeLabels = this.getEdgeLabelsBetween(EdgeType.COUSIN, v, cousin); - for (String edgeLabel : edgeLabels) { - Introspector relationshipObj = obj.newIntrospectorInstanceOfNestedProperty("relationship"); - Object result = processEdgeRelationship(relationshipObj, cousin, cleanUp, edgeLabel); - if (result != null) { - relationshipObjList.add(result); - } - } - } else { - EdgeRule edgeRule = null; + // Path represents + // v ----related-to--> otherV + // In the above case, + // path objects get(0) returns vertex v + // path objects.get(1) returns edge related-to + // path objects.get(2) returns vertex otherV + Edge edge = path.get(1); + Vertex otherV= path.get(2); + + // TODO: Come back and revisit this code + // Create a query based on the a nodetype and b nodetype + // which is also a cousin edge and ensure the version + // is used properly so for example in order to be backwards + // compatible if we had allowed a edge between a and b + // in a previous release and we decided to remove it from + // the edge rules in the future we can display the edge + // only for the older apis and the new apis if the edge rule + // is removed will not be seen in the newer version of the API - // Create a query based on the a nodetype and b nodetype - // which is also a cousin edge and ensure the version - // is used properly so for example in order to be backwards - // compatible if we had allowed a edge between a and b - // in a previous release and we decided to remove it from - // the edge rules in the future we can display the edge - // only for the older apis and the new apis if the edge rule - // is removed will not be seen in the newer version of the API + String bNodeType = null; + if (otherV.property(AAIProperties.NODE_TYPE).isPresent()) { + bNodeType = otherV.property(AAIProperties.NODE_TYPE).value().toString(); + } else { + continue; + } - EdgeRuleQuery ruleQuery = - queryBuilder.to(bNodeType).edgeType(EdgeType.COUSIN).version(obj.getVersion()).build(); + String edgeLabel = edge.label(); + EdgeRuleQuery ruleQuery = queryBuilder.to(bNodeType).label(edgeLabel).build(); - try { - edgeRule = edgeIngestor.getRule(ruleQuery); - } catch (EdgeRuleNotFoundException e) { - LOGGER.warn( - "Caught an edge rule not found exception for query {}, {}," - + " it could be the edge rule is no longer valid for the existing edge in db", - ruleQuery, LogFormatTools.getStackTop(e)); - continue; - } catch (AmbiguousRuleChoiceException e) { - LOGGER.error("Caught an ambiguous rule not found exception for query {}, {}", ruleQuery, - LogFormatTools.getStackTop(e)); - continue; - } + if(!edgeIngestor.hasRule(ruleQuery)){ + LOGGER.debug( "Caught an edge rule not found for query {}", ruleQuery); + continue; + } - Introspector relationshipObj = obj.newIntrospectorInstanceOfNestedProperty("relationship"); - Object result = processEdgeRelationship(relationshipObj, cousin, cleanUp, edgeRule.getLabel()); - if (result != null) { - relationshipObjList.add(result); - } - } - } else { - Introspector relationshipObj = obj.newIntrospectorInstanceOfNestedProperty("relationship"); - Object result = processEdgeRelationship(relationshipObj, cousin, cleanUp, null); - if (result != null) { - relationshipObjList.add(result); - } + Introspector relationshipObj = obj.newIntrospectorInstanceOfNestedProperty(RELATIONSHIP); + Object result = processEdgeRelationship(relationshipObj, otherV, cleanUp, edgeLabel, isSkipRelatedTo); + if (result != null) { + relationshipObjList.add(result); } } @@ -1228,23 +1504,17 @@ public class DBSerializer { * Process edge relationship. * * @param relationshipObj the relationship obj - * @param edge the edge + * @param edgeLabel the edge's label * @param cleanUp the clean up * @return the object - * @throws InstantiationException the instantiation exception - * @throws IllegalAccessException the illegal access exception * @throws IllegalArgumentException the illegal argument exception - * @throws InvocationTargetException the invocation target exception - * @throws NoSuchMethodException the no such method exception * @throws SecurityException the security exception * @throws UnsupportedEncodingException the unsupported encoding exception - * @throws AAIException the AAI exception - * @throws MalformedURLException the malformed URL exception * @throws AAIUnknownObjectException * @throws URISyntaxException */ private Object processEdgeRelationship(Introspector relationshipObj, Vertex cousin, String cleanUp, - String edgeLabel) throws UnsupportedEncodingException, AAIUnknownObjectException { + String edgeLabel, boolean isSkipRelatedTo) throws UnsupportedEncodingException, AAIUnknownObjectException { VertexProperty aaiUriProperty = cousin.property("aai-uri"); @@ -1254,8 +1524,8 @@ public class DBSerializer { URI uri = UriBuilder.fromUri(aaiUriProperty.value().toString()).build(); - URIToRelationshipObject uriParser = null; - Introspector result = null; + URIToRelationshipObject uriParser; + Introspector result; try { uriParser = new URIToRelationshipObject(relationshipObj.getLoader(), uri, this.baseURL); result = uriParser.getResult(); @@ -1269,13 +1539,13 @@ public class DBSerializer { if (cousinVertexNodeType.isPresent()) { String cousinType = cousinVertexNodeType.value().toString(); - if (namedPropNodes.contains(cousinType)) { + if (namedPropNodes.contains(cousinType) && !isSkipRelatedTo) { this.addRelatedToProperty(result, cousin, cousinType); } } - if (edgeLabel != null && result.hasProperty("relationship-label")) { - result.setValue("relationship-label", edgeLabel); + if (edgeLabel != null && result.hasProperty(RELATIONSHIP_LABEL)) { + result.setValue(RELATIONSHIP_LABEL, edgeLabel); } return result.getUnderlyingObject(); @@ -1286,11 +1556,7 @@ public class DBSerializer { * * @param v the v * @return the URI for vertex - * @throws InstantiationException the instantiation exception - * @throws IllegalAccessException the illegal access exception * @throws IllegalArgumentException the illegal argument exception - * @throws InvocationTargetException the invocation target exception - * @throws NoSuchMethodException the no such method exception * @throws SecurityException the security exception * @throws UnsupportedEncodingException the unsupported encoding exception * @throws AAIUnknownObjectException @@ -1300,7 +1566,7 @@ public class DBSerializer { return getURIForVertex(v, false); } - public URI getURIForVertex(Vertex v, boolean overwrite) throws UnsupportedEncodingException { + public URI getURIForVertex(Vertex v, boolean overwrite) { URI uri = UriBuilder.fromPath("/unknown-uri").build(); String aaiUri = v.<String>property(AAIProperties.AAI_URI).orElse(null); @@ -1312,28 +1578,11 @@ public class DBSerializer { return uri; } - /** - * Gets the URI from list. - * - * @param list the list - * @return the URI from list - * @throws UnsupportedEncodingException the unsupported encoding exception - */ - private URI getURIFromList(List<Introspector> list) throws UnsupportedEncodingException { - String uri = ""; - StringBuilder sb = new StringBuilder(); - for (Introspector i : list) { - sb.insert(0, i.getURI()); - } - - uri = sb.toString(); - return UriBuilder.fromPath(uri).build(); - } public void addRelatedToProperty(Introspector relationship, Vertex cousinVertex, String cousinType) throws AAIUnknownObjectException { - Introspector obj = null; + Introspector obj; try { obj = this.loader.introspectorFromName(cousinType); @@ -1360,7 +1609,7 @@ public class DBSerializer { } if (!relatedToProperties.isEmpty()) { - List relatedToList = (List) relationship.getValue("related-to-property"); + List<Object> relatedToList = relationship.getValue("related-to-property"); for (Introspector introspector : relatedToProperties) { relatedToList.add(introspector.getUnderlyingObject()); } @@ -1389,22 +1638,22 @@ public class DBSerializer { * @throws UnsupportedEncodingException the unsupported encoding exception * @throws AAIException the AAI exception */ - public boolean createEdge(Introspector relationship, Vertex inputVertex) + public Vertex createEdge(Introspector relationship, Vertex inputVertex) throws UnsupportedEncodingException, AAIException { - Vertex relatedVertex = null; + Vertex relatedVertex; StopWatch.conditionalStart(); QueryParser parser = engine.getQueryBuilder().createQueryFromRelationship(relationship); String label = null; - if (relationship.hasProperty("relationship-label")) { - label = relationship.getValue("relationship-label"); + if (relationship.hasProperty(RELATIONSHIP_LABEL)) { + label = relationship.getValue(RELATIONSHIP_LABEL); } List<Vertex> results = parser.getQueryBuilder().toList(); if (results.isEmpty()) { dbTimeMsecs += StopWatch.stopIfStarted(); - AAIException e = new AAIException("AAI_6129", + AAIException e = new AAIException(AAI_6129, "Node of type " + parser.getResultType() + ". Could not find object at: " + parser.getUri()); e.getTemplateVars().add(parser.getResultType()); e.getTemplateVars().add(parser.getUri().toString()); @@ -1420,7 +1669,10 @@ public class DBSerializer { try { e = this.getEdgeBetween(EdgeType.COUSIN, inputVertex, relatedVertex, label); if (e == null) { - edgeSer.addEdge(this.engine.asAdmin().getTraversalSource(), inputVertex, relatedVertex, label); + e = edgeSer.addEdge(this.engine.asAdmin().getTraversalSource(), inputVertex, relatedVertex, label); + if(isDeltaEventsEnabled) { + deltaForEdge(inputVertex.property(AAIProperties.AAI_URI).value().toString(), e, DeltaAction.CREATE_REL, DeltaAction.UPDATE); + } } else { // attempted to link two vertexes already linked } @@ -1430,7 +1682,7 @@ public class DBSerializer { } dbTimeMsecs += StopWatch.stopIfStarted(); - return true; + return relatedVertex; } /** @@ -1439,8 +1691,6 @@ public class DBSerializer { * @param aVertex the out vertex * @param bVertex the in vertex * @return the edges between - * @throws AAIException the AAI exception - * @throws NoEdgeRuleFoundException */ private Edge getEdgeBetweenWithLabel(EdgeType type, Vertex aVertex, Vertex bVertex, EdgeRule edgeRule) { @@ -1476,42 +1726,11 @@ public class DBSerializer { } /** - * Gets all the edges between of the type. - * - * @param aVertex the out vertex - * @param bVertex the in vertex - * @return the edges between - * @throws AAIException the AAI exception - * @throws NoEdgeRuleFoundException - */ - private List<Edge> getEdgesBetween(EdgeType type, Vertex aVertex, Vertex bVertex) { - - List<Edge> result = new ArrayList<>(); - - if (bVertex != null) { - GraphTraversal<Vertex, Edge> findEdgesBetween = null; - findEdgesBetween = this.engine.asAdmin().getTraversalSource().V(aVertex).bothE(); - if (EdgeType.TREE.equals(type)) { - findEdgesBetween = findEdgesBetween.not(__.or(__.has(EdgeProperty.CONTAINS.toString(), "NONE"), - __.has(EdgeField.PRIVATE.toString(), true))); - } else { - findEdgesBetween = findEdgesBetween.has(EdgeProperty.CONTAINS.toString(), "NONE") - .not(__.has(EdgeField.PRIVATE.toString(), true)); - } - findEdgesBetween = findEdgesBetween.filter(__.otherV().hasId(bVertex.id())); - result = findEdgesBetween.toList(); - } - - return result; - } - - /** * Gets all the edges string between of the type. * * @param aVertex the out vertex * @param bVertex the in vertex * @return the edges between - * @throws AAIException the AAI exception * @throws NoEdgeRuleFoundException */ private List<String> getEdgeLabelsBetween(EdgeType type, Vertex aVertex, Vertex bVertex) { @@ -1535,30 +1754,6 @@ public class DBSerializer { } /** - * Gets all the edges string between of the type. - * - * @param aVertex the out vertex - * @param bVertex the in vertex - * @return the edges between - * @throws AAIException the AAI exception - * @throws NoEdgeRuleFoundException - */ - private Long getEdgeLabelsCount(Vertex aVertex, Vertex bVertex) { - - Long result = null; - - if (bVertex != null) { - GraphTraversal<Vertex, Edge> findEdgesBetween = null; - findEdgesBetween = this.engine.asAdmin().getTraversalSource().V(aVertex).bothE(); - findEdgesBetween = findEdgesBetween.has(EdgeProperty.CONTAINS.toString(), "NONE") - .not(__.has(EdgeField.PRIVATE.toString(), true)); - findEdgesBetween = findEdgesBetween.filter(__.otherV().hasId(bVertex.id())); - result = findEdgesBetween.count().next(); - } - return result; - } - - /** * Gets all the edges between the vertexes with the label and type. * * @param aVertex the out vertex @@ -1628,23 +1823,23 @@ public class DBSerializer { * @throws UnsupportedEncodingException the unsupported encoding exception * @throws AAIException the AAI exception */ - public boolean deleteEdge(Introspector relationship, Vertex inputVertex) + public Optional<Vertex> deleteEdge(Introspector relationship, Vertex inputVertex) throws UnsupportedEncodingException, AAIException { - Vertex relatedVertex = null; + Vertex relatedVertex; StopWatch.conditionalStart(); QueryParser parser = engine.getQueryBuilder().createQueryFromRelationship(relationship); List<Vertex> results = parser.getQueryBuilder().toList(); String label = null; - if (relationship.hasProperty("relationship-label")) { - label = relationship.getValue("relationship-label"); + if (relationship.hasProperty(RELATIONSHIP_LABEL)) { + label = relationship.getValue(RELATIONSHIP_LABEL); } if (results.isEmpty()) { dbTimeMsecs += StopWatch.stopIfStarted(); - return false; + return Optional.empty(); } relatedVertex = results.get(0); @@ -1653,29 +1848,19 @@ public class DBSerializer { edge = this.getEdgeBetween(EdgeType.COUSIN, inputVertex, relatedVertex, label); } catch (NoEdgeRuleFoundException e) { dbTimeMsecs += StopWatch.stopIfStarted(); - throw new AAIException("AAI_6129", e); + throw new AAIException(AAI_6129, e); } if (edge != null) { + if(isDeltaEventsEnabled) { + String mainUri = inputVertex.property(AAIProperties.AAI_URI).value().toString(); + deltaForEdge(mainUri, edge, DeltaAction.DELETE_REL, DeltaAction.UPDATE); + } edge.remove(); dbTimeMsecs += StopWatch.stopIfStarted(); - return true; + return Optional.of(relatedVertex); } else { dbTimeMsecs += StopWatch.stopIfStarted(); - return false; - } - - } - - /** - * Delete items with traversal. - * - * @param vertexes the vertexes - * @throws IllegalStateException the illegal state exception - */ - public void deleteItemsWithTraversal(List<Vertex> vertexes) throws IllegalStateException { - - for (Vertex v : vertexes) { - deleteWithTraversal(v); + return Optional.empty(); } } @@ -1688,12 +1873,7 @@ public class DBSerializer { public void deleteWithTraversal(Vertex startVertex) { StopWatch.conditionalStart(); List<Vertex> results = this.engine.getQueryEngine().findDeletable(startVertex); - - for (Vertex v : results) { - LOGGER.debug("Removing vertex {} with label {}", v.id(), v.label()); - v.remove(); - } - dbTimeMsecs += StopWatch.stopIfStarted(); + this.delete(results); } /** @@ -1720,12 +1900,47 @@ public class DBSerializer { for (Vertex v : vertices) { LOGGER.debug("Removing vertex {} with label {}", v.id(), v.label()); + if(isDeltaEventsEnabled) { + deltaForVertexDelete(v); + } + //add the cousin vertexes of v to have their resource-version updated and notified on. + v.edges(Direction.BOTH) + .forEachRemaining(e -> { + if (e.property(EdgeProperty.CONTAINS.toString()).isPresent() + && AAIDirection.NONE.toString().equals(e.<String>value(EdgeProperty.CONTAINS.toString()))) { + e.bothVertices().forEachRemaining(cousinV -> { + if (!v.equals(cousinV)) { + edgeVertexes.add(cousinV); + } + }); + } + }); + + //if somewhere along the way v was added to the sets tracking the what is to be updated/notified on + // it should be removed from them as v is to be deleted + edgeVertexes.remove(v); + updatedVertexes.remove(v); v.remove(); } dbTimeMsecs += StopWatch.stopIfStarted(); } + private void deltaForVertexDelete(Vertex v) { + String aaiUri = v.property(AAIProperties.AAI_URI).value().toString(); + v.keys().forEach(k -> { + List<Object> list = new ArrayList<>(); + v.properties(k).forEachRemaining(vp -> list.add(vp.value())); + if (list.size() == 1) { + addPropDelta(aaiUri, k, PropertyDeltaFactory.getDelta(DeltaAction.DELETE, list.get(0)), DeltaAction.DELETE); + } else { + addPropDelta(aaiUri, k, PropertyDeltaFactory.getDelta(DeltaAction.DELETE, list), DeltaAction.DELETE); + } + + }); + v.edges(Direction.BOTH).forEachRemaining(e -> deltaForEdge(aaiUri, e, DeltaAction.DELETE, DeltaAction.DELETE)); + } + /** * Delete. * @@ -1741,7 +1956,7 @@ public class DBSerializer { boolean result = verifyDeleteSemantics(v, resourceVersion, enableResourceVersion); /* * The reason why I want to call PreventDeleteSemantics second time is to catch the prevent-deletes in a chain - * These are far-fewer than seeing a prevnt-delete on the vertex to be deleted + * These are far-fewer than seeing a prevent-delete on the vertex to be deleted * So its better to make these in 2 steps */ if (result && !deletableVertices.isEmpty()) { @@ -1756,7 +1971,6 @@ public class DBSerializer { } } - } /** @@ -1782,7 +1996,6 @@ public class DBSerializer { } } - } /** @@ -1795,15 +2008,14 @@ public class DBSerializer { */ private boolean verifyDeleteSemantics(Vertex vertex, String resourceVersion, boolean enableResourceVersion) throws AAIException { - boolean result = true; - String nodeType = ""; - String errorDetail = " unknown delete semantic found"; - String aaiExceptionCode = ""; + boolean result; + String nodeType; nodeType = vertex.<String>property(AAIProperties.NODE_TYPE).orElse(null); - if (enableResourceVersion && !this.verifyResourceVersion("delete", nodeType, - vertex.<String>property(AAIProperties.RESOURCE_VERSION).orElse(null), resourceVersion, nodeType)) { + if (enableResourceVersion) { + this.verifyResourceVersion("delete", nodeType, + vertex.<String>property(AAIProperties.RESOURCE_VERSION).orElse(null), resourceVersion, nodeType); } - List<Vertex> vertices = new ArrayList<Vertex>(); + List<Vertex> vertices = new ArrayList<>(); vertices.add(vertex); result = verifyPreventDeleteSemantics(vertices); @@ -1819,7 +2031,6 @@ public class DBSerializer { */ private boolean verifyPreventDeleteSemantics(List<Vertex> vertices) throws AAIException { boolean result = true; - String nodeType = ""; String errorDetail = " unknown delete semantic found"; String aaiExceptionCode = ""; @@ -1987,6 +2198,35 @@ public class DBSerializer { /** * Db to object With Filters * This is for a one-time run with Tenant Isloation to only filter relationships + * + * @param obj the obj + * @param v the vertex from the graph + * @param depth the depth + * @param nodeOnly specify if to exclude relationships or not + * @param filterCousinNodes + * @return the introspector + * @throws AAIException the AAI exception + * @throws IllegalAccessException the illegal access exception + * @throws IllegalArgumentException the illegal argument exception + * @throws InvocationTargetException the invocation target exception + * @throws SecurityException the security exception + * @throws InstantiationException the instantiation exception + * @throws NoSuchMethodException the no such method exception + * @throws UnsupportedEncodingException the unsupported encoding exception + * @throws MalformedURLException the malformed URL exception + * @throws AAIUnknownObjectException + * @throws URISyntaxException + */ + public Introspector dbToObjectWithFilters(Introspector obj, Vertex v, Set<Vertex> seen, int depth, boolean nodeOnly, + List<String> filterCousinNodes, List<String> filterParentNodes) + throws AAIException, UnsupportedEncodingException { + return dbToObjectWithFilters(obj, v, seen, depth, nodeOnly, + filterCousinNodes, filterParentNodes, false); + } + + /** + * Db to object With Filters + * This is for a one-time run with Tenant Isloation to only filter relationships * TODO: Chnage the original dbToObject to take filter parent/cousins * * @param obj the obj @@ -1994,6 +2234,7 @@ public class DBSerializer { * @param depth the depth * @param nodeOnly specify if to exclude relationships or not * @param filterCousinNodes + * @param isSkipRelatedTo determine to incorporated related-to-property data * @return the introspector * @throws AAIException the AAI exception * @throws IllegalAccessException the illegal access exception @@ -2009,9 +2250,9 @@ public class DBSerializer { */ // TODO - See if you can merge the 2 dbToObjectWithFilters public Introspector dbToObjectWithFilters(Introspector obj, Vertex v, Set<Vertex> seen, int depth, boolean nodeOnly, - List<String> filterCousinNodes, List<String> filterParentNodes) + List<String> filterCousinNodes, List<String> filterParentNodes, boolean isSkipRelatedTo) throws AAIException, UnsupportedEncodingException { - String cleanUp = "false"; + String cleanUp = FALSE; if (depth < 0) { return null; } @@ -2020,7 +2261,6 @@ public class DBSerializer { boolean modified = false; for (String property : obj.getProperties(PropertyPredicates.isVisible())) { List<Object> getList = null; - Vertex[] vertices = null; if (!(obj.isComplexType(property) || obj.isListType(property))) { this.copySimpleProperty(property, obj, v); @@ -2032,7 +2272,7 @@ public class DBSerializer { if (!property.equals("relationship-list") && depth >= 0) { Introspector argumentObject = obj.newIntrospectorInstanceOfProperty(property); Object result = dbToObjectWithFilters(argumentObject, v, seen, depth + 1, nodeOnly, - filterCousinNodes, filterParentNodes); + filterCousinNodes, filterParentNodes, isSkipRelatedTo); if (result != null) { obj.setValue(property, argumentObject.getUnderlyingObject()); modified = true; @@ -2041,9 +2281,8 @@ public class DBSerializer { /* relationships need to be handled correctly */ Introspector relationshipList = obj.newIntrospectorInstanceOfProperty(property); relationshipList = - createFilteredRelationshipList(v, relationshipList, cleanUp, filterCousinNodes); + createFilteredRelationshipList(v, relationshipList, cleanUp, filterCousinNodes, isSkipRelatedTo); if (relationshipList != null) { - modified = true; obj.setValue(property, relationshipList.getUnderlyingObject()); modified = true; } @@ -2060,7 +2299,7 @@ public class DBSerializer { String vType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null); EdgeRule rule; - boolean isthisParentRequired = + boolean isThisParentRequired = filterParentNodes.parallelStream().anyMatch(childDbName::contains); EdgeRuleQuery q = new EdgeRuleQuery.Builder(vType, childDbName).edgeType(EdgeType.TREE).build(); @@ -2072,34 +2311,30 @@ public class DBSerializer { } catch (AmbiguousRuleChoiceException e) { throw new MultipleEdgeRuleFoundException(e); } - if (!rule.getContains().equals(AAIDirection.NONE.toString()) && isthisParentRequired) { - // vertices = this.queryEngine.findRelatedVertices(v, Direction.OUT, rule.getLabel(), - // childDbName); + if (!rule.getContains().equals(AAIDirection.NONE.toString()) && isThisParentRequired) { Direction ruleDirection = rule.getDirection(); - Iterator<Vertex> itr = v.vertices(ruleDirection, rule.getLabel()); - List<Vertex> verticesList = (List<Vertex>) IteratorUtils.toList(itr); - itr = verticesList.stream().filter(item -> { - return item.property(AAIProperties.NODE_TYPE).orElse("").equals(childDbName); - }).iterator(); - if (itr.hasNext()) { - getList = (List<Object>) obj.getValue(property); + List<Vertex> verticesList = new ArrayList<>(); + v.vertices(ruleDirection, rule.getLabel()).forEachRemaining(vertex -> { + if (vertex.property(AAIProperties.NODE_TYPE).orElse("").equals(childDbName)) { + verticesList.add(vertex); + } + }); + if (!verticesList.isEmpty()) { + getList = obj.getValue(property); } int processed = 0; - int removed = 0; - while (itr.hasNext()) { - Vertex childVertex = itr.next(); + for (Vertex childVertex : verticesList) { if (!seen.contains(childVertex)) { Introspector argumentObject = obj.newIntrospectorInstanceOfNestedProperty(property); Object result = dbToObjectWithFilters(argumentObject, childVertex, seen, depth, - nodeOnly, filterCousinNodes, filterParentNodes); + nodeOnly, filterCousinNodes, filterParentNodes, isSkipRelatedTo); if (result != null) { getList.add(argumentObject.getUnderlyingObject()); } processed++; } else { - removed++; LOGGER.warn("Cycle found while serializing vertex id={}", childVertex.id().toString()); } @@ -2115,7 +2350,7 @@ public class DBSerializer { } else if (obj.isSimpleGenericType(property)) { List<Object> temp = this.engine.getListProperty(v, property); if (temp != null) { - getList = (List<Object>) obj.getValue(property); + getList = obj.getValue(property); getList.addAll(temp); modified = true; } @@ -2143,19 +2378,13 @@ public class DBSerializer { * @param obj the obj * @param cleanUp the clean up * @return the object - * @throws InstantiationException the instantiation exception - * @throws IllegalAccessException the illegal access exception * @throws IllegalArgumentException the illegal argument exception - * @throws InvocationTargetException the invocation target exception - * @throws NoSuchMethodException the no such method exception * @throws SecurityException the security exception * @throws UnsupportedEncodingException the unsupported encoding exception * @throws AAIException the AAI exception - * @throws MalformedURLException the malformed URL exception - * @throws URISyntaxException */ private Introspector createFilteredRelationshipList(Vertex v, Introspector obj, String cleanUp, - List<String> filterNodes) throws UnsupportedEncodingException, AAIException { + List<String> filterNodes, boolean isSkipRelatedTo) throws UnsupportedEncodingException, AAIException { List<Vertex> allCousins = this.engine.getQueryEngine().findCousinVertices(v); Iterator<Vertex> cousinVertices = allCousins.stream().filter(item -> { @@ -2163,14 +2392,14 @@ public class DBSerializer { return filterNodes.parallelStream().anyMatch(node::contains); }).iterator(); - List<Vertex> cousins = (List<Vertex>) IteratorUtils.toList(cousinVertices); + List<Object> relationshipObjList = obj.getValue(RELATIONSHIP); - // items.parallelStream().anyMatch(inputStr::contains) - List<Object> relationshipObjList = obj.getValue("relationship"); + List<Vertex> cousins = new ArrayList<>(); + cousinVertices.forEachRemaining(cousins::add); for (Vertex cousin : cousins) { - Introspector relationshipObj = obj.newIntrospectorInstanceOfNestedProperty("relationship"); - Object result = processEdgeRelationship(relationshipObj, cousin, cleanUp, null); + Introspector relationshipObj = obj.newIntrospectorInstanceOfNestedProperty(RELATIONSHIP); + Object result = processEdgeRelationship(relationshipObj, cousin, cleanUp, null, isSkipRelatedTo); if (result != null) { relationshipObjList.add(result); } @@ -2184,4 +2413,31 @@ public class DBSerializer { } } + public Set<Vertex> touchStandardVertexPropertiesForEdges() { + this.edgeVertexes.forEach(v -> this.touchStandardVertexProperties(v, false)); + return this.edgeVertexes; + } + + public void addVertexToEdgeVertexes(Vertex vertex){ + this.edgeVertexes.add(vertex); + } + + private String urlToUri(String url) { + if (url.startsWith("/")) { + url = url.substring(1); + } + + if (url.endsWith("/")) { + url = url.substring(0, url.length() - 1); + } + + // TODO - Check if this makes to do for model driven for base uri path + url = url.replaceFirst("[a-z][a-z]*/v\\d+/", ""); + if (url.charAt(0) != '/') { + url = '/' + url; + } + + return url; + } + } diff --git a/aai-core/src/main/java/org/onap/aai/serialization/db/GraphSingleton.java b/aai-core/src/main/java/org/onap/aai/serialization/db/GraphSingleton.java index cb713d56..3a7c6d2d 100644 --- a/aai-core/src/main/java/org/onap/aai/serialization/db/GraphSingleton.java +++ b/aai-core/src/main/java/org/onap/aai/serialization/db/GraphSingleton.java @@ -20,11 +20,10 @@ package org.onap.aai.serialization.db; -import java.util.concurrent.atomic.AtomicInteger; - import org.janusgraph.core.JanusGraph; import org.onap.aai.dbmap.AAIGraph; -import org.onap.aai.dbmap.DBConnectionType; + +import java.util.concurrent.atomic.AtomicInteger; /* This class simply calls AAIGraph under the covers for now */ public class GraphSingleton { @@ -63,7 +62,4 @@ public class GraphSingleton { return AAIGraph.getInstance().getGraph(); } - public JanusGraph getTxGraph(DBConnectionType connectionType) { - return AAIGraph.getInstance().getGraph(connectionType); - } } diff --git a/aai-core/src/main/java/org/onap/aai/serialization/db/ImpliedDelete.java b/aai-core/src/main/java/org/onap/aai/serialization/db/ImpliedDelete.java new file mode 100644 index 00000000..437f1634 --- /dev/null +++ b/aai-core/src/main/java/org/onap/aai/serialization/db/ImpliedDelete.java @@ -0,0 +1,205 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 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========================================================= + */ +package org.onap.aai.serialization.db; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.apache.commons.lang.StringUtils; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.onap.aai.exceptions.AAIException; +import org.onap.aai.introspection.Introspector; +import org.onap.aai.logging.LogFormatTools; +import org.onap.aai.serialization.engines.TransactionalGraphEngine; +import org.onap.aai.serialization.engines.query.QueryEngine; +import org.onap.aai.util.AAIConfigProxy; +import org.onap.aai.util.AAIConstants; + +import java.util.List; +import java.util.Objects; + +/** + * <b>ImpliedDelete</b> class is responsible for deleting children + * of a parent vertex if the client explicitly asks to remove them + * It will check if they are allowed and based on that information + * it will decide whether to proceed with the deletion or + * throw an exception back to the requester if they are not allowed + * + * It implements the AAIProxy Interface and any calls to the + * AAIConfig should be using the proxy methods and any new + * methods that needs to be invoked should be added there first + * + * @see org.onap.aai.util.AAIConfigProxy + */ +public class ImpliedDelete implements AAIConfigProxy { + + private static final Logger LOGGER = LoggerFactory.getLogger(ImpliedDelete.class); + + private static final String IMPLICIT_DELETE = "Implicit DELETE"; + private static final String STAR = "*"; + + private TransactionalGraphEngine engine; + private DBSerializer serializer; + + public ImpliedDelete(TransactionalGraphEngine engine, DBSerializer serializer){ + this.engine = engine; + this.serializer = serializer; + } + + /** + * Checks if the user is allowed to execute implied delete + * If they are allowed to do the delete, then for all the dependent vertices + * it will identify all the deletable vertices to them + * and log them based on the following aaiconfig properties: + * + * aai.implied.delete.log.enabled=true + * aai.implied.delete.log.limit=-1 + * + * Above properties are the default assumption of the code if they are not overwritten + * So the code will log for every vertex it is about to delete + * If there are thousands of vertexes that get implicitly deleted, + * its preferable that the operation timeout rather than + * someone accidentally deleting thousands of children + * + * @param id - Identifier of the vertex whose children could be potentially deleted + * @param sot - source of truth of who the requester who is making the request + * @param objectType - type of the parent object whose children are being deleted + * @param dependentVertexes - list of children vertexes + * @throws AAIException if the user is not allowed to implicitly delete children + */ + public List<Vertex> execute(Object id, String sot, String objectType, List<Vertex> dependentVertexes) throws AAIException { + if(dependentVertexes != null && !dependentVertexes.isEmpty()){ + // Find all the deletable vertices from the dependent vertices that should be deleted + // So for each of the following dependent vertices, + // we will use the edge properties and do the cascade delete + QueryEngine queryEngine = this.engine.getQueryEngine(); + List<Vertex> impliedDeleteVertices = queryEngine.findDeletable(dependentVertexes); + if(this.allow(sot, objectType)){ + + int impliedDeleteCount = impliedDeleteVertices.size(); + + LOGGER.warn( + "For the vertex with id {}, doing an implicit delete on update will delete total of {} vertexes", + id, + impliedDeleteCount + ); + + String impliedDeleteLogEnabled = get(AAIConstants.AAI_IMPLIED_DELETE_LOG_ENABLED, "true"); + + int impliedDeleteLogLimit = getInt(AAIConstants.AAI_IMPLIED_DELETE_LOG_LIMIT, "-1"); + + if (impliedDeleteLogLimit == -1) { + impliedDeleteLogLimit = Integer.MAX_VALUE; + } + + // If the logging is enabled for implied delete + // then log the payload in the latest format + if ("true".equals(impliedDeleteLogEnabled) && impliedDeleteCount <= impliedDeleteLogLimit) { + for (Vertex vertex : impliedDeleteVertices) { + Introspector introspector = null; + try { + introspector = serializer.getLatestVersionView(vertex); + if (LOGGER.isInfoEnabled()) { + LOGGER.info("Implied delete object in json format {}", introspector.marshal(false)); + } + } catch (Exception ex) { + LOGGER.warn( + "Encountered an exception during retrieval of vertex properties with vertex-id {} -> {}", + id, LogFormatTools.getStackTop(ex)); + } + } + } + } else { + LOGGER.error("User {} is not allowed to implicit delete on parent object {}", sot, objectType); + throw new AAIException("AAI_9109"); + } + return impliedDeleteVertices; + } else { + // Return null or an empty list back to the user based on input + return dependentVertexes; + } + } + + public void delete(List<Vertex> vertices){ + // After all the appropriate logging, calling the serializer delete to delete the affected vertices + if(vertices != null && !vertices.isEmpty()){ + serializer.delete(vertices); + } + } + + /** + * Checks the property in the aaiconfig properties + * to see if the user is allowed to do implicit delete + * + * Expecting the aaiconfig.properties to have following type of properties + * + * <code> + * aai.implied.delete.whitelist.sdnc=* + * aai.implied.delete.whitelist.sdc='pserver','vserver' + * </code> + * + * So in the above code, the expectation is for any of the following user: + * + * <ul> + * <li>SDC</li> + * <li>SDc</li> + * <li>Sdc</li> + * <li>sDc</li> + * <li>SdC</li> + * <li>sdC</li> + * <li>sdc</li> + * </ul> + * + * They are allowed to delete the children of pserver and vserver by implicit delete + * + * Note: The reason the property values are placed inside the single quotes is + * so if there is an object called volume and there is another object called volume-group + * when doing an contains it can falsely allow volume-group children to be implicitly deleted + * and the cost of turning the string into an array and then searching if its inside it + * or loading into an set which is unnecessary and it could potentially be done for every request + * + * @param sourceOfTruth - the original requester that the request is coming from, + * derived from HTTP Header X-FromAppId + * @param parentObjectType - parent object in which they are trying to do the implicit delete against + * + * @return true - if the requester is allowed to implicit delete against the object type + * false - if they are not allowed + */ + private boolean allow(String sourceOfTruth, String parentObjectType){ + Objects.requireNonNull(sourceOfTruth); + Objects.requireNonNull(parentObjectType); + + String propertyName = AAIConstants.AAI_IMPLIED_DELETE_WHITELIST + sourceOfTruth.toLowerCase(); + String whitelist = get(propertyName, StringUtils.EMPTY); + + if(whitelist.isEmpty()){ + return false; + } + + if(STAR.equals(whitelist)){ + return true; + } + + if(whitelist.contains("'" + parentObjectType + "'")){ + return true; + } + + return false; + } +} diff --git a/aai-core/src/main/java/org/onap/aai/serialization/db/InMemoryGraphSingleton.java b/aai-core/src/main/java/org/onap/aai/serialization/db/InMemoryGraphSingleton.java index 90f71db5..2ca96b5b 100644 --- a/aai-core/src/main/java/org/onap/aai/serialization/db/InMemoryGraphSingleton.java +++ b/aai-core/src/main/java/org/onap/aai/serialization/db/InMemoryGraphSingleton.java @@ -21,7 +21,6 @@ package org.onap.aai.serialization.db; import org.janusgraph.core.JanusGraph; -import org.onap.aai.dbmap.DBConnectionType; public class InMemoryGraphSingleton extends GraphSingleton { @@ -51,8 +50,4 @@ public class InMemoryGraphSingleton extends GraphSingleton { return inMemgraph; } - @Override - public JanusGraph getTxGraph(DBConnectionType connectionType) { - return inMemgraph; - } } diff --git a/aai-core/src/main/java/org/onap/aai/serialization/engines/InMemoryDBEngine.java b/aai-core/src/main/java/org/onap/aai/serialization/engines/InMemoryDBEngine.java index 86c32f4a..66509c97 100644 --- a/aai-core/src/main/java/org/onap/aai/serialization/engines/InMemoryDBEngine.java +++ b/aai-core/src/main/java/org/onap/aai/serialization/engines/InMemoryDBEngine.java @@ -20,23 +20,22 @@ package org.onap.aai.serialization.engines; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ReadOnlyStrategy; import org.apache.tinkerpop.gremlin.structure.Graph; import org.apache.tinkerpop.gremlin.structure.Vertex; import org.apache.tinkerpop.gremlin.structure.VertexProperty; import org.janusgraph.core.JanusGraph; -import org.onap.aai.dbmap.DBConnectionType; import org.onap.aai.introspection.Loader; import org.onap.aai.query.builder.*; import org.onap.aai.serialization.db.InMemoryGraphSingleton; import org.onap.aai.serialization.engines.query.GraphTraversalQueryEngine; import org.onap.aai.serialization.engines.query.QueryEngine; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + public class InMemoryDBEngine extends TransactionalGraphEngine { /** @@ -49,10 +48,8 @@ public class InMemoryDBEngine extends TransactionalGraphEngine { */ private JanusGraph graph = null; - private static final TransactionalGraphEngine.Admin admin = null; - - public InMemoryDBEngine(QueryStyle style, DBConnectionType connectionType, Loader loader, JanusGraph graph) { - super(style, loader, connectionType, InMemoryGraphSingleton.getInstance(graph)); + public InMemoryDBEngine(QueryStyle style, Loader loader, JanusGraph graph) { + super(style, loader, InMemoryGraphSingleton.getInstance(graph)); this.graph = graph; } @@ -195,8 +192,7 @@ public class InMemoryDBEngine extends TransactionalGraphEngine { if (this.tx() == null) { this.currentTx = graph.newTransaction(); this.currentTraversal = this.tx().traversal(); - this.readOnlyTraversal = - this.tx().traversal(GraphTraversalSource.build().with(ReadOnlyStrategy.instance())); + this.readOnlyTraversal = this.tx().traversal().withStrategies(ReadOnlyStrategy.instance()); } return currentTx; } diff --git a/aai-core/src/main/java/org/onap/aai/serialization/engines/JanusGraphDBEngine.java b/aai-core/src/main/java/org/onap/aai/serialization/engines/JanusGraphDBEngine.java index 346cf026..2a4511d0 100644 --- a/aai-core/src/main/java/org/onap/aai/serialization/engines/JanusGraphDBEngine.java +++ b/aai-core/src/main/java/org/onap/aai/serialization/engines/JanusGraphDBEngine.java @@ -20,16 +20,15 @@ package org.onap.aai.serialization.engines; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - import org.apache.tinkerpop.gremlin.structure.Vertex; import org.apache.tinkerpop.gremlin.structure.VertexProperty; -import org.onap.aai.dbmap.DBConnectionType; import org.onap.aai.introspection.Loader; import org.onap.aai.serialization.db.JanusGraphSingleton; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + public class JanusGraphDBEngine extends TransactionalGraphEngine { /** @@ -38,8 +37,8 @@ public class JanusGraphDBEngine extends TransactionalGraphEngine { * @param style the style * @param loader the loader */ - public JanusGraphDBEngine(QueryStyle style, DBConnectionType connectionType, Loader loader) { - super(style, loader, connectionType, JanusGraphSingleton.getInstance()); + public JanusGraphDBEngine(QueryStyle style, Loader loader) { + super(style, loader, JanusGraphSingleton.getInstance()); } /** @@ -82,7 +81,7 @@ public class JanusGraphDBEngine extends TransactionalGraphEngine { @Override public List<Object> getListProperty(Vertex v, String name) { - List<Object> result = new ArrayList<Object>(); + List<Object> result = new ArrayList<>(); Iterator<VertexProperty<Object>> iterator = v.properties(name); @@ -90,7 +89,7 @@ public class JanusGraphDBEngine extends TransactionalGraphEngine { result.add(iterator.next().value()); } - if (result.size() == 0) { + if (result.isEmpty()) { result = null; } diff --git a/aai-core/src/main/java/org/onap/aai/serialization/engines/QueryStyle.java b/aai-core/src/main/java/org/onap/aai/serialization/engines/QueryStyle.java index c291fbcb..f69e4d34 100644 --- a/aai-core/src/main/java/org/onap/aai/serialization/engines/QueryStyle.java +++ b/aai-core/src/main/java/org/onap/aai/serialization/engines/QueryStyle.java @@ -21,5 +21,5 @@ package org.onap.aai.serialization.engines; public enum QueryStyle { - GREMLIN_TRAVERSAL, GREMLIN_UNIQUE, GREMLINPIPELINE_TRAVERSAL, TRAVERSAL, TRAVERSAL_URI + GREMLIN_TRAVERSAL, GREMLIN_UNIQUE, GREMLINPIPELINE_TRAVERSAL, TRAVERSAL, TRAVERSAL_URI, HISTORY_TRAVERSAL, HISTORY_GREMLIN_TRAVERSAL } diff --git a/aai-core/src/main/java/org/onap/aai/serialization/engines/TransactionalGraphEngine.java b/aai-core/src/main/java/org/onap/aai/serialization/engines/TransactionalGraphEngine.java index 731d6c23..b945db05 100644 --- a/aai-core/src/main/java/org/onap/aai/serialization/engines/TransactionalGraphEngine.java +++ b/aai-core/src/main/java/org/onap/aai/serialization/engines/TransactionalGraphEngine.java @@ -20,29 +20,26 @@ package org.onap.aai.serialization.engines; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; - import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ReadOnlyStrategy; import org.apache.tinkerpop.gremlin.structure.Graph; import org.apache.tinkerpop.gremlin.structure.Vertex; import org.janusgraph.core.JanusGraph; import org.janusgraph.core.schema.JanusGraphManagement; -import org.onap.aai.dbmap.DBConnectionType; import org.onap.aai.introspection.Loader; import org.onap.aai.query.builder.*; import org.onap.aai.serialization.db.GraphSingleton; import org.onap.aai.serialization.engines.query.GraphTraversalQueryEngine; import org.onap.aai.serialization.engines.query.QueryEngine; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + public abstract class TransactionalGraphEngine { protected GraphSingleton singleton = null; - protected QueryEngine queryEngine = null; protected QueryBuilder<Vertex> queryBuilder = null; - protected QueryStyle style = null; - protected final DBConnectionType connectionType; + protected QueryStyle style; protected final Loader loader; protected Graph currentTx = null; protected GraphTraversalSource currentTraversal = null; @@ -55,19 +52,16 @@ public abstract class TransactionalGraphEngine { * @param style the style * @param loader the loader */ - public TransactionalGraphEngine(QueryStyle style, Loader loader, DBConnectionType connectionType, - GraphSingleton singleton) { + public TransactionalGraphEngine(QueryStyle style, Loader loader, GraphSingleton singleton) { this.loader = loader; this.style = style; this.singleton = singleton; - this.connectionType = connectionType; admin = new Admin(); } public TransactionalGraphEngine(QueryStyle style, Loader loader) { this.loader = loader; this.style = style; - this.connectionType = DBConnectionType.REALTIME; admin = new Admin(); } @@ -97,7 +91,7 @@ public abstract class TransactionalGraphEngine { * @return the graph */ private JanusGraph getGraph() { - return singleton.getTxGraph(this.connectionType); + return singleton.getTxGraph(); } /** @@ -150,6 +144,10 @@ public abstract class TransactionalGraphEngine { return getQueryBuilder(this.style, loader); } + public QueryBuilder<Vertex> getQueryBuilder(QueryStyle style, GraphTraversalSource source) { + return getQueryBuilder(style, this.loader, source); + } + public QueryBuilder<Vertex> getQueryBuilder(QueryStyle style, Loader loader) { if (style.equals(QueryStyle.GREMLIN_TRAVERSAL)) { return new GremlinTraversal<>(loader, this.asAdmin().getTraversalSource()); @@ -161,7 +159,32 @@ public abstract class TransactionalGraphEngine { return new TraversalQuery<>(loader, this.asAdmin().getTraversalSource()); } else if (style.equals(QueryStyle.TRAVERSAL_URI)) { return new TraversalURIOptimizedQuery<>(loader, this.asAdmin().getTraversalSource()); - } else { + } else if (style.equals(QueryStyle.HISTORY_TRAVERSAL)) { + throw new IllegalArgumentException("History Traversal needs history traversal source"); + } else if (style.equals(QueryStyle.HISTORY_GREMLIN_TRAVERSAL)) { + throw new IllegalArgumentException("History Gremlin Traversal needs history traversal source"); + }else { + throw new IllegalArgumentException("Query Builder type not recognized"); + } + return queryBuilder; + } + + public QueryBuilder<Vertex> getQueryBuilder(QueryStyle style, Loader loader, GraphTraversalSource source) { + if (style.equals(QueryStyle.GREMLIN_TRAVERSAL)) { + return new GremlinTraversal<>(loader, source); + } else if (style.equals(QueryStyle.GREMLIN_UNIQUE)) { + return new GremlinUnique<>(loader, source); + } else if (style.equals(QueryStyle.GREMLINPIPELINE_TRAVERSAL)) { + // return new GremlinPipelineTraversal(loader); + } else if (style.equals(QueryStyle.TRAVERSAL)) { + return new TraversalQuery<>(loader, source); + } else if (style.equals(QueryStyle.TRAVERSAL_URI)) { + return new TraversalURIOptimizedQuery<>(loader, source); + } else if (style.equals(QueryStyle.HISTORY_TRAVERSAL)) { + return new HistoryTraversalURIOptimizedQuery<>(loader, source); + }else if (style.equals(QueryStyle.HISTORY_GREMLIN_TRAVERSAL)) { + return new HistoryGremlinTraversal<>(loader, source); + }else { throw new IllegalArgumentException("Query Builder type not recognized"); } return queryBuilder; @@ -202,8 +225,7 @@ public abstract class TransactionalGraphEngine { if (this.tx() == null) { this.currentTx = this.getGraph().newTransaction(); this.currentTraversal = this.tx().traversal(); - this.readOnlyTraversal = - this.tx().traversal(GraphTraversalSource.build().with(ReadOnlyStrategy.instance())); + this.readOnlyTraversal =this.tx().traversal().withStrategies(ReadOnlyStrategy.instance()); } return currentTx; } diff --git a/aai-core/src/main/java/org/onap/aai/serialization/engines/query/GraphTraversalQueryEngine.java b/aai-core/src/main/java/org/onap/aai/serialization/engines/query/GraphTraversalQueryEngine.java index e012aef3..376a2798 100644 --- a/aai-core/src/main/java/org/onap/aai/serialization/engines/query/GraphTraversalQueryEngine.java +++ b/aai-core/src/main/java/org/onap/aai/serialization/engines/query/GraphTraversalQueryEngine.java @@ -20,18 +20,9 @@ package org.onap.aai.serialization.engines.query; -import static org.onap.aai.edges.enums.AAIDirection.IN; -import static org.onap.aai.edges.enums.AAIDirection.NONE; -import static org.onap.aai.edges.enums.AAIDirection.OUT; -import static org.onap.aai.edges.enums.EdgeField.PRIVATE; -import static org.onap.aai.edges.enums.EdgeProperty.CONTAINS; -import static org.onap.aai.edges.enums.EdgeProperty.DELETE_OTHER_V; - -import java.util.List; -import java.util.Set; - import org.apache.tinkerpop.gremlin.process.traversal.Order; import org.apache.tinkerpop.gremlin.process.traversal.P; +import org.apache.tinkerpop.gremlin.process.traversal.Path; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__; @@ -41,9 +32,19 @@ import org.apache.tinkerpop.gremlin.structure.Edge; import org.apache.tinkerpop.gremlin.structure.Element; import org.apache.tinkerpop.gremlin.structure.Vertex; import org.onap.aai.db.props.AAIProperties; +import org.onap.aai.edges.enums.EdgeField; +import org.onap.aai.edges.enums.EdgeProperty; import org.onap.aai.introspection.Loader; import org.onap.aai.logging.StopWatch; +import java.util.List; +import java.util.Set; + +import static org.onap.aai.edges.enums.AAIDirection.*; +import static org.onap.aai.edges.enums.EdgeField.PRIVATE; +import static org.onap.aai.edges.enums.EdgeProperty.CONTAINS; +import static org.onap.aai.edges.enums.EdgeProperty.DELETE_OTHER_V; + /* * This class needs some big explanation despite its compact size. * This controls all the queries performed by the CRUD API in A&AI. @@ -256,6 +257,15 @@ public class GraphTraversalQueryEngine extends QueryEngine { return pipeline.toList(); } + public List<Path> findCousinsAsPath(Vertex start){ + return this.g.V(start).bothE().where( + __.and( + __.has(EdgeProperty.CONTAINS.toString(), NONE.toString()), + __.not(__.has(EdgeField.PRIVATE.toString(), true)) + ) + ).otherV().path().toList(); + } + public double getDBTimeMsecs() { return (dbTimeMsecs); } diff --git a/aai-core/src/main/java/org/onap/aai/serialization/engines/query/QueryEngine.java b/aai-core/src/main/java/org/onap/aai/serialization/engines/query/QueryEngine.java index 4f30b564..b250d8f3 100644 --- a/aai-core/src/main/java/org/onap/aai/serialization/engines/query/QueryEngine.java +++ b/aai-core/src/main/java/org/onap/aai/serialization/engines/query/QueryEngine.java @@ -22,6 +22,7 @@ package org.onap.aai.serialization.engines.query; import java.util.List; +import org.apache.tinkerpop.gremlin.process.traversal.Path; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree; import org.apache.tinkerpop.gremlin.structure.Direction; @@ -81,7 +82,7 @@ public abstract class QueryEngine { /** * Finds all immediate children of start (no grandchildren or so forth) of the given type - * + * * @param start - the start vertex * @param type - the desired aai-node-type * @return the list of immediate child vertices of given type @@ -90,7 +91,7 @@ public abstract class QueryEngine { /** * Finds all immediate children of start (no grandchildren or so forth) - * + * * @param start - the start vertex * @return the list of immediate child vertices */ @@ -173,6 +174,8 @@ public abstract class QueryEngine { */ public abstract List<Vertex> findCousinVertices(Vertex start, String... labels); + public abstract List<Path> findCousinsAsPath(Vertex start); + public abstract double getDBTimeMsecs(); } diff --git a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/Aggregate.java b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/Aggregate.java new file mode 100644 index 00000000..4c37aaa1 --- /dev/null +++ b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/Aggregate.java @@ -0,0 +1,313 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 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========================================================= + */ + +package org.onap.aai.serialization.queryformats; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import com.google.gson.*; +import org.apache.tinkerpop.gremlin.structure.Direction; +import org.apache.tinkerpop.gremlin.structure.Edge; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.apache.tinkerpop.gremlin.structure.VertexProperty; +import org.onap.aai.db.props.AAIProperties; +import org.onap.aai.introspection.Loader; +import org.onap.aai.logging.LogFormatTools; +import org.onap.aai.serialization.db.DBSerializer; +import org.onap.aai.serialization.queryformats.exceptions.AAIFormatQueryResultFormatNotSupported; +import org.onap.aai.serialization.queryformats.exceptions.AAIFormatVertexException; +import org.onap.aai.serialization.queryformats.params.AsTree; +import org.onap.aai.serialization.queryformats.params.Depth; +import org.onap.aai.serialization.queryformats.params.NodesOnly; +import org.onap.aai.serialization.queryformats.utils.UrlBuilder; + +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class Aggregate extends MultiFormatMapper { + private static final Logger LOGGER = LoggerFactory.getLogger(LifecycleFormat.class); + protected JsonParser parser = new JsonParser(); + protected final DBSerializer serializer; + protected final Loader loader; + protected final UrlBuilder urlBuilder; + protected final int depth; + protected final boolean nodesOnly; + + protected Aggregate(Builder builder) { + this.urlBuilder = builder.getUrlBuilder(); + this.loader = builder.getLoader(); + this.serializer = builder.getSerializer(); + this.depth = builder.getDepth(); + this.nodesOnly = builder.isNodesOnly(); + this.isTree = builder.isTree(); + } + + @Override + public Optional<JsonObject> getJsonFromVertex(Vertex v, Map<String, List<String>> selectedProps) throws AAIFormatVertexException{ + JsonObject json = new JsonObject(); + JsonObject outer = new JsonObject(); + Optional<JsonObject> properties = this.createSelectedPropertiesObject(v,selectedProps); + if (properties.isPresent()) { + json.add("properties", properties.get()); + outer.add(this.urlBuilder.pathed(v),json.getAsJsonObject()); + } else { + return Optional.empty(); + } + return Optional.of(outer); + } + + @Override + public int parallelThreshold() { + return 100; + } + + public Optional<JsonObject> createPropertiesObject(Vertex v) throws AAIFormatVertexException { + JsonObject json = new JsonObject(); + Iterator<VertexProperty<Object>> iter = v.properties(); + + while (iter.hasNext()) { + VertexProperty<Object> prop = iter.next(); + if (prop.value() instanceof String) { + json.addProperty(prop.key(), (String) prop.value()); + } else if (prop.value() instanceof Boolean) { + json.addProperty(prop.key(), (Boolean) prop.value()); + } else if (prop.value() instanceof Number) { + json.addProperty(prop.key(), (Number) prop.value()); + } else if (prop.value() instanceof List) { + Gson gson = new Gson(); + String list = gson.toJson(prop.value()); + + json.addProperty(prop.key(), list); + } else { + // throw exception? + return null; + } + } + + return Optional.of(json); + } + + public Optional<JsonObject> createSelectedPropertiesObject(Vertex v, Map<String, List<String>> selectedProps) throws AAIFormatVertexException { + JsonObject json = new JsonObject(); + Set<String> propList = null; + String nodeType = v.<String>value(AAIProperties.NODE_TYPE); + if (selectedProps != null && !selectedProps.isEmpty() && selectedProps.containsKey(nodeType)) { + propList = removeSingleQuotesForProperties(selectedProps.get(nodeType)); + } + Iterator<VertexProperty<Object>> iter = v.properties(); + + Gson gson = new Gson(); + while (iter.hasNext()) { + VertexProperty<Object> prop = iter.next(); + if (propList != null && !propList.isEmpty()) { + if (propList.contains(prop.label())) { + if (prop.value() instanceof String) { + json.addProperty(prop.key(), (String) prop.value()); + } else if (prop.value() instanceof Boolean) { + json.addProperty(prop.key(), (Boolean) prop.value()); + } else if (prop.value() instanceof Number) { + json.addProperty(prop.key(), (Number) prop.value()); + } else if (prop.value() instanceof List) { + json.addProperty(prop.key(), gson.toJson(prop.value())); + } else { + // throw exception? + return null; + } + } + } else { + return this.createPropertiesObject(v); + } + } + + return Optional.of(json); + } + + private Set<String> removeSingleQuotesForProperties(List<String> props){ + if (props != null && !props.isEmpty()) { + return props.stream().map( + e -> e.substring(1, e.length()-1)).collect(Collectors.toSet()); + } else { + return Collections.emptySet(); + } + } + + public JsonArray process(List<Object> queryResults, Map<String, List<String>> properties) { + JsonArray body = new JsonArray(); + Stream<Object> stream; + if (queryResults.size() >= this.parallelThreshold()) { + stream = queryResults.parallelStream(); + } else { + stream = queryResults.stream(); + } + final boolean isParallel = stream.isParallel(); + + stream.map(o -> { + try { + return this.formatObject(o, properties); + } catch (AAIFormatVertexException e) { + LOGGER.warn("Failed to format vertex, returning a partial list " + LogFormatTools.getStackTop(e)); + } catch (AAIFormatQueryResultFormatNotSupported e) { + LOGGER.warn("Failed to format result type of the query " + LogFormatTools.getStackTop(e)); + } + + return Optional.<JsonObject>empty(); + }).filter(Optional::isPresent) + .map(Optional::get) + .forEach(json -> { + if (isParallel) { + synchronized (body) { + body.add(json); + } + } else { + body.add(json); + } + }); + return body; + } + + @Override + public Optional<JsonObject> formatObject(Object input, Map<String, List<String>> properties) + throws AAIFormatVertexException, AAIFormatQueryResultFormatNotSupported { + JsonObject json = new JsonObject(); + if (input instanceof ArrayList) { + Optional<JsonArray> ja = processInput(input, properties); + json.add("results", ja.get()); + } else { + throw new AAIFormatQueryResultFormatNotSupported(); + } + return Optional.of(json); + } + + private Optional<JsonArray> processInput(Object input, Map properties) throws AAIFormatVertexException { + JsonArray json = new JsonArray(); + for (Object l : (ArrayList) input) { + if (l instanceof ArrayList) { + JsonArray inner = new JsonArray(); + for (Vertex o : (ArrayList<Vertex>) l) { + if (o instanceof Vertex) { + Optional<JsonObject> obj = this.getJsonFromVertex((Vertex) o, properties); + if (obj.isPresent()) { + inner.add(obj.get()); + } else { + continue; + } + } + } + json.add(inner); + } else { + Optional<JsonObject> obj = this.getJsonFromVertex((Vertex)l, properties); + json.add(obj.get()); + } + } + return Optional.of(json); + } + + public static class Builder implements NodesOnly<Builder>, Depth<Builder>, AsTree<Builder> { + + protected final Loader loader; + protected final DBSerializer serializer; + protected final UrlBuilder urlBuilder; + protected boolean includeUrl = false; + protected boolean nodesOnly = false; + protected int depth = 1; + protected boolean modelDriven = false; + private boolean tree = false; + + public Builder(Loader loader, DBSerializer serializer, UrlBuilder urlBuilder) { + this.loader = loader; + this.serializer = serializer; + this.urlBuilder = urlBuilder; + } + + protected boolean isTree() { return this.tree; } + + public Builder isTree(Boolean tree) { + this.tree = tree; + return this; + } + + protected Loader getLoader() { + return this.loader; + } + + protected DBSerializer getSerializer() { + return this.serializer; + } + + protected UrlBuilder getUrlBuilder() { + return this.urlBuilder; + } + + public Builder includeUrl() { + this.includeUrl = true; + return this; + } + + public Builder nodesOnly(Boolean nodesOnly) { + this.nodesOnly = nodesOnly; + return this; + } + + public boolean isNodesOnly() { + return this.nodesOnly; + } + + public Builder depth(Integer depth) { + this.depth = depth; + return this; + } + + public int getDepth() { + return this.depth; + } + + public boolean isIncludeUrl() { + return this.includeUrl; + } + + public Builder modelDriven() { + this.modelDriven = true; + return this; + } + + public boolean getModelDriven() { + return this.modelDriven; + } + + public Aggregate build() { + return new Aggregate(this); + } + } + + @Override + protected Optional<JsonObject> getJsonFromVertex(Vertex v) throws AAIFormatVertexException { + + JsonObject json = new JsonObject(); + json.addProperty("url", this.urlBuilder.pathed(v)); + Optional<JsonObject> properties = this.createPropertiesObject(v); + if (properties.isPresent()) { + json.add("properties", properties.get()); + } else { + return Optional.empty(); + } + return Optional.of(json); + } +} diff --git a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/ChangesFormat.java b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/ChangesFormat.java new file mode 100644 index 00000000..bbaed360 --- /dev/null +++ b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/ChangesFormat.java @@ -0,0 +1,95 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 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========================================================= + */ + +package org.onap.aai.serialization.queryformats; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import org.apache.tinkerpop.gremlin.structure.Direction; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.onap.aai.config.SpringContextAware; +import org.onap.aai.db.props.AAIProperties; +import org.onap.aai.serialization.queryformats.exceptions.AAIFormatVertexException; + +import java.util.*; +import java.util.concurrent.TimeUnit; + +public class ChangesFormat extends MultiFormatMapper { + + private Long startTs = 0L; + + public void startTs(String startTime) { + /* + * StartTs = truncate time + */ + if (startTime == null || startTime.isEmpty() || "now".equals(startTime) || "0".equals(startTime) || "-1".equals(startTime)){ + String historyTruncateDays = SpringContextAware.getApplicationContext().getEnvironment().getProperty("history.truncate.window.days", "365"); + this.startTs = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(Long.parseLong(historyTruncateDays)); + } else { + this.startTs = Long.parseLong(startTime); + } + } + + @Override + protected Optional<JsonObject> getJsonFromVertex(Vertex v) { + JsonObject json = new JsonObject(); + if (!v.properties(AAIProperties.RESOURCE_VERSION).hasNext() || + !v.properties(AAIProperties.NODE_TYPE).hasNext() || + !v.properties(AAIProperties.AAI_URI).hasNext()) { + return Optional.empty(); + } + json.addProperty("node-type", v.<String>value(AAIProperties.NODE_TYPE)); + json.addProperty("uri", v.<String>value(AAIProperties.AAI_URI)); + + final Set<Long> changes = new HashSet<>(); + v.properties(AAIProperties.RESOURCE_VERSION).forEachRemaining(o-> + o.properties(AAIProperties.START_TS, AAIProperties.END_TS) + .forEachRemaining(p -> { + Long val = (Long) p.value(); + if(val >= startTs) { + changes.add(val); + } + } + )); + v.edges(Direction.BOTH).forEachRemaining(e -> { + if(e.property(AAIProperties.START_TS).isPresent() && (Long)e.property(AAIProperties.START_TS).value() >= startTs) { + changes.add((Long) e.property(AAIProperties.START_TS).value()); + } + if(e.property(AAIProperties.END_TS).isPresent() && (Long)e.property(AAIProperties.END_TS).value() >= startTs) { + changes.add((Long) e.property(AAIProperties.END_TS).value()); + } + }); + + List<Long> sortedList = new ArrayList<>(changes); + sortedList.sort(Comparator.naturalOrder()); + JsonArray jsonArray = new JsonArray(); + sortedList.forEach(jsonArray::add); + + json.add("changes", jsonArray); + + return Optional.of(json); + } + + @Override + protected Optional<JsonObject> getJsonFromVertex(Vertex input, Map<String, List<String>> properties) throws AAIFormatVertexException { + return Optional.empty(); + } + +} diff --git a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/Console.java b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/Console.java index ba20c652..7e230c3a 100644 --- a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/Console.java +++ b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/Console.java @@ -22,8 +22,11 @@ package org.onap.aai.serialization.queryformats; import com.google.gson.JsonObject; +import java.util.List; +import java.util.Map; import java.util.Optional; +import org.onap.aai.serialization.queryformats.exceptions.AAIFormatQueryResultFormatNotSupported; import org.onap.aai.serialization.queryformats.exceptions.AAIFormatVertexException; public class Console implements FormatMapper { @@ -38,6 +41,13 @@ public class Console implements FormatMapper { } @Override + public Optional<JsonObject> formatObject(Object o, Map<String, List<String>> properties) throws AAIFormatVertexException, AAIFormatQueryResultFormatNotSupported { + JsonObject json = new JsonObject(); + json.addProperty("result", o.toString()); + return Optional.of(json); + } + + @Override public int parallelThreshold() { return 100; } diff --git a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/Count.java b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/Count.java index 8ee4e3a4..60a10c51 100644 --- a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/Count.java +++ b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/Count.java @@ -23,6 +23,7 @@ package org.onap.aai.serialization.queryformats; import com.google.gson.JsonObject; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.stream.Collectors; @@ -37,8 +38,7 @@ import org.onap.aai.serialization.queryformats.exceptions.AAIFormatVertexExcepti public class Count implements FormatMapper { @Override - public Optional<JsonObject> formatObject(Object o) - throws AAIFormatVertexException, AAIFormatQueryResultFormatNotSupported { + public Optional<JsonObject> formatObject(Object o) { @SuppressWarnings("unchecked") List<Object> list = (List<Object>) o; @@ -46,12 +46,17 @@ public class Count implements FormatMapper { list.stream().map(this::getCount).filter(Optional::isPresent).map(Optional::get) .collect(Collectors.toConcurrentMap(Pair::getValue0, Pair::getValue1, Long::sum)) - .forEach((k, v) -> countResult.addProperty(k, v)); + .forEach(countResult::addProperty); return Optional.of(countResult); } @Override + public Optional<JsonObject> formatObject(Object o, Map<String, List<String>> properties) throws AAIFormatVertexException, AAIFormatQueryResultFormatNotSupported { + return Optional.empty(); + } + + @Override public int parallelThreshold() { return 20; } @@ -72,10 +77,10 @@ public class Count implements FormatMapper { } if (pair == null) { - return Optional.<Pair<String, Long>>empty(); + return Optional.empty(); } - return Optional.<Pair<String, Long>>of(pair); + return Optional.of(pair); } } diff --git a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/Format.java b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/Format.java index 8de38117..f471b3c1 100644 --- a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/Format.java +++ b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/Format.java @@ -23,7 +23,7 @@ package org.onap.aai.serialization.queryformats; import org.onap.aai.exceptions.AAIException; public enum Format { - graphson, pathed, pathed_resourceversion, id, resource, simple, resource_and_url, console, raw, count, resource_with_sot; + graphson, pathed, pathed_resourceversion, id, resource, simple, resource_and_url, console, raw, count, resource_with_sot, state, lifecycle, changes, aggregate; public static Format getFormat(String format) throws AAIException { try { diff --git a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/FormatFactory.java b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/FormatFactory.java index 854a20f4..0ae0c5fe 100644 --- a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/FormatFactory.java +++ b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/FormatFactory.java @@ -20,9 +20,6 @@ package org.onap.aai.serialization.queryformats; -import javax.ws.rs.core.MultivaluedHashMap; -import javax.ws.rs.core.MultivaluedMap; - import org.onap.aai.exceptions.AAIException; import org.onap.aai.introspection.Loader; import org.onap.aai.serialization.db.DBSerializer; @@ -31,6 +28,9 @@ import org.onap.aai.serialization.queryformats.utils.QueryParamInjector; import org.onap.aai.serialization.queryformats.utils.UrlBuilder; import org.onap.aai.setup.SchemaVersions; +import javax.ws.rs.core.MultivaluedHashMap; +import javax.ws.rs.core.MultivaluedMap; + public class FormatFactory { private final Loader loader; @@ -47,7 +47,7 @@ public class FormatFactory { } public Formatter get(Format format) throws AAIException { - return get(format, new MultivaluedHashMap<String, String>()); + return get(format, new MultivaluedHashMap<>()); } public Formatter get(Format format, MultivaluedMap<String, String> params) throws AAIException { @@ -59,29 +59,34 @@ public class FormatFactory { formatter = new Formatter(inject(new GraphSON(), params)); break; case pathed: - formatter = new Formatter(inject(new PathedURL(loader, urlBuilder), params)); + formatter = new Formatter(inject(new PathedURL.Builder(loader, serializer, urlBuilder), params).build(), params); break; case pathed_resourceversion: - formatter = new Formatter(inject(new PathedURL(loader, urlBuilder).includeUrl(), params)); + formatter = new Formatter(inject(new PathedURL.Builder(loader, serializer, urlBuilder).includeUrl(), params).build(), params); break; case id: - formatter = new Formatter(inject(new IdURL(loader, urlBuilder), params)); + formatter = new Formatter(inject(new IdURL.Builder(loader, serializer, urlBuilder), params).build(), params); break; case resource: - formatter = new Formatter(inject(new Resource.Builder(loader, serializer, urlBuilder), params).build()); + formatter = new Formatter(inject(new Resource.Builder(loader, serializer, urlBuilder, params), params).build(), params); break; case resource_and_url: formatter = new Formatter( - inject(new Resource.Builder(loader, serializer, urlBuilder).includeUrl(), params).build()); + inject(new Resource.Builder(loader, serializer, urlBuilder, params).includeUrl(), params).build(), params); break; case raw: formatter = - new Formatter(inject(new RawFormat.Builder(loader, serializer, urlBuilder), params).build()); + new Formatter(inject(new RawFormat.Builder(loader, serializer, urlBuilder), params).build(), params); break; case simple: formatter = new Formatter( inject(new RawFormat.Builder(loader, serializer, urlBuilder).depth(0).modelDriven(), params) - .build()); + .build(), params); + break; + case aggregate: + formatter = new Formatter( + inject(new Aggregate.Builder(loader, serializer, urlBuilder).depth(0).modelDriven(), params) + .build(), params); break; case console: formatter = new Formatter(inject(new Console(), params)); @@ -91,7 +96,19 @@ public class FormatFactory { break; case resource_with_sot: formatter = new Formatter( - inject(new ResourceWithSoT.Builder(loader, serializer, urlBuilder), params).build()); + inject(new ResourceWithSoT.Builder(loader, serializer, urlBuilder), params).build(), params); + break; + case changes: + formatter = + new Formatter(inject(new ChangesFormat(), params)); + break; + case state: + formatter = + new Formatter(inject(new StateFormat.Builder(loader, serializer, urlBuilder), params).build(format)); + break; + case lifecycle: + formatter = + new Formatter(inject(new LifecycleFormat.Builder(loader, serializer, urlBuilder), params).build(format)); break; default: break; diff --git a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/FormatMapper.java b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/FormatMapper.java index 26af2e31..cf967f0f 100644 --- a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/FormatMapper.java +++ b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/FormatMapper.java @@ -22,6 +22,8 @@ package org.onap.aai.serialization.queryformats; import com.google.gson.JsonObject; +import java.util.List; +import java.util.Map; import java.util.Optional; import org.onap.aai.serialization.queryformats.exceptions.AAIFormatQueryResultFormatNotSupported; @@ -30,6 +32,7 @@ import org.onap.aai.serialization.queryformats.exceptions.AAIFormatVertexExcepti public interface FormatMapper { Optional<JsonObject> formatObject(Object o) throws AAIFormatVertexException, AAIFormatQueryResultFormatNotSupported; + Optional<JsonObject> formatObject(Object o, Map<String, List<String>> properties) throws AAIFormatVertexException, AAIFormatQueryResultFormatNotSupported; int parallelThreshold(); } diff --git a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/Formatter.java b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/Formatter.java index a19bd3f6..0e15173a 100644 --- a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/Formatter.java +++ b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/Formatter.java @@ -20,46 +20,70 @@ package org.onap.aai.serialization.queryformats; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.google.gson.JsonArray; +import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; +import org.json.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.onap.aai.logging.LogFormatTools; +import org.onap.aai.serialization.queryformats.exceptions.AAIFormatQueryResultFormatNotSupported; +import org.onap.aai.serialization.queryformats.exceptions.AAIFormatVertexException; +import javax.ws.rs.core.MultivaluedMap; +import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.stream.Stream; -import org.onap.aai.logging.LogFormatTools; -import org.onap.aai.serialization.queryformats.exceptions.AAIFormatQueryResultFormatNotSupported; -import org.onap.aai.serialization.queryformats.exceptions.AAIFormatVertexException; - public class Formatter { - private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(Formatter.class); + private static final Logger LOGGER = LoggerFactory.getLogger(Formatter.class); - protected JsonParser parser = new JsonParser(); protected final FormatMapper format; + protected MultivaluedMap<String, String> params; public Formatter(FormatMapper format) { this.format = format; } - public JsonObject output(List<Object> queryResults) { + public Formatter(FormatMapper format, MultivaluedMap<String, String> params) { + this.format = format; + this.params = params; + } - Stream<Object> stream; - JsonObject result = new JsonObject(); - JsonArray body = new JsonArray(); + public JsonObject output(List<Object> queryResults, Map<String, List<String>> properties) { + + final JsonArray body; if (this.format instanceof Count) { JsonObject countResult; + body = new JsonArray(); try { countResult = format.formatObject(queryResults).orElseThrow(() -> new AAIFormatVertexException("")); body.add(countResult); } catch (Exception e) { LOGGER.warn("Failed to format result type of the query " + LogFormatTools.getStackTop(e)); } + } else if (this.format instanceof LifecycleFormat) { + LifecycleFormat lifecycleFormat = (LifecycleFormat) format; + body = lifecycleFormat.process(queryResults); + } else if (this.format instanceof Aggregate) { + Aggregate aggregateFormat = (Aggregate) format; + body = aggregateFormat.process(queryResults, properties); + JsonObject result = new JsonObject(); + if (body != null && body.size() > 0) { + result.add("results", (body.get(0)).getAsJsonObject().get("results")); + } + return result; } else { + + body = new JsonArray(); + Stream<Object> stream; if (queryResults.size() >= format.parallelThreshold()) { stream = queryResults.parallelStream(); } else { @@ -70,7 +94,11 @@ public class Formatter { stream.map(o -> { try { - return format.formatObject(o); + if (properties!= null && !properties.isEmpty()){ + return format.formatObject(o, properties); + } else { + return format.formatObject(o); + } } catch (AAIFormatVertexException e) { LOGGER.warn("Failed to format vertex, returning a partial list " + LogFormatTools.getStackTop(e)); } catch (AAIFormatQueryResultFormatNotSupported e) { @@ -78,19 +106,38 @@ public class Formatter { } return Optional.<JsonObject>empty(); - }).filter(Optional::isPresent).map(Optional::get).forEach(json -> { - if (isParallel) { - synchronized (body) { + }).filter(Optional::isPresent) + .map(Optional::get) + .forEach(json -> { + if (isParallel) { + synchronized (body) { + body.add(json); + } + } else { body.add(json); } - } else { - body.add(json); - } - }); + }); } + + if (params !=null && params.containsKey("as-tree")) { + String isAsTree = params.get("as-tree").get(0); + if (isAsTree != null && isAsTree.equalsIgnoreCase("true") + && body != null && body.size() != 0) { + JsonObject jsonObjectBody = body.get(0).getAsJsonObject(); + if (jsonObjectBody != null && jsonObjectBody.size() > 0) { + return body.get(0).getAsJsonObject(); + } + } + } + JsonObject result = new JsonObject(); result.add("results", body); return result.getAsJsonObject(); + + } + + public JsonObject output(List<Object> queryResults) { + return output(queryResults, null); } } diff --git a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/GraphSON.java b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/GraphSON.java index eeac2195..609f6b0f 100644 --- a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/GraphSON.java +++ b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/GraphSON.java @@ -28,16 +28,15 @@ import com.google.gson.JsonParser; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.Optional; +import java.util.*; import org.apache.tinkerpop.gremlin.structure.Direction; import org.apache.tinkerpop.gremlin.structure.Vertex; import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONMapper; import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONWriter; import org.janusgraph.graphdb.tinkerpop.JanusGraphIoRegistry; +import org.onap.aai.serialization.queryformats.exceptions.AAIFormatQueryResultFormatNotSupported; +import org.onap.aai.serialization.queryformats.exceptions.AAIFormatVertexException; public class GraphSON implements FormatMapper { @@ -79,6 +78,11 @@ public class GraphSON implements FormatMapper { } + @Override + public Optional<JsonObject> formatObject(Object o, Map<String, List<String>> properties) throws AAIFormatVertexException, AAIFormatQueryResultFormatNotSupported { + return Optional.empty(); + } + /** * Removes the private edges from the json object * diff --git a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/HistoryFormat.java b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/HistoryFormat.java new file mode 100644 index 00000000..b11f14aa --- /dev/null +++ b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/HistoryFormat.java @@ -0,0 +1,246 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 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 + * <p> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p> + * 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.aai.serialization.queryformats; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import org.apache.tinkerpop.gremlin.structure.*; +import org.onap.aai.db.props.AAIProperties; +import org.onap.aai.introspection.Loader; +import org.onap.aai.serialization.db.DBSerializer; +import org.onap.aai.serialization.queryformats.exceptions.AAIFormatVertexException; +import org.onap.aai.serialization.queryformats.params.Depth; +import org.onap.aai.serialization.queryformats.params.EndTs; +import org.onap.aai.serialization.queryformats.params.NodesOnly; +import org.onap.aai.serialization.queryformats.params.StartTs; +import org.onap.aai.serialization.queryformats.utils.UrlBuilder; + +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public abstract class HistoryFormat extends MultiFormatMapper { + + private static final Logger LOGGER = LoggerFactory.getLogger(HistoryFormat.class); + + protected static final String KEY = "key"; + protected static final String VALUE = "value"; + protected static final String TIMESTAMP = "timestamp"; + protected static final String NODE_TYPE = "node-type"; + protected static final String END_TIMESTAMP = "end-timestamp"; + protected static final String SOT = "sot"; + protected static final String END_SOT = "end-sot"; + protected static final String TX_ID = "tx-id"; + protected static final String END_TX_ID = "end-tx-id"; + protected static final String PROPERTIES = "properties"; + protected static final String RELATED_TO = "related-to"; + protected static final String NODE_ACTIONS = "node-actions"; + + protected JsonParser parser = new JsonParser(); + protected final DBSerializer serializer; + protected final Loader loader; + protected final UrlBuilder urlBuilder; + protected final int depth; + protected final boolean nodesOnly; + protected long startTs; + protected long endTs; + protected static final Set<String> ignoredKeys = + Stream.of(AAIProperties.LAST_MOD_TS, AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, AAIProperties.CREATED_TS) + .collect(Collectors.toSet()); + + protected HistoryFormat(Builder builder) { + this.urlBuilder = builder.getUrlBuilder(); + this.loader = builder.getLoader(); + this.serializer = builder.getSerializer(); + this.depth = builder.getDepth(); + this.nodesOnly = builder.isNodesOnly(); + this.startTs = builder.getStartTs(); + this.endTs = builder.getEndTs(); + } + + @Override + public int parallelThreshold() { + return 100; + } + + protected JsonObject createMetaPropertiesObject(VertexProperty<Object> prop) { + JsonObject json = new JsonObject(); + Iterator iter = prop.properties(); + + while (iter.hasNext()) { + Property<Object> metaProp = (Property) iter.next(); + mapPropertyValues(json, metaProp.key(), metaProp.value()); + } + + return json; + } + + protected JsonObject mapPropertyValues(JsonObject json, String propertyKey, Object propertyValue) { + if (propertyValue instanceof String) { + json.addProperty(propertyKey, (String) propertyValue); + } else if (propertyValue instanceof Boolean) { + json.addProperty(propertyKey, (Boolean) propertyValue); + } else if (propertyValue instanceof Number) { + json.addProperty(propertyKey, (Number) propertyValue); + } else { + if (!(propertyValue instanceof List)) { + return json; + } + + Gson gson = new Gson(); + String list = gson.toJson(propertyValue); + json.addProperty(propertyKey, list); + } + return json; + } + + protected JsonArray createRelationshipObject(Vertex v) throws AAIFormatVertexException { + JsonArray relatedToList = new JsonArray(); + Iterator<Edge> inIter = v.edges(Direction.IN); + Iterator<Edge> outIter = v.edges(Direction.OUT); + + while (inIter.hasNext()) { + Edge e = inIter.next(); + if (isValidEdge(e)) { + relatedToList.add(getRelatedObject(e, e.outVertex())); + } + } + + while (outIter.hasNext()) { + Edge e = outIter.next(); + if (isValidEdge(e)) { + relatedToList.add(getRelatedObject(e, e.inVertex())); + } + } + + return relatedToList; + + } + + protected abstract boolean isValidEdge(Edge e); + + protected abstract JsonObject getRelatedObject(Edge e, Vertex related) throws AAIFormatVertexException; + + + + public static class Builder implements NodesOnly<Builder>, Depth<Builder>, StartTs<Builder>, EndTs<Builder> { + + protected final Loader loader; + protected final DBSerializer serializer; + protected final UrlBuilder urlBuilder; + protected boolean includeUrl = false; + protected boolean nodesOnly = false; + protected int depth = 1; + protected boolean modelDriven = false; + protected long startTs = -1; + protected long endTs = -1; + + public Builder(Loader loader, DBSerializer serializer, UrlBuilder urlBuilder) { + this.loader = loader; + this.serializer = serializer; + this.urlBuilder = urlBuilder; + } + + protected Loader getLoader() { + return this.loader; + } + + protected DBSerializer getSerializer() { + return this.serializer; + } + + protected UrlBuilder getUrlBuilder() { + return this.urlBuilder; + } + + public Builder includeUrl() { + this.includeUrl = true; + return this; + } + + public Builder nodesOnly(Boolean nodesOnly) { + this.nodesOnly = nodesOnly; + return this; + } + + public Builder startTs(String startTs) { + this.startTs = Long.parseLong(startTs); + return this; + } + + public Builder endTs(String endTs) { + this.endTs = Long.parseLong(endTs); + return this; + } + + + public boolean isNodesOnly() { + return this.nodesOnly; + } + + public Builder depth(Integer depth) { + this.depth = depth; + return this; + } + + public int getDepth() { + return this.depth; + } + + public boolean isIncludeUrl() { + return this.includeUrl; + } + + public Builder modelDriven() { + this.modelDriven = true; + return this; + } + + public boolean getModelDriven() { + return this.modelDriven; + } + + public long getStartTs() { + return this.startTs; + } + + public long getEndTs() { + return this.endTs; + } + + public HistoryFormat build(Format format) { + + if(Format.state.equals(format)) { + return new StateFormat(this); + } else { + return new LifecycleFormat(this); + } + + } + } + +} diff --git a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/IdURL.java b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/IdURL.java index c5cb9254..c2c252a2 100644 --- a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/IdURL.java +++ b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/IdURL.java @@ -23,6 +23,8 @@ package org.onap.aai.serialization.queryformats; import com.google.gson.JsonObject; import com.google.gson.JsonParser; +import java.util.List; +import java.util.Map; import java.util.Optional; import org.apache.tinkerpop.gremlin.structure.Vertex; @@ -31,9 +33,15 @@ import org.onap.aai.exceptions.AAIException; import org.onap.aai.introspection.Introspector; import org.onap.aai.introspection.Loader; import org.onap.aai.introspection.exceptions.AAIUnknownObjectException; +import org.onap.aai.serialization.db.DBSerializer; import org.onap.aai.serialization.queryformats.exceptions.AAIFormatVertexException; +import org.onap.aai.serialization.queryformats.params.AsTree; +import org.onap.aai.serialization.queryformats.params.Depth; +import org.onap.aai.serialization.queryformats.params.NodesOnly; import org.onap.aai.serialization.queryformats.utils.UrlBuilder; +import javax.ws.rs.core.MultivaluedMap; + public class IdURL extends MultiFormatMapper { private final UrlBuilder urlBuilder; @@ -46,6 +54,13 @@ public class IdURL extends MultiFormatMapper { this.loader = loader; } + public IdURL(Builder builder) throws AAIException { + this.urlBuilder = builder.getUrlBuilder(); + this.parser = new JsonParser(); + this.loader = builder.getLoader(); + this.isTree = builder.isTree(); + } + @Override public int parallelThreshold() { return 2500; @@ -69,4 +84,101 @@ public class IdURL extends MultiFormatMapper { } } + + @Override + protected Optional<JsonObject> getJsonFromVertex(Vertex input, Map<String, List<String>> properties) throws AAIFormatVertexException { + return Optional.empty(); + } + + public static class Builder implements NodesOnly<Builder>, Depth<Builder>, AsTree<Builder> { + + private final Loader loader; + private final DBSerializer serializer; + private final UrlBuilder urlBuilder; + private boolean includeUrl = false; + private boolean nodesOnly = false; + private int depth = 1; + private MultivaluedMap<String, String> params; + private boolean tree = false; + + public Builder(Loader loader, DBSerializer serializer, UrlBuilder urlBuilder) { + this.loader = loader; + this.serializer = serializer; + this.urlBuilder = urlBuilder; + } + + public Builder(Loader loader, DBSerializer serializer, UrlBuilder urlBuilder, MultivaluedMap<String, String> params) { + this.loader = loader; + this.serializer = serializer; + this.urlBuilder = urlBuilder; + this.params = params; + } + + protected Loader getLoader() { + return this.loader; + } + + protected DBSerializer getSerializer() { + return this.serializer; + } + + protected UrlBuilder getUrlBuilder() { + return this.urlBuilder; + } + + protected MultivaluedMap<String, String> getParams() { return this.params; } + + public boolean isSkipRelatedTo() { + if (params != null) { + boolean isSkipRelatedTo = true; + if (params.containsKey("skip-related-to")) { + String skipRelatedTo = params.getFirst("skip-related-to"); + isSkipRelatedTo = !(skipRelatedTo != null && skipRelatedTo.equals("false")); + } else { + // if skip-related-to param is missing, then default it to false; + isSkipRelatedTo = false; + } + return isSkipRelatedTo; + } + return true; + } + + protected boolean isTree() { return this.tree; } + + public Builder isTree(Boolean tree) { + this.tree = tree; + return this; + } + + public Builder includeUrl() { + this.includeUrl = true; + return this; + } + + public Builder nodesOnly(Boolean nodesOnly) { + this.nodesOnly = nodesOnly; + return this; + } + + public boolean isNodesOnly() { + return this.nodesOnly; + } + + public Builder depth(Integer depth) { + this.depth = depth; + return this; + } + + public int getDepth() { + return this.depth; + } + + public boolean isIncludeUrl() { + return this.includeUrl; + } + + public IdURL build() throws AAIException { + return new IdURL(this); + } + } } diff --git a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/LifecycleFormat.java b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/LifecycleFormat.java new file mode 100644 index 00000000..57bb17c2 --- /dev/null +++ b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/LifecycleFormat.java @@ -0,0 +1,313 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 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========================================================= + */ + +package org.onap.aai.serialization.queryformats; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import org.apache.tinkerpop.gremlin.structure.Edge; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.apache.tinkerpop.gremlin.structure.VertexProperty; +import org.onap.aai.db.props.AAIProperties; +import org.onap.aai.logging.LogFormatTools; +import org.onap.aai.serialization.queryformats.exceptions.AAIFormatQueryResultFormatNotSupported; +import org.onap.aai.serialization.queryformats.exceptions.AAIFormatVertexException; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; + +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + + +public class LifecycleFormat extends HistoryFormat { + + private static final Logger LOGGER = LoggerFactory.getLogger(LifecycleFormat.class); + + protected LifecycleFormat(Builder builder) { + super(builder); + } + + protected JsonArray createPropertiesObject(Vertex v) { + JsonArray jsonArray = new JsonArray(); + Iterator<VertexProperty<Object>> iter = v.properties(); + List<JsonObject> jsonList = new ArrayList<>(); + + Map<String, Set<Long>> propStartTimes = new HashMap<>(); //vertex end + while (iter.hasNext()) { + JsonObject json = new JsonObject(); + VertexProperty<Object> prop = iter.next(); + if(prop.key() != null && ignoredKeys.contains(prop.key())){ + continue; + } + if (!propStartTimes.containsKey(prop.key())) { + propStartTimes.put(prop.key(), new HashSet<>()); + if (v.property(AAIProperties.END_TS).isPresent()) { + propStartTimes.get(prop.key()).add(v.<Long>value(AAIProperties.END_TS)); + } + } + + json.addProperty(KEY, prop.key()); + json = mapPropertyValues(json, VALUE, prop.value()); + JsonObject metaProperties = createMetaPropertiesObject(prop); + if (isTsInRange(metaProperties.get(AAIProperties.START_TS).getAsLong())) { + JsonObject jo = new JsonObject(); + jo.add(KEY, json.get(KEY)); + jo.add(VALUE, json.get(VALUE)); + jo.add(TIMESTAMP, metaProperties.get(AAIProperties.START_TS)); + jo.add(SOT, metaProperties.get(AAIProperties.SOURCE_OF_TRUTH)); + jo.add(TX_ID, metaProperties.get(AAIProperties.START_TX_ID)); + jsonList.add(jo); + propStartTimes.get(prop.key()).add(metaProperties.get(AAIProperties.START_TS).getAsLong()); + } + if (!AAIProperties.RESOURCE_VERSION.equals(prop.key()) + && metaProperties.has(AAIProperties.END_TS) + && isTsInRange(metaProperties.get(AAIProperties.END_TS).getAsLong()) + && !propStartTimes.get(prop.key()).contains(metaProperties.get(AAIProperties.END_TS).getAsLong())) { + JsonObject jo = new JsonObject(); + jo.add(KEY, json.get(KEY)); + jo.add(VALUE, null); + jo.add(TIMESTAMP, metaProperties.get(AAIProperties.END_TS)); + jo.add(SOT, metaProperties.get(AAIProperties.END_SOT)); + jo.add(TX_ID, metaProperties.get(AAIProperties.END_TX_ID)); + jsonList.add(jo); + } + + } + jsonList.stream() + // remove all the null values that is the start time for another value + .filter(jo -> !jo.get(VALUE).isJsonNull() || !propStartTimes.get(jo.get(KEY).getAsString()).contains(jo.get(TIMESTAMP).getAsLong())) + // sort by ts in decreasing order + .sorted((o1, o2) -> { + if (o1.get(TIMESTAMP).getAsLong() == o2.get(TIMESTAMP).getAsLong()) { + return o1.get(KEY).getAsString().compareTo(o2.get(KEY).getAsString()); + } else { + return Long.compare(o2.get(TIMESTAMP).getAsLong(), o1.get(TIMESTAMP).getAsLong()); + } + }).forEach(jsonArray::add); + + return jsonArray; + } + + private boolean isTsInRange(long ts) { + return ts >= startTs && ts <= endTs; + } + + + @Override + protected boolean isValidEdge(Edge e) { + if (e.property(AAIProperties.END_TS).isPresent()) { + long edgeStartTs = e.<Long>value(AAIProperties.START_TS); + long edgeEndTs = e.<Long>value(AAIProperties.END_TS); + return isTsInRange(edgeStartTs) || isTsInRange(edgeEndTs); + } else { + long edgeStartTs = e.<Long>value(AAIProperties.START_TS); + return isTsInRange(edgeStartTs); + } + } + + @Override + protected JsonObject getRelatedObject(Edge e, Vertex related) throws AAIFormatVertexException { + + JsonObject json = new JsonObject(); + json.addProperty("relationship-label", e.label()); + json.addProperty("node-type", related.<String>value(AAIProperties.NODE_TYPE)); + json.addProperty("url", this.urlBuilder.pathed(related)); + if (related.property(AAIProperties.AAI_URI).isPresent()) { + json.addProperty("uri", related.<String>value(AAIProperties.AAI_URI)); + } else { + LOGGER.warn("Vertex {} is missing aai-uri", related.id()); + json.addProperty("uri", "NA"); + } + + if(e.property(AAIProperties.START_TS).isPresent()) { + long edgeStartTimestamp = e.<Long>value(AAIProperties.START_TS); + if (isTsInRange(edgeStartTimestamp)) { + json.addProperty(TIMESTAMP, e.property(AAIProperties.START_TS).isPresent()? e.<Long>value(AAIProperties.START_TS) : 0); + json.addProperty(SOT, e.property(AAIProperties.SOURCE_OF_TRUTH).isPresent()? e.value(AAIProperties.SOURCE_OF_TRUTH) : ""); + json.addProperty(TX_ID, e.property(AAIProperties.START_TX_ID).isPresent()? e.value(AAIProperties.START_TX_ID) : "N/A"); + } + } + + if(e.property(AAIProperties.END_TS).isPresent()) { + long edgeEndTimestamp = e.<Long>value(AAIProperties.END_TS); + if (isTsInRange(edgeEndTimestamp)) { + json.addProperty(END_TIMESTAMP, edgeEndTimestamp); + json.addProperty(END_SOT, e.property(AAIProperties.END_SOT).isPresent() ? e.value(AAIProperties.END_SOT) : ""); + json.addProperty(END_TX_ID, e.property(AAIProperties.END_TX_ID).isPresent() ? e.value(AAIProperties.END_TX_ID) : "N/A"); + } + } + + return json; + } + + @Override + protected Optional<JsonObject> getJsonFromVertex(Vertex v) throws AAIFormatVertexException { + JsonObject json = new JsonObject(); + json.addProperty(NODE_TYPE, v.<String>value(AAIProperties.NODE_TYPE)); + json.addProperty("url", this.urlBuilder.pathed(v)); + if (v.property(AAIProperties.AAI_URI).isPresent()) { + json.addProperty("uri", v.<String>value(AAIProperties.AAI_URI)); + } else { + LOGGER.warn("Vertex {} is missing aai-uri", v.id()); + json.addProperty("uri", "NA"); + } + json.addProperty(TIMESTAMP, v.<Long>value(AAIProperties.START_TS)); + + json.add(PROPERTIES, this.createPropertiesObject(v)); + + if (!nodesOnly) { + json.add(RELATED_TO, this.createRelationshipObject(v)); + } + + json.add(NODE_ACTIONS, getNodeActions(v, json)); + + if (json.getAsJsonObject().get(PROPERTIES).getAsJsonArray().size() == 0 + && json.getAsJsonObject().get(RELATED_TO).getAsJsonArray().size() == 0 + && json.getAsJsonObject().get(NODE_ACTIONS).getAsJsonArray().size() == 0) { + return Optional.empty(); + } else if (json.getAsJsonObject().get(PROPERTIES).getAsJsonArray().size() == 1 + && (json.getAsJsonObject().get(RELATED_TO).getAsJsonArray().size() > 0 + || json.getAsJsonObject().get(NODE_ACTIONS).getAsJsonArray().size() > 0)) { + if (json.getAsJsonObject().get(PROPERTIES).getAsJsonArray() + .get(0).getAsJsonObject().get("key").getAsString().equals(AAIProperties.END_TS)) { + json.getAsJsonObject().add(PROPERTIES, new JsonArray()); + } + } + + return Optional.of(json); + } + + @Override + protected Optional<JsonObject> getJsonFromVertex(Vertex input, Map<String, List<String>> properties) throws AAIFormatVertexException { + return Optional.empty(); + } + + private JsonArray getNodeActions(Vertex v, JsonObject json) { + JsonArray nodeActions = new JsonArray(); + JsonObject action; + if (v.property(AAIProperties.END_TS).isPresent()) { + long deletedTs = (Long) v.property(AAIProperties.END_TS).value(); + if (isTsInRange(deletedTs)) { + action = new JsonObject(); + action.addProperty("action", "DELETED"); + action.addProperty(TIMESTAMP, deletedTs); + if (v.property(AAIProperties.END_TS).property(AAIProperties.SOURCE_OF_TRUTH).isPresent()) { + action.addProperty(SOT, v.property(AAIProperties.END_TS).<String>value(AAIProperties.SOURCE_OF_TRUTH)); + } + if (v.property(AAIProperties.END_TS).property(AAIProperties.END_TX_ID).isPresent()) { + action.addProperty(TX_ID, v.property(AAIProperties.END_TS).<String>value(AAIProperties.END_TX_ID)); + } else { + action.addProperty(TX_ID, "N/A"); + } + nodeActions.add(action); + } + } + long createdTs = json.get(TIMESTAMP).getAsLong(); + if (isTsInRange(createdTs)) { + action = new JsonObject(); + action.addProperty("action", "CREATED"); + action.addProperty(TIMESTAMP, createdTs); + action.addProperty(SOT, v.<String>value(AAIProperties.SOURCE_OF_TRUTH)); + if (v.property(AAIProperties.SOURCE_OF_TRUTH).property(AAIProperties.START_TX_ID).isPresent()) { + action.addProperty(TX_ID, v.property(AAIProperties.SOURCE_OF_TRUTH).<String>value(AAIProperties.START_TX_ID)); + } else { + action.addProperty(TX_ID, "N/A"); + } + nodeActions.add(action); + } + return nodeActions; + } + + public JsonArray process(List<Object> queryResults) { + JsonArray body = new JsonArray(); + Stream<Object> stream; + if (queryResults.size() >= this.parallelThreshold()) { + stream = queryResults.parallelStream(); + } else { + stream = queryResults.stream(); + } + + final boolean isParallel = stream.isParallel(); + + stream.map(o -> { + try { + return this.formatObject(o); + } catch (AAIFormatVertexException e) { + LOGGER.warn("Failed to format vertex, returning a partial list " + LogFormatTools.getStackTop(e)); + } catch (AAIFormatQueryResultFormatNotSupported e) { + LOGGER.warn("Failed to format result type of the query " + LogFormatTools.getStackTop(e)); + } + + return Optional.<JsonObject>empty(); + }).filter(Optional::isPresent) + .map(Optional::get) + .forEach(json -> { + if (isParallel) { + synchronized (body) { + body.add(json); + } + } else { + body.add(json); + } + }); + JsonArray result = organizeBody(body); + result.forEach(jsonElement -> jsonElement.getAsJsonObject().remove(TIMESTAMP)); + return result; + } + + private JsonArray organizeBody(JsonArray body) { + + final MultiValueMap<String, Integer> toBeMerged = new LinkedMultiValueMap<>(); + for (int i = 0; i < body.size(); i++) { + toBeMerged.add(body.get(i).getAsJsonObject().get("uri").getAsString(), i); + } + + final List<List<Integer>> dupes = toBeMerged.values().stream().filter(l -> l.size() > 1).collect(Collectors.toList()); + if (dupes.isEmpty()) { + return body; + } else { + Set<Integer> remove = new HashSet<>(); + for (List<Integer> dupe : dupes) { + dupe.sort((a,b) -> Long.compare(body.get(b).getAsJsonObject().get(TIMESTAMP).getAsLong(), body.get(a).getAsJsonObject().get(TIMESTAMP).getAsLong())); + int keep = dupe.remove(0); + for (Integer idx : dupe) { + body.get(keep).getAsJsonObject().getAsJsonArray(NODE_ACTIONS) + .addAll(body.get(idx).getAsJsonObject().getAsJsonArray(NODE_ACTIONS)); + body.get(keep).getAsJsonObject().getAsJsonArray(PROPERTIES) + .addAll(body.get(idx).getAsJsonObject().getAsJsonArray(PROPERTIES)); + body.get(keep).getAsJsonObject().getAsJsonArray(RELATED_TO) + .addAll(body.get(idx).getAsJsonObject().getAsJsonArray(RELATED_TO)); + remove.add(idx); + } + } + final JsonArray newBody = new JsonArray(); + for (int i = 0; i < body.size(); i++) { + if (!remove.contains(i)) { + newBody.add(body.get(i)); + } + } + return newBody; + } + } + +} diff --git a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/MultiFormatMapper.java b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/MultiFormatMapper.java index 21b666f2..b06ef7c3 100644 --- a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/MultiFormatMapper.java +++ b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/MultiFormatMapper.java @@ -22,26 +22,49 @@ package org.onap.aai.serialization.queryformats; import com.google.gson.JsonArray; import com.google.gson.JsonObject; - -import java.util.Iterator; -import java.util.List; -import java.util.Optional; - import org.apache.tinkerpop.gremlin.process.traversal.Path; import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree; import org.apache.tinkerpop.gremlin.structure.Vertex; import org.onap.aai.serialization.queryformats.exceptions.AAIFormatQueryResultFormatNotSupported; import org.onap.aai.serialization.queryformats.exceptions.AAIFormatVertexException; +import java.util.List; +import java.util.Map; +import java.util.Optional; + public abstract class MultiFormatMapper implements FormatMapper { + protected boolean isTree = false; + @Override public Optional<JsonObject> formatObject(Object input) throws AAIFormatVertexException, AAIFormatQueryResultFormatNotSupported { if (input instanceof Vertex) { return this.getJsonFromVertex((Vertex) input); } else if (input instanceof Tree) { - return this.getJsonFomTree((Tree<?>) input); + if (isTree) { + return this.getRelatedNodesFromTree((Tree<?>) input); + } else { + return this.getJsonFomTree((Tree<?>) input); + } + } else if (input instanceof Path) { + return this.getJsonFromPath((Path) input); + } else { + throw new AAIFormatQueryResultFormatNotSupported(); + } + } + + @Override + public Optional<JsonObject> formatObject(Object input, Map<String, List<String>> properties) + throws AAIFormatVertexException, AAIFormatQueryResultFormatNotSupported { + if (input instanceof Vertex) { + return this.getJsonFromVertex((Vertex) input, properties); + } else if (input instanceof Tree) { + if (isTree) { + return this.getRelatedNodesFromTree((Tree<?>) input); + } else { + return this.getJsonFomTree((Tree<?>) input); + } } else if (input instanceof Path) { return this.getJsonFromPath((Path) input); } else { @@ -50,6 +73,7 @@ public abstract class MultiFormatMapper implements FormatMapper { } protected abstract Optional<JsonObject> getJsonFromVertex(Vertex input) throws AAIFormatVertexException; + protected abstract Optional<JsonObject> getJsonFromVertex(Vertex input, Map<String, List<String>> properties) throws AAIFormatVertexException; protected Optional<JsonObject> getJsonFromPath(Path input) throws AAIFormatVertexException { List<Object> path = input.objects(); @@ -59,7 +83,8 @@ public abstract class MultiFormatMapper implements FormatMapper { for (Object o : path) { if (o instanceof Vertex) { - ja.add(this.getJsonFromVertex((Vertex) o).get()); + Optional<JsonObject> obj = this.getJsonFromVertex((Vertex) o); + obj.ifPresent(ja::add); } } @@ -74,7 +99,7 @@ public abstract class MultiFormatMapper implements FormatMapper { } JsonObject t = new JsonObject(); - JsonArray ja = this.getNodesArray(tree); + JsonArray ja = this.getNodesArray(tree, "nodes"); if (ja.size() > 0) { t.add("nodes", ja); } @@ -82,20 +107,37 @@ public abstract class MultiFormatMapper implements FormatMapper { return Optional.of(t); } - private JsonArray getNodesArray(Tree<?> tree) throws AAIFormatVertexException { + protected Optional<JsonObject> getRelatedNodesFromTree(Tree<?> tree) throws AAIFormatVertexException { + if (tree.isEmpty()) { + return Optional.of(new JsonObject()); + } - JsonArray nodes = new JsonArray(); - Iterator<?> it = tree.keySet().iterator(); + JsonObject t = new JsonObject(); + JsonArray ja = this.getNodesArray(tree, "related-nodes"); + if (ja.size() > 0) { + t.add("results", ja); + return Optional.of(t); + } + + return Optional.empty(); + } + + protected JsonArray getNodesArray(Tree<?> tree, String nodeIdentifier) throws AAIFormatVertexException { - while (it.hasNext()) { - Object o = it.next(); + JsonArray nodes = new JsonArray(); + for (Map.Entry<?, ? extends Tree<?>> entry : tree.entrySet()) { JsonObject me = new JsonObject(); - if (o instanceof Vertex) { - me = this.getJsonFromVertex((Vertex) o).get(); + if (entry.getKey() instanceof Vertex) { + Optional<JsonObject> obj = this.getJsonFromVertex((Vertex) entry.getKey()); + if (obj.isPresent()) { + me = obj.get(); + } else { + continue; + } } - JsonArray ja = this.getNodesArray((Tree<?>) tree.get(o)); + JsonArray ja = this.getNodesArray(entry.getValue(), nodeIdentifier); if (ja.size() > 0) { - me.add("nodes", ja); + me.add(nodeIdentifier, ja); } nodes.add(me); } diff --git a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/PathedURL.java b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/PathedURL.java index a99ba7f4..417f73cd 100644 --- a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/PathedURL.java +++ b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/PathedURL.java @@ -23,6 +23,8 @@ package org.onap.aai.serialization.queryformats; import com.google.gson.JsonObject; import com.google.gson.JsonParser; +import java.util.List; +import java.util.Map; import java.util.Optional; import org.apache.tinkerpop.gremlin.structure.Vertex; @@ -31,9 +33,15 @@ import org.onap.aai.exceptions.AAIException; import org.onap.aai.introspection.Introspector; import org.onap.aai.introspection.Loader; import org.onap.aai.introspection.exceptions.AAIUnknownObjectException; +import org.onap.aai.serialization.db.DBSerializer; import org.onap.aai.serialization.queryformats.exceptions.AAIFormatVertexException; +import org.onap.aai.serialization.queryformats.params.AsTree; +import org.onap.aai.serialization.queryformats.params.Depth; +import org.onap.aai.serialization.queryformats.params.NodesOnly; import org.onap.aai.serialization.queryformats.utils.UrlBuilder; +import javax.ws.rs.core.MultivaluedMap; + public final class PathedURL extends MultiFormatMapper { private final UrlBuilder urlBuilder; @@ -47,6 +55,13 @@ public final class PathedURL extends MultiFormatMapper { this.loader = loader; } + public PathedURL(Builder builder) { + this.urlBuilder = builder.getUrlBuilder(); + this.parser = new JsonParser(); + this.loader = builder.getLoader(); + this.isTree = builder.isTree(); + } + @Override public int parallelThreshold() { return 20; @@ -79,4 +94,101 @@ public final class PathedURL extends MultiFormatMapper { } + @Override + protected Optional<JsonObject> getJsonFromVertex(Vertex input, Map<String, List<String>> properties) throws AAIFormatVertexException { + return Optional.empty(); + } + + public static class Builder implements NodesOnly<Builder>, Depth<Builder>, AsTree<Builder> { + + private final Loader loader; + private final DBSerializer serializer; + private final UrlBuilder urlBuilder; + private boolean includeUrl = false; + private boolean nodesOnly = false; + private int depth = 1; + private MultivaluedMap<String, String> params; + private boolean tree = false; + + public Builder(Loader loader, DBSerializer serializer, UrlBuilder urlBuilder) { + this.loader = loader; + this.serializer = serializer; + this.urlBuilder = urlBuilder; + } + + public Builder(Loader loader, DBSerializer serializer, UrlBuilder urlBuilder, MultivaluedMap<String, String> params) { + this.loader = loader; + this.serializer = serializer; + this.urlBuilder = urlBuilder; + this.params = params; + } + + protected Loader getLoader() { + return this.loader; + } + + protected DBSerializer getSerializer() { + return this.serializer; + } + + protected UrlBuilder getUrlBuilder() { + return this.urlBuilder; + } + + protected MultivaluedMap<String, String> getParams() { return this.params; } + + public boolean isSkipRelatedTo() { + if (params != null) { + boolean isSkipRelatedTo = true; + if (params.containsKey("skip-related-to")) { + String skipRelatedTo = params.getFirst("skip-related-to"); + isSkipRelatedTo = !(skipRelatedTo != null && skipRelatedTo.equals("false")); + } else { + // if skip-related-to param is missing, then default it to false; + isSkipRelatedTo = false; + } + return isSkipRelatedTo; + } + return true; + } + + protected boolean isTree() { return this.tree; } + + public Builder isTree(Boolean tree) { + this.tree = tree; + return this; + } + + public Builder includeUrl() { + this.includeUrl = true; + return this; + } + + public Builder nodesOnly(Boolean nodesOnly) { + this.nodesOnly = nodesOnly; + return this; + } + + public boolean isNodesOnly() { + return this.nodesOnly; + } + + public Builder depth(Integer depth) { + this.depth = depth; + return this; + } + + public int getDepth() { + return this.depth; + } + + public boolean isIncludeUrl() { + return this.includeUrl; + } + + public PathedURL build() throws AAIException { + return new PathedURL(this); + } + } + } diff --git a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/RawFormat.java b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/RawFormat.java index 8636ebfa..8dcd3a83 100644 --- a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/RawFormat.java +++ b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/RawFormat.java @@ -25,9 +25,8 @@ import com.google.gson.JsonArray; import com.google.gson.JsonObject; import com.google.gson.JsonParser; -import java.util.Iterator; -import java.util.List; -import java.util.Optional; +import java.util.*; +import java.util.stream.Collectors; import org.apache.tinkerpop.gremlin.structure.Direction; import org.apache.tinkerpop.gremlin.structure.Edge; @@ -38,6 +37,7 @@ import org.onap.aai.introspection.Loader; import org.onap.aai.serialization.db.DBSerializer; import org.onap.aai.serialization.queryformats.exceptions.AAIFormatVertexException; import org.onap.aai.serialization.queryformats.params.Depth; +import org.onap.aai.serialization.queryformats.params.AsTree; import org.onap.aai.serialization.queryformats.params.NodesOnly; import org.onap.aai.serialization.queryformats.utils.UrlBuilder; @@ -55,6 +55,25 @@ public class RawFormat extends MultiFormatMapper { this.serializer = builder.getSerializer(); this.depth = builder.getDepth(); this.nodesOnly = builder.isNodesOnly(); + this.isTree = builder.isTree(); + } + + @Override + public Optional<JsonObject> getJsonFromVertex(Vertex v, Map<String, List<String>> selectedProps) throws AAIFormatVertexException { + JsonObject json = new JsonObject(); + json.addProperty("id", v.id().toString()); + json.addProperty("node-type", v.<String>value(AAIProperties.NODE_TYPE)); + json.addProperty("url", this.urlBuilder.pathed(v)); + Optional<JsonObject> properties = this.createSelectedPropertiesObject(v, selectedProps); + if (properties.isPresent()) { + json.add("properties", properties.get()); + } else { + return Optional.empty(); + } + if (!nodesOnly) { + json.add("related-to", this.createRelationshipObject(v)); + } + return Optional.of(json); } @Override @@ -88,6 +107,48 @@ public class RawFormat extends MultiFormatMapper { return Optional.of(json); } + public Optional<JsonObject> createSelectedPropertiesObject(Vertex v, Map<String, List<String>> selectedProps) throws AAIFormatVertexException { + JsonObject json = new JsonObject(); + String nodeType = v.<String>value(AAIProperties.NODE_TYPE); + Set<String> propList = removeSingleQuotesForProperties(selectedProps.get(nodeType)); + Iterator<VertexProperty<Object>> iter = v.properties(); + + Gson gson = new Gson(); + while (iter.hasNext()) { + VertexProperty<Object> prop = iter.next(); + if (propList != null && !propList.isEmpty()) { + if (propList.contains(prop.label())) { + if (prop.value() instanceof String) { + json.addProperty(prop.key(), (String) prop.value()); + } else if (prop.value() instanceof Boolean) { + json.addProperty(prop.key(), (Boolean) prop.value()); + } else if (prop.value() instanceof Number) { + json.addProperty(prop.key(), (Number) prop.value()); + } else if (prop.value() instanceof List) { + json.addProperty(prop.key(), gson.toJson(prop.value())); + } else { + // throw exception? + return null; + } + } + } else { + return this.createPropertiesObject(v); + } + } + + return Optional.of(json); + } + + private Set<String> removeSingleQuotesForProperties(List<String> props){ + if (props != null && !props.isEmpty()) { + return props.stream().map( + e -> e.substring(1, e.length()-1)).collect(Collectors.toSet()); + } else { + return Collections.emptySet(); + } + + } + protected JsonArray createRelationshipObject(Vertex v) throws AAIFormatVertexException { JsonArray jarray = new JsonArray(); Iterator<Edge> inIter = v.edges(Direction.IN); @@ -122,7 +183,7 @@ public class RawFormat extends MultiFormatMapper { return json; } - public static class Builder implements NodesOnly<Builder>, Depth<Builder> { + public static class Builder implements NodesOnly<Builder>, Depth<Builder>, AsTree<Builder> { protected final Loader loader; protected final DBSerializer serializer; @@ -131,6 +192,7 @@ public class RawFormat extends MultiFormatMapper { protected boolean nodesOnly = false; protected int depth = 1; protected boolean modelDriven = false; + protected boolean tree = false; public Builder(Loader loader, DBSerializer serializer, UrlBuilder urlBuilder) { this.loader = loader; @@ -150,6 +212,13 @@ public class RawFormat extends MultiFormatMapper { return this.urlBuilder; } + protected boolean isTree() { return this.tree; } + + public Builder isTree(Boolean tree) { + this.tree = tree; + return this; + } + public Builder includeUrl() { this.includeUrl = true; return this; diff --git a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/Resource.java b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/Resource.java index b92f5858..a53be6a3 100644 --- a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/Resource.java +++ b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/Resource.java @@ -20,14 +20,17 @@ package org.onap.aai.serialization.queryformats; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import java.io.UnsupportedEncodingException; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; +import java.util.*; +import java.util.stream.Stream; +import org.apache.tinkerpop.gremlin.process.traversal.step.util.BulkSet; +import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree; import org.apache.tinkerpop.gremlin.structure.Vertex; import org.onap.aai.db.props.AAIProperties; import org.onap.aai.exceptions.AAIException; @@ -37,9 +40,12 @@ import org.onap.aai.introspection.exceptions.AAIUnknownObjectException; import org.onap.aai.serialization.db.DBSerializer; import org.onap.aai.serialization.queryformats.exceptions.AAIFormatVertexException; import org.onap.aai.serialization.queryformats.params.Depth; +import org.onap.aai.serialization.queryformats.params.AsTree; import org.onap.aai.serialization.queryformats.params.NodesOnly; import org.onap.aai.serialization.queryformats.utils.UrlBuilder; +import javax.ws.rs.core.MultivaluedMap; + public class Resource extends MultiFormatMapper { private final Loader loader; @@ -49,8 +55,9 @@ public class Resource extends MultiFormatMapper { private final boolean includeUrl; private final boolean nodesOnly; private final int depth; + private final boolean isSkipRelatedTo; - private Resource(Builder builder) { + public Resource(Builder builder) { this.parser = new JsonParser(); this.loader = builder.getLoader(); this.serializer = builder.getSerializer(); @@ -58,6 +65,54 @@ public class Resource extends MultiFormatMapper { this.includeUrl = builder.isIncludeUrl(); this.nodesOnly = builder.isNodesOnly(); this.depth = builder.getDepth(); + this.isSkipRelatedTo = builder.isSkipRelatedTo(); + this.isTree = builder.isTree(); + } + + @Override + protected Optional<JsonObject> getRelatedNodesFromTree(Tree<?> tree) throws AAIFormatVertexException { + if (tree.isEmpty()) { + return Optional.of(new JsonObject()); + } + JsonObject t = new JsonObject(); + JsonArray ja = this.getRelatedNodesArray(tree, "related-nodes"); + if (ja.size() > 0) { + t.add("results", ja); + return Optional.of(t); + } + + return Optional.empty(); + } + + protected JsonArray getRelatedNodesArray(Tree<?> tree, String nodeIdentifier) throws AAIFormatVertexException { + JsonArray nodes = new JsonArray(); + if (tree.isEmpty()) { + return nodes; + } + for (Map.Entry<?, ? extends Tree<?>> entry : tree.entrySet()) { + JsonObject me = new JsonObject(); + if (entry.getKey() instanceof Vertex) { + Optional<JsonObject> obj = null; + if (entry.getKey() != null) { + obj = this.getJsonFromVertex((Vertex) entry.getKey()); + } + if (obj != null && obj.isPresent()) { + me = obj.get(); + } else { + continue; + } + } + JsonArray ja = this.getRelatedNodesArray(entry.getValue(), nodeIdentifier); + if (ja.size() > 0) { + try { + me.entrySet().stream().findFirst().get().getValue().getAsJsonObject().add(nodeIdentifier, ja); + } catch(Exception e) { + throw new AAIFormatVertexException("Failed to add related-nodes array: " + e.getMessage(), e); + } + } + nodes.add(me); + } + return nodes; } @Override @@ -77,7 +132,15 @@ public class Resource extends MultiFormatMapper { return Optional.of(json); } + @Override + protected Optional<JsonObject> getJsonFromVertex(Vertex input, Map<String, List<String>> properties) throws AAIFormatVertexException { + return Optional.empty(); + } + protected Optional<JsonObject> vertexToJsonObject(Vertex v) throws AAIFormatVertexException { + if (v == null) { + return Optional.empty(); + } try { final Introspector obj = getLoader().introspectorFromName(v.<String>property(AAIProperties.NODE_TYPE).orElse(null)); @@ -87,7 +150,7 @@ public class Resource extends MultiFormatMapper { wrapper.add(v); try { - getSerializer().dbToObject(wrapper, obj, this.depth, this.nodesOnly, "false"); + getSerializer().dbToObject(wrapper, obj, this.depth, this.nodesOnly, "false", isSkipRelatedTo); } catch (AAIException | UnsupportedEncodingException e) { throw new AAIFormatVertexException( "Failed to format vertex - error while serializing: " + e.getMessage(), e); @@ -118,7 +181,7 @@ public class Resource extends MultiFormatMapper { return parser; } - public static class Builder implements NodesOnly<Builder>, Depth<Builder> { + public static class Builder implements NodesOnly<Builder>, Depth<Builder>, AsTree<Builder> { private final Loader loader; private final DBSerializer serializer; @@ -126,6 +189,8 @@ public class Resource extends MultiFormatMapper { private boolean includeUrl = false; private boolean nodesOnly = false; private int depth = 1; + private MultivaluedMap<String, String> params; + private boolean tree = false; public Builder(Loader loader, DBSerializer serializer, UrlBuilder urlBuilder) { this.loader = loader; @@ -133,6 +198,13 @@ public class Resource extends MultiFormatMapper { this.urlBuilder = urlBuilder; } + public Builder(Loader loader, DBSerializer serializer, UrlBuilder urlBuilder, MultivaluedMap<String, String> params) { + this.loader = loader; + this.serializer = serializer; + this.urlBuilder = urlBuilder; + this.params = params; + } + protected Loader getLoader() { return this.loader; } @@ -145,6 +217,31 @@ public class Resource extends MultiFormatMapper { return this.urlBuilder; } + protected MultivaluedMap<String, String> getParams() { return this.params; } + + public boolean isSkipRelatedTo() { + if (params != null) { + boolean isSkipRelatedTo = true; + if (params.containsKey("skip-related-to")) { + String skipRelatedTo = params.getFirst("skip-related-to"); + isSkipRelatedTo = !(skipRelatedTo != null && skipRelatedTo.equals("false")); + } else { + // if skip-related-to param is missing, then default it to false; + isSkipRelatedTo = false; + } + return isSkipRelatedTo; + } + return true; + } + + protected boolean isTree() { return this.tree; } + + public Builder isTree(Boolean tree) { + this.tree = tree; + return this; + } + + public Builder includeUrl() { this.includeUrl = true; return this; diff --git a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/ResourceWithSoT.java b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/ResourceWithSoT.java index e4107aa9..d70f5c8e 100644 --- a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/ResourceWithSoT.java +++ b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/ResourceWithSoT.java @@ -23,6 +23,8 @@ package org.onap.aai.serialization.queryformats; import com.google.gson.JsonObject; import com.google.gson.JsonParser; +import java.util.List; +import java.util.Map; import java.util.Optional; import org.apache.tinkerpop.gremlin.structure.Vertex; @@ -30,11 +32,14 @@ import org.onap.aai.db.props.AAIProperties; import org.onap.aai.introspection.Loader; import org.onap.aai.serialization.db.DBSerializer; import org.onap.aai.serialization.queryformats.exceptions.AAIFormatVertexException; +import org.onap.aai.serialization.queryformats.params.AsTree; import org.onap.aai.serialization.queryformats.params.Depth; import org.onap.aai.serialization.queryformats.params.NodesOnly; import org.onap.aai.serialization.queryformats.utils.UrlBuilder; import org.onap.aai.util.AAIConfig; +import java.util.Optional; + public class ResourceWithSoT extends MultiFormatMapper { protected JsonParser parser = new JsonParser(); protected final DBSerializer serializer; @@ -49,6 +54,7 @@ public class ResourceWithSoT extends MultiFormatMapper { this.serializer = builder.getSerializer(); this.depth = builder.getDepth(); this.nodesOnly = builder.isNodesOnly(); + this.isTree = builder.isTree(); } @Override @@ -56,7 +62,7 @@ public class ResourceWithSoT extends MultiFormatMapper { return 100; } - public static class Builder implements NodesOnly<Builder>, Depth<Builder> { + public static class Builder implements NodesOnly<Builder>, Depth<Builder>, AsTree<Builder> { protected final Loader loader; protected final DBSerializer serializer; @@ -65,6 +71,7 @@ public class ResourceWithSoT extends MultiFormatMapper { protected boolean nodesOnly = false; protected int depth = 1; protected boolean modelDriven = false; + protected boolean tree = false; public Builder(Loader loader, DBSerializer serializer, UrlBuilder urlBuilder) { this.loader = loader; @@ -89,6 +96,13 @@ public class ResourceWithSoT extends MultiFormatMapper { return this; } + protected boolean isTree() { return this.tree; } + + public Builder isTree(Boolean tree) { + this.tree = tree; + return this; + } + public Builder nodesOnly(Boolean nodesOnly) { this.nodesOnly = nodesOnly; return this; @@ -139,8 +153,9 @@ public class ResourceWithSoT extends MultiFormatMapper { @Override protected Optional<JsonObject> getJsonFromVertex(Vertex v) throws AAIFormatVertexException { // Null check - if (v == null) + if (v == null) { return null; + } JsonObject json = new JsonObject(); @@ -148,9 +163,9 @@ public class ResourceWithSoT extends MultiFormatMapper { Object lastModifiedTimestampObj = v.property(AAIProperties.LAST_MOD_TS).value(); Object sotObj = v.property(AAIProperties.SOURCE_OF_TRUTH).value(); Object lastModSotObj = v.property(AAIProperties.LAST_MOD_SOURCE_OF_TRUTH).value(); - long createdTimestamp = Long.valueOf(createdTimestampObj.toString()); - long lastModifiedTimestamp = Long.valueOf(lastModifiedTimestampObj.toString()); - long threshold = Long.valueOf(AAIConfig.get("aai.resource.format.threshold", "10")); + long createdTimestamp = Long.parseLong(createdTimestampObj.toString()); + long lastModifiedTimestamp = Long.parseLong(lastModifiedTimestampObj.toString()); + long threshold = Long.parseLong(AAIConfig.get("aai.resource.format.threshold", "10")); // Add to the property field of the JSON payload json.addProperty("aai-created-ts", createdTimestampObj.toString()); @@ -172,4 +187,9 @@ public class ResourceWithSoT extends MultiFormatMapper { return Optional.of(json); } + + @Override + protected Optional<JsonObject> getJsonFromVertex(Vertex input, Map<String, List<String>> properties) throws AAIFormatVertexException { + return Optional.empty(); + } } diff --git a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/StateFormat.java b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/StateFormat.java new file mode 100644 index 00000000..b2813476 --- /dev/null +++ b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/StateFormat.java @@ -0,0 +1,144 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 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========================================================= + */ + +package org.onap.aai.serialization.queryformats; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import org.apache.tinkerpop.gremlin.structure.Edge; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.apache.tinkerpop.gremlin.structure.VertexProperty; +import org.onap.aai.db.props.AAIProperties; +import org.onap.aai.serialization.queryformats.exceptions.AAIFormatVertexException; + +import java.util.*; + +public class StateFormat extends HistoryFormat { + + private static final Logger LOGGER = LoggerFactory.getLogger(StateFormat.class); + + protected StateFormat(HistoryFormat.Builder builder) { + super(builder); + } + + protected JsonArray createPropertiesObject(Vertex v) { + Iterator<VertexProperty<Object>> iter = v.properties(); + List<JsonObject> jsonList = new ArrayList<>(); + while (iter.hasNext()) { + VertexProperty<Object> prop = iter.next(); + if (prop.key() != null && ignoredKeys.contains(prop.key())) { + continue; + } + + JsonObject metaProperties = createMetaPropertiesObject(prop); + if (isTsInRange(metaProperties)) { + JsonObject json = new JsonObject(); + json.addProperty(KEY, prop.key()); + json = mapPropertyValues(json, VALUE, prop.value()); + addMetaProperties(json, metaProperties); + jsonList.add(json); + } + } + + JsonArray jsonArray = new JsonArray(); + jsonList.stream().sorted(Comparator.comparingLong(o -> o.get(TIMESTAMP).getAsLong())).forEach(jsonArray::add); + return jsonArray; + } + + private boolean isTsInRange(JsonObject metaProperties) { + long sTs = metaProperties.get(AAIProperties.START_TS).getAsLong(); + long eTs = Long.MAX_VALUE; + if (metaProperties.has(AAIProperties.END_TS)) { + eTs = metaProperties.get(AAIProperties.END_TS).getAsLong(); + } + + return startTs >= sTs && eTs > startTs; + } + + @Override + protected boolean isValidEdge(Edge e) { + if (e.property(AAIProperties.END_TS).isPresent()) { + long edgeEndTs = e.value(AAIProperties.END_TS); + if (startTs >= edgeEndTs) { + return false; + } + } + if (e.property(AAIProperties.START_TS).isPresent()) { + long edgeStartTs = e.value(AAIProperties.START_TS); + return startTs >= edgeStartTs; + } + return true; + } + + @Override + protected JsonObject getRelatedObject(Edge e, Vertex related) throws AAIFormatVertexException { + + JsonObject json = new JsonObject(); + json.addProperty("relationship-label", e.label()); + json.addProperty(NODE_TYPE, related.<String>value(AAIProperties.NODE_TYPE)); + json.addProperty("url", this.urlBuilder.pathed(related)); + if (related.property(AAIProperties.AAI_URI).isPresent()) { + json.addProperty("uri", related.<String>value(AAIProperties.AAI_URI)); + } else { + LOGGER.warn("Vertex {} is missing aai-uri", related.id()); + json.addProperty("uri", "NA"); + } + json.addProperty(TIMESTAMP, e.property(AAIProperties.START_TS).isPresent()? e.value(AAIProperties.START_TS) : 0); + json.addProperty(SOT, e.property(AAIProperties.SOURCE_OF_TRUTH).isPresent()? e.value(AAIProperties.SOURCE_OF_TRUTH) : ""); + json.addProperty(TX_ID, e.property(AAIProperties.START_TX_ID).isPresent()? e.value(AAIProperties.START_TX_ID) : "N/A"); + + return json; + } + + + protected void addMetaProperties(JsonObject json, JsonObject metaProperties) { + json.addProperty(TIMESTAMP, metaProperties.get(AAIProperties.START_TS) != null ? metaProperties.get(AAIProperties.START_TS).getAsLong() : 0); + json.addProperty(SOT, metaProperties.get(AAIProperties.SOURCE_OF_TRUTH) != null ? metaProperties.get(AAIProperties.SOURCE_OF_TRUTH).getAsString() : ""); + json.addProperty(TX_ID, metaProperties.get(AAIProperties.START_TX_ID) != null ? metaProperties.get(AAIProperties.START_TX_ID).getAsString() : "N/A"); + } + + @Override + protected Optional<JsonObject> getJsonFromVertex(Vertex v) throws AAIFormatVertexException { + + JsonObject json = new JsonObject(); + json.addProperty(NODE_TYPE, v.<String>value(AAIProperties.NODE_TYPE)); + json.addProperty("url", this.urlBuilder.pathed(v)); + json.addProperty("uri", v.property(AAIProperties.AAI_URI).value().toString()); + JsonArray properties = this.createPropertiesObject(v); + + if (properties.size() > 0) { + json.add(PROPERTIES, properties); + } else { + return Optional.empty(); + } + if (!nodesOnly) { + json.add(RELATED_TO, this.createRelationshipObject(v)); + } + return Optional.of(json); + } + + @Override + protected Optional<JsonObject> getJsonFromVertex(Vertex input, Map<String, List<String>> properties) throws AAIFormatVertexException { + return Optional.empty(); + } + +} diff --git a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/params/AsTree.java b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/params/AsTree.java new file mode 100644 index 00000000..c7479147 --- /dev/null +++ b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/params/AsTree.java @@ -0,0 +1,28 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 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========================================================= + */ + +package org.onap.aai.serialization.queryformats.params; + +@Inject(name = "as-tree") +public interface AsTree<T> { + + @Setter + public T isTree(Boolean tree); +} diff --git a/aai-schema-ingest/src/test/java/org/onap/aai/restclient/RestClientTest.java b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/params/EndTs.java index 36b8fb3e..937d87f2 100644 --- a/aai-schema-ingest/src/test/java/org/onap/aai/restclient/RestClientTest.java +++ b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/params/EndTs.java @@ -18,8 +18,11 @@ * ============LICENSE_END========================================================= */ -package org.onap.aai.restclient; +package org.onap.aai.serialization.queryformats.params; -public class RestClientTest { +@Inject(name = "endTs") +public interface EndTs<T> { + @Setter + public T endTs(String endTs); } diff --git a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/params/StartTs.java b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/params/StartTs.java new file mode 100644 index 00000000..e94b893d --- /dev/null +++ b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/params/StartTs.java @@ -0,0 +1,28 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 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========================================================= + */ + +package org.onap.aai.serialization.queryformats.params; + +@Inject(name = "startTs") +public interface StartTs<T> { + + @Setter + public T startTs(String startTs); +} diff --git a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/utils/QueryParamInjector.java b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/utils/QueryParamInjector.java index 1b51088e..f90907e2 100644 --- a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/utils/QueryParamInjector.java +++ b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/utils/QueryParamInjector.java @@ -20,25 +20,23 @@ package org.onap.aai.serialization.queryformats.utils; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.Set; +import org.onap.aai.serialization.queryformats.exceptions.QueryParamInjectionException; +import org.onap.aai.serialization.queryformats.params.*; import javax.ws.rs.core.MultivaluedMap; - -import org.onap.aai.serialization.queryformats.exceptions.QueryParamInjectionException; -import org.onap.aai.serialization.queryformats.params.Inject; -import org.onap.aai.serialization.queryformats.params.Setter; -import org.reflections.Reflections; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; public class QueryParamInjector { - private final Set<Class<?>> results; - - private QueryParamInjector() { - Reflections reflections = new Reflections("org.onap.aai.serialization.queryformats.params"); - results = reflections.getTypesAnnotatedWith(Inject.class); - } + //TODO reimplement this using reflections. + private static final Class<?>[] PARAM_CLASSES = new Class[] { + AsTree.class, + Depth.class, + EndTs.class, + NodesOnly.class, + StartTs.class + }; private static class Helper { private static final QueryParamInjector INSTANCE = new QueryParamInjector(); @@ -50,7 +48,7 @@ public class QueryParamInjector { public <T> T injectParams(T obj, MultivaluedMap<String, String> params) throws QueryParamInjectionException { try { - for (Class<?> item : results) { + for (Class<?> item : PARAM_CLASSES) { if (item.isAssignableFrom(obj.getClass())) { String name = item.getAnnotation(Inject.class).name(); diff --git a/aai-core/src/main/java/org/onap/aai/service/NodeValidationService.java b/aai-core/src/main/java/org/onap/aai/service/NodeValidationService.java index 316e3017..6c57616e 100644 --- a/aai-core/src/main/java/org/onap/aai/service/NodeValidationService.java +++ b/aai-core/src/main/java/org/onap/aai/service/NodeValidationService.java @@ -20,8 +20,8 @@ package org.onap.aai.service; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.annotation.PostConstruct; @@ -37,7 +37,7 @@ import org.springframework.stereotype.Service; @PropertySource(value = "file:${schema.ingest.file}", ignoreResourceNotFound = true) public class NodeValidationService { - private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(NodeValidationService.class); + private static final Logger LOGGER = LoggerFactory.getLogger(NodeValidationService.class); @Autowired(required = false) private NodeValidator nodeValidator; diff --git a/aai-core/src/main/java/org/onap/aai/tasks/ScheduledTasks.java b/aai-core/src/main/java/org/onap/aai/tasks/ScheduledTasks.java index 911603d2..16c41166 100644 --- a/aai-core/src/main/java/org/onap/aai/tasks/ScheduledTasks.java +++ b/aai-core/src/main/java/org/onap/aai/tasks/ScheduledTasks.java @@ -20,32 +20,30 @@ package org.onap.aai.tasks; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; - -import java.io.File; -import java.util.Arrays; -import java.util.Date; -import java.util.UUID; - import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.comparator.LastModifiedFileComparator; -import org.onap.aai.logging.LoggingContext; -import org.onap.aai.logging.LoggingContext.StatusCode; +import org.onap.aai.aailog.logs.AaiScheduledTaskAuditLog; import org.onap.aai.util.AAIConfig; import org.onap.aai.util.AAIConstants; +import org.onap.logging.filter.base.ONAPComponents; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; +import java.io.File; +import java.util.Arrays; +import java.util.Date; + @Component public class ScheduledTasks { - private static EELFLogger LOGGER = EELFManager.getInstance().getLogger(ScheduledTasks.class); + @Autowired + private AaiScheduledTaskAuditLog auditLog; - private static final String COMPONENT = "Scheduler"; - private static final String FROM_APP_ID = "CronApp"; + private static Logger LOGGER = LoggerFactory.getLogger(ScheduledTasks.class); private static final long PROPERTY_READ_INTERVAL = 60000; // every minute - private String GlobalPropFileName = AAIConstants.AAI_CONFIG_FILENAME; // for read and possibly reloading aaiconfig.properties and other @@ -55,19 +53,7 @@ public class ScheduledTasks { // configuration properties files @Scheduled(fixedRate = PROPERTY_READ_INTERVAL) public void loadAAIProperties() { - final UUID transId = UUID.randomUUID(); - - // LoggingContext.init(); - LoggingContext.save(); - LoggingContext.requestId(transId); - LoggingContext.partnerName(FROM_APP_ID); - LoggingContext.component(COMPONENT); - LoggingContext.targetEntity("AAI"); - LoggingContext.targetServiceName("loadAAIProperties"); - LoggingContext.serviceName("AAI"); - LoggingContext.statusCode(StatusCode.COMPLETE); - LoggingContext.responseCode(LoggingContext.SUCCESS); - + auditLog.logBefore("LoadAaiPropertiesTask", ONAPComponents.AAI.toString() ); String dir = FilenameUtils.getFullPathNoEndSeparator(GlobalPropFileName); if (dir == null || dir.length() < 3) { dir = "/opt/aai/etc"; @@ -94,6 +80,6 @@ public class ScheduledTasks { break; } } - LoggingContext.restoreIfPossible(); + auditLog.logAfter(); } } diff --git a/aai-core/src/main/java/org/onap/aai/transforms/XmlFormatTransformer.java b/aai-core/src/main/java/org/onap/aai/transforms/XmlFormatTransformer.java new file mode 100644 index 00000000..ce7ead4f --- /dev/null +++ b/aai-core/src/main/java/org/onap/aai/transforms/XmlFormatTransformer.java @@ -0,0 +1,70 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 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========================================================= + */ +package org.onap.aai.transforms; + +import com.bazaarvoice.jolt.Chainr; +import com.bazaarvoice.jolt.JsonUtils; +import org.json.JSONObject; +import org.json.XML; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; + +public class XmlFormatTransformer { + + private static final Logger LOGGER = LoggerFactory.getLogger(XmlFormatTransformer.class); + + private static final String RESULT_WITH_QUOTES = "\"result\""; + private static final String RESULTS_STRING = "results"; + + private Chainr chainr; + + public XmlFormatTransformer() { + List<Object> spec = JsonUtils.classpathToList("/specs/transform-related-to-node.json"); + this.chainr = Chainr.fromSpec(spec); + } + + public String transform(String input) { + + Object transformedOutput; + + if(!input.contains(RESULT_WITH_QUOTES)){ + Object inputMap = JsonUtils.jsonToMap(input); + transformedOutput = chainr.transform(inputMap); + + JSONObject jsonObject; + if(transformedOutput == null){ + LOGGER.debug("For the input {}, unable to transform it so returning null", input); + jsonObject = new JSONObject(); + } else { + jsonObject = new JSONObject(JsonUtils.toJsonString(transformedOutput)); + } + + return XML.toString(jsonObject, RESULTS_STRING); + } else { + // If the json is already conforming to the following format + // {"results":[{"results":"v[2]"}]} + // Then no transformation is required + return XML.toString(new JSONObject(input)); + } + + } +} diff --git a/aai-core/src/main/java/org/onap/aai/util/HttpsAuthClient.java b/aai-core/src/main/java/org/onap/aai/util/HttpsAuthClient.java index 133c26a7..c2bfabf4 100644 --- a/aai-core/src/main/java/org/onap/aai/util/HttpsAuthClient.java +++ b/aai-core/src/main/java/org/onap/aai/util/HttpsAuthClient.java @@ -27,10 +27,13 @@ import com.sun.jersey.api.client.config.DefaultClientConfig; import com.sun.jersey.api.client.filter.LoggingFilter; import com.sun.jersey.api.json.JSONConfiguration; import com.sun.jersey.client.urlconnection.HTTPSProperties; +import org.onap.aai.aailog.filter.RestControllerClientLoggingInterceptor; +import org.onap.aai.exceptions.AAIException; import java.io.FileInputStream; -import java.security.KeyManagementException; -import java.security.KeyStore; +import java.io.IOException; +import java.security.*; +import java.security.cert.CertificateException; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; @@ -63,29 +66,25 @@ public class HttpsAuthClient { e.printStackTrace(); } } - /** * Gets the client. * + * @param truststorePath the truststore path + * @param truststorePassword the truststore password + * @param keystorePath the keystore path + * @param keystorePassword the keystore password * @return the client * @throws KeyManagementException the key management exception */ - public static Client getClient() throws KeyManagementException { + public static Client getClient(String truststorePath, String truststorePassword, String keystorePath, String keystorePassword) throws KeyManagementException, UnrecoverableKeyException, CertificateException, NoSuchAlgorithmException, KeyStoreException, IOException { ClientConfig config = new DefaultClientConfig(); config.getFeatures().put(JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE); config.getClasses().add(org.onap.aai.restcore.CustomJacksonJaxBJsonProvider.class); - SSLContext ctx = null; try { - String truststore_path = - AAIConstants.AAI_HOME_ETC_AUTH + AAIConfig.get(AAIConstants.AAI_TRUSTSTORE_FILENAME); - String truststore_password = AAIConfig.get(AAIConstants.AAI_TRUSTSTORE_PASSWD); - String keystore_path = AAIConstants.AAI_HOME_ETC_AUTH + AAIConfig.get(AAIConstants.AAI_KEYSTORE_FILENAME); - String keystore_password = AAIConfig.get(AAIConstants.AAI_KEYSTORE_PASSWD); - - System.setProperty("javax.net.ssl.trustStore", truststore_path); - System.setProperty("javax.net.ssl.trustStorePassword", truststore_password); + System.setProperty("javax.net.ssl.trustStore", truststorePath); + System.setProperty("javax.net.ssl.trustStorePassword", truststorePassword); HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() { public boolean verify(String string, SSLSession ssls) { return true; @@ -96,36 +95,62 @@ public class HttpsAuthClient { KeyManagerFactory kmf = null; try { kmf = KeyManagerFactory.getInstance("SunX509"); - FileInputStream fin = new FileInputStream(keystore_path); + FileInputStream fin = new FileInputStream(keystorePath); KeyStore ks = KeyStore.getInstance("PKCS12"); - char[] pwd = keystore_password.toCharArray(); + char[] pwd = keystorePassword.toCharArray(); ks.load(fin, pwd); kmf.init(ks, pwd); } catch (Exception e) { System.out.println("Error setting up kmf: exiting"); e.printStackTrace(); - System.exit(1); + throw e; + //System.exit(1); } 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 true; - } - }, ctx)); + new HTTPSProperties(new HostnameVerifier() { + @Override + public boolean verify(String s, SSLSession sslSession) { + return true; + } + }, ctx)); } catch (Exception e) { System.out.println("Error setting up config: exiting"); e.printStackTrace(); - System.exit(1); + throw e; + //System.exit(1); } Client client = Client.create(config); + client.addFilter(new RestControllerClientLoggingInterceptor()); // uncomment this line to get more logging for the request/response // client.addFilter(new LoggingFilter(System.out)); return client; } + /** + * Gets the client. + * + * @return the client + * @throws KeyManagementException the key management exception + */ + public static Client getClient() throws KeyManagementException, AAIException, UnrecoverableKeyException, CertificateException, NoSuchAlgorithmException, KeyStoreException, IOException { + String truststore_path = null; + String truststore_password = null; + String keystore_path = null; + String keystore_password = null; + try { + truststore_path = + AAIConstants.AAI_HOME_ETC_AUTH + AAIConfig.get(AAIConstants.AAI_TRUSTSTORE_FILENAME); + truststore_password = AAIConfig.get(AAIConstants.AAI_TRUSTSTORE_PASSWD); + keystore_path = AAIConstants.AAI_HOME_ETC_AUTH + AAIConfig.get(AAIConstants.AAI_KEYSTORE_FILENAME); + keystore_password = AAIConfig.get(AAIConstants.AAI_KEYSTORE_PASSWD); + } + catch (AAIException e) { + throw e; + } + return(getClient(truststore_path, truststore_password, keystore_path, keystore_password)); + } } diff --git a/aai-core/src/main/java/org/onap/aai/util/PojoUtils.java b/aai-core/src/main/java/org/onap/aai/util/PojoUtils.java index 218f0dd8..05cbf97c 100644 --- a/aai-core/src/main/java/org/onap/aai/util/PojoUtils.java +++ b/aai-core/src/main/java/org/onap/aai/util/PojoUtils.java @@ -129,11 +129,7 @@ public class PojoUtils { mapper.registerModule(new JaxbAnnotationModule()); - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - - mapper.writeValue(baos, clazz); - - return baos.toString(); + return mapper.writeValueAsString(clazz); } /** diff --git a/aai-core/src/main/java/org/onap/aai/util/RestController.java b/aai-core/src/main/java/org/onap/aai/util/RestController.java index a1419d14..8527ffe5 100644 --- a/aai-core/src/main/java/org/onap/aai/util/RestController.java +++ b/aai-core/src/main/java/org/onap/aai/util/RestController.java @@ -20,26 +20,30 @@ package org.onap.aai.util; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.type.TypeFactory; import com.sun.jersey.api.client.Client; import com.sun.jersey.api.client.ClientHandlerException; import com.sun.jersey.api.client.ClientResponse; +import java.io.IOException; import java.security.KeyManagementException; +import java.security.KeyStoreException; +import java.security.UnrecoverableKeyException; +import java.security.cert.CertificateException; +import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.List; import java.util.UUID; import org.onap.aai.exceptions.AAIException; -import org.onap.aai.logging.LoggingContext; public class RestController implements RestControllerInterface { private static final String TARGET_NAME = "AAI"; - private static EELFLogger LOGGER = EELFManager.getInstance().getLogger(RestController.class); + private static Logger LOGGER = LoggerFactory.getLogger(RestController.class); private static Client client = null; @@ -85,6 +89,9 @@ public class RestController implements RestControllerInterface { this.initRestClient(); } + public RestController(String truststorePath, String truststorePassword, String keystorePath, String keystorePassword) throws AAIException { + this.initRestClient(truststorePath, truststorePassword, keystorePath, keystorePassword); + } /** * Inits the rest client. * @@ -101,11 +108,29 @@ public class RestController implements RestControllerInterface { } } } + /** + * Inits the rest client. + * + * @throws AAIException the AAI exception + */ + public void initRestClient(String truststorePath, String truststorePassword, String keystorePath, String keystorePassword) throws AAIException { + if (client == null) { + try { + client = getHttpsAuthClient(truststorePath, truststorePassword, keystorePath, keystorePassword); + } catch (KeyManagementException e) { + throw new AAIException("AAI_7117", "KeyManagementException in REST call to DB: " + e.toString()); + } catch (Exception e) { + throw new AAIException("AAI_7117", " Exception in REST call to DB: " + e.toString()); + } + } + } + public Client getHttpsAuthClient(String truststorePath, String truststorePassword, String keystorePath, String keystorePassword) throws KeyManagementException, UnrecoverableKeyException, CertificateException, NoSuchAlgorithmException, KeyStoreException, IOException { + return HttpsAuthClient.getClient(truststorePath, truststorePassword, keystorePath, keystorePassword); + } - public Client getHttpsAuthClient() throws KeyManagementException { + public Client getHttpsAuthClient() throws KeyManagementException, UnrecoverableKeyException, CertificateException, NoSuchAlgorithmException, KeyStoreException, IOException, AAIException { return HttpsAuthClient.getClient(); } - /** * Sets the rest srvr base URL. * @@ -151,13 +176,6 @@ public class RestController implements RestControllerInterface { String url = ""; transId += ":" + UUID.randomUUID().toString(); - LoggingContext.save(); - LoggingContext.partnerName(sourceID); - LoggingContext.targetEntity(TARGET_NAME); - LoggingContext.requestId(transId); - LoggingContext.serviceName(methodName); - LoggingContext.targetServiceName(methodName); - LOGGER.debug(methodName + " start"); restObject.set(t); @@ -177,7 +195,6 @@ public class RestController implements RestControllerInterface { AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP)) + path; } } - initRestClient(); LOGGER.debug(url + " for the get REST API"); ClientResponse cres = client.resource(url).accept("application/json").header("X-TransactionId", transId) .header("X-FromAppId", sourceID).header("Real-Time", "true").type("application/json") @@ -192,12 +209,9 @@ public class RestController implements RestControllerInterface { restObject.set(t); LOGGER.debug(methodName + "REST api GET was successfull!"); } else { - LoggingContext.restore(); // System.out.println(methodName + ": url=" + url + " failed with status=" + cres.getStatus()); throw new AAIException("AAI_7116", methodName + " with status=" + cres.getStatus() + ", url=" + url); } - - LoggingContext.restore(); } /** @@ -219,20 +233,12 @@ public class RestController implements RestControllerInterface { String url = ""; transId += ":" + UUID.randomUUID().toString(); - LoggingContext.save(); - LoggingContext.partnerName(sourceID); - LoggingContext.targetEntity(TARGET_NAME); - LoggingContext.requestId(transId); - LoggingContext.serviceName(methodName); - LoggingContext.targetServiceName(methodName); - LOGGER.debug(methodName + " start"); restObject.set(t); url = AAIConfig.get(AAIConstants.AAI_SERVER_URL_BASE) + apiVersion + "/" + path; - initRestClient(); LOGGER.debug(url + " for the get REST API"); ClientResponse cres = client.resource(url).accept("application/json").header("X-TransactionId", transId) .header("X-FromAppId", sourceID).header("Real-Time", "true").type("application/json") @@ -247,12 +253,9 @@ public class RestController implements RestControllerInterface { restObject.set(t); LOGGER.debug(methodName + "REST api GET was successfull!"); } else { - LoggingContext.restore(); // System.out.println(methodName + ": url=" + url + " failed with status=" + cres.getStatus()); throw new AAIException("AAI_7116", methodName + " with status=" + cres.getStatus() + ", url=" + url); } - - LoggingContext.restore(); } /** @@ -320,17 +323,8 @@ public class RestController implements RestControllerInterface { String url = ""; transId += ":" + UUID.randomUUID().toString(); - LoggingContext.save(); - LoggingContext.partnerName(sourceID); - LoggingContext.targetEntity(TARGET_NAME); - LoggingContext.requestId(transId); - LoggingContext.serviceName(methodName); - LoggingContext.targetServiceName(methodName); - LOGGER.debug(methodName + " start"); - initRestClient(); - if (oldserver) { url = AAIConfig.get(AAIConstants.AAI_OLDSERVER_URL) + path; } else { @@ -356,9 +350,7 @@ public class RestController implements RestControllerInterface { int statuscode = cres.getStatus(); if (statuscode >= 200 && statuscode <= 299) { LOGGER.debug(methodName + ": url=" + url + ", request=" + path); - LoggingContext.restore(); } else { - LoggingContext.restore(); throw new AAIException("AAI_7116", methodName + " with status=" + statuscode + ", url=" + url + ", msg=" + cres.getEntity(String.class)); } @@ -381,16 +373,8 @@ public class RestController implements RestControllerInterface { String url = ""; transId += ":" + UUID.randomUUID().toString(); - LoggingContext.save(); - LoggingContext.partnerName(sourceID); - LoggingContext.targetEntity(TARGET_NAME); - LoggingContext.requestId(transId); - LoggingContext.serviceName(methodName); - LoggingContext.targetServiceName(methodName); - LOGGER.debug(methodName + " start"); - initRestClient(); String request = "{}"; if (overrideLocalHost == null) { overrideLocalHost = AAIConfig.get(AAIConstants.AAI_LOCAL_OVERRIDE, AAIConstants.AAI_LOCAL_OVERRIDE_DEFAULT); @@ -408,13 +392,10 @@ public class RestController implements RestControllerInterface { if (cres.getStatus() == 404) { // resource not found LOGGER.info("Resource does not exist...: " + cres.getStatus() + ":" + cres.getEntity(String.class)); - LoggingContext.restore(); } else if (cres.getStatus() == 200 || cres.getStatus() == 204) { LOGGER.info("Resource " + url + " deleted"); - LoggingContext.restore(); } else { LOGGER.error("Deleting Resource failed: " + cres.getStatus() + ":" + cres.getEntity(String.class)); - LoggingContext.restore(); throw new AAIException("AAI_7116", "Error during DELETE"); } } @@ -440,18 +421,10 @@ public class RestController implements RestControllerInterface { String url = ""; transId += ":" + UUID.randomUUID().toString(); - LoggingContext.save(); - LoggingContext.partnerName(sourceID); - LoggingContext.targetEntity(TARGET_NAME); - LoggingContext.requestId(transId); - LoggingContext.serviceName(methodName); - LoggingContext.targetServiceName(methodName); - LOGGER.debug(methodName + " start"); try { - initRestClient(); url = AAIConfig.get(AAIConstants.AAI_SERVER_URL_BASE) + apiVersion + "/" + path; ClientResponse cres = client.resource(url).accept("application/json").header("X-TransactionId", transId) @@ -473,7 +446,6 @@ public class RestController implements RestControllerInterface { throw new AAIException("AAI_7116", methodName + " with url=" + url + ", Exception: " + e.toString()); } finally { - LoggingContext.restore(); } } @@ -558,13 +530,6 @@ public class RestController implements RestControllerInterface { String url = ""; transId += ":" + UUID.randomUUID().toString(); - LoggingContext.save(); - LoggingContext.partnerName(sourceID); - LoggingContext.targetEntity(TARGET_NAME); - LoggingContext.requestId(transId); - LoggingContext.serviceName(methodName); - LoggingContext.targetServiceName(methodName); - int numRetries = 5; ClientResponse cres = null; int statusCode = -1; @@ -582,7 +547,6 @@ public class RestController implements RestControllerInterface { AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP)) + path; } - initRestClient(); do { cres = client.resource(url).accept("application/json").header("X-TransactionId", transId) @@ -613,7 +577,6 @@ public class RestController implements RestControllerInterface { throw new AAIException("AAI_7116", methodName + " with url=" + url + ", Exception: " + e.toString()); } finally { - LoggingContext.restore(); } } diff --git a/aai-core/src/main/java/org/onap/aai/util/StoreNotificationEvent.java b/aai-core/src/main/java/org/onap/aai/util/StoreNotificationEvent.java index 8b2bf50a..01d21ca7 100644 --- a/aai-core/src/main/java/org/onap/aai/util/StoreNotificationEvent.java +++ b/aai-core/src/main/java/org/onap/aai/util/StoreNotificationEvent.java @@ -20,8 +20,8 @@ package org.onap.aai.util; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.StringWriter; import java.util.Iterator; @@ -45,7 +45,7 @@ import org.springframework.core.env.Environment; public class StoreNotificationEvent { - private static final EELFLogger logger = EELFManager.getInstance().getLogger(StoreNotificationEvent.class); + private static final Logger LOGGER = LoggerFactory.getLogger(StoreNotificationEvent.class); private MessageProducer messageProducer; private String fromAppId = ""; @@ -81,7 +81,7 @@ public class StoreNotificationEvent { * @throws AAIException * the AAI exception */ - public String storeEvent(NotificationEvent.EventHeader eh, Object obj) throws AAIException { + public String storeEventAndSendToJms(NotificationEvent.EventHeader eh, Object obj) throws AAIException { if (obj == null) { throw new AAIException("AAI_7350"); @@ -235,7 +235,94 @@ public class StoreNotificationEvent { } } - public String storeEvent(Loader loader, Introspector eventHeader, Introspector obj) throws AAIException { + public String storeEventOnly(Loader loader, Introspector eventHeader, Introspector obj) throws AAIException { + if (obj == null) { + throw new AAIException("AAI_7350"); + } + + try { + final Introspector notificationEvent = loader.introspectorFromName("notification-event"); + + if (eventHeader.getValue("id") == null) { + eventHeader.setValue("id", genDate2() + "-" + UUID.randomUUID().toString()); + } + + if (eventHeader.getValue("timestamp") == null) { + eventHeader.setValue("timestamp", genDate()); + } + + if (eventHeader.getValue("entity-link") == null) { + eventHeader.setValue("entity-link", "UNK"); + } + + if (eventHeader.getValue("action") == null) { + eventHeader.setValue("action", "UNK"); + } + + if (eventHeader.getValue("event-type") == null) { + eventHeader.setValue("event-type", AAIConfig.get("aai.notificationEvent.default.eventType", "UNK")); + } + + if (eventHeader.getValue("domain") == null) { + eventHeader.setValue("domain", AAIConfig.get("aai.notificationEvent.default.domain", "UNK")); + } + + if (eventHeader.getValue("source-name") == null) { + eventHeader.setValue("source-name", AAIConfig.get("aai.notificationEvent.default.sourceName", "UNK")); + } + + if (eventHeader.getValue("sequence-number") == null) { + eventHeader.setValue("sequence-number", + AAIConfig.get("aai.notificationEvent.default.sequenceNumber", "UNK")); + } + + if (eventHeader.getValue("severity") == null) { + eventHeader.setValue("severity", AAIConfig.get("aai.notificationEvent.default.severity", "UNK")); + } + + if (eventHeader.getValue("version") == null) { + eventHeader.setValue("version", AAIConfig.get("aai.notificationEvent.default.version", "UNK")); + } + + if (notificationEvent.getValue("cambria-partition") == null) { + notificationEvent.setValue("cambria-partition", + AAIConfig.get("aai.notificationEvent.default.partition", AAIConstants.UEB_PUB_PARTITION_AAI)); + } + + notificationEvent.setValue("event-header", eventHeader.getUnderlyingObject()); + notificationEvent.setValue("entity", obj.getUnderlyingObject()); + + String entityJson = notificationEvent.marshal(false); + JSONObject entityJsonObject = new JSONObject(entityJson); + + JSONObject entityJsonObjectUpdated = new JSONObject(); + + JSONObject entityHeader = entityJsonObject.getJSONObject("event-header"); + String cambriaPartition = entityJsonObject.getString("cambria.partition"); + + entityJsonObject.remove("event-header"); + entityJsonObject.remove("cambria.partition"); + + entityJsonObjectUpdated.put("event-header", entityHeader); + entityJsonObjectUpdated.put("cambria.partition", cambriaPartition); + + Iterator<String> iter = entityJsonObject.keys(); + JSONObject entity = new JSONObject(); + if (iter.hasNext()) { + entity = entityJsonObject.getJSONObject(iter.next()); + } + + entityJsonObjectUpdated.put("entity", entity); + + return entityJsonObjectUpdated.toString(); + } catch (JSONException e) { + throw new AAIException("AAI_7350", e); + } catch (AAIUnknownObjectException e) { + throw new AAIException("AAI_7350", e); + } + } + + public String storeEventAndSendToJms(Loader loader, Introspector eventHeader, Introspector obj) throws AAIException { if (obj == null) { throw new AAIException("AAI_7350"); } diff --git a/aai-core/src/main/java/org/onap/aai/util/delta/DeltaAction.java b/aai-core/src/main/java/org/onap/aai/util/delta/DeltaAction.java new file mode 100644 index 00000000..1b1e49ae --- /dev/null +++ b/aai-core/src/main/java/org/onap/aai/util/delta/DeltaAction.java @@ -0,0 +1,30 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2019 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========================================================= + */ + +package org.onap.aai.util.delta; + +public enum DeltaAction { + CREATE, + UPDATE, + DELETE, + CREATE_REL, + DELETE_REL, + STATIC +} diff --git a/aai-core/src/main/java/org/onap/aai/util/delta/DeltaEvents.java b/aai-core/src/main/java/org/onap/aai/util/delta/DeltaEvents.java new file mode 100644 index 00000000..f240f4e8 --- /dev/null +++ b/aai-core/src/main/java/org/onap/aai/util/delta/DeltaEvents.java @@ -0,0 +1,136 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2019 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========================================================= + */ + +package org.onap.aai.util.delta; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import com.google.gson.*; +import org.onap.aai.db.props.AAIProperties; +import org.onap.aai.dmaap.AAIDmaapEventJMSProducer; +import org.onap.aai.dmaap.MessageProducer; +import org.onap.aai.util.AAIConfig; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Map; + +public class DeltaEvents { + + private static final Logger LOGGER = LoggerFactory.getLogger(DeltaEvents.class); + + private static final Gson gson = new GsonBuilder() + .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_DASHES) + .create(); + + private String transId; + private String sourceName; + private String eventVersion = "v1"; + private String schemaVersion; + private Map<String, ObjectDelta> objectDeltas; + + private MessageProducer messageProducer; + + public DeltaEvents(String transId, String sourceName, String schemaVersion, Map<String, ObjectDelta> objectDeltas) { + this(transId, sourceName, schemaVersion, objectDeltas, new AAIDmaapEventJMSProducer()); + } + + public DeltaEvents(String transId, String sourceName, String schemaVersion, Map<String, ObjectDelta> objectDeltas, MessageProducer messageProducer) { + this.transId = transId; + this.sourceName = sourceName; + this.schemaVersion = schemaVersion; + this.objectDeltas = objectDeltas; + this.messageProducer = messageProducer; + } + + public boolean triggerEvents() { + if (objectDeltas.isEmpty()) { + return false; + } + + JsonObject finalJson = new JsonObject(); + finalJson.addProperty("event-topic", "DELTA"); + finalJson.addProperty("transId", transId); + finalJson.addProperty("fromAppId", sourceName); + finalJson.addProperty("fullId", ""); + finalJson.add("aaiEventPayload", buildEvent()); + + this.messageProducer.sendMessageToDefaultDestination(finalJson.toString()); + return true; + } + + private JsonObject buildEvent() { + JsonObject event = new JsonObject(); + event.addProperty("cambria.partition", this.getPartition()); + event.add("event-header", getHeader()); + event.add("entities", gson.toJsonTree(objectDeltas.values())); + return event; + } + + private String getPartition() { + return "DELTA"; + } + + private JsonObject getHeader() { + ObjectDelta first = objectDeltas.values().iterator().next(); + JsonObject header = new JsonObject(); + header.addProperty("id", this.transId); + header.addProperty("timestamp", this.getTimeStamp(first.getTimestamp())); + header.addProperty("source-name", this.sourceName); + header.addProperty("domain", this.getDomain()); + header.addProperty("event-type", this.getEventType()); + header.addProperty("event-version", this.eventVersion); + header.addProperty("schema-version", this.schemaVersion); + header.addProperty("action", first.getAction().toString()); + header.addProperty("entity-type", this.getEntityType(first)); + header.addProperty("entity-link", first.getUri()); + header.addProperty("entity-uuid", this.getUUID(first)); + + return header; + } + + private String getUUID(ObjectDelta objectDelta) { + return (String) objectDelta.getPropertyDeltas().get(AAIProperties.AAI_UUID).getValue(); + } + + private String getEntityType(ObjectDelta objectDelta) { + return (String) objectDelta.getPropertyDeltas().get(AAIProperties.NODE_TYPE).getValue(); + } + + private String getEventType() { + return "DELTA"; + } + + private String getDomain() { + return AAIConfig.get("aai.notificationEvent.default.domain", "UNK"); + } + + /** + * Given Long timestamp convert to format YYYYMMdd-HH:mm:ss:SSS + * @param timestamp milliseconds since epoc + * @return long timestamp in format YYYYMMdd-HH:mm:ss:SSS + */ + private String getTimeStamp(long timestamp) { + //SimpleDateFormat is not thread safe new instance needed + DateFormat df = new SimpleDateFormat("YYYYMMdd-HH:mm:ss:SSS"); + return df.format(new Date(timestamp)); + } +} diff --git a/aai-core/src/main/java/org/onap/aai/util/delta/ObjectDelta.java b/aai-core/src/main/java/org/onap/aai/util/delta/ObjectDelta.java new file mode 100644 index 00000000..c560dbf6 --- /dev/null +++ b/aai-core/src/main/java/org/onap/aai/util/delta/ObjectDelta.java @@ -0,0 +1,126 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2019 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========================================================= + */ + +package org.onap.aai.util.delta; + +import com.google.gson.annotations.SerializedName; +import org.apache.commons.lang3.builder.ToStringBuilder; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class ObjectDelta { + + @SerializedName("uri") + private String uri; + + @SerializedName("action") + private DeltaAction action; + + @SerializedName("source-of-truth") + private String sourceOfTruth; + + @SerializedName("timestamp") + private long timestamp; + + @SerializedName("property-deltas") + private Map<String, PropertyDelta> propertyDeltas = new HashMap<>(); + + @SerializedName("relationship-deltas") + private List<RelationshipDelta> relationshipDeltas = new ArrayList<>(); + + public ObjectDelta(String uri, DeltaAction action, String sourceOfTruth, long timestamp) { + this.uri = uri; + this.action = action; + this.sourceOfTruth = sourceOfTruth; + this.timestamp = timestamp; + } + + public void addPropertyDelta(String prop, PropertyDelta propertyDelta) { + propertyDeltas.put(prop, propertyDelta); + } + + public void addRelationshipDelta(RelationshipDelta relationshipDelta) { + relationshipDeltas.add(relationshipDelta); + } + + + public String getUri() { + return uri; + } + + public void setUri(String uri) { + this.uri = uri; + } + + public DeltaAction getAction() { + return action; + } + + public void setAction(DeltaAction action) { + this.action = action; + } + + public String getSourceOfTruth() { + return sourceOfTruth; + } + + public void setSourceOfTruth(String sourceOfTruth) { + this.sourceOfTruth = sourceOfTruth; + } + + public long getTimestamp() { + return timestamp; + } + + public void setTimestamp(long timestamp) { + this.timestamp = timestamp; + } + + public void setPropertyDeltas(Map<String, PropertyDelta> propertyDeltas) { + this.propertyDeltas = propertyDeltas; + } + + public void setRelationshipDeltas(List<RelationshipDelta> relationshipDeltas) { + this.relationshipDeltas = relationshipDeltas; + } + + public Map<String, PropertyDelta> getPropertyDeltas() { + return propertyDeltas; + } + + public List<RelationshipDelta> getRelationshipDeltas() { + return relationshipDeltas; + } + + @Override + public String toString() { + return new ToStringBuilder(this) + .append("uri", uri) + .append("action", action) + .append("sourceOfTruth", sourceOfTruth) + .append("timestamp", timestamp) + .append("propertyDeltas", propertyDeltas) + .append("relationshipDeltas", relationshipDeltas) + .toString(); + } +} diff --git a/aai-core/src/main/java/org/onap/aai/util/delta/PropertyDelta.java b/aai-core/src/main/java/org/onap/aai/util/delta/PropertyDelta.java new file mode 100644 index 00000000..46a0072c --- /dev/null +++ b/aai-core/src/main/java/org/onap/aai/util/delta/PropertyDelta.java @@ -0,0 +1,79 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2019 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========================================================= + */ +package org.onap.aai.util.delta; + +import com.google.gson.annotations.SerializedName; +import org.apache.commons.lang3.builder.ToStringBuilder; + +public class PropertyDelta { + + @SerializedName("action") + protected DeltaAction action; + + @SerializedName("value") + protected Object value; + + @SerializedName("old-value") + private Object oldValue; + + + public PropertyDelta(DeltaAction action, Object value) { + this.action = action; + this.value = value; + } + + public PropertyDelta(DeltaAction action, Object value, Object oldValue) { + this(action, value); + this.oldValue = oldValue; + } + + public DeltaAction getAction() { + return action; + } + + public void setAction(DeltaAction action) { + this.action = action; + } + + public Object getValue() { + return value; + } + + public void setValue(Object value) { + this.value = value; + } + + public Object getOldValue() { + return oldValue; + } + + public void setOldValue(Object oldValue) { + this.oldValue = oldValue; + } + + @Override + public String toString() { + return new ToStringBuilder(this) + .append("action", action) + .append("value", value) + .append("oldValue", oldValue) + .toString(); + } +} diff --git a/aai-core/src/main/java/org/onap/aai/util/delta/PropertyDeltaFactory.java b/aai-core/src/main/java/org/onap/aai/util/delta/PropertyDeltaFactory.java new file mode 100644 index 00000000..366d6886 --- /dev/null +++ b/aai-core/src/main/java/org/onap/aai/util/delta/PropertyDeltaFactory.java @@ -0,0 +1,34 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2019 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========================================================= + */ + +package org.onap.aai.util.delta; + +public class PropertyDeltaFactory { + + public static PropertyDelta getDelta(DeltaAction action, Object value, Object oldValue) { + //TODO handle if action is not UPDATE + return new PropertyDelta(action, value, oldValue); + } + + public static PropertyDelta getDelta(DeltaAction action, Object value) { + //TODO handle if action is UPDATE + return new PropertyDelta(action, value); + } +} diff --git a/aai-core/src/main/java/org/onap/aai/util/delta/RelationshipDelta.java b/aai-core/src/main/java/org/onap/aai/util/delta/RelationshipDelta.java new file mode 100644 index 00000000..1dcad1b3 --- /dev/null +++ b/aai-core/src/main/java/org/onap/aai/util/delta/RelationshipDelta.java @@ -0,0 +1,133 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 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========================================================= + */ + +package org.onap.aai.util.delta; + +import com.google.gson.annotations.SerializedName; +import org.apache.commons.lang3.builder.ToStringBuilder; + +import java.util.HashMap; +import java.util.Map; + +public class RelationshipDelta { + + @SerializedName("action") + private DeltaAction action; + + @SerializedName("in-v-uuid") + private String inVUuid; + + @SerializedName("out-v-uuid") + private String outVUuid; + + @SerializedName("in-v-uri") + private String inVUri; + + @SerializedName("out-v-uri") + private String outVUri; + + @SerializedName("label") + private String label; + + @SerializedName("props") + private Map<String, Object> props = new HashMap<>(); + + public RelationshipDelta(DeltaAction action, String inVUUID, String outVUUID, String inVUri, String outVUri, String label) { + this.action = action; + this.inVUuid = inVUUID; + this.outVUuid = outVUUID; + this.inVUri = inVUri; + this.outVUri = outVUri; + this.label = label; + } + + public DeltaAction getAction() { + return action; + } + + public void setAction(DeltaAction action) { + this.action = action; + } + + public String getInVUuid() { + return inVUuid; + } + + public void setInVUuid(String inVUuid) { + this.inVUuid = inVUuid; + } + + public String getOutVUuid() { + return outVUuid; + } + + public void setOutVUuid(String outVUuid) { + this.outVUuid = outVUuid; + } + + public String getInVUri() { + return inVUri; + } + + public void setInVUri(String inVUri) { + this.inVUri = inVUri; + } + + public String getOutVUri() { + return outVUri; + } + + public void setOutVUri(String outVUri) { + this.outVUri = outVUri; + } + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + + public Map<String, Object> getProps() { + return props; + } + + public void setProps(Map<String, Object> props) { + this.props = props; + } + + public void addProp(String key, String value) { + this.props.put(key, value); + } + + @Override + public String toString() { + return new ToStringBuilder(this) + .append("action", action) + .append("inVUuid", inVUuid) + .append("outVUuid", outVUuid) + .append("inVUri", inVUri) + .append("outVUri", outVUri) + .append("label", label) + .append("props", props) + .toString(); + } +} diff --git a/aai-core/src/main/java/org/onap/aai/web/EventClientPublisher.java b/aai-core/src/main/java/org/onap/aai/web/EventClientPublisher.java index d552f231..c5629254 100644 --- a/aai-core/src/main/java/org/onap/aai/web/EventClientPublisher.java +++ b/aai-core/src/main/java/org/onap/aai/web/EventClientPublisher.java @@ -20,8 +20,8 @@ package org.onap.aai.web; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.UnsupportedEncodingException; import java.util.Base64; @@ -37,7 +37,7 @@ import org.springframework.web.client.RestTemplate; @Configuration public class EventClientPublisher { - private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(EventClientPublisher.class); + private static final Logger LOGGER = LoggerFactory.getLogger(EventClientPublisher.class); @Value("${dmaap.ribbon.listOfServers:}") private String hosts; diff --git a/aai-core/src/main/resources/specs/transform-related-to-node.json b/aai-core/src/main/resources/specs/transform-related-to-node.json new file mode 100644 index 00000000..c7e018a8 --- /dev/null +++ b/aai-core/src/main/resources/specs/transform-related-to-node.json @@ -0,0 +1,21 @@ +[ + { + "operation": "shift", + "spec": { + "results": "result", + "*": "&" + } + }, + { + "operation": "shift", + "spec": { + "result": { + "*": { + "related-to": "result.[&(1,0)].&(0,0).node", + "*": "result.[&(1,0)].&(0,0)" + } + }, + "*": "&" + } + } +]
\ No newline at end of file diff --git a/aai-core/src/main/resources/swagger.html.ftl b/aai-core/src/main/resources/swagger.html.ftl new file mode 100644 index 00000000..1a2827f8 --- /dev/null +++ b/aai-core/src/main/resources/swagger.html.ftl @@ -0,0 +1,241 @@ +<#-- + + ============LICENSE_START======================================================= + org.onap.aai + ================================================================================ + Copyright © 2017-18 AT&T Intellectual Property. All rights reserved. + Copyright © 2018 Huawei Technologies (Australia) Pty Ltd. 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========================================================= + + ECOMP is a trademark and service mark of AT&T Intellectual Property. + +--> +<!DOCTYPE html> +<html> +<head> +<style>/*! + * Bootstrap v3.3.6 (http://getbootstrap.com) + * Copyright 2011-2015 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + *//*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-appearance:textfield;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:bold}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,*:before,*:after{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="#"]:after,a[href^="javascript:"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000 !important}.label{border:1px solid #000}.table{border-collapse:collapse !important}.table td,.table th{background-color:#fff !important}.table-bordered th,.table-bordered td{border:1px solid #ddd !important}}@font-face{p EdgeRules.ftl + ont-family:'Glyphicons Halflings';src:url('../fonts/glyphicons-halflings-regular.eot');src:url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'),url('../fonts/glyphicons-halflings-regular.woff2') format('woff2'),url('../fonts/glyphicons-halflings-regular.woff') format('woff'),url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'),url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:normal;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\002a"}.glyphicon-plus:before{content:"\002b"}.glyphicon-euro:before,.glyphicon-eur:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.glyphicon-cd:before{content:"\e201"}.glyphicon-save-file:before{content:"\e202"}.glyphicon-open-file:before{content:"\e203"}.glyphicon-level-up:before{content:"\e204"}.glyphicon-copy:before{content:"\e205"}.glyphicon-paste:before{content:"\e206"}.glyphicon-alert:before{content:"\e209"}.glyphicon-equalizer:before{content:"\e210"}.glyphicon-king:before{content:"\e211"}.glyphicon-queen:before{content:"\e212"}.glyphicon-pawn:before{content:"\e213"}.glyphicon-bishop:before{content:"\e214"}.glyphicon-knight:before{content:"\e215"}.glyphicon-baby-formula:before{content:"\e216"}.glyphicon-tent:before{content:"\26fa"}.glyphicon-blackboard:before{content:"\e218"}.glyphicon-bed:before{content:"\e219"}.glyphicon-apple:before{content:"\f8ff"}.glyphicon-erase:before{content:"\e221"}.glyphicon-hourglass:before{content:"\231b"}.glyphicon-lamp:before{content:"\e223"}.glyphicon-duplicate:before{content:"\e224"}.glyphicon-piggy-bank:before{content:"\e225"}.glyphicon-scissors:before{content:"\e226"}.glyphicon-bitcoin:before{content:"\e227"}.glyphicon-btc:before{content:"\e227"}.glyphicon-xbt:before{content:"\e227"}.glyphicon-yen:before{content:"\00a5"}.glyphicon-jpy:before{content:"\00a5"}.glyphicon-ruble:before{content:"\20bd"}.glyphicon-rub:before{content:"\20bd"}.glyphicon-scale:before{content:"\e230"}.glyphicon-ice-lolly:before{content:"\e231"}.glyphicon-ice-lolly-tasted:before{content:"\e232"}.glyphicon-education:before{content:"\e233"}.glyphicon-option-horizontal:before{content:"\e234"}.glyphicon-option-vertical:before{content:"\e235"}.glyphicon-menu-hamburger:before{content:"\e236"}.glyphicon-modal-window:before{content:"\e237"}.glyphicon-oil:before{content:"\e238"}.glyphicon-grain:before{content:"\e239"}.glyphicon-sunglasses:before{content:"\e240"}.glyphicon-text-size:before{content:"\e241"}.glyphicon-text-color:before{content:"\e242"}.glyphicon-text-background:before{content:"\e243"}.glyphicon-object-align-top:before{content:"\e244"}.glyphicon-object-align-bottom:before{content:"\e245"}.glyphicon-object-align-horizontal:before{content:"\e246"}.glyphicon-object-align-left:before{content:"\e247"}.glyphicon-object-align-vertical:before{content:"\e248"}.glyphicon-object-align-right:before{content:"\e249"}.glyphicon-triangle-right:before{content:"\e250"}.glyphicon-triangle-left:before{content:"\e251"}.glyphicon-triangle-bottom:before{content:"\e252"}.glyphicon-triangle-top:before{content:"\e253"}.glyphicon-console:before{content:"\e254"}.glyphicon-superscript:before{content:"\e255"}.glyphicon-subscript:before{content:"\e256"}.glyphicon-menu-left:before{content:"\e257"}.glyphicon-menu-right:before{content:"\e258"}.glyphicon-menu-down:before{content:"\e259"}.glyphicon-menu-up:before{content:"\e260"}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}*:before,*:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}input,button,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#337ab7;text-decoration:none}a:hover,a:focus{color:#23527c;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.img-responsive,.thumbnail>img,.thumbnail a>img,.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out;display:inline-block;max-width:100%;height:auto}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}[role="button"]{cursor:pointer}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small,.h1 small,.h2 small,.h3 small,.h4 small,.h5 small,.h6 small,h1 .small,h2 .small,h3 .small,h4 .small,h5 .small,h6 .small,.h1 .small,.h2 .small,.h3 .small,.h4 .small,.h5 .small,.h6 .small{font-weight:normal;line-height:1;color:#777}h1,.h1,h2,.h2,h3,.h3{margin-top:20px;margin-bottom:10px}h1 small,.h1 small,h2 small,.h2 small,h3 small,.h3 small,h1 .small,.h1 .small,h2 .small,.h2 .small,h3 .small,.h3 .small{font-size:65%}h4,.h4,h5,.h5,h6,.h6{margin-top:10px;margin-bottom:10px}h4 small,.h4 small,h5 small,.h5 small,h6 small,.h6 small,h4 .small,.h4 .small,h5 .small,.h5 .small,h6 .small,.h6 .small{font-size:75%}h1,.h1{font-size:36px}h2,.h2{font-size:30px}h3,.h3{font-size:24px}h4,.h4{font-size:18px}h5,.h5{font-size:14px}h6,.h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}small,.small{font-size:85%}mark,.mark{background-color:#fcf8e3;padding:.2em}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#777}.text-primary{color:#337ab7}a.text-primary:hover,a.text-primary:focus{color:#286090}.text-success{color:#3c763d}a.text-success:hover,a.text-success:focus{color:#2b542c}.text-info{color:#31708f}a.text-info:hover,a.text-info:focus{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:hover,a.text-warning:focus{color:#66512c}.text-danger{color:#a94442}a.text-danger:hover,a.text-danger:focus{color:#843534}.bg-primary{color:#fff;background-color:#337ab7}a.bg-primary:hover,a.bg-primary:focus{background-color:#286090}.bg-success{background-color:#dff0d8}a.bg-success:hover,a.bg-success:focus{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:hover,a.bg-info:focus{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:hover,a.bg-warning:focus{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:hover,a.bg-danger:focus{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ul,ol{margin-top:0;margin-bottom:10px}ul ul,ol ul,ul ol,ol ol{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none;margin-left:-5px}.list-inline>li{display:inline-block;padding-left:5px;padding-right:5px}dl{margin-top:0;margin-bottom:20px}dt,dd{line-height:1.42857143}dt{font-weight:bold}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #777}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote p:last-child,blockquote ul:last-child,blockquote ol:last-child{margin-bottom:0}blockquote footer,blockquote small,blockquote .small{display:block;font-size:80%;line-height:1.42857143;color:#777}blockquote footer:before,blockquote small:before,blockquote .small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0;text-align:right}.blockquote-reverse footer:before,blockquote.pull-right footer:before,.blockquote-reverse small:before,blockquote.pull-right small:before,.blockquote-reverse .small:before,blockquote.pull-right .small:before{content:''}.blockquote-reverse footer:after,blockquote.pull-right footer:after,.blockquote-reverse small:after,blockquote.pull-right small:after,.blockquote-reverse .small:after,blockquote.pull-right .small:after{content:'\00A0 \2014'}address{margin-bottom:20px;font-style:normal;line-height:1.42857143}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#fff;background-color:#333;border-radius:3px;box-shadow:inset 0 -1px 0 rgba(0,0,0,0.25)}kbd kbd{padding:0;font-size:100%;font-weight:bold;box-shadow:none}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.42857143;word-break:break-all;word-wrap:break-word;color:#333;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}@media (min-width:768px){.container{width:800px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:900px}}.container-fluid{margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}.row{margin-left:-15px;margin-right:-15px}.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12{position:relative;min-height:1px;padding-left:15px;padding-right:15px}.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}table{background-color:transparent}caption{padding-top:8px;padding-bottom:8px;color:#777;text-align:left}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:20px}.table>thead>tr>th,.table>tbody>tr>th,.table>tfoot>tr>th,.table>thead>tr>td,.table>tbody>tr>td,.table>tfoot>tr>td{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>th,.table>caption+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>td,.table>thead:first-child>tr:first-child>td{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>thead>tr>th,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>tbody>tr>td,.table-condensed>tfoot>tr>td{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>tbody>tr>td,.table-bordered>tfoot>tr>td{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>thead>tr>td{border-bottom-width:2px}.table-striped>tbody>tr:nth-of-type(odd){background-color:#f9f9f9}.table-hover>tbody>tr:hover{background-color:#f5f5f5}table col[class*="col-"]{position:static;float:none;display:table-column}table td[class*="col-"],table th[class*="col-"]{position:static;float:none;display:table-cell}.table>thead>tr>td.active,.table>tbody>tr>td.active,.table>tfoot>tr>td.active,.table>thead>tr>th.active,.table>tbody>tr>th.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>tbody>tr.active>td,.table>tfoot>tr.active>td,.table>thead>tr.active>th,.table>tbody>tr.active>th,.table>tfoot>tr.active>th{background-color:#f5f5f5}.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover,.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr.active:hover>th{background-color:#e8e8e8}.table>thead>tr>td.success,.table>tbody>tr>td.success,.table>tfoot>tr>td.success,.table>thead>tr>th.success,.table>tbody>tr>th.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>tbody>tr.success>td,.table>tfoot>tr.success>td,.table>thead>tr.success>th,.table>tbody>tr.success>th,.table>tfoot>tr.success>th{background-color:#dff0d8}.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover,.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr.success:hover>th{background-color:#d0e9c6}.table>thead>tr>td.info,.table>tbody>tr>td.info,.table>tfoot>tr>td.info,.table>thead>tr>th.info,.table>tbody>tr>th.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>tbody>tr.info>td,.table>tfoot>tr.info>td,.table>thead>tr.info>th,.table>tbody>tr.info>th,.table>tfoot>tr.info>th{background-color:#d9edf7}.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover,.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr.info:hover>th{background-color:#c4e3f3}.table>thead>tr>td.warning,.table>tbody>tr>td.warning,.table>tfoot>tr>td.warning,.table>thead>tr>th.warning,.table>tbody>tr>th.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>tbody>tr.warning>td,.table>tfoot>tr.warning>td,.table>thead>tr.warning>th,.table>tbody>tr.warning>th,.table>tfoot>tr.warning>th{background-color:#fcf8e3}.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover,.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr.warning:hover>th{background-color:#faf2cc}.table>thead>tr>td.danger,.table>tbody>tr>td.danger,.table>tfoot>tr>td.danger,.table>thead>tr>th.danger,.table>tbody>tr>th.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>tbody>tr.danger>td,.table>tfoot>tr.danger>td,.table>thead>tr.danger>th,.table>tbody>tr.danger>th,.table>tfoot>tr.danger>th{background-color:#f2dede}.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover,.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr.danger:hover>th{background-color:#ebcccc}.table-responsive{overflow-x:auto;min-height:.01%}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>thead>tr>th,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tfoot>tr>td{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>thead>tr>th:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.table-responsive>.table-bordered>thead>tr>th:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>th,.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}}fieldset{padding:0;margin:0;border:0;min-width:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:bold}input[type="search"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type="radio"],input[type="checkbox"]{margin:4px 0 0;margin-top:1px \9;line-height:normal}input[type="file"]{display:block}input[type="range"]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:7px;font-size:14px;line-height:1.42857143;color:#555}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.42857143;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border-color ease-in-out .15s, box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s, box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s, box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6)}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control::-ms-expand{border:0;background-color:transparent}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{background-color:#eee;opacity:1}.form-control[disabled],fieldset[disabled] .form-control{cursor:not-allowed}textarea.form-control{height:auto}input[type="search"]{-webkit-appearance:none}@media screen and (-webkit-min-device-pixel-ratio:0){input[type="date"].form-control,input[type="time"].form-control,input[type="datetime-local"].form-control,input[type="month"].form-control{line-height:34px}input[type="date"].input-sm,input[type="time"].input-sm,input[type="datetime-local"].input-sm,input[type="month"].input-sm,.input-group-sm input[type="date"],.input-group-sm input[type="time"],.input-group-sm input[type="datetime-local"],.input-group-sm input[type="month"]{line-height:30px}input[type="date"].input-lg,input[type="time"].input-lg,input[type="datetime-local"].input-lg,input[type="month"].input-lg,.input-group-lg input[type="date"],.input-group-lg input[type="time"],.input-group-lg input[type="datetime-local"],.input-group-lg input[type="month"]{line-height:46px}}.form-group{margin-bottom:15px}.radio,.checkbox{position:relative;display:block;margin-top:10px;margin-bottom:10px}.radio label,.checkbox label{min-height:20px;padding-left:20px;margin-bottom:0;font-weight:normal;cursor:pointer}.radio input[type="radio"],.radio-inline input[type="radio"],.checkbox input[type="checkbox"],.checkbox-inline input[type="checkbox"]{position:absolute;margin-left:-20px;margin-top:4px \9}.radio+.radio,.checkbox+.checkbox{margin-top:-5px}.radio-inline,.checkbox-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;vertical-align:middle;font-weight:normal;cursor:pointer}.radio-inline+.radio-inline,.checkbox-inline+.checkbox-inline{margin-top:0;margin-left:10px}input[type="radio"][disabled],input[type="checkbox"][disabled],input[type="radio"].disabled,input[type="checkbox"].disabled,fieldset[disabled] input[type="radio"],fieldset[disabled] input[type="checkbox"]{cursor:not-allowed}.radio-inline.disabled,.checkbox-inline.disabled,fieldset[disabled] .radio-inline,fieldset[disabled] .checkbox-inline{cursor:not-allowed}.radio.disabled label,.checkbox.disabled label,fieldset[disabled] .radio label,fieldset[disabled] .checkbox label{cursor:not-allowed}.form-control-static{padding-top:7px;padding-bottom:7px;margin-bottom:0;min-height:34px}.form-control-static.input-lg,.form-control-static.input-sm{padding-left:0;padding-right:0}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}textarea.input-sm,select[multiple].input-sm{height:auto}.form-group-sm .form-control{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.form-group-sm select.form-control{height:30px;line-height:30px}.form-group-sm textarea.form-control,.form-group-sm select[multiple].form-control{height:auto}.form-group-sm .form-control-static{height:30px;min-height:32px;padding:6px 10px;font-size:12px;line-height:1.5}.input-lg{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-lg{height:46px;line-height:46px}textarea.input-lg,select[multiple].input-lg{height:auto}.form-group-lg .form-control{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.form-group-lg select.form-control{height:46px;line-height:46px}.form-group-lg textarea.form-control,.form-group-lg select[multiple].form-control{height:auto}.form-group-lg .form-control-static{height:46px;min-height:38px;padding:11px 16px;font-size:18px;line-height:1.3333333}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.form-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center;pointer-events:none}.input-lg+.form-control-feedback,.input-group-lg+.form-control-feedback,.form-group-lg .form-control+.form-control-feedback{width:46px;height:46px;line-height:46px}.input-sm+.form-control-feedback,.input-group-sm+.form-control-feedback,.form-group-sm .form-control+.form-control-feedback{width:30px;height:30px;line-height:30px}.has-success .help-block,.has-success .control-label,.has-success .radio,.has-success .checkbox,.has-success .radio-inline,.has-success .checkbox-inline,.has-success.radio label,.has-success.checkbox label,.has-success.radio-inline label,.has-success.checkbox-inline label{color:#3c763d}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;border-color:#3c763d;background-color:#dff0d8}.has-success .form-control-feedback{color:#3c763d}.has-warning .help-block,.has-warning .control-label,.has-warning .radio,.has-warning .checkbox,.has-warning .radio-inline,.has-warning .checkbox-inline,.has-warning.radio label,.has-warning.checkbox label,.has-warning.radio-inline label,.has-warning.checkbox-inline label{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;border-color:#8a6d3b;background-color:#fcf8e3}.has-warning .form-control-feedback{color:#8a6d3b}.has-error .help-block,.has-error .control-label,.has-error .radio,.has-error .checkbox,.has-error .radio-inline,.has-error .checkbox-inline,.has-error.radio label,.has-error.checkbox label,.has-error.radio-inline label,.has-error.checkbox-inline label{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;border-color:#a94442;background-color:#f2dede}.has-error .form-control-feedback{color:#a94442}.has-feedback label~.form-control-feedback{top:25px}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-static{display:inline-block}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn,.form-inline .input-group .form-control{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .radio,.form-inline .checkbox{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .radio label,.form-inline .checkbox label{padding-left:0}.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .radio,.form-horizontal .checkbox,.form-horizontal .radio-inline,.form-horizontal .checkbox-inline{margin-top:0;margin-bottom:0;padding-top:7px}.form-horizontal .radio,.form-horizontal .checkbox{min-height:27px}.form-horizontal .form-group{margin-left:-15px;margin-right:-15px}@media (min-width:768px){.form-horizontal .control-label{text-align:right;margin-bottom:0;padding-top:7px}}.form-horizontal .has-feedback .form-control-feedback{right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:11px;font-size:18px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px;font-size:12px}}.btn{display:inline-block;margin-bottom:0;font-weight:normal;text-align:center;vertical-align:middle;touch-action:manipulation;cursor:pointer;background-image:none;border:1px solid transparent;white-space:nowrap;padding:6px 12px;font-size:14px;line-height:1.42857143;border-radius:4px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.btn:focus,.btn:active:focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn.active.focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn:hover,.btn:focus,.btn.focus{color:#333;text-decoration:none}.btn:active,.btn.active{outline:0;background-image:none;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none}a.btn.disabled,fieldset[disabled] a.btn{pointer-events:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default:focus,.btn-default.focus{color:#333;background-color:#e6e6e6;border-color:#8c8c8c}.btn-default:hover{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default:active,.btn-default.active,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default:active:hover,.btn-default.active:hover,.open>.dropdown-toggle.btn-default:hover,.btn-default:active:focus,.btn-default.active:focus,.open>.dropdown-toggle.btn-default:focus,.btn-default:active.focus,.btn-default.active.focus,.open>.dropdown-toggle.btn-default.focus{color:#333;background-color:#d4d4d4;border-color:#8c8c8c}.btn-default:active,.btn-default.active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled:hover,.btn-default[disabled]:hover,fieldset[disabled] .btn-default:hover,.btn-default.disabled:focus,.btn-default[disabled]:focus,fieldset[disabled] .btn-default:focus,.btn-default.disabled.focus,.btn-default[disabled].focus,fieldset[disabled] .btn-default.focus{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#337ab7;border-color:#2e6da4}.btn-primary:focus,.btn-primary.focus{color:#fff;background-color:#286090;border-color:#122b40}.btn-primary:hover{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary:active,.btn-primary.active,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary:active:hover,.btn-primary.active:hover,.open>.dropdown-toggle.btn-primary:hover,.btn-primary:active:focus,.btn-primary.active:focus,.open>.dropdown-toggle.btn-primary:focus,.btn-primary:active.focus,.btn-primary.active.focus,.open>.dropdown-toggle.btn-primary.focus{color:#fff;background-color:#204d74;border-color:#122b40}.btn-primary:active,.btn-primary.active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled:hover,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary:hover,.btn-primary.disabled:focus,.btn-primary[disabled]:focus,fieldset[disabled] .btn-primary:focus,.btn-primary.disabled.focus,.btn-primary[disabled].focus,fieldset[disabled] .btn-primary.focus{background-color:#337ab7;border-color:#2e6da4}.btn-primary .badge{color:#337ab7;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success:focus,.btn-success.focus{color:#fff;background-color:#449d44;border-color:#255625}.btn-success:hover{color:#fff;background-color:#449d44;border-color:#398439}.btn-success:active,.btn-success.active,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439}.btn-success:active:hover,.btn-success.active:hover,.open>.dropdown-toggle.btn-success:hover,.btn-success:active:focus,.btn-success.active:focus,.open>.dropdown-toggle.btn-success:focus,.btn-success:active.focus,.btn-success.active.focus,.open>.dropdown-toggle.btn-success.focus{color:#fff;background-color:#398439;border-color:#255625}.btn-success:active,.btn-success.active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled:hover,.btn-success[disabled]:hover,fieldset[disabled] .btn-success:hover,.btn-success.disabled:focus,.btn-success[disabled]:focus,fieldset[disabled] .btn-success:focus,.btn-success.disabled.focus,.btn-success[disabled].focus,fieldset[disabled] .btn-success.focus{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info:focus,.btn-info.focus{color:#fff;background-color:#31b0d5;border-color:#1b6d85}.btn-info:hover{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info:active,.btn-info.active,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info:active:hover,.btn-info.active:hover,.open>.dropdown-toggle.btn-info:hover,.btn-info:active:focus,.btn-info.active:focus,.open>.dropdown-toggle.btn-info:focus,.btn-info:active.focus,.btn-info.active.focus,.open>.dropdown-toggle.btn-info.focus{color:#fff;background-color:#269abc;border-color:#1b6d85}.btn-info:active,.btn-info.active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled:hover,.btn-info[disabled]:hover,fieldset[disabled] .btn-info:hover,.btn-info.disabled:focus,.btn-info[disabled]:focus,fieldset[disabled] .btn-info:focus,.btn-info.disabled.focus,.btn-info[disabled].focus,fieldset[disabled] .btn-info.focus{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning:focus,.btn-warning.focus{color:#fff;background-color:#ec971f;border-color:#985f0d}.btn-warning:hover{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning:active,.btn-warning.active,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning:active:hover,.btn-warning.active:hover,.open>.dropdown-toggle.btn-warning:hover,.btn-warning:active:focus,.btn-warning.active:focus,.open>.dropdown-toggle.btn-warning:focus,.btn-warning:active.focus,.btn-warning.active.focus,.open>.dropdown-toggle.btn-warning.focus{color:#fff;background-color:#d58512;border-color:#985f0d}.btn-warning:active,.btn-warning.active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled:hover,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning:hover,.btn-warning.disabled:focus,.btn-warning[disabled]:focus,fieldset[disabled] .btn-warning:focus,.btn-warning.disabled.focus,.btn-warning[disabled].focus,fieldset[disabled] .btn-warning.focus{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger:focus,.btn-danger.focus{color:#fff;background-color:#c9302c;border-color:#761c19}.btn-danger:hover{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger:active,.btn-danger.active,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger:active:hover,.btn-danger.active:hover,.open>.dropdown-toggle.btn-danger:hover,.btn-danger:active:focus,.btn-danger.active:focus,.open>.dropdown-toggle.btn-danger:focus,.btn-danger:active.focus,.btn-danger.active.focus,.open>.dropdown-toggle.btn-danger.focus{color:#fff;background-color:#ac2925;border-color:#761c19}.btn-danger:active,.btn-danger.active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled:hover,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger:hover,.btn-danger.disabled:focus,.btn-danger[disabled]:focus,fieldset[disabled] .btn-danger:focus,.btn-danger.disabled.focus,.btn-danger[disabled].focus,fieldset[disabled] .btn-danger.focus{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{color:#337ab7;font-weight:normal;border-radius:0}.btn-link,.btn-link:active,.btn-link.active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:hover,.btn-link:focus,.btn-link:active{border-color:transparent}.btn-link:hover,.btn-link:focus{color:#23527c;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,fieldset[disabled] .btn-link:hover,.btn-link[disabled]:focus,fieldset[disabled] .btn-link:focus{color:#777;text-decoration:none}.btn-lg,.btn-group-lg>.btn{padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.btn-sm,.btn-group-sm>.btn{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-xs,.btn-group-xs>.btn{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition-property:height, visibility;transition-property:height, visibility;-webkit-transition-duration:.35s;transition-duration:.35s;-webkit-transition-timing-function:ease;transition-timing-function:ease}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px dashed;border-top:4px solid \9;border-right:4px solid transparent;border-left:4px solid transparent}.dropup,.dropdown{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;font-size:14px;text-align:left;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,0.175);box-shadow:0 6px 12px rgba(0,0,0,0.175);background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:1.42857143;color:#333;white-space:nowrap}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{text-decoration:none;color:#262626;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;outline:0;background-color:#337ab7}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#777}.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);cursor:not-allowed}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{left:auto;right:0}.dropdown-menu-left{left:0;right:auto}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.42857143;color:#777;white-space:nowrap}.dropdown-backdrop{position:fixed;left:0;right:0;bottom:0;top:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px dashed;border-bottom:4px solid \9;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px}@media (min-width:768px){.navbar-right .dropdown-menu{left:auto;right:0}.navbar-right .dropdown-menu-left{left:0;right:auto}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;float:left}.btn-group>.btn:hover,.btn-group-vertical>.btn:hover,.btn-group>.btn:focus,.btn-group-vertical>.btn:focus,.btn-group>.btn:active,.btn-group-vertical>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn.active{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn,.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-top-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-top-right-radius:0}.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child{border-bottom-left-radius:0;border-top-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-left:8px;padding-right:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-left:12px;padding-right:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:4px;border-top-left-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-right-radius:0;border-top-left-radius:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-right-radius:0;border-top-left-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{float:none;display:table-cell;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle="buttons"]>.btn input[type="radio"],[data-toggle="buttons"]>.btn-group>.btn input[type="radio"],[data-toggle="buttons"]>.btn input[type="checkbox"],[data-toggle="buttons"]>.btn-group>.btn input[type="checkbox"]{position:absolute;clip:rect(0, 0, 0, 0);pointer-events:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*="col-"]{float:none;padding-left:0;padding-right:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group .form-control:focus{z-index:3}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn,select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn,select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn{height:auto}.input-group-addon,.input-group-btn,.input-group .form-control{display:table-cell}.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child),.input-group .form-control:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:normal;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type="radio"],.input-group-addon input[type="checkbox"]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle),.input-group-btn:last-child>.btn-group:not(:last-child)>.btn{border-bottom-right-radius:0;border-top-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:first-child>.btn-group:not(:first-child)>.btn{border-bottom-left-radius:0;border-top-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:hover,.input-group-btn>.btn:focus,.input-group-btn>.btn:active{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{z-index:2;margin-left:-1px}.nav{margin-bottom:0;padding-left:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#777}.nav>li.disabled>a:hover,.nav>li.disabled>a:focus{color:#777;text-decoration:none;background-color:transparent;cursor:not-allowed}.nav .open>a,.nav .open>a:hover,.nav .open>a:focus{background-color:#eee;border-color:#337ab7}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{color:#555;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent;cursor:default}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{text-align:center;margin-bottom:5px}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:hover,.nav-pills>li.active>a:focus{color:#fff;background-color:#337ab7}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{text-align:center;margin-bottom:5px}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border:1px solid #ddd}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-right-radius:0;border-top-left-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{overflow-x:visible;padding-right:15px;padding-left:15px;border-top:1px solid transparent;box-shadow:inset 0 1px 0 rgba(255,255,255,0.1);-webkit-overflow-scrolling:touch}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;box-shadow:none}.navbar-collapse.collapse{display:block !important;height:auto !important;padding-bottom:0;overflow:visible !important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{padding-left:0;padding-right:0}}.navbar-fixed-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{max-height:340px}@media (max-device-width:480px) and (orientation:landscape){.navbar-fixed-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{max-height:200px}}.container>.navbar-header,.container-fluid>.navbar-header,.container>.navbar-collapse,.container-fluid>.navbar-collapse{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container>.navbar-header,.container-fluid>.navbar-header,.container>.navbar-collapse,.container-fluid>.navbar-collapse{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030}@media (min-width:768px){.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;padding:15px 15px;font-size:18px;line-height:20px;height:50px}.navbar-brand:hover,.navbar-brand:focus{text-decoration:none}.navbar-brand>img{display:block}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;margin-right:15px;padding:9px 10px;margin-top:8px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;box-shadow:none}.navbar-nav .open .dropdown-menu>li>a,.navbar-nav .open .dropdown-menu .dropdown-header{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:hover,.navbar-nav .open .dropdown-menu>li>a:focus{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}.navbar-form{margin-left:-15px;margin-right:-15px;padding:10px 15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);margin-top:8px;margin-bottom:8px}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .form-control-static{display:inline-block}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn,.navbar-form .input-group .form-control{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .radio,.navbar-form .checkbox{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .radio label,.navbar-form .checkbox label{padding-left:0}.navbar-form .radio input[type="radio"],.navbar-form .checkbox input[type="checkbox"]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}.navbar-form .form-group:last-child{margin-bottom:0}}@media (min-width:768px){.navbar-form{width:auto;border:0;margin-left:0;margin-right:0;padding-top:0;padding-bottom:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-right-radius:0;border-top-left-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{margin-bottom:0;border-top-right-radius:4px;border-top-left-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media (min-width:768px){.navbar-text{float:left;margin-left:15px;margin-right:15px}}@media (min-width:768px){.navbar-left{float:left !important}.navbar-right{float:right !important;margin-right:-15px}.navbar-right~.navbar-right{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:hover,.navbar-default .navbar-brand:focus{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:hover,.navbar-default .navbar-nav>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:hover,.navbar-default .navbar-nav>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:hover,.navbar-default .navbar-nav>.disabled>a:focus{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:hover,.navbar-default .navbar-toggle:focus{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:hover,.navbar-default .navbar-nav>.open>a:focus{background-color:#e7e7e7;color:#555}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-default .btn-link{color:#777}.navbar-default .btn-link:hover,.navbar-default .btn-link:focus{color:#333}.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:hover,.navbar-default .btn-link[disabled]:focus,fieldset[disabled] .navbar-default .btn-link:focus{color:#ccc}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#9d9d9d}.navbar-inverse .navbar-brand:hover,.navbar-inverse .navbar-brand:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a:hover,.navbar-inverse .navbar-nav>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:hover,.navbar-inverse .navbar-nav>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:hover,.navbar-inverse .navbar-nav>.disabled>a:focus{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:hover,.navbar-inverse .navbar-toggle:focus{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:hover,.navbar-inverse .navbar-nav>.open>a:focus{background-color:#080808;color:#fff}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#9d9d9d}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .btn-link{color:#9d9d9d}.navbar-inverse .btn-link:hover,.navbar-inverse .btn-link:focus{color:#fff}.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:hover,.navbar-inverse .btn-link[disabled]:focus,fieldset[disabled] .navbar-inverse .btn-link:focus{color:#444}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{content:"/\00a0";padding:0 5px;color:#ccc}.breadcrumb>.active{color:#777}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;line-height:1.42857143;text-decoration:none;color:#337ab7;background-color:#fff;border:1px solid #ddd;margin-left:-1px}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-bottom-left-radius:4px;border-top-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-bottom-right-radius:4px;border-top-right-radius:4px}.pagination>li>a:hover,.pagination>li>span:hover,.pagination>li>a:focus,.pagination>li>span:focus{z-index:2;color:#23527c;background-color:#eee;border-color:#ddd}.pagination>.active>a,.pagination>.active>span,.pagination>.active>a:hover,.pagination>.active>span:hover,.pagination>.active>a:focus,.pagination>.active>span:focus{z-index:3;color:#fff;background-color:#337ab7;border-color:#337ab7;cursor:default}.pagination>.disabled>span,.pagination>.disabled>span:hover,.pagination>.disabled>span:focus,.pagination>.disabled>a,.pagination>.disabled>a:hover,.pagination>.disabled>a:focus{color:#777;background-color:#fff;border-color:#ddd;cursor:not-allowed}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px;line-height:1.3333333}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-bottom-left-radius:6px;border-top-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-bottom-right-radius:6px;border-top-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px;line-height:1.5}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-bottom-left-radius:3px;border-top-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-bottom-right-radius:3px;border-top-right-radius:3px}.pager{padding-left:0;margin:20px 0;list-style:none;text-align:center}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#777;background-color:#fff;cursor:not-allowed}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:bold;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}a.label:hover,a.label:focus{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#777}.label-default[href]:hover,.label-default[href]:focus{background-color:#5e5e5e}.label-primary{background-color:#337ab7}.label-primary[href]:hover,.label-primary[href]:focus{background-color:#286090}.label-success{background-color:#5cb85c}.label-success[href]:hover,.label-success[href]:focus{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:hover,.label-info[href]:focus{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:hover,.label-warning[href]:focus{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:hover,.label-danger[href]:focus{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:bold;color:#fff;line-height:1;vertical-align:middle;white-space:nowrap;text-align:center;background-color:#777;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-xs .badge,.btn-group-xs>.btn .badge{top:0;padding:1px 5px}a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#337ab7;background-color:#fff}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding-top:30px;padding-bottom:30px;margin-bottom:30px;color:inherit;background-color:#eee}.jumbotron h1,.jumbotron .h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.jumbotron>hr{border-top-color:#d5d5d5}.container .jumbotron,.container-fluid .jumbotron{border-radius:6px;padding-left:15px;padding-right:15px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron,.container-fluid .jumbotron{padding-left:60px;padding-right:60px}.jumbotron h1,.jumbotron .h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:border .2s ease-in-out;-o-transition:border .2s ease-in-out;transition:border .2s ease-in-out}.thumbnail>img,.thumbnail a>img{margin-left:auto;margin-right:auto}a.thumbnail:hover,a.thumbnail:focus,a.thumbnail.active{border-color:#337ab7}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:bold}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{background-color:#dff0d8;border-color:#d6e9c6;color:#3c763d}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{background-color:#d9edf7;border-color:#bce8f1;color:#31708f}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{background-color:#fcf8e3;border-color:#faebcc;color:#8a6d3b}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{background-color:#f2dede;border-color:#ebccd1;color:#a94442}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{overflow:hidden;height:20px;margin-bottom:20px;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#337ab7;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress-striped .progress-bar,.progress-bar-striped{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-size:40px 40px}.progress.active .progress-bar,.progress-bar.active{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.media{margin-top:15px}.media:first-child{margin-top:0}.media,.media-body{zoom:1;overflow:hidden}.media-body{width:10000px}.media-object{display:block}.media-object.img-thumbnail{max-width:none}.media-right,.media>.pull-right{padding-left:10px}.media-left,.media>.pull-left{padding-right:10px}.media-left,.media-right,.media-body{display:table-cell;vertical-align:top}.media-middle{vertical-align:middle}.media-bottom{vertical-align:bottom}.media-heading{margin-top:0;margin-bottom:5px}.media-list{padding-left:0;list-style:none}.list-group{margin-bottom:20px;padding-left:0}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-right-radius:4px;border-top-left-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}a.list-group-item,button.list-group-item{color:#555}a.list-group-item .list-group-item-heading,button.list-group-item .list-group-item-heading{color:#333}a.list-group-item:hover,button.list-group-item:hover,a.list-group-item:focus,button.list-group-item:focus{text-decoration:none;color:#555;background-color:#f5f5f5}button.list-group-item{width:100%;text-align:left}.list-group-item.disabled,.list-group-item.disabled:hover,.list-group-item.disabled:focus{background-color:#eee;color:#777;cursor:not-allowed}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text{color:#777}.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{z-index:2;color:#fff;background-color:#337ab7;border-color:#337ab7}.list-group-item.active .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>.small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:hover .list-group-item-text,.list-group-item.active:focus .list-group-item-text{color:#c7ddef}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success,button.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading,button.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:hover,button.list-group-item-success:hover,a.list-group-item-success:focus,button.list-group-item-success:focus{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,button.list-group-item-success.active,a.list-group-item-success.active:hover,button.list-group-item-success.active:hover,a.list-group-item-success.active:focus,button.list-group-item-success.active:focus{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info,button.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading,button.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:hover,button.list-group-item-info:hover,a.list-group-item-info:focus,button.list-group-item-info:focus{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,button.list-group-item-info.active,a.list-group-item-info.active:hover,button.list-group-item-info.active:hover,a.list-group-item-info.active:focus,button.list-group-item-info.active:focus{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning,button.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading,button.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:hover,button.list-group-item-warning:hover,a.list-group-item-warning:focus,button.list-group-item-warning:focus{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,button.list-group-item-warning.active,a.list-group-item-warning.active:hover,button.list-group-item-warning.active:hover,a.list-group-item-warning.active:focus,button.list-group-item-warning.active:focus{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger,button.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading,button.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:hover,button.list-group-item-danger:hover,a.list-group-item-danger:focus,button.list-group-item-danger:focus{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,button.list-group-item-danger.active,a.list-group-item-danger.active:hover,button.list-group-item-danger.active:hover,a.list-group-item-danger.active:focus,button.list-group-item-danger.active:focus{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.05);box-shadow:0 1px 1px rgba(0,0,0,0.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-right-radius:3px;border-top-left-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>a,.panel-title>small,.panel-title>.small,.panel-title>small>a,.panel-title>.small>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.list-group,.panel>.panel-collapse>.list-group{margin-bottom:0}.panel>.list-group .list-group-item,.panel>.panel-collapse>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child,.panel>.panel-collapse>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-right-radius:3px;border-top-left-radius:3px}.panel>.list-group:last-child .list-group-item:last-child,.panel>.panel-collapse>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.panel-heading+.panel-collapse>.list-group .list-group-item:first-child{border-top-right-radius:0;border-top-left-radius:0}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.list-group+.panel-footer{border-top-width:0}.panel>.table,.panel>.table-responsive>.table,.panel>.panel-collapse>.table{margin-bottom:0}.panel>.table caption,.panel>.table-responsive>.table caption,.panel>.panel-collapse>.table caption{padding-left:15px;padding-right:15px}.panel>.table:first-child,.panel>.table-responsive:first-child>.table:first-child{border-top-right-radius:3px;border-top-left-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table:last-child,.panel>.table-responsive:last-child>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child{border-bottom-left-radius:3px;border-bottom-right-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive,.panel>.table+.panel-body,.panel>.table-responsive+.panel-body{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child th,.panel>.table>tbody:first-child>tr:first-child td{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{border:0;margin-bottom:0}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.panel-body,.panel-group .panel-heading+.panel-collapse>.list-group{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ddd}.panel-default>.panel-heading .badge{color:#f5f5f5;background-color:#333}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#337ab7}.panel-primary>.panel-heading{color:#fff;background-color:#337ab7;border-color:#337ab7}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#337ab7}.panel-primary>.panel-heading .badge{color:#337ab7;background-color:#fff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#337ab7}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading .badge{color:#dff0d8;background-color:#3c763d}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading .badge{color:#d9edf7;background-color:#31708f}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#bce8f1}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading .badge{color:#fcf8e3;background-color:#8a6d3b}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading .badge{color:#f2dede;background-color:#a94442}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ebccd1}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive iframe,.embed-responsive embed,.embed-responsive object,.embed-responsive video{position:absolute;top:0;left:0;bottom:0;height:100%;width:100%;border:0}.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,0.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:bold;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;opacity:.5;filter:alpha(opacity=50)}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.modal-open{overflow:hidden}.modal{display:none;overflow:hidden;position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transform:translate(0, -25%);-ms-transform:translate(0, -25%);-o-transform:translate(0, -25%);transform:translate(0, -25%);-webkit-transition:-webkit-transform 0.3s ease-out;-moz-transition:-moz-transform 0.3s ease-out;-o-transition:-o-transform 0.3s ease-out;transition:transform 0.3s ease-out}.modal.in .modal-dialog{-webkit-transform:translate(0, 0);-ms-transform:translate(0, 0);-o-transform:translate(0, 0);transform:translate(0, 0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,0.2);border-radius:6px;-webkit-box-shadow:0 3px 9px rgba(0,0,0,0.5);box-shadow:0 3px 9px rgba(0,0,0,0.5);background-clip:padding-box;outline:0}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0;filter:alpha(opacity=0)}.modal-backdrop.in{opacity:.5;filter:alpha(opacity=50)}.modal-header{padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-left:5px;margin-bottom:0}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,0.5);box-shadow:0 5px 15px rgba(0,0,0,0.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-style:normal;font-weight:normal;letter-spacing:normal;line-break:auto;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;white-space:normal;word-break:normal;word-spacing:normal;word-wrap:normal;font-size:12px;opacity:0;filter:alpha(opacity=0)}.tooltip.in{opacity:.9;filter:alpha(opacity=90)}.tooltip.top{margin-top:-3px;padding:5px 0}.tooltip.right{margin-left:3px;padding:0 5px}.tooltip.bottom{margin-top:3px;padding:5px 0}.tooltip.left{margin-left:-3px;padding:0 5px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{bottom:0;right:5px;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{bottom:0;left:5px;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;right:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;left:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-style:normal;font-weight:normal;letter-spacing:normal;line-break:auto;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;white-space:normal;word-break:normal;word-spacing:normal;word-wrap:normal;font-size:14px;background-color:#fff;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2)}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{margin:0;padding:8px 14px;font-size:14px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{border-width:10px;content:""}.popover.top>.arrow{left:50%;margin-left:-11px;border-bottom-width:0;border-top-color:#999;border-top-color:rgba(0,0,0,0.25);bottom:-11px}.popover.top>.arrow:after{content:" ";bottom:1px;margin-left:-10px;border-bottom-width:0;border-top-color:#fff}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-left-width:0;border-right-color:#999;border-right-color:rgba(0,0,0,0.25)}.popover.right>.arrow:after{content:" ";left:1px;bottom:-10px;border-left-width:0;border-right-color:#fff}.popover.bottom>.arrow{left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,0.25);top:-11px}.popover.bottom>.arrow:after{content:" ";top:1px;margin-left:-10px;border-top-width:0;border-bottom-color:#fff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,0.25)}.popover.left>.arrow:after{content:" ";right:1px;border-right-width:0;border-left-color:#fff;bottom:-10px}.carousel{position:relative}.carousel-inner{position:relative;overflow:hidden;width:100%}.carousel-inner>.item{display:none;position:relative;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{line-height:1}@media all and (transform-3d),(-webkit-transform-3d){.carousel-inner>.item{-webkit-transition:-webkit-transform 0.6s ease-in-out;-moz-transition:-moz-transform 0.6s ease-in-out;-o-transition:-o-transform 0.6s ease-in-out;transition:transform 0.6s ease-in-out;-webkit-backface-visibility:hidden;-moz-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000px;-moz-perspective:1000px;perspective:1000px}.carousel-inner>.item.next,.carousel-inner>.item.active.right{-webkit-transform:translate3d(100%, 0, 0);transform:translate3d(100%, 0, 0);left:0}.carousel-inner>.item.prev,.carousel-inner>.item.active.left{-webkit-transform:translate3d(-100%, 0, 0);transform:translate3d(-100%, 0, 0);left:0}.carousel-inner>.item.next.left,.carousel-inner>.item.prev.right,.carousel-inner>.item.active{-webkit-transform:translate3d(0, 0, 0);transform:translate3d(0, 0, 0);left:0}}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;left:0;bottom:0;width:15%;opacity:.5;filter:alpha(opacity=50);font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,0.6);background-color:rgba(0,0,0,0)}.carousel-control.left{background-image:-webkit-linear-gradient(left, rgba(0,0,0,0.5) 0, rgba(0,0,0,0.0001) 100%);background-image:-o-linear-gradient(left, rgba(0,0,0,0.5) 0, rgba(0,0,0,0.0001) 100%);background-image:linear-gradient(to right, rgba(0,0,0,0.5) 0, rgba(0,0,0,0.0001) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1)}.carousel-control.right{left:auto;right:0;background-image:-webkit-linear-gradient(left, rgba(0,0,0,0.0001) 0, rgba(0,0,0,0.5) 100%);background-image:-o-linear-gradient(left, rgba(0,0,0,0.0001) 0, rgba(0,0,0,0.5) 100%);background-image:linear-gradient(to right, rgba(0,0,0,0.0001) 0, rgba(0,0,0,0.5) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1)}.carousel-control:hover,.carousel-control:focus{outline:0;color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}.carousel-control .icon-prev,.carousel-control .icon-next,.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right{position:absolute;top:50%;margin-top:-10px;z-index:5;display:inline-block}.carousel-control .icon-prev,.carousel-control .glyphicon-chevron-left{left:50%;margin-left:-10px}.carousel-control .icon-next,.carousel-control .glyphicon-chevron-right{right:50%;margin-right:-10px}.carousel-control .icon-prev,.carousel-control .icon-next{width:20px;height:20px;line-height:1;font-family:serif}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;margin-left:-30%;padding-left:0;list-style:none;text-align:center}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;border:1px solid #fff;border-radius:10px;cursor:pointer;background-color:#000 \9;background-color:rgba(0,0,0,0)}.carousel-indicators .active{margin:0;width:12px;height:12px;background-color:#fff}.carousel-caption{position:absolute;left:15%;right:15%;bottom:20px;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,0.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-prev,.carousel-control .icon-next{width:30px;height:30px;margin-top:-10px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-10px}.carousel-caption{left:20%;right:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.clearfix:before,.clearfix:after,.dl-horizontal dd:before,.dl-horizontal dd:after,.container:before,.container:after,.container-fluid:before,.container-fluid:after,.row:before,.row:after,.form-horizontal .form-group:before,.form-horizontal .form-group:after,.btn-toolbar:before,.btn-toolbar:after,.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after,.nav:before,.nav:after,.navbar:before,.navbar:after,.navbar-header:before,.navbar-header:after,.navbar-collapse:before,.navbar-collapse:after,.pager:before,.pager:after,.panel-body:before,.panel-body:after,.modal-header:before,.modal-header:after,.modal-footer:before,.modal-footer:after{content:" ";display:table}.clearfix:after,.dl-horizontal dd:after,.container:after,.container-fluid:after,.row:after,.form-horizontal .form-group:after,.btn-toolbar:after,.btn-group-vertical>.btn-group:after,.nav:after,.navbar:after,.navbar-header:after,.navbar-collapse:after,.pager:after,.panel-body:after,.modal-header:after,.modal-footer:after{clear:both}.center-block{display:block;margin-left:auto;margin-right:auto}.pull-right{float:right !important}.pull-left{float:left !important}.hide{display:none !important}.show{display:block !important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none !important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-xs,.visible-sm,.visible-md,.visible-lg{display:none !important}.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block{display:none !important}@media (max-width:767px){.visible-xs{display:block !important}table.visible-xs{display:table !important}tr.visible-xs{display:table-row !important}th.visible-xs,td.visible-xs{display:table-cell !important}}@media (max-width:767px){.visible-xs-block{display:block !important}}@media (max-width:767px){.visible-xs-inline{display:inline !important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block !important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block !important}table.visible-sm{display:table !important}tr.visible-sm{display:table-row !important}th.visible-sm,td.visible-sm{display:table-cell !important}}@media (min-width:768px) and (max-width:991px){.visible-sm-block{display:block !important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline{display:inline !important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline-block{display:inline-block !important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block !important}table.visible-md{display:table !important}tr.visible-md{display:table-row !important}th.visible-md,td.visible-md{display:table-cell !important}}@media (min-width:992px) and (max-width:1199px){.visible-md-block{display:block !important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline{display:inline !important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline-block{display:inline-block !important}}@media (min-width:1200px){.visible-lg{display:block !important}table.visible-lg{display:table !important}tr.visible-lg{display:table-row !important}th.visible-lg,td.visible-lg{display:table-cell !important}}@media (min-width:1200px){.visible-lg-block{display:block !important}}@media (min-width:1200px){.visible-lg-inline{display:inline !important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block !important}}@media (max-width:767px){.hidden-xs{display:none !important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none !important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none !important}}@media (min-width:1200px){.hidden-lg{display:none !important}}.visible-print{display:none !important}@media print{.visible-print{display:block !important}table.visible-print{display:table !important}tr.visible-print{display:table-row !important}th.visible-print,td.visible-print{display:table-cell !important}}.visible-print-block{display:none !important}@media print{.visible-print-block{display:block !important}}.visible-print-inline{display:none !important}@media print{.visible-print-inline{display:inline !important}}.visible-print-inline-block{display:none !important}@media print{.visible-print-inline-block{display:inline-block !important}}@media print{.hidden-print{display:none !important}}.panel-definition{border-color:#a2a2a2}.panel-definition>.panel-heading{color:#000;background-color:#eee;border-color:#a2a2a2}.panel-definition>.panel-heading+.panel-collapse>.panel-body{border-top-color:#a2a2a2}.panel-definition>.panel-heading .badge{color:#eee;background-color:#000}.panel-definition>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#a2a2a2}.json-schema-description:before{font-weight:bold;color:#555;text-transform:uppercase;content:"Description";padding-bottom:.5em;display:block}.json-schema-description:not(:last-child){padding-bottom:1.5em}.json-schema-properties:before{font-weight:bold;color:#555;text-transform:uppercase;content:"Properties";padding-bottom:.5em;display:block}.json-schema-properties:not(:last-child){padding-bottom:1.5em}.json-schema-properties dd:not(:last-child){padding-bottom:1em}.json-schema-properties dl{margin:0}.json-schema-example:before{font-weight:bold;color:#555;text-transform:uppercase;content:"Example";padding-bottom:.5em;display:block}.json-schema-example:not(:last-child){padding-bottom:1.5em}.json-schema-array-items:before{font-weight:bold;color:#555;text-transform:uppercase;content:"Items";padding-bottom:.5em;display:block}.json-schema-array-items:not(:last-child){padding-bottom:1.5em}.json-schema-allOf-inherited:before{font-weight:bold;color:#555;text-transform:uppercase;content:"Inherited";padding-bottom:.5em;display:block}.json-schema-allOf-inherited:not(:last-child){padding-bottom:1.5em}.json-schema-allOf-inherited ul{padding-left:0;list-style:none}.json-schema-anyOf>dl{border-left:2px solid #a2a2a2;padding-left:1em}.json-schema-anyOf>dl dt:not(:first-child):before{content:"or "}.json-schema-anyOf>dl dt:first-child:before{content:"either "}.json-schema-additionalProperties:before{font-weight:bold;color:#555;text-transform:uppercase;content:"Additional properties";padding-bottom:.5em;display:block}.json-schema-additionalProperties:not(:last-child){padding-bottom:1.5em}.json-inner-schema .json-schema-properties,.json-inner-schema .json-schema-array-items,.json-inner-schema .json-schema-description,.json-inner-schema .json-schema-example{padding-left:1em;margin-top:.5em;padding-bottom:.5em;border-left:2px solid #a2a2a2}.json-property-discriminator:before{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:bold;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em;background-color:#777;content:"discriminator"}a.json-property-discriminator:before:hover,a.json-property-discriminator:before:focus{color:#fff;text-decoration:none;cursor:pointer}.json-property-discriminator:before:empty{display:none}.btn .json-property-discriminator:before{position:relative;top:-1px}.json-property-discriminator:before[href]:hover,.json-property-discriminator:before[href]:focus{background-color:#5e5e5e}.json-property-required:before{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:bold;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em;background-color:#777;content:"required"}a.json-property-required:before:hover,a.json-property-required:before:focus{color:#fff;text-decoration:none;cursor:pointer}.json-property-required:before:empty{display:none}.btn .json-property-required:before{position:relative;top:-1px}.json-property-required:before[href]:hover,.json-property-required:before[href]:focus{background-color:#5e5e5e}.json-property-read-only:before{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:bold;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em;background-color:#777;content:"read only"}a.json-property-read-only:before:hover,a.json-property-read-only:before:focus{color:#fff;text-decoration:none;cursor:pointer}.json-property-read-only:before:empty{display:none}.btn .json-property-read-only:before{position:relative;top:-1px}.json-property-read-only:before[href]:hover,.json-property-read-only:before[href]:focus{background-color:#5e5e5e}.json-property-type{font-style:italic;font-weight:100}.json-property-format{font-size:smaller}.json-property-enum{font-weight:lighter;font-size:small}.json-property-default-value{font-weight:lighter;font-size:small}.json-property-default-value:before{content:'(default: "'}.json-property-default-value:after{content:'")'}.json-property-enum-item{font-weight:lighter;font-size:small}.json-property-enum-item:before,.json-property-enum-item:after{content:"\""}.json-schema--reference{font-size:90%}.table.swagger--summary>tbody>tr>td.swagger--summary-path{vertical-align:middle}.table.swagger--summary>tbody>tr>td p{margin:0}.swagger--panel-operation-post{border-color:#78cc94}.swagger--panel-operation-post>.panel-heading{color:#333;background-color:#e7f6ec;border-color:#78cc94}.swagger--panel-operation-post>.panel-heading+.panel-collapse>.panel-body{border-top-color:#78cc94}.swagger--panel-operation-post>.panel-heading .badge{color:#e7f6ec;background-color:#333}.swagger--panel-operation-post>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#78cc94}.swagger--panel-operation-post .operation-name{font-weight:bold}.swagger--panel-operation-post .operation-summary{float:right !important}.swagger--panel-operation-get{border-color:#74a8d1}.swagger--panel-operation-get>.panel-heading{color:#333;background-color:#e7f0f7;border-color:#74a8d1}.swagger--panel-operation-get>.panel-heading+.panel-collapse>.panel-body{border-top-color:#74a8d1}.swagger--panel-operation-get>.panel-heading .badge{color:#e7f0f7;background-color:#333}.swagger--panel-operation-get>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#74a8d1}.swagger--panel-operation-get .operation-name{font-weight:bold}.swagger--panel-operation-get .operation-summary{float:right !important}.swagger--panel-operation-put{border-color:#d8ab71}.swagger--panel-operation-put>.panel-heading{color:#333;background-color:#f9f2e9;border-color:#d8ab71}.swagger--panel-operation-put>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d8ab71}.swagger--panel-operation-put>.panel-heading .badge{color:#f9f2e9;background-color:#333}.swagger--panel-operation-put>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d8ab71}.swagger--panel-operation-put .operation-name{font-weight:bold}.swagger--panel-operation-put .operation-summary{float:right !important}.swagger--panel-operation-patch{border-color:#ed7c59}.swagger--panel-operation-patch>.panel-heading{color:#333;background-color:#FCE9E3;border-color:#ed7c59}.swagger--panel-operation-patch>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ed7c59}.swagger--panel-operation-patch>.panel-heading .badge{color:#FCE9E3;background-color:#333}.swagger--panel-operation-patch>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ed7c59}.swagger--panel-operation-patch .operation-name{font-weight:bold}.swagger--panel-operation-patch .operation-summary{float:right !important}.swagger--panel-operation-options{border-color:#74a8d1}.swagger--panel-operation-options>.panel-heading{color:#333;background-color:#e7f0f7;border-color:#74a8d1}.swagger--panel-operation-options>.panel-heading+.panel-collapse>.panel-body{border-top-color:#74a8d1}.swagger--panel-operation-options>.panel-heading .badge{color:#e7f0f7;background-color:#333}.swagger--panel-operation-options>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#74a8d1}.swagger--panel-operation-options .operation-name{font-weight:bold}.swagger--panel-operation-options .operation-summary{float:right !important}.swagger--panel-operation-delete{border-color:#c77d7d}.swagger--panel-operation-delete>.panel-heading{color:#333;background-color:#f5e8e8;border-color:#c77d7d}.swagger--panel-operation-delete>.panel-heading+.panel-collapse>.panel-body{border-top-color:#c77d7d}.swagger--panel-operation-delete>.panel-heading .badge{color:#f5e8e8;background-color:#333}.swagger--panel-operation-delete>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#c77d7d}.swagger--panel-operation-delete .operation-name{font-weight:bold}.swagger--panel-operation-delete .operation-summary{float:right !important}.swagger--panel-operation-head{border-color:#f3ff34}.swagger--panel-operation-head>.panel-heading{color:#333;background-color:#fcffcd;border-color:#f3ff34}.swagger--panel-operation-head>.panel-heading+.panel-collapse>.panel-body{border-top-color:#f3ff34}.swagger--panel-operation-head>.panel-heading .badge{color:#fcffcd;background-color:#333}.swagger--panel-operation-head>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#f3ff34}.swagger--panel-operation-head .operation-name{font-weight:bold}.swagger--panel-operation-head .operation-summary{float:right !important}.sw-operation-description:before{font-weight:bold;color:#555;text-transform:uppercase;content:"Description";padding-bottom:.5em;display:block}.sw-operation-description:not(:last-child){padding-bottom:1.5em}.sw-request-params:before{font-weight:bold;color:#555;text-transform:uppercase;content:"Request parameters";padding-bottom:.5em;display:block}.sw-request-params:not(:last-child){padding-bottom:1.5em}.sw-request-body:before{font-weight:bold;color:#555;text-transform:uppercase;content:"Request body";padding-bottom:.5em;display:block}.sw-request-body:not(:last-child){padding-bottom:1.5em}.sw-responses:before{font-weight:bold;color:#555;text-transform:uppercase;content:"Responses";padding-bottom:.5em;display:block}.sw-responses:not(:last-child){padding-bottom:1.5em}.swagger--global:before{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:bold;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em;background-color:#777;content:'global'}a.swagger--global:before:hover,a.swagger--global:before:focus{color:#fff;text-decoration:none;cursor:pointer}.swagger--global:before:empty{display:none}.btn .swagger--global:before{position:relative;top:-1px}.swagger--global:before[href]:hover,.swagger--global:before[href]:focus{background-color:#5e5e5e}table.table th.sw-param-key{width:auto}table.table th.sw-param-key:before{content:"Key"}table.table th.sw-param-name{width:auto}table.table th.sw-param-name:before{content:"Name"}table.table th.sw-param-description{width:auto}table.table th.sw-param-description:before{content:"Description"}table.table th.sw-param-data-type{width:auto}table.table th.sw-param-data-type:before{content:"Data type"}table.table th.sw-param-type{width:auto}table.table th.sw-param-type:before{content:"Type"}table.table th.sw-request-security-schema{width:auto}table.table th.sw-request-security-schema:before{content:"Schema"}table.table th.sw-request-security-scopes{width:auto}table.table th.sw-request-security-scopes:before{content:"Scopes"}table.table th.sw-response-header-name{width:auto}table.table th.sw-response-header-name:before{content:"Header"}table.table th.sw-response-header-description{width:auto}table.table th.sw-response-header-description:before{content:"Description"}table.table th.sw-response-header-data-type{width:auto}table.table th.sw-response-header-data-type:before{content:"Data type"}.sw-response-name-value{font-weight:bold}.sw-response-description-text{padding-bottom:.5em}code.highlight{padding:0}.panel-security-definition{border-color:#a2a2a2}.panel-security-definition>.panel-heading{color:#000;background-color:#eee;border-color:#a2a2a2}.panel-security-definition>.panel-heading+.panel-collapse>.panel-body{border-top-color:#a2a2a2}.panel-security-definition>.panel-heading .badge{color:#eee;background-color:#000}.panel-security-definition>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#a2a2a2}.sw-request-security:before{font-weight:bold;color:#555;text-transform:uppercase;content:"Security";padding-bottom:.5em;display:block}.sw-request-security:not(:last-child){padding-bottom:1.5em}.sw-security-definition-basic:before{color:#555;font-size:smaller;content:"(HTTP Basic Authentication)"}span.sw-default-value-header{font-weight:bold}.sw-info-version{font-weight:bold}.sw-info-version span{font-family:monospace;font-weight:normal;font-size:1.1em}</style> + + <meta charset="UTF-8"> + <title>Active and Available Inventory REST API.</title> +</head> +<body> +<div class="container"> + <h1>Active and Available Inventory REST API.</h1> + <p class="sw-info-version">Version: <span>${version}</span></p> + <p><p>${description}</p> + </p> + + <div id="sw-schemes" class="sw-default-value"> + <span class="sw-default-value-header">Schemes:</span> + https + </div> + + <h2 id="swagger--summary-tags">Summary</h2> + <ol> + <#list aaiApis?keys as key> + <li><a href="#tag-${key}">Tag: ${key}</a> + </#list> + <li><a href="#Paths">Paths</a> + <li><a href="#SchemaDefinitions">Schema definitions</a> + </ol> + + <#list aaiApis?keys as key> + <h3 id="tag-${key}" class="swagger-summary-tag">Tag: ${key}</h3> + <table class="table table-bordered table-condensed swagger--summary"> + <thead><tr> + <th>Operation</th><th>Description</th> + </tr></thead> + <tbody> + <#list aaiApis[key] as api> + <#list api.getHttpMethods() as httpVerb> + <tr><td><a href="#operation-${api.getOperation()}${httpVerb.getType()}"> + ${httpVerb.getType()?upper_case} ${api.getPath()}</a></td> + <td><p>${httpVerb.getSummary()}</p></td> + </tr> + </#list> + </#list> + </tbody> + </table> + </#list> + + <h2 id="Paths">Paths</h2> + <#list sortedAaiApis?keys as key> + <#list sortedAaiApis[key] as api> + <#list api.getHttpMethods() as httpVerb> + <span id="path-${api.getOperation()}"></span> + <div id="operation-${api.getOperation()}${httpVerb.getType()}" class="swagger--panel-operation-${httpVerb.getType()} panel"> + <div class="panel-heading"> + <div class="operation-summary">${httpVerb.getSummary()}</div> + <h3 class="panel-title"><span class="operation-name">${httpVerb.getType()?upper_case}</span> + <strong>${api.getPath()}</strong></h3> + Tags: <a href="#tag-${api.getTag()}">${api.getTag()}</a> + </div> + <div class="panel-body"> + <section class="sw-operation-description"> + <p>${httpVerb.getSummary()}</p> + </section> + <#if httpVerb.isConsumerEnabled()> + <section class="sw-request-body"> + <p><span class="label label-default">application/json</span> <span class="label label-default">application/xml</span> </p> + <#if httpVerb.isBodyParametersEnabled()> + <div class="row"> + <div class="col-md-6"> + <p><p>${httpVerb.getBodyParameters()["description"]}</p></p> + </div> + <div class="col-md-6 sw-request-model"> + <div class="panel panel-definition"> + <div class="panel-body"> + <a class="json-schema-ref" href="${httpVerb.getSchemaLink()}">${httpVerb.getSchemaType()}</a> + </div></div></div></div> + </#if> + </section> + </#if> + <#if httpVerb.isParametersEnabled()> + <section class="sw-request-params"> + <table class="table"> + <thead><tr> + <th class="sw-param-name"></th> + <th class="sw-param-description"></th> + <th class="sw-param-type"></th> + <th class="sw-param-data-type"></th> + <th class="sw-param-annotation"></th> + </tr></thead> + <tbody> + <#list httpVerb.getParameters() as param> + <tr><td>${param["name"]}</td> + <td> + <#if param['description']??> + <p>${param["description"]}</p> + </#if> + </td> + <td>${param["in"]}</td> + <td> + <#if param['type']??> + <span class="json-property-type">${param["type"]}</span> + <span class="json-property-range" title="Value limits"></span> + </#if> + </td> + <td> + <#if param['required']> + <span class="json-property-required"></span> + </#if> + </td> + </tr> + </#list> + </tbody> + </table></section> + </#if> + + <section class="sw-responses"> + <p><span class="label label-default">application/json</span> <span class="label label-default">application/xml</span> </p> + <dl> + <#list httpVerb.getResponses() as response> + <dt class="sw-response-${response.getResponseCode()}"> + ${response.getResponseCode()} OK + </dt> + <dd class="sw-response-${response.getResponseCode()}"> + <div class="row"><div class="col-md-12"> + <p>successful operation</p> + </div></div> + <div class="row"> + <#if httpVerb.isHasReturnSchema()> + <div class="col-md-6 sw-response-model"> + <div class="panel panel-definition"> + <div class="panel-body"> + <a class="json-schema-ref" href="${httpVerb.getReturnSchemaLink()}">${httpVerb.getReturnSchemaObject()}</a> + </div></div></div> + </#if> + </div> + </dd> + </#list> + <dt class="sw-response-default">default</dt> + <dd class="sw-response-default"> + <div class="row"><div class="col-md-12"> + <p>Response codes found in <a href="${wikiLink}">response codes</a>.</p> + </div></div> + <div class="row"><div class="col-md-6 sw-response-model"></div></div> + </dd> + </dl> + </section> + </div> + </div> + + </#list> + </#list> + </#list> + + <h2 id="SchemaDefinitions">Schema definitions</h2> + <#list definitions as definition> + <div id="definition-${definition.getDefinitionName()}" class="panel panel-definition"> + <div class="panel-heading"><h3 class="panel-title"> + <a name="/definitions/${definition.getDefinitionName()}"></a>${definition.getDefinitionName()}: + <span class="json-property-type"><span class="json-property-type">object</span> + <span class="json-property-range" title="Value limits"></span></span> + </h3></div> + <div class="panel-body"> + <#if definition.isHasDescription()> + <section class="json-schema-description"> + ${definition.getDefinitionDescription()} + </section> + </#if> + <section class="json-schema-properties"><dl> + <#list definition.getRegularPropertyList() as definitionProperty> + <dt data-property-name="${definitionProperty.getPropertyName()}"> + <span class="json-property-name">${definitionProperty.getPropertyName()}:</span> + <#if definitionProperty.isHasType()> + <span class="json-property-type">${definitionProperty.getPropertyType()}</span> + </#if> + <span class="json-property-range" title="Value limits"></span> + <#if definitionProperty.isRequired()> + <span class="json-property-required"></span> + </#if> + </dt> + <dd> + <#if definitionProperty.isHasPropertyDescription()> + <p>${definitionProperty.getPropertyDescription()}</p> + </#if> + <div class="json-inner-schema"></div> + </dd> + </#list> + <#list definition.getSchemaPropertyList() as definitionProperty> + <dt data-property-name="${definitionProperty.getPropertyName()}"> + <span class="json-property-name">${definitionProperty.getPropertyName()}:</span> + <#if definitionProperty.isHasType()> + <span class="json-property-type">${definitionProperty.getPropertyType()}</span> + </#if> + <span class="json-property-range" title="Value limits"></span> + <#if definitionProperty.isRequired()> + <span class="json-property-required"></span> + </#if> + </dt> + <dd><div class="json-inner-schema"><section class="json-schema-array-items"> + <span class="json-property-type"> + <a class="json-schema-ref" href="${definitionProperty.getPropertyReference()}">${definitionProperty.getPropertyReferenceObjectName()}</a></span> + <span class="json-property-range" title="Value limits"></span> + <div class="json-inner-schema"></div> + </section></div></dd> + </#list> + </dl></section> + </div></div> + + </#list> +</div> +</body> +</html> diff --git a/aai-core/src/test/java/org/onap/aai/AAISetup.java b/aai-core/src/test/java/org/onap/aai/AAISetup.java index 4bc30b8c..ac9cba68 100644 --- a/aai-core/src/test/java/org/onap/aai/AAISetup.java +++ b/aai-core/src/test/java/org/onap/aai/AAISetup.java @@ -20,15 +20,10 @@ package org.onap.aai; -import java.util.Map; - -import org.junit.Before; +import org.junit.BeforeClass; import org.junit.ClassRule; import org.junit.Rule; -import org.onap.aai.config.ConfigConfiguration; -import org.onap.aai.config.IntrospectionConfig; -import org.onap.aai.config.RestBeanConfig; -import org.onap.aai.config.SpringContextAware; +import org.onap.aai.config.*; import org.onap.aai.edges.EdgeIngestor; import org.onap.aai.introspection.LoaderFactory; import org.onap.aai.introspection.MoxyLoader; @@ -47,13 +42,30 @@ import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit4.rules.SpringClassRule; import org.springframework.test.context.junit4.rules.SpringMethodRule; +import java.util.Map; + @ContextConfiguration( - classes = {ConfigConfiguration.class, AAIConfigTranslator.class, EdgeIngestor.class, EdgeSerializer.class, - NodeIngestor.class, SpringContextAware.class, IntrospectionConfig.class, RestBeanConfig.class}) + classes = { + ConfigConfiguration.class, + AAIConfigTranslator.class, + EdgeIngestor.class, + EdgeSerializer.class, + NodeIngestor.class, + SpringContextAware.class, + IntrospectionConfig.class, + RestBeanConfig.class, + XmlFormatTransformerConfiguration.class + } +) @TestPropertySource( - properties = {"schema.uri.base.path = /aai", "schema.xsd.maxoccurs = 5000", "schema.translator.list=config", - "schema.nodes.location=src/test/resources/onap/oxm", - "schema.edges.location=src/test/resources/onap/dbedgerules"}) + properties = { + "schema.uri.base.path = /aai", + "schema.xsd.maxoccurs = 5000", + "schema.translator.list=config", + "schema.nodes.location=src/test/resources/onap/oxm", + "schema.edges.location=src/test/resources/onap/dbedgerules" + } +) public abstract class AAISetup { @ClassRule @@ -88,8 +100,8 @@ public abstract class AAISetup { protected static final String SERVICE_NAME = "JUNIT"; - @Before - public void setupBundleconfig() throws Exception { + @BeforeClass + public static void setupBundleconfig() throws Exception { System.setProperty("AJSC_HOME", "."); System.setProperty("BUNDLECONFIG_DIR", "src/test/resources/bundleconfig-local"); System.setProperty("aai.service.name", SERVICE_NAME); diff --git a/aai-core/src/test/java/org/onap/aai/DataLinkSetup.java b/aai-core/src/test/java/org/onap/aai/DataLinkSetup.java index f4d62d44..8a093669 100644 --- a/aai-core/src/test/java/org/onap/aai/DataLinkSetup.java +++ b/aai-core/src/test/java/org/onap/aai/DataLinkSetup.java @@ -25,10 +25,7 @@ import java.util.Map; import org.junit.BeforeClass; import org.junit.ClassRule; import org.junit.Rule; -import org.onap.aai.config.ConfigConfiguration; -import org.onap.aai.config.IntrospectionConfig; -import org.onap.aai.config.RestBeanConfig; -import org.onap.aai.config.SpringContextAware; +import org.onap.aai.config.*; import org.onap.aai.edges.EdgeIngestor; import org.onap.aai.introspection.LoaderFactory; import org.onap.aai.introspection.MoxyLoader; @@ -53,7 +50,7 @@ import org.springframework.test.context.junit4.rules.SpringMethodRule; @ContextConfiguration( classes = {ConfigConfiguration.class, TestUtilConfigTranslatorforDataLink.class, EdgeIngestor.class, EdgeSerializer.class, NodeIngestor.class, SpringContextAware.class, IntrospectionConfig.class, - RestBeanConfig.class}) + RestBeanConfig.class, XmlFormatTransformerConfiguration.class}) @TestPropertySource( properties = {"schema.uri.base.path = /aai", "schema.xsd.maxoccurs = 5000", "schema.version.api.default = v4", "schema.version.edge.label.start = v4", "schema.version.depth.start = v3", diff --git a/aai-core/src/test/java/org/onap/aai/HttpTestUtil.java b/aai-core/src/test/java/org/onap/aai/HttpTestUtil.java index 6a9e7256..588cbc95 100644 --- a/aai-core/src/test/java/org/onap/aai/HttpTestUtil.java +++ b/aai-core/src/test/java/org/onap/aai/HttpTestUtil.java @@ -20,32 +20,20 @@ package org.onap.aai; -import static org.mockito.Matchers.anyObject; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.when; - -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; - -import java.io.UnsupportedEncodingException; -import java.net.URI; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - -import javax.ws.rs.core.*; - +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.javatuples.Pair; import org.mockito.Mockito; import org.onap.aai.config.SpringContextAware; -import org.onap.aai.dbmap.DBConnectionType; import org.onap.aai.exceptions.AAIException; import org.onap.aai.introspection.Introspector; import org.onap.aai.introspection.Loader; +import org.onap.aai.introspection.LoaderFactory; import org.onap.aai.parsers.query.QueryParser; import org.onap.aai.parsers.uri.URIToObject; import org.onap.aai.rest.db.DBRequest; import org.onap.aai.rest.db.HttpEntry; +import org.onap.aai.rest.ueb.UEBNotification; import org.onap.aai.restcore.HttpMethod; import org.onap.aai.restcore.RESTAPI; import org.onap.aai.serialization.engines.QueryStyle; @@ -53,15 +41,24 @@ import org.onap.aai.serialization.engines.TransactionalGraphEngine; import org.onap.aai.setup.SchemaVersion; import org.onap.aai.setup.SchemaVersions; +import javax.ws.rs.core.*; +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.util.*; + +import static org.mockito.Matchers.anyObject; +import static org.mockito.Mockito.*; + public class HttpTestUtil extends RESTAPI { protected HttpEntry traversalHttpEntry; protected HttpEntry traversalUriHttpEntry; - private static final EELFLogger logger = EELFManager.getInstance().getLogger(HttpTestUtil.class); + private static final Logger logger = LoggerFactory.getLogger(HttpTestUtil.class); protected static final MediaType APPLICATION_JSON = MediaType.valueOf("application/json"); + protected static final MediaType APPLICATION_XML = MediaType.valueOf("application/xml"); private static final String EMPTY = ""; private final QueryStyle queryStyle; @@ -74,12 +71,40 @@ public class HttpTestUtil extends RESTAPI { protected List<String> aaiRequestContextList; protected List<MediaType> outputMediaTypes; + protected LoaderFactory loaderFactory; + protected SchemaVersions schemaVersions; + protected UEBNotification notification; + protected int notificationDepth; + protected String acceptType; public HttpTestUtil(QueryStyle qs) { + this(qs, "application/json"); + } + + public HttpTestUtil(QueryStyle qs, String acceptType) { this.queryStyle = qs; traversalHttpEntry = SpringContextAware.getBean("traversalUriHttpEntry", HttpEntry.class); traversalUriHttpEntry = SpringContextAware.getBean("traversalUriHttpEntry", HttpEntry.class); + loaderFactory = SpringContextAware.getBean(LoaderFactory.class); + schemaVersions = (SchemaVersions) SpringContextAware.getBean("schemaVersions"); + notification = null; + this.acceptType = acceptType; + } + + public HttpTestUtil(QueryStyle qs, UEBNotification uebNotification, int notificationDepth) { + this(qs, uebNotification, notificationDepth, "application/json"); + } + + public HttpTestUtil(QueryStyle qs, UEBNotification uebNotification, int notificationDepth, String acceptType) { + this.queryStyle = qs; + this.traversalHttpEntry = SpringContextAware.getBean("traversalUriHttpEntry", HttpEntry.class); + this.traversalUriHttpEntry = SpringContextAware.getBean("traversalUriHttpEntry", HttpEntry.class); + this.loaderFactory = SpringContextAware.getBean(LoaderFactory.class); + this.schemaVersions = (SchemaVersions) SpringContextAware.getBean("schemaVersions"); + this.notification = uebNotification; + this.notificationDepth = notificationDepth; + this.acceptType = acceptType; } public void init() { @@ -93,11 +118,15 @@ public class HttpTestUtil extends RESTAPI { headersMultiMap.add("X-FromAppId", "JUNIT"); headersMultiMap.add("X-TransactionId", UUID.randomUUID().toString()); headersMultiMap.add("Real-Time", "true"); - headersMultiMap.add("Accept", "application/json"); + headersMultiMap.add("Accept", acceptType); headersMultiMap.add("aai-request-context", ""); outputMediaTypes = new ArrayList<>(); - outputMediaTypes.add(APPLICATION_JSON); + if(acceptType.equals("application/json")){ + outputMediaTypes.add(APPLICATION_JSON); + } else { + outputMediaTypes.add(APPLICATION_XML); + } aaiRequestContextList = new ArrayList<>(); aaiRequestContextList.add(""); @@ -112,9 +141,127 @@ public class HttpTestUtil extends RESTAPI { doReturn(null).when(queryParameters).remove(anyObject()); when(httpHeaders.getMediaType()).thenReturn(APPLICATION_JSON); + + try { + if(notification != null){ + doNothing().when(notification).triggerEvents(); + } + } catch (AAIException e) { + e.printStackTrace(); + } } public Response doPut(String uri, String payload) throws UnsupportedEncodingException, AAIException { + Map<String, String> puts = new HashMap<>(); + puts.put(uri, payload); + return this.doPut(puts); + } + + public Response doPut(Map<String, String> uriPayload) throws UnsupportedEncodingException, AAIException { + + this.init(); + Response response = null; + boolean success = true; + TransactionalGraphEngine dbEngine = null; + + try { + + List<DBRequest> dbRequestList = new ArrayList<>(); + for(Map.Entry<String, String> entry : uriPayload.entrySet()){ + + String uri = entry.getKey(); + String payload = entry.getValue(); + if (uri.startsWith("/aai/")) { + uri = uri.substring(5); + } + + logger.info("Starting the put request for the uri {} with payload {}", uri, payload); + + String[] arr = uri.split("/"); + + SchemaVersion version = null; + + if (arr.length > 1) { + if (arr[0].matches("^v\\d+")) { + version = new SchemaVersion(arr[0]); + uri = uri.replaceAll("^v\\d+", ""); + } + } + + if (version == null) { + version = schemaVersions.getDefaultVersion(); + } + Mockito.when(uriInfo.getPath()).thenReturn(uri); + + if(notification != null){ + traversalHttpEntry.setHttpEntryProperties(version, notification, notificationDepth); + } else { + traversalHttpEntry.setHttpEntryProperties(version); + } + Loader loader = traversalHttpEntry.getLoader(); + dbEngine = traversalHttpEntry.getDbEngine(); + + URI uriObject = UriBuilder.fromPath(uri).build(); + URIToObject uriToObject = new URIToObject(loader, uriObject); + + String objType = uriToObject.getEntityName(); + QueryParser uriQuery = dbEngine.getQueryBuilder().createQueryFromURI(uriObject); + + logger.info("Unmarshalling the payload to this {}", objType); + + Introspector obj; + HttpMethod httpMethod; + if (uri.contains("/relationship-list/relationship")) { + obj = loader.unmarshal("relationship", payload, + org.onap.aai.restcore.MediaType.getEnum("application/json")); + httpMethod = HttpMethod.PUT_EDGE; + } else { + obj = loader.unmarshal(objType, payload, org.onap.aai.restcore.MediaType.getEnum("application/json")); + httpMethod = HttpMethod.PUT; + this.validateIntrospector(obj, loader, uriObject, httpMethod); + } + + DBRequest dbRequest = new DBRequest.Builder(httpMethod, uriObject, uriQuery, obj, httpHeaders, uriInfo, + "JUNIT-TRANSACTION").rawRequestContent(payload).build(); + + dbRequestList.add(dbRequest); + + } + + Pair<Boolean, List<Pair<URI, Response>>> responsesTuple = + traversalHttpEntry.process(dbRequestList, "JUNIT"); + response = responsesTuple.getValue1().get(0).getValue1(); + + } catch (AAIException e) { + response = this.consumerExceptionResponseGenerator(httpHeaders, uriInfo, HttpMethod.PUT, e); + success = false; + } catch (Exception e) { + AAIException ex = new AAIException("AAI_4000", e); + response = this.consumerExceptionResponseGenerator(httpHeaders, uriInfo, HttpMethod.PUT, ex); + success = false; + } finally { + if (success) { + if (response != null) { + if ((response.getStatus() / 100) == 2) { + logger.info("Successfully completed the PUT request with status {} and committing it to DB", + response.getStatus()); + } else { + logFailure(HttpMethod.PUT, response); + } + } + dbEngine.commit(); + } else { + if (response != null) { + logFailure(HttpMethod.PUT, response); + } + dbEngine.rollback(); + } + } + + return response; + } + + public Response doPatch(String uri, String payload) throws UnsupportedEncodingException, AAIException { this.init(); Response response = null; @@ -133,22 +280,23 @@ public class HttpTestUtil extends RESTAPI { SchemaVersion version = null; - if (arr != null && arr.length > 1) { + if (arr.length > 1) { if (arr[0].matches("^v\\d+")) { version = new SchemaVersion(arr[0]); uri = uri.replaceAll("^v\\d+", ""); } } - SchemaVersions schemaVersions = (SchemaVersions) SpringContextAware.getBean("schemaVersions"); if (version == null) { version = schemaVersions.getDefaultVersion(); } Mockito.when(uriInfo.getPath()).thenReturn(uri); - DBConnectionType type = DBConnectionType.REALTIME; - - traversalHttpEntry.setHttpEntryProperties(version, type); + if(notification != null){ + traversalHttpEntry.setHttpEntryProperties(version, notification, notificationDepth); + } else { + traversalHttpEntry.setHttpEntryProperties(version); + } Loader loader = traversalHttpEntry.getLoader(); dbEngine = traversalHttpEntry.getDbEngine(); @@ -162,24 +310,18 @@ public class HttpTestUtil extends RESTAPI { Introspector obj; HttpMethod httpMethod; - if (uri.contains("/relationship-list/relationship")) { - obj = loader.unmarshal("relationship", payload, - org.onap.aai.restcore.MediaType.getEnum("application/json")); - httpMethod = HttpMethod.PUT_EDGE; - } else { - obj = loader.unmarshal(objType, payload, org.onap.aai.restcore.MediaType.getEnum("application/json")); - httpMethod = HttpMethod.PUT; - this.validateIntrospector(obj, loader, uriObject, httpMethod); - } + obj = loader.unmarshal(objType, payload, org.onap.aai.restcore.MediaType.getEnum("application/json")); + httpMethod = HttpMethod.MERGE_PATCH; + this.validateIntrospector(obj, loader, uriObject, httpMethod); DBRequest dbRequest = new DBRequest.Builder(httpMethod, uriObject, uriQuery, obj, httpHeaders, uriInfo, - "JUNIT-TRANSACTION").rawRequestContent(payload).build(); + "JUNIT-TRANSACTION").rawRequestContent(payload).build(); List<DBRequest> dbRequestList = new ArrayList<>(); dbRequestList.add(dbRequest); Pair<Boolean, List<Pair<URI, Response>>> responsesTuple = - traversalHttpEntry.process(dbRequestList, "JUNIT"); + traversalHttpEntry.process(dbRequestList, "JUNIT"); response = responsesTuple.getValue1().get(0).getValue1(); } catch (AAIException e) { @@ -194,7 +336,7 @@ public class HttpTestUtil extends RESTAPI { if (response != null) { if ((response.getStatus() / 100) == 2) { logger.info("Successfully completed the PUT request with status {} and committing it to DB", - response.getStatus()); + response.getStatus()); } else { logFailure(HttpMethod.PUT, response); } @@ -211,7 +353,11 @@ public class HttpTestUtil extends RESTAPI { return response; } - public Response doGet(String uri, String depth) { + public Response doGet(String uri, String depth){ + return doGet(uri, depth, null); + } + + public Response doGet(String uri, String depth, String format) { this.init(); Response response = null; @@ -230,20 +376,22 @@ public class HttpTestUtil extends RESTAPI { SchemaVersion version = null; - if (arr != null && arr.length > 1) { + if (arr.length > 1) { if (arr[0].matches("^v\\d+")) { version = new SchemaVersion(arr[0]); uri = uri.replaceAll("^v\\d+", ""); } } - SchemaVersions schemaVersions = (SchemaVersions) SpringContextAware.getBean("schemaVersions"); if (version == null) { version = schemaVersions.getDefaultVersion(); } - DBConnectionType type = DBConnectionType.REALTIME; - traversalHttpEntry.setHttpEntryProperties(version, type); + if(notification != null){ + traversalHttpEntry.setHttpEntryProperties(version, notification, notificationDepth); + } else { + traversalHttpEntry.setHttpEntryProperties(version); + } Loader loader = traversalHttpEntry.getLoader(); dbEngine = traversalHttpEntry.getDbEngine(); @@ -253,6 +401,10 @@ public class HttpTestUtil extends RESTAPI { queryParameters.add("depth", depth); } + if(format != null){ + queryParameters.add("format", format); + } + QueryParser uriQuery = dbEngine.getQueryBuilder().createQueryFromURI(uriObject, queryParameters); Mockito.when(uriInfo.getPath()).thenReturn(uri); @@ -309,7 +461,7 @@ public class HttpTestUtil extends RESTAPI { return this.doGet(uri, "all"); } - public Response doDelete(String uri, String resourceVersion) throws UnsupportedEncodingException, AAIException { + public Response doDelete(Map<String, Pair<String, String>> deletes){ this.init(); Response response = null; @@ -318,77 +470,81 @@ public class HttpTestUtil extends RESTAPI { try { - uri = uri.replaceAll("/aai/", ""); - logger.info("Starting the delete request for the uri {} with resource version {}", uri, resourceVersion); + List<DBRequest> dbRequestList = new ArrayList<>(); + for (Map.Entry<String, Pair<String, String>> delete : deletes.entrySet()) { + String uri = delete.getKey(); + String resourceVersion = delete.getValue().getValue0(); + String content = delete.getValue().getValue1(); + uri = uri.replaceAll("/aai/", ""); + logger.info("Starting the delete request for the uri {} with resource version {}", uri, resourceVersion); - String[] arr = uri.split("/"); + String[] arr = uri.split("/"); - SchemaVersion version = null; + SchemaVersion version = null; - if (arr != null && arr.length > 1) { - if (arr[0].matches("^v\\d+")) { - version = new SchemaVersion(arr[0]); - if (!uri.contains("relationship-list/relationship")) { + if (arr.length > 1) { + if (arr[0].matches("^v\\d+")) { + version = new SchemaVersion(arr[0]); uri = uri.replaceAll("^v\\d+", ""); } } - } - SchemaVersions schemaVersions = (SchemaVersions) SpringContextAware.getBean("schemaVersions"); - if (version == null) { - version = schemaVersions.getDefaultVersion(); - } + if (version == null) { + version = schemaVersions.getDefaultVersion(); + } - Mockito.when(uriInfo.getPath()).thenReturn(uri); - DBConnectionType type = DBConnectionType.REALTIME; - traversalHttpEntry.setHttpEntryProperties(version, type); + Mockito.when(uriInfo.getPath()).thenReturn(uri); + if (notification != null) { + traversalHttpEntry.setHttpEntryProperties(version, notification, notificationDepth); + } else { + traversalHttpEntry.setHttpEntryProperties(version); + } + Loader loader = traversalHttpEntry.getLoader(); + dbEngine = traversalHttpEntry.getDbEngine(); - traversalHttpEntry.setHttpEntryProperties(version, type); - Loader loader = traversalHttpEntry.getLoader(); - dbEngine = traversalHttpEntry.getDbEngine(); + URI uriObject = UriBuilder.fromPath(uri).build(); + URIToObject uriToObject = new URIToObject(loader, uriObject); - URI uriObject = UriBuilder.fromPath(uri).build(); - URIToObject uriToObject = new URIToObject(loader, uriObject); + String objType = uriToObject.getEntityName(); + queryParameters.add("resource-version", resourceVersion); + QueryParser uriQuery = dbEngine.getQueryBuilder().createQueryFromURI(uriObject, queryParameters); - String objType = uriToObject.getEntityName(); - queryParameters.add("resource-version", resourceVersion); - QueryParser uriQuery = dbEngine.getQueryBuilder().createQueryFromURI(uriObject, queryParameters); + logger.info("Unmarshalling the payload to this {}", objType); - logger.info("Unmarshalling the payload to this {}", objType); + Introspector obj; - Introspector obj; - HttpMethod httpMethod; - if (uri.contains("/relationship-list/relationship")) { - obj = loader.introspectorFromName("relationship"); - httpMethod = HttpMethod.DELETE_EDGE; - } else { - obj = loader.introspectorFromName(objType); - httpMethod = HttpMethod.DELETE; - } + HttpMethod httpMethod; - DBRequest dbRequest = new DBRequest.Builder(httpMethod, uriObject, uriQuery, obj, httpHeaders, uriInfo, - "JUNIT-TRANSACTION").build(); + if (uri.contains("/relationship-list/relationship")) { + httpMethod = HttpMethod.DELETE_EDGE; + obj = loader.unmarshal("relationship", content, org.onap.aai.restcore.MediaType.getEnum("application/json")); + } else { + obj = loader.introspectorFromName(objType); + httpMethod = HttpMethod.DELETE; + } - List<DBRequest> dbRequestList = new ArrayList<>(); - dbRequestList.add(dbRequest); + DBRequest dbRequest = new DBRequest.Builder(httpMethod, uriObject, uriQuery, obj, httpHeaders, uriInfo, "JUNIT-TRANSACTION").build(); + + dbRequestList.add(dbRequest); + } Pair<Boolean, List<Pair<URI, Response>>> responsesTuple = - traversalHttpEntry.process(dbRequestList, "JUNIT"); + traversalHttpEntry.process(dbRequestList, "JUNIT"); response = responsesTuple.getValue1().get(0).getValue1(); } catch (AAIException e) { - response = this.consumerExceptionResponseGenerator(httpHeaders, uriInfo, HttpMethod.PUT, e); + response = this.consumerExceptionResponseGenerator(httpHeaders, uriInfo, HttpMethod.DELETE, e); success = false; } catch (Exception e) { AAIException ex = new AAIException("AAI_4000", e); - response = this.consumerExceptionResponseGenerator(httpHeaders, uriInfo, HttpMethod.PUT, ex); + response = this.consumerExceptionResponseGenerator(httpHeaders, uriInfo, HttpMethod.DELETE, ex); success = false; } finally { if (success) { if (response != null) { if ((response.getStatus() / 100) == 2) { logger.info("Successfully completed the DELETE request with status {} and committing it to DB", - response.getStatus()); + response.getStatus()); } else { logFailure(HttpMethod.DELETE, response); } @@ -403,6 +559,15 @@ public class HttpTestUtil extends RESTAPI { return response; } + public Response doDelete(String uri, String resourceVersion) { + return this.doDelete(uri, resourceVersion, null); + } + public Response doDelete(String uri, String resourceVersion, String content) { + Map<String, Pair<String, String>> deletes = new HashMap<>(); + deletes.put(uri, new Pair<>(resourceVersion, content)); + return this.doDelete(deletes); + } + public static void logFailure(HttpMethod httpMethod, Response response) { logger.info("Unable to complete the {} request with status {} and rolling back", httpMethod.toString(), response.getStatus()); diff --git a/aai-core/src/test/java/org/onap/aai/dbmap/AAIGraphTest.java b/aai-core/src/test/java/org/onap/aai/dbmap/AAIGraphTest.java index 48d2583d..f2c7b27c 100644 --- a/aai-core/src/test/java/org/onap/aai/dbmap/AAIGraphTest.java +++ b/aai-core/src/test/java/org/onap/aai/dbmap/AAIGraphTest.java @@ -20,17 +20,6 @@ package org.onap.aai.dbmap; -import static org.hamcrest.CoreMatchers.containsString; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.Matchers.matchesPattern; -import static org.junit.Assert.*; - -import java.io.FileNotFoundException; -import java.util.HashSet; -import java.util.Map; -import java.util.Optional; -import java.util.Set; - import org.janusgraph.core.JanusGraph; import org.janusgraph.core.JanusGraphFactory; import org.janusgraph.core.schema.JanusGraphIndex; @@ -48,6 +37,17 @@ import org.onap.aai.schema.enums.PropertyMetadata; import org.onap.aai.setup.SchemaVersions; import org.onap.aai.util.AAIConstants; +import java.io.FileNotFoundException; +import java.util.HashSet; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.Matchers.matchesPattern; +import static org.junit.Assert.*; + public class AAIGraphTest extends AAISetup { @Before public void setup() { @@ -67,21 +67,9 @@ public class AAIGraphTest extends AAISetup { graphMgt.rollback(); } - @Test - public void getCachedInstanceConnectionName() throws Exception { - - JanusGraphManagement graphMgt = AAIGraph.getInstance().getGraph(DBConnectionType.CACHED).openManagement(); - String connectionInstanceName = - graphMgt.getOpenInstances().stream().filter(c -> c.contains("current")).findFirst().get(); - assertThat(connectionInstanceName, containsString(SERVICE_NAME)); - assertThat(connectionInstanceName, containsString("cached")); - assertThat(connectionInstanceName, - matchesPattern("^\\d+_[\\w\\-\\d]+_" + SERVICE_NAME + "_cached_\\d+\\(current\\)$")); - graphMgt.rollback(); - } @Test - public void JanusGraphOpenNameTest() throws Exception { + public void janusGraphOpenNameTest() throws Exception { JanusGraph graph = JanusGraphFactory.open(new AAIGraphConfig.Builder(AAIConstants.REALTIME_DB_CONFIG) .forService(SERVICE_NAME).withGraphType("graphType").buildConfiguration()); JanusGraphManagement graphMgt = graph.openManagement(); @@ -94,7 +82,7 @@ public class AAIGraphTest extends AAISetup { } @Test(expected = FileNotFoundException.class) - public void JanusGraphOpenNameWithInvalidFilePathTest() throws Exception { + public void janusGraphOpenNameWithInvalidFilePathTest() throws Exception { JanusGraph graph = JanusGraphFactory.open(new AAIGraphConfig.Builder("invalid").forService(SERVICE_NAME) .withGraphType("graphType").buildConfiguration()); JanusGraphManagement graphMgt = graph.openManagement(); diff --git a/aai-core/src/test/java/org/onap/aai/introspection/JSONStrategyTest.java b/aai-core/src/test/java/org/onap/aai/introspection/JSONStrategyTest.java index 8b44b312..b684e3fa 100644 --- a/aai-core/src/test/java/org/onap/aai/introspection/JSONStrategyTest.java +++ b/aai-core/src/test/java/org/onap/aai/introspection/JSONStrategyTest.java @@ -20,16 +20,18 @@ package org.onap.aai.introspection; -import java.util.HashSet; -import java.util.Set; - import org.json.simple.JSONArray; import org.json.simple.JSONObject; import org.junit.Assert; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.onap.aai.AAISetup; +import java.util.HashSet; +import java.util.Set; + +@Ignore("Not a used/flushed out feature") public class JSONStrategyTest extends AAISetup { private JSONStrategy jsonStrategy; private JSONStrategy jsonStrategyContainer; diff --git a/aai-core/src/test/java/org/onap/aai/introspection/MoxyEngineTest.java b/aai-core/src/test/java/org/onap/aai/introspection/MoxyEngineTest.java index 0e6a9aab..fe128353 100644 --- a/aai-core/src/test/java/org/onap/aai/introspection/MoxyEngineTest.java +++ b/aai-core/src/test/java/org/onap/aai/introspection/MoxyEngineTest.java @@ -20,6 +20,7 @@ package org.onap.aai.introspection; +import org.junit.Assert; import org.junit.Test; import org.onap.aai.introspection.exceptions.AAIUnknownObjectException; import org.springframework.test.annotation.DirtiesContext; @@ -43,4 +44,23 @@ public class MoxyEngineTest extends IntrospectorTestSpec { } + @Test + public void testDslStartNodeProps() throws AAIUnknownObjectException { + Loader loader = loaderFactory.createLoaderForVersion(ModelType.MOXY, schemaVersions.getDepthVersion()); + Introspector obj = loader.introspectorFromName("pserver"); + Assert.assertFalse(obj.getDslStartNodeProperties().contains("in-maint")); + Assert.assertTrue(obj.getDslStartNodeProperties().contains("pserver-name2")); + + } + + @Test + public void testDslStartNodePropsDefault() throws AAIUnknownObjectException { + /* + * Use indexedprops when there is no dslStartNodeProps + */ + Loader loader = loaderFactory.createLoaderForVersion(ModelType.MOXY, schemaVersions.getDepthVersion()); + Introspector obj = loader.introspectorFromName("vserver"); + Assert.assertTrue(obj.getDslStartNodeProperties().contains("in-maint")); + } + } diff --git a/aai-core/src/test/java/org/onap/aai/introspection/sideeffect/DataCopyTest.java b/aai-core/src/test/java/org/onap/aai/introspection/sideeffect/DataCopyTest.java index 79597355..7dadb14a 100644 --- a/aai-core/src/test/java/org/onap/aai/introspection/sideeffect/DataCopyTest.java +++ b/aai-core/src/test/java/org/onap/aai/introspection/sideeffect/DataCopyTest.java @@ -20,19 +20,6 @@ package org.onap.aai.introspection.sideeffect; -import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.when; - -import java.io.FileInputStream; -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.lang.reflect.InvocationTargetException; -import java.net.MalformedURLException; -import java.net.URISyntaxException; -import java.util.Arrays; -import java.util.Collection; - import org.apache.commons.io.IOUtils; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; import org.apache.tinkerpop.gremlin.structure.Graph; @@ -48,10 +35,11 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.onap.aai.AAISetup; import org.onap.aai.db.props.AAIProperties; -import org.onap.aai.dbmap.DBConnectionType; import org.onap.aai.edges.enums.EdgeProperty; import org.onap.aai.exceptions.AAIException; -import org.onap.aai.introspection.*; +import org.onap.aai.introspection.Introspector; +import org.onap.aai.introspection.Loader; +import org.onap.aai.introspection.ModelType; import org.onap.aai.introspection.sideeffect.exceptions.AAIMissingRequiredPropertyException; import org.onap.aai.parsers.query.QueryParser; import org.onap.aai.serialization.db.DBSerializer; @@ -59,13 +47,24 @@ import org.onap.aai.serialization.engines.JanusGraphDBEngine; import org.onap.aai.serialization.engines.QueryStyle; import org.onap.aai.serialization.engines.TransactionalGraphEngine; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.Collection; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + @RunWith(value = Parameterized.class) public class DataCopyTest extends AAISetup { private static JanusGraph graph; private final static ModelType introspectorFactoryType = ModelType.MOXY; - private final static DBConnectionType type = DBConnectionType.REALTIME; private static Loader loader; private static TransactionalGraphEngine dbEngine; @Mock @@ -77,7 +76,7 @@ public class DataCopyTest extends AAISetup { @Rule public ExpectedException thrown = ExpectedException.none(); - @Parameterized.Parameter(value = 0) + @Parameterized.Parameter public QueryStyle queryStyle; @Parameterized.Parameters(name = "QueryStyle.{0}") @@ -86,27 +85,40 @@ public class DataCopyTest extends AAISetup { } @BeforeClass - public static void setup() throws NoSuchFieldException, SecurityException, Exception { + public static void setup() { graph = JanusGraphFactory.build().set("storage.backend", "inmemory").open(); System.setProperty("AJSC_HOME", "."); System.setProperty("BUNDLECONFIG_DIR", "src/test/resources/bundleconfig-local"); graph.traversal() - .addV("aai-node-type", "model", "model-invariant-id", "key1", AAIProperties.AAI_URI, - "/service-design-and-creation/models/model/key1") - .as("v1") - .addV("aai-node-type", "model-ver", "model-ver", "myValue", "model-version-id", "key2", "model-version", - "testValue", AAIProperties.AAI_URI, - "/service-design-and-creation/models/model/key1/model-vers/model-ver/key2") - .addOutE("org.onap.relationships.inventory.BelongsTo", "v1", EdgeProperty.CONTAINS.toString(), true) - .addV("aai-node-type", "model", "model-invariant-id", "key3", AAIProperties.AAI_URI, - "/service-design-and-creation/models/model/key3") - .as("v2") - .addV("aai-node-type", "model-ver", "model-ver", "myValue", "model-version-id", "key4", - AAIProperties.AAI_URI, - "/service-design-and-creation/models/model/key3/model-vers/model-ver/key4") - .addOutE("org.onap.relationships.inventory.BelongsTo", "v2", EdgeProperty.CONTAINS.toString(), true) - .next(); + .addV("model") + .property("aai-node-type", "model") + .property("model-invariant-id", "key1") + .property(AAIProperties.AAI_URI,"/service-design-and-creation/models/model/key1") + .as("v1") + .addV("model-ver") + .property("aai-node-type", "model-ver") + .property("model-ver", "myValue") + .property("model-version-id", "key2") + .property("model-version", "testValue") + .property(AAIProperties.AAI_URI, "/service-design-and-creation/models/model/key1/model-vers/model-ver/key2") + .as("v2") + .addE("org.onap.relationships.inventory.BelongsTo").to("v1").from("v2") + .property(EdgeProperty.CONTAINS.toString(), true) + .addV("model") + .property("aai-node-type", "model") + .property("model-invariant-id", "key3") + .property(AAIProperties.AAI_URI, "/service-design-and-creation/models/model/key3") + .as("v3") + .addV() + .property("aai-node-type", "model-ver") + .property("model-ver", "myValue") + .property("model-version-id", "key4") + .property(AAIProperties.AAI_URI, "/service-design-and-creation/models/model/key3/model-vers/model-ver/key4") + .as("v4") + .addE("org.onap.relationships.inventory.BelongsTo").to("v3").from("v4") + .property(EdgeProperty.CONTAINS.toString(), true) + .next(); graph.tx().commit(); } @@ -120,13 +132,12 @@ public class DataCopyTest extends AAISetup { public void initMock() { loader = loaderFactory.createLoaderForVersion(introspectorFactoryType, schemaVersions.getDefaultVersion()); MockitoAnnotations.initMocks(this); - dbEngine = new JanusGraphDBEngine(queryStyle, type, loader); + dbEngine = new JanusGraphDBEngine(queryStyle, loader); } @Test - public void runPopulatePersonaModelVer() throws URISyntaxException, AAIException, UnsupportedEncodingException, - IllegalAccessException, IllegalArgumentException, InvocationTargetException, SecurityException, - InstantiationException, NoSuchMethodException, MalformedURLException { + public void runPopulatePersonaModelVer() throws AAIException, UnsupportedEncodingException, + IllegalArgumentException, SecurityException { final Loader loader = loaderFactory.createLoaderForVersion(ModelType.MOXY, schemaVersions.getDefaultVersion()); final Introspector obj = loader.introspectorFromName("generic-vnf"); @@ -154,13 +165,10 @@ public class DataCopyTest extends AAISetup { } @Test - public void verifyNestedSideEffect() - throws URISyntaxException, AAIException, IllegalAccessException, IllegalArgumentException, - InvocationTargetException, SecurityException, InstantiationException, NoSuchMethodException, IOException { + public void verifyNestedSideEffect() throws AAIException, IllegalArgumentException, SecurityException, IOException { final Loader loader = loaderFactory.createLoaderForVersion(ModelType.MOXY, schemaVersions.getDefaultVersion()); final Introspector obj = loader.unmarshal("customer", this.getJsonString("nested-case.json")); - // System.out.println(obj.marshal(true)); TransactionalGraphEngine spy = spy(dbEngine); TransactionalGraphEngine.Admin adminSpy = spy(dbEngine.asAdmin()); Graph g = graph.newTransaction(); @@ -251,15 +259,15 @@ public class DataCopyTest extends AAISetup { runner.execute(obj, self); - assertEquals("no model-version-id", true, obj.getValue("model-version-id") == null); - assertEquals("no model-invariant-id", true, obj.getValue("model-invariant-id") == null); + assertNull("no model-version-id", obj.getValue("model-version-id")); + assertNull("no model-invariant-id", obj.getValue("model-invariant-id")); } private String getJsonString(String filename) throws IOException { FileInputStream is = new FileInputStream("src/test/resources/oxm/sideeffect/" + filename); - String s = IOUtils.toString(is, "UTF-8"); + String s = IOUtils.toString(is, StandardCharsets.UTF_8); IOUtils.closeQuietly(is); return s; diff --git a/aai-core/src/test/java/org/onap/aai/introspection/sideeffect/DataLinkTest.java b/aai-core/src/test/java/org/onap/aai/introspection/sideeffect/DataLinkTest.java index cec342ea..62c366cb 100644 --- a/aai-core/src/test/java/org/onap/aai/introspection/sideeffect/DataLinkTest.java +++ b/aai-core/src/test/java/org/onap/aai/introspection/sideeffect/DataLinkTest.java @@ -20,54 +20,51 @@ package org.onap.aai.introspection.sideeffect; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.*; -import static org.junit.Assert.*; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.when; - -import java.io.UnsupportedEncodingException; -import java.lang.reflect.InvocationTargetException; -import java.net.MalformedURLException; -import java.net.URISyntaxException; -import java.util.Arrays; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; - import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; -import org.apache.tinkerpop.gremlin.structure.Direction; -import org.apache.tinkerpop.gremlin.structure.Edge; import org.apache.tinkerpop.gremlin.structure.Graph; import org.apache.tinkerpop.gremlin.structure.Vertex; import org.apache.tinkerpop.gremlin.structure.VertexProperty; +import org.janusgraph.core.Cardinality; import org.janusgraph.core.JanusGraph; import org.janusgraph.core.JanusGraphFactory; +import org.janusgraph.core.schema.JanusGraphManagement; import org.junit.*; import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import org.onap.aai.AAISetup; import org.onap.aai.DataLinkSetup; import org.onap.aai.db.props.AAIProperties; -import org.onap.aai.dbmap.DBConnectionType; import org.onap.aai.edges.enums.EdgeProperty; import org.onap.aai.exceptions.AAIException; -import org.onap.aai.introspection.*; +import org.onap.aai.introspection.Introspector; +import org.onap.aai.introspection.Loader; +import org.onap.aai.introspection.ModelType; import org.onap.aai.parsers.query.QueryParser; import org.onap.aai.serialization.db.DBSerializer; import org.onap.aai.serialization.engines.JanusGraphDBEngine; import org.onap.aai.serialization.engines.QueryStyle; import org.onap.aai.serialization.engines.TransactionalGraphEngine; +import java.io.UnsupportedEncodingException; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.UUID; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; +import static org.junit.Assert.*; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + @RunWith(value = Parameterized.class) public class DataLinkTest extends DataLinkSetup { private static JanusGraph graph; private final static ModelType introspectorFactoryType = ModelType.MOXY; - private final static DBConnectionType type = DBConnectionType.REALTIME; private static Loader loader; private static TransactionalGraphEngine dbEngine; @Mock @@ -79,7 +76,7 @@ public class DataLinkTest extends DataLinkSetup { @Rule public ExpectedException thrown = ExpectedException.none(); - @Parameterized.Parameter(value = 0) + @Parameterized.Parameter public QueryStyle queryStyle; @Parameterized.Parameters(name = "QueryStyle.{0}") @@ -88,50 +85,133 @@ public class DataLinkTest extends DataLinkSetup { } @BeforeClass - public static void setup() throws NoSuchFieldException, SecurityException, Exception { + public static void setup() { graph = JanusGraphFactory.build().set("storage.backend", "inmemory").open(); + JanusGraphManagement graphMgt = graph.openManagement(); + graphMgt.makePropertyKey(AAIProperties.CREATED_TS).dataType(Long.class).cardinality(Cardinality.SINGLE) + .make(); + graphMgt.makePropertyKey(AAIProperties.LAST_MOD_TS).dataType(Long.class).cardinality(Cardinality.SINGLE) + .make(); + graphMgt.commit(); graph.traversal() - .addV("aai-node-type", "vpn-binding", "vpn-id", "addKey", AAIProperties.AAI_URI, - "/network/vpn-bindings/vpn-binding/addKey") - .as("v1") - .addV("aai-node-type", "vpn-binding", "vpn-id", "modifyKey", AAIProperties.AAI_URI, - "/network/vpn-bindings/vpn-binding/modifyKey") - .as("v2") - .addV("aai-node-type", "route-target", "global-route-target", "modifyTargetKey", "route-target-role", - "modifyRoleKey", "linked", true, AAIProperties.AAI_URI, - "/network/vpn-bindings/vpn-binding/modifyKey/route-targets/route-target/modifyTargetKey/modifyRoleKey") - .addOutE("org.onap.relationships.inventory.BelongsTo", "v2", EdgeProperty.CONTAINS.toString(), true) - .addV("aai-node-type", "vpn-binding", "vpn-id", "deleteKey", AAIProperties.AAI_URI, - "/network/vpn-bindings/vpn-binding/deleteKey") - .as("v3") - .addV("aai-node-type", "route-target", "global-route-target", "deleteTargetKey", "route-target-role", - "deleteRoleKey", "linked", true, AAIProperties.AAI_URI, - "/network/vpn-bindings/vpn-binding/deleteKey/route-targets/route-target/deleteTargetKey/deleteRoleKey") - .addOutE("org.onap.relationships.inventory.BelongsTo", "v3", EdgeProperty.CONTAINS.toString(), true) - .addV("aai-node-type", "vpn-binding", "vpn-id", "getKey", AAIProperties.AAI_URI, - "/network/vpn-bindings/vpn-binding/getKey") - .as("v4") - .addV("aai-node-type", "route-target", "global-route-target", "getTargetKey", "route-target-role", - "getRoleKey", "linked", true, AAIProperties.AAI_URI, - "/network/vpn-bindings/vpn-binding/getKey/route-targets/route-target/getTargetKeyNoLink/getRoleKeyNoLink") - .addOutE("org.onap.relationships.inventory.BelongsTo", "v4", EdgeProperty.CONTAINS.toString(), true) - .addV("aai-node-type", "vpn-binding", "vpn-id", "getKeyNoLink", AAIProperties.AAI_URI, - "/network/vpn-bindings/vpn-binding/getKeyNoLink") - .as("v5") - .addV("aai-node-type", "route-target", "global-route-target", "getTargetKeyNoLink", "route-target-role", - "getRoleKeyNoLink", AAIProperties.AAI_URI, - "/network/vpn-bindings/vpn-binding/getKeyNoLink/route-targets/route-target/getTargetKeyNoLink/getRoleKeyNoLink") - .addOutE("org.onap.relationships.inventory.BelongsTo", "v5", EdgeProperty.CONTAINS.toString(), true) + .addV() + .property("aai-node-type", "vpn-binding") + .property("vpn-id", "addKey") + .property(AAIProperties.AAI_URI, "/network/vpn-bindings/vpn-binding/addKey") + .property(AAIProperties.AAI_UUID, UUID.randomUUID().toString()) + .property(AAIProperties.CREATED_TS, 123) + .property(AAIProperties.SOURCE_OF_TRUTH, "sot") + .property(AAIProperties.RESOURCE_VERSION, "123") + .property(AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot") + .property(AAIProperties.LAST_MOD_TS, 333) + .as("v1") + .addV() + .property("aai-node-type", "vpn-binding") + .property("vpn-id", "modifyKey") + .property(AAIProperties.AAI_URI, "/network/vpn-bindings/vpn-binding/modifyKey") + .property(AAIProperties.AAI_UUID, UUID.randomUUID().toString()) + .property(AAIProperties.CREATED_TS, 123) + .property(AAIProperties.SOURCE_OF_TRUTH, "sot") + .property(AAIProperties.RESOURCE_VERSION, "123") + .property(AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot") + .property(AAIProperties.LAST_MOD_TS, 333) + .as("v2") + .addV() + .property("aai-node-type", "route-target") + .property("global-route-target", "modifyTargetKey") + .property("route-target-role", "modifyRoleKey") + .property("linked", true) + .property(AAIProperties.AAI_URI, "/network/vpn-bindings/vpn-binding/modifyKey/route-targets/route-target/modifyTargetKey/modifyRoleKey") + .property(AAIProperties.AAI_UUID, UUID.randomUUID().toString()) + .property(AAIProperties.CREATED_TS, 123) + .property(AAIProperties.SOURCE_OF_TRUTH, "sot") + .property(AAIProperties.RESOURCE_VERSION, "123") + .property(AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot") + .property(AAIProperties.LAST_MOD_TS, 333) + .as("v3") + .addE("org.onap.relationships.inventory.BelongsTo").to("v2").from("v3") + .property(EdgeProperty.CONTAINS.toString(), true) + .addV() + .property("aai-node-type", "vpn-binding") + .property("vpn-id", "deleteKey") + .property(AAIProperties.AAI_URI, "/network/vpn-bindings/vpn-binding/deleteKey") + .property(AAIProperties.AAI_UUID, UUID.randomUUID().toString()) + .property(AAIProperties.CREATED_TS, 123) + .property(AAIProperties.SOURCE_OF_TRUTH, "sot") + .property(AAIProperties.RESOURCE_VERSION, "123") + .property(AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot") + .property(AAIProperties.LAST_MOD_TS, 333) + .as("v4") + .addV() + .property("aai-node-type", "route-target") + .property("global-route-target", "deleteTargetKey") + .property("route-target-role", "deleteRoleKey") + .property("linked", true) + .property(AAIProperties.AAI_URI, "/network/vpn-bindings/vpn-binding/deleteKey/route-targets/route-target/deleteTargetKey/deleteRoleKey") + .property(AAIProperties.AAI_UUID, UUID.randomUUID().toString()) + .property(AAIProperties.CREATED_TS, 123) + .property(AAIProperties.SOURCE_OF_TRUTH, "sot") + .property(AAIProperties.RESOURCE_VERSION, "123") + .property(AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot") + .property(AAIProperties.LAST_MOD_TS, 333) + .as("v5") + .addE("org.onap.relationships.inventory.BelongsTo").to("v4").from("v5") + .property(EdgeProperty.CONTAINS.toString(), true) + .addV() + .property("aai-node-type", "vpn-binding") + .property("vpn-id", "getKey") + .property(AAIProperties.AAI_URI, "/network/vpn-bindings/vpn-binding/getKey") + .property(AAIProperties.AAI_UUID, UUID.randomUUID().toString()) + .property(AAIProperties.CREATED_TS, 123) + .property(AAIProperties.SOURCE_OF_TRUTH, "sot") + .property(AAIProperties.RESOURCE_VERSION, "123") + .property(AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot") + .property(AAIProperties.LAST_MOD_TS, 333) + .as("v6") + .addV() + .property("aai-node-type", "route-target") + .property("global-route-target", "getTargetKey") + .property("route-target-role", "getRoleKey") + .property("linked", true) + .property(AAIProperties.AAI_URI, "/network/vpn-bindings/vpn-binding/getKey/route-targets/route-target/getTargetKeyNoLink/getRoleKeyNoLink") + .property(AAIProperties.AAI_UUID, UUID.randomUUID().toString()) + .property(AAIProperties.CREATED_TS, 123) + .property(AAIProperties.SOURCE_OF_TRUTH, "sot") + .property(AAIProperties.RESOURCE_VERSION, "123") + .property(AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot") + .property(AAIProperties.LAST_MOD_TS, 333) + .as("v7") + .addE("org.onap.relationships.inventory.BelongsTo").to("v6").from("v7") + .property(EdgeProperty.CONTAINS.toString(), true) + .addV() + .property("aai-node-type", "vpn-binding") + .property("vpn-id", "getKeyNoLink") + .property(AAIProperties.AAI_URI, "/network/vpn-bindings/vpn-binding/getKeyNoLink") + .property(AAIProperties.AAI_UUID, UUID.randomUUID().toString()) + .property(AAIProperties.CREATED_TS, 123) + .property(AAIProperties.SOURCE_OF_TRUTH, "sot") + .property(AAIProperties.RESOURCE_VERSION, "123") + .property(AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot") + .property(AAIProperties.LAST_MOD_TS, 333) + .as("v8") + .addV() + .property("aai-node-type", "route-target") + .property("global-route-target", "getTargetKeyNoLink") + .property("route-target-role", "getRoleKeyNoLink") + .property(AAIProperties.AAI_URI, "/network/vpn-bindings/vpn-binding/getKeyNoLink/route-targets/route-target/getTargetKeyNoLink/getRoleKeyNoLink") + .property(AAIProperties.AAI_UUID, UUID.randomUUID().toString()) + .property(AAIProperties.CREATED_TS, 123) + .property(AAIProperties.SOURCE_OF_TRUTH, "sot") + .property(AAIProperties.RESOURCE_VERSION, "123") + .property(AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot") + .property(AAIProperties.LAST_MOD_TS, 333) + .as("v9") + .addE("org.onap.relationships.inventory.BelongsTo").to("v8").from("v9") + .property(EdgeProperty.CONTAINS.toString(), true) .next(); graph.tx().commit(); - /* - * Commented for SysOut issues - */ - // graph.traversal().V().has("aai-uri","/network/vpn-bindings/vpn-binding/deleteKey").properties().forEachRemaining(p->System.out.println(p.key() - // +" : " + p.value())); - } @AfterClass @@ -144,13 +224,12 @@ public class DataLinkTest extends DataLinkSetup { public void initMock() { loader = loaderFactory.createLoaderForVersion(introspectorFactoryType, schemaVersions.getDefaultVersion()); MockitoAnnotations.initMocks(this); - dbEngine = new JanusGraphDBEngine(queryStyle, type, loader); + dbEngine = new JanusGraphDBEngine(queryStyle, loader); } @Test - public void verifyCreationOfVertex() throws URISyntaxException, AAIException, UnsupportedEncodingException, - IllegalAccessException, IllegalArgumentException, InvocationTargetException, SecurityException, - InstantiationException, NoSuchMethodException, MalformedURLException { + public void verifyCreationOfVertex() throws AAIException, UnsupportedEncodingException, + IllegalArgumentException, SecurityException { final Loader loader = loaderFactory.createLoaderForVersion(ModelType.MOXY, schemaVersions.getDepthVersion()); final Introspector obj = loader.introspectorFromName("vpn-binding"); @@ -161,25 +240,6 @@ public class DataLinkTest extends DataLinkSetup { TransactionalGraphEngine.Admin adminSpy = spy(dbEngine.asAdmin()); Graph g = graph.newTransaction(); GraphTraversalSource traversal = g.traversal(); - // Graph g = graph.newTransaction(); - // GraphTraversalSource traversal = g; - // System.out.println("Begin method inventory:"); - Iterator<Vertex> vertexItr = traversal.V(); - while (vertexItr != null && vertexItr.hasNext()) { - Vertex v = vertexItr.next(); - // System.out.println("\nnodeType="+v.<String>property("aai-node-type")); - for (String key : v.keys()) { - // System.out.println("label="+v.label()+";key= "+key+";value= "+v.value(key)+";id= "+v.id()); - } - Direction d = null; - Iterator<Edge> edgeItr = v.edges(Direction.BOTH); - while (edgeItr != null && edgeItr.hasNext()) { - Edge e = edgeItr.next(); - // System.out.println("outV="+e.outVertex().property(AAIProperties.NODE_TYPE)+"/"+e.outVertex().id()+";inV= - // "+e.inVertex().property(AAIProperties.NODE_TYPE)+"/"+e.inVertex().id()); - } - } - // System.out.println("End method inventory:"); when(spy.asAdmin()).thenReturn(adminSpy); when(adminSpy.getTraversalSource()).thenReturn(traversal); when(spy.tx()).thenReturn(g); @@ -192,16 +252,14 @@ public class DataLinkTest extends DataLinkSetup { runner.execute(obj, self); - assertEquals("route-target vertex found", true, traversal.V().has(AAIProperties.NODE_TYPE, "route-target") - .has("global-route-target", "key1").has("route-target-role", "key2").has("linked", true).hasNext()); + assertTrue("route-target vertex found", traversal.V().has(AAIProperties.NODE_TYPE, "route-target").has("global-route-target", "key1").has("route-target-role", "key2").has("linked", true).hasNext()); g.tx().rollback(); } @Test - public void verifyModificationOfVertex() throws URISyntaxException, AAIException, UnsupportedEncodingException, - IllegalAccessException, IllegalArgumentException, InvocationTargetException, SecurityException, - InstantiationException, NoSuchMethodException, MalformedURLException { + public void verifyModificationOfVertex() throws AAIException, UnsupportedEncodingException, + IllegalArgumentException, SecurityException { final Loader loader = loaderFactory.createLoaderForVersion(ModelType.MOXY, schemaVersions.getDepthVersion()); final Introspector obj = loader.introspectorFromName("vpn-binding"); @@ -210,30 +268,11 @@ public class DataLinkTest extends DataLinkSetup { obj.setValue("route-target-role", "modifyRoleKey2"); TransactionalGraphEngine spy = spy(dbEngine); TransactionalGraphEngine.Admin adminSpy = spy(dbEngine.asAdmin()); - // Graph g = graph.newTransaction(); - // GraphTraversalSource traversal = g; Graph g = graph.newTransaction(); GraphTraversalSource traversal = g.traversal(); - Iterator<Vertex> vertexItr = traversal.V(); - while (vertexItr != null && vertexItr.hasNext()) { - Vertex v = vertexItr.next(); - // System.out.println("\nnodeType="+v.<String>property("aai-node-type")); - for (String key : v.keys()) { - // System.out.println("label="+v.label()+";key= "+key+";value= "+v.value(key)+"/"+v.id()); - } - Direction d = null; - Iterator<Edge> edgeItr = v.edges(Direction.BOTH); - while (edgeItr != null && edgeItr.hasNext()) { - Edge e = edgeItr.next(); - // System.out.println("outV="+e.outVertex().property(AAIProperties.NODE_TYPE)+"/"+e.outVertex().id()+";inV= - // "+e.inVertex().property(AAIProperties.NODE_TYPE)+"/"+e.inVertex().id()); - } - } - // System.out.println("End method inventory:"); when(spy.asAdmin()).thenReturn(adminSpy); when(adminSpy.getTraversalSource()).thenReturn(traversal); - // when(spy.tx()).thenReturn(graph); when(spy.tx()).thenReturn(g); when(self.<String>property(AAIProperties.AAI_URI)).thenReturn(prop); when(prop.orElse(null)).thenReturn(obj.getURI()); @@ -241,44 +280,8 @@ public class DataLinkTest extends DataLinkSetup { new DBSerializer(schemaVersions.getDefaultVersion(), spy, introspectorFactoryType, "AAI_TEST"); SideEffectRunner runner = new SideEffectRunner.Builder(spy, serializer).addSideEffect(DataLinkWriter.class).build(); - // System.out.println("Traversal Source: "+traversal.toString()); - vertexItr = traversal.V(); - // System.out.println("Begin method inventory:"); - while (vertexItr != null && vertexItr.hasNext()) { - Vertex v = vertexItr.next(); - // System.out.println("\nnodeType="+v.<String>property("aai-node-type")); - for (String key : v.keys()) { - // System.out.println("label="+v.label()+";key= "+key+";value= "+v.value(key)+"/"+v.id()); - } - Iterator<Edge> edgeItr = v.edges(Direction.BOTH); - while (edgeItr != null && edgeItr.hasNext()) { - Edge e = edgeItr.next(); - // System.out.println("outV="+e.outVertex().property(AAIProperties.NODE_TYPE)+"/"+e.outVertex().id()+";inV= - // "+e.inVertex().property(AAIProperties.NODE_TYPE)+"/"+e.inVertex().id()); - } - } - // System.out.println("End method inventory:"); - try { - runner.execute(obj, self); - } catch (Exception e) { - - } - // runner.execute(obj, self); - // System.out.println("=================\n"); - vertexItr = traversal.V(); - while (vertexItr != null && vertexItr.hasNext()) { - Vertex v = vertexItr.next(); - // System.out.println("\nnodeType="+v.<String>property("aai-node-type")); - for (String key : v.keys()) { - // System.out.println("label="+v.label()+";key= "+key+";value= "+v.value(key)+"/"+v.id()); - } - Iterator<Edge> edgeItr = v.edges(Direction.BOTH); - while (edgeItr != null && edgeItr.hasNext()) { - Edge e = edgeItr.next(); - // System.out.println("outV="+e.outVertex().property(AAIProperties.NODE_TYPE)+"/"+e.outVertex().id()+";inV= - // "+e.inVertex().property(AAIProperties.NODE_TYPE)+"/"+e.inVertex().id()); - } - } + runner.execute(obj, self); + assertThat("new route-target vertex found with/or without link", traversal.V().has(AAIProperties.NODE_TYPE, "route-target") .has("global-route-target", "modifyTargetKey2").has("route-target-role", "modifyRoleKey2") @@ -301,9 +304,7 @@ public class DataLinkTest extends DataLinkSetup { } @Test - public void verifyDeleteOfVertex() throws URISyntaxException, AAIException, UnsupportedEncodingException, - IllegalAccessException, IllegalArgumentException, InvocationTargetException, SecurityException, - InstantiationException, NoSuchMethodException, MalformedURLException { + public void verifyDeleteOfVertex() throws Exception { final Loader loader = loaderFactory.createLoaderForVersion(ModelType.MOXY, schemaVersions.getDepthVersion()); final Introspector obj = loader.introspectorFromName("vpn-binding"); @@ -325,18 +326,14 @@ public class DataLinkTest extends DataLinkSetup { runner.execute(obj, self); - assertEquals("route-target vertex not found", false, - traversal.V().has(AAIProperties.NODE_TYPE, "route-target").has("global-route-target", "deleteTargetKey") - .has("route-target-role", "deleteRoleKey").has("linked", true).hasNext()); + assertFalse("route-target vertex not found", traversal.V().has(AAIProperties.NODE_TYPE, "route-target").has("global-route-target", "deleteTargetKey").has("route-target-role", "deleteRoleKey").has("linked", true).hasNext()); g.tx().rollback(); } @Test - public void verifyPropertyPopulation() throws URISyntaxException, AAIException, UnsupportedEncodingException, - IllegalAccessException, IllegalArgumentException, InvocationTargetException, SecurityException, - InstantiationException, NoSuchMethodException, MalformedURLException { + public void verifyPropertyPopulation() throws Exception { final Loader loader = loaderFactory.createLoaderForVersion(ModelType.MOXY, schemaVersions.getDepthVersion()); final Introspector obj = loader.introspectorFromName("vpn-binding"); @@ -357,17 +354,14 @@ public class DataLinkTest extends DataLinkSetup { runner.execute(obj, self); - assertEquals("both properties have been populated in target object", true, - obj.getValue("global-route-target").equals("getTargetKey") - && obj.getValue("route-target-role").equals("getRoleKey")); + assertTrue("both properties have been populated in target object", obj.getValue("global-route-target").equals("getTargetKey") && obj.getValue("route-target-role").equals("getRoleKey")); g.tx().rollback(); } @Test - public void verifyPropertyPopulationWithV10OnlyPut() throws URISyntaxException, AAIException, - UnsupportedEncodingException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, - SecurityException, InstantiationException, NoSuchMethodException, MalformedURLException { + public void verifyPropertyPopulationWithV10OnlyPut() throws AAIException, + UnsupportedEncodingException, IllegalArgumentException, SecurityException { final Introspector obj = loader.introspectorFromName("vpn-binding"); obj.setValue("vpn-id", "getKeyNoLink"); final Introspector routeTargets = loader.introspectorFromName("route-targets"); diff --git a/aai-core/src/test/java/org/onap/aai/introspection/sideeffect/PrivateEdgeTest.java b/aai-core/src/test/java/org/onap/aai/introspection/sideeffect/PrivateEdgeTest.java index 1bae4065..6a7bfd33 100644 --- a/aai-core/src/test/java/org/onap/aai/introspection/sideeffect/PrivateEdgeTest.java +++ b/aai-core/src/test/java/org/onap/aai/introspection/sideeffect/PrivateEdgeTest.java @@ -20,19 +20,6 @@ package org.onap.aai.introspection.sideeffect; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.empty; -import static org.hamcrest.Matchers.not; -import static org.hamcrest.core.Is.is; -import static org.hamcrest.core.StringContains.containsString; -import static org.junit.Assert.*; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.when; - -import java.util.Arrays; -import java.util.Collection; -import java.util.List; - import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; import org.apache.tinkerpop.gremlin.structure.Edge; import org.apache.tinkerpop.gremlin.structure.Graph; @@ -46,29 +33,42 @@ import org.junit.runners.Parameterized; import org.mockito.MockitoAnnotations; import org.onap.aai.AAISetup; import org.onap.aai.db.props.AAIProperties; -import org.onap.aai.dbmap.DBConnectionType; import org.onap.aai.edges.enums.EdgeProperty; -import org.onap.aai.introspection.*; +import org.onap.aai.introspection.Introspector; +import org.onap.aai.introspection.Loader; +import org.onap.aai.introspection.ModelType; import org.onap.aai.serialization.db.DBSerializer; import org.onap.aai.serialization.engines.JanusGraphDBEngine; import org.onap.aai.serialization.engines.QueryStyle; import org.onap.aai.serialization.engines.TransactionalGraphEngine; import org.springframework.test.annotation.DirtiesContext; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.empty; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.StringContains.containsString; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + @RunWith(value = Parameterized.class) @DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS) public class PrivateEdgeTest extends AAISetup { private static JanusGraph graph; private final static ModelType introspectorFactoryType = ModelType.MOXY; - private final static DBConnectionType type = DBConnectionType.REALTIME; - private Loader loader; private static TransactionalGraphEngine dbEngine; @Rule public ExpectedException thrown = ExpectedException.none(); - @Parameterized.Parameter(value = 0) + @Parameterized.Parameter public QueryStyle queryStyle; @Parameterized.Parameters(name = "QueryStyle.{0}") @@ -77,7 +77,7 @@ public class PrivateEdgeTest extends AAISetup { } @BeforeClass - public static void setup() throws Exception { + public static void setup() { graph = JanusGraphFactory.build().set("storage.backend", "inmemory").open(); @@ -85,28 +85,48 @@ public class PrivateEdgeTest extends AAISetup { System.setProperty("BUNDLECONFIG_DIR", "src/test/resources/bundleconfig-local"); graph.traversal() - .addV("aai-node-type", "model", "model-invariant-id", "key1", AAIProperties.AAI_URI, - "/service-design-and-creation/models/model/key1") - .as("v1") - .addV("aai-node-type", "model-ver", "model-ver", "myValue", "model-version-id", "key2", "model-version", - "testValue", AAIProperties.AAI_URI, - "/service-design-and-creation/models/model/key1/model-vers/model-ver/key2") - .addOutE("org.onap.relationships.inventory.BelongsTo", "v1", EdgeProperty.CONTAINS.toString(), true) - .addV("aai-node-type", "model", "model-invariant-id", "key100", AAIProperties.AAI_URI, - "/service-design-and-creation/models/model/key100") - .as("v5") - .addV("aai-node-type", "model-ver", "model-ver", "myValue", "model-version-id", "key200", - "model-version", "testValue", AAIProperties.AAI_URI, - "/service-design-and-creation/models/model/key100/model-vers/model-ver/key200") - .addOutE("org.onap.relationships.inventory.BelongsTo", "v5", EdgeProperty.CONTAINS.toString(), true) - .addV("aai-node-type", "model", "model-invariant-id", "key3", AAIProperties.AAI_URI, - "/service-design-and-creation/models/model/key3") - .as("v2") - .addV("aai-node-type", "model-ver", "model-ver", "myValue", "model-version-id", "key4", - AAIProperties.AAI_URI, - "/service-design-and-creation/models/model/key3/model-vers/model-ver/key4") - .addOutE("org.onap.relationships.inventory.BelongsTo", "v2", EdgeProperty.CONTAINS.toString(), true) - .next(); + .addV() + .property("aai-node-type", "model") + .property("model-invariant-id", "key1") + .property(AAIProperties.AAI_URI, "/service-design-and-creation/models/model/key1") + .as("v1") + .addV() + .property("aai-node-type", "model-ver") + .property("model-ver", "myValue") + .property("model-version-id", "key2") + .property("model-version", "testValue") + .property(AAIProperties.AAI_URI, "/service-design-and-creation/models/model/key1/model-vers/model-ver/key2") + .as("v2") + .addE("org.onap.relationships.inventory.BelongsTo").to("v1").from("v2") + .property(EdgeProperty.CONTAINS.toString(), true) + .addV() + .property("aai-node-type", "model") + .property("model-invariant-id", "key100") + .property(AAIProperties.AAI_URI, "/service-design-and-creation/models/model/key100") + .as("v3") + .addV() + .property("aai-node-type", "model-ver") + .property("model-ver", "myValue") + .property("model-version-id", "key200") + .property("model-version", "testValue") + .property(AAIProperties.AAI_URI, "/service-design-and-creation/models/model/key100/model-vers/model-ver/key200") + .as("v4") + .addE("org.onap.relationships.inventory.BelongsTo").to("v3").from("v4") + .property(EdgeProperty.CONTAINS.toString(), true) + .addV() + .property("aai-node-type", "model") + .property("model-invariant-id", "key3") + .property(AAIProperties.AAI_URI, "/service-design-and-creation/models/model/key3") + .as("v5") + .addV() + .property("aai-node-type", "model-ver") + .property("model-ver", "myValue") + .property("model-version-id", "key4") + .property(AAIProperties.AAI_URI, "/service-design-and-creation/models/model/key3/model-vers/model-ver/key4") + .as("v6") + .addE("org.onap.relationships.inventory.BelongsTo").to("v5").from("v6") + .property(EdgeProperty.CONTAINS.toString(), true) + .next(); graph.tx().commit(); } @@ -118,9 +138,9 @@ public class PrivateEdgeTest extends AAISetup { @Before public void initMock() { - loader = loaderFactory.createLoaderForVersion(introspectorFactoryType, schemaVersions.getDefaultVersion()); + Loader loader = loaderFactory.createLoaderForVersion(introspectorFactoryType, schemaVersions.getDefaultVersion()); MockitoAnnotations.initMocks(this); - dbEngine = new JanusGraphDBEngine(queryStyle, type, loader); + dbEngine = new JanusGraphDBEngine(queryStyle, loader); } @Test @@ -137,8 +157,12 @@ public class PrivateEdgeTest extends AAISetup { when(spy.asAdmin()).thenReturn(adminSpy); when(adminSpy.getTraversalSource()).thenReturn(traversal); - Vertex selfV = traversal.addV("aai-node-type", "generic-vnf", "vnf-id", "myId", "aai-uri", obj.getURI(), - "model-invariant-id", "key1").next(); + Vertex selfV = traversal.addV("generic-vnf") + .property("aai-node-type", "generic-vnf") + .property("vnf-id", "myId") + .property("aai-uri", obj.getURI()) + .property("model-invariant-id", "key1") + .next(); thrown.expectMessage(containsString("Cannot complete privateEdge uri")); DBSerializer serializer = @@ -150,7 +174,7 @@ public class PrivateEdgeTest extends AAISetup { assertNull(edgeList); assertThat(edgeList, is(not(empty()))); - assertThat(edgeList.size(), is(1)); + assertEquals(1, edgeList.size()); g.tx().rollback(); } diff --git a/aai-core/src/test/java/org/onap/aai/logging/CustomLogPatternLayoutTest.java b/aai-core/src/test/java/org/onap/aai/logging/CustomLogPatternLayoutTest.java index dce34b53..250cdda8 100644 --- a/aai-core/src/test/java/org/onap/aai/logging/CustomLogPatternLayoutTest.java +++ b/aai-core/src/test/java/org/onap/aai/logging/CustomLogPatternLayoutTest.java @@ -20,13 +20,11 @@ package org.onap.aai.logging; +import org.junit.Test; + import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; -import org.junit.Test; -import org.onap.aai.logging.CNName; -import org.onap.aai.logging.CustomLogPatternLayout; - public class CustomLogPatternLayoutTest { /** diff --git a/aai-core/src/test/java/org/onap/aai/logging/DME2RestFlagTest.java b/aai-core/src/test/java/org/onap/aai/logging/DME2RestFlagTest.java index bc7f9499..72b1150e 100644 --- a/aai-core/src/test/java/org/onap/aai/logging/DME2RestFlagTest.java +++ b/aai-core/src/test/java/org/onap/aai/logging/DME2RestFlagTest.java @@ -20,12 +20,12 @@ package org.onap.aai.logging; -import static org.junit.Assert.*; -import static org.mockito.Mockito.*; - import ch.qos.logback.access.spi.IAccessEvent; +import org.junit.Before; +import org.junit.Test; -import org.junit.*; +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.*; public class DME2RestFlagTest { diff --git a/aai-core/src/test/java/org/onap/aai/logging/EcompResponseCodeTest.java b/aai-core/src/test/java/org/onap/aai/logging/EcompResponseCodeTest.java deleted file mode 100644 index 8319f9a3..00000000 --- a/aai-core/src/test/java/org/onap/aai/logging/EcompResponseCodeTest.java +++ /dev/null @@ -1,49 +0,0 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aai - * ================================================================================ - * Copyright © 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========================================================= - */ - -package org.onap.aai.logging; - -import static org.junit.Assert.*; -import static org.mockito.Mockito.*; - -import ch.qos.logback.classic.Level; -import ch.qos.logback.classic.spi.ILoggingEvent; - -import org.junit.*; - -public class EcompResponseCodeTest { - - EcompResponseCode _ecompResponseCode; - ILoggingEvent mockEvent; - - @Before - public void setUp() throws Exception { - - mockEvent = mock(ILoggingEvent.class); - _ecompResponseCode = spy(EcompResponseCode.class); - - } - - @Test - public void getDefaultCode() { - assertEquals(_ecompResponseCode.convert(mockEvent), LoggingContext.UNKNOWN_ERROR); - } - -} diff --git a/aai-core/src/test/java/org/onap/aai/logging/EcompResponseDescriptionTest.java b/aai-core/src/test/java/org/onap/aai/logging/EcompResponseDescriptionTest.java deleted file mode 100644 index 4bcf79cd..00000000 --- a/aai-core/src/test/java/org/onap/aai/logging/EcompResponseDescriptionTest.java +++ /dev/null @@ -1,50 +0,0 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aai - * ================================================================================ - * Copyright © 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========================================================= - */ - -package org.onap.aai.logging; - -import static org.junit.Assert.*; -import static org.mockito.Mockito.*; - -import ch.qos.logback.classic.Level; -import ch.qos.logback.classic.spi.ILoggingEvent; - -import org.junit.*; -import org.onap.aai.logging.LoggingContext.LoggingField; - -public class EcompResponseDescriptionTest { - - EcompResponseDescription _ecompResponseDescription; - ILoggingEvent mockEvent; - - @Before - public void setUp() throws Exception { - - mockEvent = mock(ILoggingEvent.class); - _ecompResponseDescription = spy(EcompResponseDescription.class); - - } - - @Test - public void getDefaultDesc() { - assertEquals(_ecompResponseDescription.convert(mockEvent), _ecompResponseDescription.DEFAULT_DESCRIPTION); - } - -} diff --git a/aai-core/src/test/java/org/onap/aai/logging/EelfClassOfCallerTest.java b/aai-core/src/test/java/org/onap/aai/logging/EelfClassOfCallerTest.java deleted file mode 100644 index bc77ae81..00000000 --- a/aai-core/src/test/java/org/onap/aai/logging/EelfClassOfCallerTest.java +++ /dev/null @@ -1,71 +0,0 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aai - * ================================================================================ - * Copyright © 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========================================================= - */ - -package org.onap.aai.logging; - -import static org.junit.Assert.*; -import static org.mockito.Mockito.*; - -import ch.qos.logback.classic.spi.ILoggingEvent; - -import org.junit.*; - -public class EelfClassOfCallerTest { - - EelfClassOfCaller _eelfClassOfCaller; - ILoggingEvent mockEvent; - StackTraceElement[] cdafive = new StackTraceElement[5]; - StackTraceElement[] cdaone = new StackTraceElement[1]; - StackTraceElement[] cdazero = new StackTraceElement[0]; - - @Before - public void setUp() throws Exception { - - mockEvent = mock(ILoggingEvent.class); - _eelfClassOfCaller = spy(EelfClassOfCaller.class); - - } - - @Test - public void getFullyQualifiedNameCDALENFiveTest() { - StackTraceElement temp = new StackTraceElement("classname_five", "methodname", "filename", 4); - cdafive[2] = temp; - when(mockEvent.getCallerData()).thenReturn(cdafive); - assertEquals(_eelfClassOfCaller.getFullyQualifiedName(mockEvent), "classname_five"); - - } - - @Test - public void getFullyQualifiedNameCDALenOneTest() { - StackTraceElement temp = new StackTraceElement("classname_one", "methodname", "filename", 4); - cdaone[0] = temp; - when(mockEvent.getCallerData()).thenReturn(cdaone); - assertEquals(_eelfClassOfCaller.getFullyQualifiedName(mockEvent), "classname_one"); - - } - - @Test - public void getFullyQualifiedNameCDALenZeroTest() { - when(mockEvent.getCallerData()).thenReturn(cdazero); - assertEquals(_eelfClassOfCaller.getFullyQualifiedName(mockEvent), "?"); - - } - -} diff --git a/aai-core/src/test/java/org/onap/aai/logging/ErrorObjectTest.java b/aai-core/src/test/java/org/onap/aai/logging/ErrorObjectTest.java index 1c55bc11..cbe5bc6b 100644 --- a/aai-core/src/test/java/org/onap/aai/logging/ErrorObjectTest.java +++ b/aai-core/src/test/java/org/onap/aai/logging/ErrorObjectTest.java @@ -20,12 +20,12 @@ package org.onap.aai.logging; -import static org.junit.Assert.*; +import org.junit.Test; -import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; -import org.junit.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; public class ErrorObjectTest { @@ -98,7 +98,7 @@ public class ErrorObjectTest { } @Test - public void SetErrorCodeTest() { + public void setErrorCodeTest() { newErrorObject.setErrorCode("newErrorCode"); assertEquals(newErrorObject.getErrorCode(), "newErrorCode"); } diff --git a/aai-core/src/test/java/org/onap/aai/logging/LoggingContextTest.java b/aai-core/src/test/java/org/onap/aai/logging/LoggingContextTest.java deleted file mode 100644 index 74347730..00000000 --- a/aai-core/src/test/java/org/onap/aai/logging/LoggingContextTest.java +++ /dev/null @@ -1,108 +0,0 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aai - * ================================================================================ - * Copyright © 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========================================================= - */ - -package org.onap.aai.logging; - -import static org.junit.Assert.*; - -import java.util.*; - -import org.junit.Test; - -public class LoggingContextTest { - - private static final int MAX_STORED_CONTEXTS = 100; - - @Test - public void testStopWatch() { - try { - LoggingContext.stopWatchStop(); - throw new AssertionError( - "No exception thrown when LoggingContext.stopWatchStop() called without a prior LoggingContext.stopWatchStart()"); - } catch (StopWatchNotStartedException e) { - // Expected - } - - LoggingContext.stopWatchStart(); - - assertTrue(LoggingContext.stopWatchStop() >= 0); - - try { - LoggingContext.stopWatchStop(); - throw new AssertionError("No exception thrown when LoggingContext.stopWatchStop() twice in succession"); - } catch (StopWatchNotStartedException e) { - // Expected - } - } - - @Test - public void testRequestId() { // AKA Transaction ID - final String sUuid = "57d51eaa-edc6-4f50-a69d-f2d4d2445120"; - - LoggingContext.requestId(sUuid); - - assertEquals(LoggingContext.requestId(), UUID.fromString(sUuid)); - - final UUID uuid = UUID.randomUUID(); - - LoggingContext.requestId(uuid); - - assertEquals(LoggingContext.requestId(), uuid); - - LoggingContext.requestId("foo"); // Illegal - this will result in a new, randomly - // generated UUID as per the logging spec - - assertNotNull(LoggingContext.requestId()); // Make sure ANY UUID was assigned - assertNotEquals(LoggingContext.requestId(), uuid); // Make sure it actually changed from the last - // known valid UUID - } - - @Test - public void testClear() { - LoggingContext.init(); - LoggingContext.clear(); - - assertEquals(Collections.emptyMap(), LoggingContext.getCopy()); - } - - @Test - public void testSaveRestore() { - - final Deque<Map<String, String>> contexts = new LinkedList<Map<String, String>>(); - - LoggingContext.init(); - - for (int i = 0; i < MAX_STORED_CONTEXTS; i++) { - LoggingContext.customField1(String.valueOf(i)); - - assertEquals(LoggingContext.customField1(), String.valueOf(i)); - - LoggingContext.save(); - - contexts.push(LoggingContext.getCopy()); - } - - while (contexts.peek() != null) { - LoggingContext.restore(); - - assertEquals(LoggingContext.getCopy(), contexts.pop()); - } - } -} diff --git a/aai-core/src/test/java/org/onap/aai/parsers/query/LegacyQueryTest.java b/aai-core/src/test/java/org/onap/aai/parsers/query/LegacyQueryTest.java index 4cdc55fa..e8ccdddd 100644 --- a/aai-core/src/test/java/org/onap/aai/parsers/query/LegacyQueryTest.java +++ b/aai-core/src/test/java/org/onap/aai/parsers/query/LegacyQueryTest.java @@ -20,15 +20,6 @@ package org.onap.aai.parsers.query; -import static org.junit.Assert.assertEquals; - -import java.io.UnsupportedEncodingException; -import java.net.URI; - -import javax.ws.rs.core.UriBuilder; -import javax.xml.bind.JAXBException; - -import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext; import org.junit.Ignore; import org.junit.Test; import org.onap.aai.AAISetup; @@ -39,12 +30,18 @@ import org.onap.aai.serialization.engines.QueryStyle; import org.onap.aai.serialization.engines.TransactionalGraphEngine; import org.onap.aai.setup.SchemaVersion; +import javax.ws.rs.core.UriBuilder; +import javax.xml.bind.JAXBException; +import java.io.UnsupportedEncodingException; +import java.net.URI; + +import static org.junit.Assert.assertEquals; + @Ignore public class LegacyQueryTest extends AAISetup { private TransactionalGraphEngine dbEngine; private SchemaVersion version; - private DynamicJAXBContext context = nodeIngestor.getContextForVersion(version); public void setup() { version = new SchemaVersion("v10"); @@ -60,7 +57,7 @@ public class LegacyQueryTest extends AAISetup { * @throws AAIException the AAI exception */ @Test - public void parentQuery() throws JAXBException, UnsupportedEncodingException, AAIException { + public void parentQuery() throws UnsupportedEncodingException, AAIException { URI uri = UriBuilder.fromPath("cloud-infrastructure/pservers/pserver/key1").build(); @@ -82,7 +79,7 @@ public class LegacyQueryTest extends AAISetup { * @throws AAIException the AAI exception */ @Test - public void childQuery() throws JAXBException, UnsupportedEncodingException, AAIException { + public void childQuery() throws UnsupportedEncodingException, AAIException { URI uri = UriBuilder.fromPath("cloud-infrastructure/pservers/pserver/key1/lag-interfaces/lag-interface/key2") .build(); QueryParser query = dbEngine.getQueryBuilder().createQueryFromURI(uri); @@ -104,7 +101,7 @@ public class LegacyQueryTest extends AAISetup { * @throws AAIException the AAI exception */ @Test - public void namingExceptions() throws JAXBException, UnsupportedEncodingException, AAIException { + public void namingExceptions() throws UnsupportedEncodingException, AAIException { URI uri = UriBuilder.fromPath("network/vces/vce/key1/port-groups/port-group/key2/cvlan-tags/cvlan-tag/655") .build(); diff --git a/aai-core/src/test/java/org/onap/aai/prevalidation/ValidationServiceTest.java b/aai-core/src/test/java/org/onap/aai/prevalidation/ValidationServiceTest.java new file mode 100644 index 00000000..883c8b61 --- /dev/null +++ b/aai-core/src/test/java/org/onap/aai/prevalidation/ValidationServiceTest.java @@ -0,0 +1,199 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2018-19 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========================================================= + */ + +package org.onap.aai.prevalidation; + +import com.google.gson.Gson; +import org.apache.http.conn.ConnectTimeoutException; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.Mockito; +import org.onap.aai.PayloadUtil; +import org.onap.aai.exceptions.AAIException; +import org.onap.aai.restclient.RestClient; +import org.springframework.boot.test.rule.OutputCapture; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; + +import java.io.IOException; +import java.net.ConnectException; +import java.net.SocketTimeoutException; +import java.util.List; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThat; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; + +public class ValidationServiceTest { + + private RestClient restClient; + + private ValidationService validationService; + + @Rule + public OutputCapture capture = new OutputCapture(); + + private Gson gson; + + @Before + public void setUp() throws Exception { + gson = new Gson(); + restClient = Mockito.mock(RestClient.class); + validationService = Mockito.spy(new ValidationService(restClient, "JUNIT", "generic-vnf", null)); + } + + @Test + public void testNodeTypeThatIsAllowedAndItShouldReturnTrue() { + boolean shouldValidate = validationService.shouldValidate("generic-vnf"); + assertThat(shouldValidate, is(true)); + } + + @Test + public void testNodeTypeThatIsNotAllowedAndItShouldReturnFalse() { + boolean shouldValidate = validationService.shouldValidate("customer"); + assertThat(shouldValidate, is(false)); + } + + @Test + public void testPreValidateWithSuccessRequestAndServiceIsDownAndShouldErrorWithConnectionRefused() throws IOException, AAIException { + + String pserverRequest = PayloadUtil.getResourcePayload("prevalidation/success-request-with-no-violations.json"); + + Mockito + .when( + restClient.execute( + eq(ValidationService.VALIDATION_ENDPOINT), + eq(HttpMethod.POST), + any(), + eq(pserverRequest) + ) + ).thenThrow(new RuntimeException(new ConnectException("Connection refused"))); + + validationService.preValidate(pserverRequest); + + assertThat(capture.toString(), containsString("Connection refused to the validation microservice due to service unreachable")); + } + + @Test + public void testPreValidateWithSuccessRequestAndServiceIsUnreachableAndShouldErrorWithConnectionTimeout() throws IOException, AAIException { + + String pserverRequest = PayloadUtil.getResourcePayload("prevalidation/success-request-with-no-violations.json"); + + Mockito + .when( + restClient.execute( + eq(ValidationService.VALIDATION_ENDPOINT), + eq(HttpMethod.POST), + any(), + eq(pserverRequest) + ) + ).thenThrow(new RuntimeException(new ConnectTimeoutException("Connection timed out"))); + + validationService.preValidate(pserverRequest); + + assertThat(capture.toString(), containsString("Connection timeout to the validation microservice as this could indicate the server is unable to reach port")); + } + + @Test + public void testPreValidateWithSuccessRequestAndRespondSuccessfullyWithinAllowedTime() throws IOException, AAIException { + + String pserverRequest = PayloadUtil.getResourcePayload("prevalidation/success-request-with-no-violations.json"); + String validationResponse = PayloadUtil.getResourcePayload("prevalidation/success-response-with-empty-violations.json"); + + ResponseEntity responseEntity = Mockito.mock(ResponseEntity.class, Mockito.RETURNS_DEEP_STUBS); + + Mockito + .when( + restClient.execute( + eq(ValidationService.VALIDATION_ENDPOINT), + eq(HttpMethod.POST), + any(), + eq(pserverRequest) + ) + ).thenReturn(responseEntity); + + Mockito.when(responseEntity.getStatusCodeValue()).thenReturn(200); + Mockito.when(responseEntity.getBody()).thenReturn(validationResponse); + + Mockito.doReturn(true).when(validationService).isSuccess(responseEntity); + + List<String> errorMessages = validationService.preValidate(pserverRequest); + assertNotNull("Expected the error messages to be not null", errorMessages); + assertThat(errorMessages.size(), is(0)); + } + + @Test + public void testPreValidateWithSuccessRequestAndServiceIsAvailableAndRequestIsTakingTooLongAndClientShouldTimeout() throws IOException, AAIException { + + String pserverRequest = PayloadUtil.getResourcePayload("prevalidation/success-request-with-no-violations.json"); + + Mockito + .when( + restClient.execute( + eq(ValidationService.VALIDATION_ENDPOINT), + eq(HttpMethod.POST), + any(), + eq(pserverRequest) + ) + ).thenThrow(new RuntimeException(new SocketTimeoutException("Request timed out due to taking longer than client expected"))); + + validationService.preValidate(pserverRequest); + + assertThat(capture.toString(), containsString("Request to validation service took longer than the currently set timeout")); + } + + @Test + public void testExtractViolationsReturnsSuccessfullyAListWhenViolationsAreFound() throws IOException { + + String genericVnfRequest = PayloadUtil.getResourcePayload("prevalidation/failed-response-with-violations.json"); + + Validation validation = gson.fromJson(genericVnfRequest, Validation.class); + List<String> errorMessages = validationService.extractViolations(validation); + assertNotNull("Expected the error messages to be not null", errorMessages); + assertThat(errorMessages.size(), is(1)); + assertThat(errorMessages.get(0), is("Invalid nf values, check nf-type, nf-role, nf-function, and nf-naming-code")); + } + + @Test + public void testErrorMessagesAreEmptyListWhenViolationsReturnEmptyList() throws IOException { + + String genericVnfRequest = PayloadUtil.getResourcePayload("prevalidation/success-response-with-empty-violations.json"); + + Validation validation = gson.fromJson(genericVnfRequest, Validation.class); + List<String> errorMessages = validationService.extractViolations(validation); + assertNotNull("Expected the error messages to be not null", errorMessages); + assertThat(errorMessages.size(), is(0)); + } + + @Test + public void testErrorMessagesAreEmptyListWhenViolationsIsNotFoundInJson() throws IOException { + + String genericVnfRequest = PayloadUtil.getResourcePayload("prevalidation/success-response-with-exclude-violations.json"); + + Validation validation = gson.fromJson(genericVnfRequest, Validation.class); + List<String> errorMessages = validationService.extractViolations(validation); + assertNotNull("Expected the error messages to be not null", errorMessages); + assertThat(errorMessages.size(), is(0)); + } +} diff --git a/aai-core/src/test/java/org/onap/aai/query/builder/QueryBuilderTestAbstraction.java b/aai-core/src/test/java/org/onap/aai/query/builder/QueryBuilderTestAbstraction.java index 0e527493..44d812c3 100644 --- a/aai-core/src/test/java/org/onap/aai/query/builder/QueryBuilderTestAbstraction.java +++ b/aai-core/src/test/java/org/onap/aai/query/builder/QueryBuilderTestAbstraction.java @@ -20,16 +20,8 @@ package org.onap.aai.query.builder; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.collection.IsIterableContainingInOrder.contains; -import static org.junit.Assert.*; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - import org.apache.tinkerpop.gremlin.process.traversal.Path; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; import org.apache.tinkerpop.gremlin.process.traversal.step.util.BulkSet; import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree; @@ -42,6 +34,7 @@ import org.junit.runner.RunWith; import org.onap.aai.config.ConfigConfiguration; import org.onap.aai.config.IntrospectionConfig; import org.onap.aai.config.SpringContextAware; +import org.onap.aai.config.XmlFormatTransformerConfiguration; import org.onap.aai.db.props.AAIProperties; import org.onap.aai.edges.EdgeIngestor; import org.onap.aai.edges.enums.EdgeType; @@ -53,7 +46,6 @@ import org.onap.aai.nodes.NodeIngestor; import org.onap.aai.serialization.db.EdgeSerializer; import org.onap.aai.serialization.db.exceptions.NoEdgeRuleFoundException; import org.onap.aai.serialization.queryformats.QueryFormatTestHelper; -import org.onap.aai.setup.SchemaLocationsBean; import org.onap.aai.setup.SchemaVersions; import org.onap.aai.util.AAIConstants; import org.springframework.beans.factory.annotation.Autowired; @@ -62,10 +54,19 @@ import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.collection.IsIterableContainingInOrder.contains; +import static org.junit.Assert.*; + @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration( classes = {ConfigConfiguration.class, QueryTestsConfigTranslator.class, NodeIngestor.class, EdgeIngestor.class, - EdgeSerializer.class, SpringContextAware.class, IntrospectionConfig.class}) + EdgeSerializer.class, SpringContextAware.class, IntrospectionConfig.class, XmlFormatTransformerConfiguration.class}) @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS) @TestPropertySource( properties = {"schema.translator.list = config", "schema.nodes.location=src/test/resources/onap/oxm", @@ -95,14 +96,14 @@ public abstract class QueryBuilderTestAbstraction { } @Before - public void configure() throws Exception { + public void configure() { loader = loaderFactory.createLoaderForVersion(ModelType.MOXY, schemaVersions.getDefaultVersion()); g = graph.traversal(); } @After - public void deConfigure() throws Exception { + public void deConfigure() { g.tx().rollback(); } @@ -111,11 +112,30 @@ public abstract class QueryBuilderTestAbstraction { graph.close(); } + /* + * This helper method was designed to minimize the changes needed due to the eventual + * removal of the addV(String...) method. + * Correct vertex creation addV(label).property(k,v).property(k,v)... + */ + @Deprecated + protected GraphTraversal<Vertex, Vertex> addVHelper(GraphTraversalSource gts, String label, Object... props) { + for (int i = 0; i < props.length; i++) { + if (props[i].equals(AAIProperties.NODE_TYPE)) { + label = props[i+1].toString(); + } + } + GraphTraversal<Vertex, Vertex> v = gts.addV(label); + for (int i = 0; i < props.length; i+=2) { + v.property(props[i], props[i+1]); + } + return v; + } + @Test public void createEdgeGVnfToVnfcTraversal() throws AAIException { - Vertex gvnf = g.addV("aai-node-type", "generic-vnf", "vnf-id", "myvnf").next(); - Vertex vnfc = g.addV("aai-node-type", "vnfc", "vnfc-name", "a-name").next(); + Vertex gvnf = this.addVHelper(g, "vertex", "aai-node-type", "generic-vnf", "vnf-id", "myvnf").next(); + Vertex vnfc = this.addVHelper(g, "vertex", "aai-node-type", "vnfc", "vnfc-name", "a-name").next(); testEdgeSer.addEdge(g, gvnf, vnfc, "uses"); QueryBuilder<Vertex> tQ = getNewVertexTraversalWithTestEdgeRules(gvnf); @@ -128,8 +148,8 @@ public abstract class QueryBuilderTestAbstraction { @Test public void createEdgeLinterfaceToLogicalLinkTraversal() throws AAIException { - Vertex lInterface = g.addV("aai-node-type", "l-interface", "interface-name", "l-interface-a").next(); - Vertex logicalLink = g.addV("aai-node-type", "logical-link", "link-name", "logical-link-a").next(); + Vertex lInterface = this.addVHelper(g, "vertex", "aai-node-type", "l-interface", "interface-name", "l-interface-a").next(); + Vertex logicalLink = this.addVHelper(g, "vertex", "aai-node-type", "logical-link", "link-name", "logical-link-a").next(); testEdgeSer.addEdge(g, lInterface, logicalLink, "sourceLInterface"); QueryBuilder<Vertex> tQ = getNewVertexTraversalWithTestEdgeRules(lInterface); @@ -144,8 +164,8 @@ public abstract class QueryBuilderTestAbstraction { @SuppressWarnings("rawtypes") @Test public void createEdgeLinterfaceToLogicalLinkTraversal_tree() throws AAIException { - Vertex lInterface = g.addV("aai-node-type", "l-interface", "interface-name", "l-interface-a").next(); - Vertex logicalLink = g.addV("aai-node-type", "logical-link", "link-name", "logical-link-a").next(); + Vertex lInterface = this.addVHelper(g, "vertex", "aai-node-type", "l-interface", "interface-name", "l-interface-a").next(); + Vertex logicalLink = this.addVHelper(g, "vertex", "aai-node-type", "logical-link", "link-name", "logical-link-a").next(); testEdgeSer.addEdge(g, lInterface, logicalLink, "sourceLInterface"); QueryBuilder<Tree> tQ = getNewTreeTraversalWithTestEdgeRules(lInterface).createEdgeTraversal(EdgeType.COUSIN, @@ -163,9 +183,9 @@ public abstract class QueryBuilderTestAbstraction { @SuppressWarnings("rawtypes") @Test public void createEdgeLinterfaceToLogicalLinkTraversal_Path() throws AAIException { - Vertex pInterface = g.addV("aai-node-type", "p-interface", "interface-name", "p-interface-a").next(); - Vertex lInterface = g.addV("aai-node-type", "l-interface", "interface-name", "l-interface-a").next(); - Vertex logicalLink = g.addV("aai-node-type", "logical-link", "link-name", "logical-link-a").next(); + Vertex pInterface = this.addVHelper(g, "vertex", "aai-node-type", "p-interface", "interface-name", "p-interface-a").next(); + Vertex lInterface = this.addVHelper(g, "vertex", "aai-node-type", "l-interface", "interface-name", "l-interface-a").next(); + Vertex logicalLink = this.addVHelper(g, "vertex", "aai-node-type", "logical-link", "link-name", "logical-link-a").next(); testEdgeSer.addEdge(g, lInterface, logicalLink); testEdgeSer.addTreeEdge(g, pInterface, lInterface); @@ -183,8 +203,8 @@ public abstract class QueryBuilderTestAbstraction { @SuppressWarnings("rawtypes") @Test public void parentVertexTest() throws AAIException { - Vertex pInterface = g.addV("aai-node-type", "p-interface", "interface-name", "p-interface-a").next(); - Vertex lInterface = g.addV("aai-node-type", "l-interface", "interface-name", "l-interface-a").next(); + Vertex pInterface = this.addVHelper(g, "vertex", "aai-node-type", "p-interface", "interface-name", "p-interface-a").next(); + Vertex lInterface = this.addVHelper(g, "vertex", "aai-node-type", "l-interface", "interface-name", "l-interface-a").next(); testEdgeSer.addTreeEdge(g, pInterface, lInterface); @@ -197,8 +217,8 @@ public abstract class QueryBuilderTestAbstraction { @Test public void createEdgeLinterfaceToLogicalLinkIntrospectorTraversal() throws AAIException { - Vertex lInterface = g.addV("aai-node-type", "l-interface", "interface-name", "l-interface-a").next(); - Vertex logicalLink = g.addV("aai-node-type", "logical-link", "link-name", "logical-link-a").next(); + Vertex lInterface = this.addVHelper(g, "vertex", "aai-node-type", "l-interface", "interface-name", "l-interface-a").next(); + Vertex logicalLink = this.addVHelper(g, "vertex", "aai-node-type", "logical-link", "link-name", "logical-link-a").next(); testEdgeSer.addEdge(g, lInterface, logicalLink, "sourceLInterface"); QueryBuilder<Vertex> tQ = getNewVertexTraversalWithTestEdgeRules(lInterface); @@ -214,8 +234,8 @@ public abstract class QueryBuilderTestAbstraction { @Test public void createEdgeLinterfaceToLogicalLinkVertexToIntrospectorTraversal() throws AAIException { - Vertex lInterface = g.addV("aai-node-type", "l-interface", "interface-name", "l-interface-a").next(); - Vertex logicalLink = g.addV("aai-node-type", "logical-link", "link-name", "logical-link-a").next(); + Vertex lInterface = this.addVHelper(g, "vertex", "aai-node-type", "l-interface", "interface-name", "l-interface-a").next(); + Vertex logicalLink = this.addVHelper(g, "vertex", "aai-node-type", "logical-link", "link-name", "logical-link-a").next(); testEdgeSer.addEdge(g, lInterface, logicalLink, "sourceLInterface"); QueryBuilder<Vertex> tQ = getNewVertexTraversalWithTestEdgeRules(lInterface); @@ -230,8 +250,8 @@ public abstract class QueryBuilderTestAbstraction { @Test public void edgeToVertexTraversalTest() throws AAIException { - Vertex gvnf = g.addV("aai-node-type", "generic-vnf", "vnf-id", "gvnf").next(); - Vertex vnfc1 = g.addV("aai-node-type", "vnfc", "vnfc-name", "a-name").next(); + Vertex gvnf = this.addVHelper(g, "vertex", "aai-node-type", "generic-vnf", "vnf-id", "gvnf").next(); + Vertex vnfc1 = this.addVHelper(g, "vertex", "aai-node-type", "vnfc", "vnfc-name", "a-name").next(); testEdgeSer.addEdge(g, gvnf, vnfc1); @@ -248,8 +268,8 @@ public abstract class QueryBuilderTestAbstraction { @Test public void edgeToVertexTraversalSingleOutRuleTest() throws AAIException { - Vertex vce = g.addV("aai-node-type", "vce", "vnf-id", "vce").next(); - Vertex vnfc1 = g.addV("aai-node-type", "vnfc", "vnfc-name", "a-name").next(); + Vertex vce = this.addVHelper(g, "vertex", "aai-node-type", "vce", "vnf-id", "vce").next(); + Vertex vnfc1 = this.addVHelper(g, "vertex", "aai-node-type", "vnfc", "vnfc-name", "a-name").next(); testEdgeSer.addEdge(g, vce, vnfc1); @@ -272,8 +292,8 @@ public abstract class QueryBuilderTestAbstraction { @Test public void edgeToVertexTraversalSingleInRuleTest() throws AAIException { - Vertex vce = g.addV("aai-node-type", "vce", "vnf-id", "vce").next(); - Vertex pserver = g.addV("aai-node-type", "pserver", "hostname", "a-name").next(); + Vertex vce = this.addVHelper(g, "vertex", "aai-node-type", "vce", "vnf-id", "vce").next(); + Vertex pserver = this.addVHelper(g, "vertex", "aai-node-type", "pserver", "hostname", "a-name").next(); testEdgeSer.addEdge(g, vce, pserver); @@ -290,9 +310,9 @@ public abstract class QueryBuilderTestAbstraction { @Test public void edgeToVertexMultiRuleTraversalTest() throws AAIException { - Vertex gvnf = g.addV("aai-node-type", "generic-vnf", "vnf-id", "gvnf").next(); - Vertex vnfc1 = g.addV("aai-node-type", "vnfc", "vnfc-name", "a-name").next(); - Vertex vnfc2 = g.addV("aai-node-type", "vnfc", "vnfc-name", "b-name").next(); + Vertex gvnf = this.addVHelper(g, "vertex", "aai-node-type", "generic-vnf", "vnf-id", "gvnf").next(); + Vertex vnfc1 = this.addVHelper(g, "vertex", "aai-node-type", "vnfc", "vnfc-name", "a-name").next(); + Vertex vnfc2 = this.addVHelper(g, "vertex", "aai-node-type", "vnfc", "vnfc-name", "b-name").next(); testEdgeSer.addEdge(g, gvnf, vnfc1); testEdgeSer.addEdge(g, gvnf, vnfc2, "re-uses"); @@ -311,9 +331,9 @@ public abstract class QueryBuilderTestAbstraction { @Test public void edgeToVertexMultiLabelTest() throws AAIException { - Vertex gvnf = g.addV("aai-node-type", "generic-vnf", "vnf-id", "gvnf").next(); - Vertex pserver = g.addV("aai-node-type", "pserver", "hostname", "a-name").next(); - Vertex vnfc1 = g.addV("aai-node-type", "vnfc", "vnfc-name", "a-name").next(); + Vertex gvnf = this.addVHelper(g, "vertex", "aai-node-type", "generic-vnf", "vnf-id", "gvnf").next(); + Vertex pserver = this.addVHelper(g, "vertex", "aai-node-type", "pserver", "hostname", "a-name").next(); + Vertex vnfc1 = this.addVHelper(g, "vertex", "aai-node-type", "vnfc", "vnfc-name", "a-name").next(); testEdgeSer.addEdge(g, gvnf, vnfc1); testEdgeSer.addEdge(g, pserver, vnfc1); @@ -329,10 +349,10 @@ public abstract class QueryBuilderTestAbstraction { } @Test - public void limitTraversalTest() throws AAIException { + public void limitTraversalTest() { - g.addV("aai-node-type", "vnfc", "vnfc-name", "a-name").next(); - g.addV("aai-node-type", "vnfc", "vnfc-name", "b-name").next(); + this.addVHelper(g, "vertex", "aai-node-type", "vnfc", "vnfc-name", "a-name").next(); + this.addVHelper(g, "vertex", "aai-node-type", "vnfc", "vnfc-name", "b-name").next(); QueryBuilder<Vertex> tQ = new GremlinTraversal<>(loader, g); tQ.getVerticesByProperty("aai-node-type", "vnfc").limit(1); @@ -344,10 +364,10 @@ public abstract class QueryBuilderTestAbstraction { } @Test - public void getVertexesByPropertiesTraversalTest() throws AAIException { + public void getVertexesByPropertiesTraversalTest() { - g.addV("aai-node-type", "vnfc", "vnfc-name", "a-name").next(); - g.addV("aai-node-type", "vnfc", "vnfc-name", "b-name").next(); + this.addVHelper(g, "vertex", "aai-node-type", "vnfc", "vnfc-name", "a-name").next(); + this.addVHelper(g, "vertex", "aai-node-type", "vnfc", "vnfc-name", "b-name").next(); QueryBuilder<Vertex> tQ = new GremlinTraversal<>(loader, g); tQ.getVerticesByProperty("vnfc-name", Arrays.asList("a-name", "b-name")); @@ -359,25 +379,38 @@ public abstract class QueryBuilderTestAbstraction { } @Test - public void getVertexesByIndexedPropertyTraversalTest() throws AAIException { + public void getVerticesByCommaSeperatedValueTraversalTest() { - g.addV("aai-node-type", "vnfc", "vnfc-name", "a-name").next(); - g.addV("aai-node-type", "vnfc", "vnfc-name", "b-name").next(); + this.addVHelper(g, "vertex", "aai-node-type", "vnfc", "vnfc-name", "a-name").next(); + this.addVHelper(g, "vertex", "aai-node-type", "vnfc", "vnfc-name", "b-name").next(); QueryBuilder<Vertex> tQ = new GremlinTraversal<>(loader, g); - tQ.getVerticesByIndexedProperty("aai-node-type", "vnfc"); + tQ.getVerticesByCommaSeperatedValue("vnfc-name","a-name, b-name"); List<Vertex> list = tQ.toList(); assertEquals("Has 2 vertexes ", 2, list.size()); + } + + @Test + public void getVertexesByIndexedPropertyTraversalTest() { + + this.addVHelper(g, "vertex", "aai-node-type", "vnfc", "vnfc-name", "a-name").next(); + this.addVHelper(g, "vertex", "aai-node-type", "vnfc", "vnfc-name", "b-name").next(); + QueryBuilder<Vertex> tQ = new GremlinTraversal<>(loader, g); + tQ.getVerticesByIndexedProperty("aai-node-type", "vnfc"); + + List<Vertex> list = tQ.toList(); + + assertEquals("Has 2 vertexes ", 2, list.size()); } @Test public void dedupTraversalTest() throws AAIException { - Vertex gvnf = g.addV("aai-node-type", "generic-vnf", "vnf-id", "gvnf").next(); - Vertex pserver = g.addV("aai-node-type", "pserver", "hostname", "a-name").next(); + Vertex gvnf = this.addVHelper(g, "vertex", "aai-node-type", "generic-vnf", "vnf-id", "gvnf").next(); + Vertex pserver = this.addVHelper(g, "vertex", "aai-node-type", "pserver", "hostname", "a-name").next(); testEdgeSer.addEdge(g, gvnf, pserver); testEdgeSer.addEdge(g, gvnf, pserver, "generic-vnf-pserver-B"); @@ -395,8 +428,8 @@ public abstract class QueryBuilderTestAbstraction { @Test public void storeCapTraversalTest() throws AAIException { - Vertex gvnf = g.addV("aai-node-type", "generic-vnf", "vnf-id", "gvnf").next(); - Vertex pserver = g.addV("aai-node-type", "pserver", "hostname", "a-name").next(); + Vertex gvnf = this.addVHelper(g, "vertex", "aai-node-type", "generic-vnf", "vnf-id", "gvnf").next(); + Vertex pserver = this.addVHelper(g, "vertex", "aai-node-type", "pserver", "hostname", "a-name").next(); testEdgeSer.addEdge(g, gvnf, pserver); testEdgeSer.addEdge(g, gvnf, pserver, "generic-vnf-pserver-B"); @@ -414,8 +447,8 @@ public abstract class QueryBuilderTestAbstraction { @Test public void storeCapUnfoldTraversalTest() throws AAIException { - Vertex gvnf = g.addV("aai-node-type", "generic-vnf", "vnf-id", "gvnf").next(); - Vertex pserver = g.addV("aai-node-type", "pserver", "hostname", "a-name").next(); + Vertex gvnf = this.addVHelper(g, "vertex", "aai-node-type", "generic-vnf", "vnf-id", "gvnf").next(); + Vertex pserver = this.addVHelper(g, "vertex", "aai-node-type", "pserver", "hostname", "a-name").next(); testEdgeSer.addEdge(g, gvnf, pserver); testEdgeSer.addEdge(g, gvnf, pserver, "generic-vnf-pserver-B"); @@ -431,10 +464,10 @@ public abstract class QueryBuilderTestAbstraction { } @Test - public void nextAndHasNextTraversalTest() throws AAIException { + public void nextAndHasNextTraversalTest() { - Vertex v1 = g.addV("aai-node-type", "vnfc", "vnfc-name", "a-name").next(); - Vertex v2 = g.addV("aai-node-type", "vnfc", "vnfc-name", "b-name").next(); + Vertex v1 = this.addVHelper(g, "vertex", "aai-node-type", "vnfc", "vnfc-name", "a-name").next(); + Vertex v2 = this.addVHelper(g, "vertex", "aai-node-type", "vnfc", "vnfc-name", "b-name").next(); QueryBuilder<Vertex> tQ = new GremlinTraversal<>(loader, g); tQ.getVerticesByProperty("aai-node-type", "vnfc"); @@ -453,8 +486,8 @@ public abstract class QueryBuilderTestAbstraction { @Test public void edgeToVertexMultiRuleOutTraversalTest() throws AAIException { - Vertex gvnf = g.addV("aai-node-type", "generic-vnf", "vnf-id", "gvnf").next(); - Vertex pserver = g.addV("aai-node-type", "pserver", "hostname", "a-name").next(); + Vertex gvnf = this.addVHelper(g, "vertex", "aai-node-type", "generic-vnf", "vnf-id", "gvnf").next(); + Vertex pserver = this.addVHelper(g, "vertex", "aai-node-type", "pserver", "hostname", "a-name").next(); testEdgeSer.addEdge(g, gvnf, pserver); testEdgeSer.addEdge(g, gvnf, pserver, "generic-vnf-pserver-B"); @@ -472,8 +505,8 @@ public abstract class QueryBuilderTestAbstraction { @Test public void edgeToVertexMultiRuleInTraversalTest() throws AAIException { - Vertex gvnf = g.addV("aai-node-type", "generic-vnf", "vnf-id", "gvnf").next(); - Vertex complex = g.addV("aai-node-type", "complex", "physical-location-id", "a-name").next(); + Vertex gvnf = this.addVHelper(g, "vertex", "aai-node-type", "generic-vnf", "vnf-id", "gvnf").next(); + Vertex complex = this.addVHelper(g, "vertex", "aai-node-type", "complex", "physical-location-id", "a-name").next(); testEdgeSer.addEdge(g, gvnf, complex); testEdgeSer.addEdge(g, gvnf, complex, "complex-generic-vnf-B"); @@ -491,8 +524,8 @@ public abstract class QueryBuilderTestAbstraction { @Test public void edgeTraversalSingleInRuleTest() throws AAIException { - Vertex vce = g.addV("aai-node-type", "vce", "vnf-id", "vce").next(); - Vertex pserver = g.addV("aai-node-type", "pserver", "hostname", "a-name").next(); + Vertex vce = this.addVHelper(g, "vertex", "aai-node-type", "vce", "vnf-id", "vce").next(); + Vertex pserver = this.addVHelper(g, "vertex", "aai-node-type", "pserver", "hostname", "a-name").next(); Edge e = testEdgeSer.addEdge(g, vce, pserver); @@ -509,8 +542,8 @@ public abstract class QueryBuilderTestAbstraction { @Test public void edgeTraversalSingleOutRuleTest() throws AAIException { - Vertex vce = g.addV("aai-node-type", "vce", "vnf-id", "vce").next(); - Vertex vnfc1 = g.addV("aai-node-type", "vnfc", "vnfc-name", "a-name").next(); + Vertex vce = this.addVHelper(g, "vertex", "aai-node-type", "vce", "vnf-id", "vce").next(); + Vertex vnfc1 = this.addVHelper(g, "vertex", "aai-node-type", "vnfc", "vnfc-name", "a-name").next(); Edge e = testEdgeSer.addEdge(g, vce, vnfc1); @@ -527,8 +560,8 @@ public abstract class QueryBuilderTestAbstraction { @Test public void edgeTraversalMultiRuleOutTraversalTest() throws AAIException { - Vertex gvnf = g.addV("aai-node-type", "generic-vnf", "vnf-id", "gvnf").next(); - Vertex pserver = g.addV("aai-node-type", "pserver", "hostname", "a-name").next(); + Vertex gvnf = this.addVHelper(g, "vertex", "aai-node-type", "generic-vnf", "vnf-id", "gvnf").next(); + Vertex pserver = this.addVHelper(g, "vertex", "aai-node-type", "pserver", "hostname", "a-name").next(); Edge e1 = testEdgeSer.addEdge(g, gvnf, pserver); Edge e2 = testEdgeSer.addEdge(g, gvnf, pserver, "generic-vnf-pserver-B"); @@ -547,8 +580,8 @@ public abstract class QueryBuilderTestAbstraction { @Test public void edgeTraversalMultiRuleInTraversalTest() throws AAIException { - Vertex gvnf = g.addV("aai-node-type", "generic-vnf", "vnf-id", "gvnf").next(); - Vertex complex = g.addV("aai-node-type", "complex", "physical-location-id", "a-name").next(); + Vertex gvnf = this.addVHelper(g, "vertex", "aai-node-type", "generic-vnf", "vnf-id", "gvnf").next(); + Vertex complex = this.addVHelper(g, "vertex", "aai-node-type", "complex", "physical-location-id", "a-name").next(); Edge e1 = testEdgeSer.addEdge(g, gvnf, complex); Edge e2 = testEdgeSer.addEdge(g, gvnf, complex, "complex-generic-vnf-B"); @@ -567,9 +600,9 @@ public abstract class QueryBuilderTestAbstraction { @Test public void edgeTraversalMultiRuleTraversalTest() throws AAIException { - Vertex gvnf = g.addV("aai-node-type", "generic-vnf", "vnf-id", "gvnf").next(); - Vertex vnfc1 = g.addV("aai-node-type", "vnfc", "vnfc-name", "a-name").next(); - Vertex vnfc2 = g.addV("aai-node-type", "vnfc", "vnfc-name", "b-name").next(); + Vertex gvnf = this.addVHelper(g, "vertex", "aai-node-type", "generic-vnf", "vnf-id", "gvnf").next(); + Vertex vnfc1 = this.addVHelper(g, "vertex", "aai-node-type", "vnfc", "vnfc-name", "a-name").next(); + Vertex vnfc2 = this.addVHelper(g, "vertex", "aai-node-type", "vnfc", "vnfc-name", "b-name").next(); Edge e1 = testEdgeSer.addEdge(g, gvnf, vnfc1); Edge e2 = testEdgeSer.addEdge(g, gvnf, vnfc2, "re-uses"); @@ -589,8 +622,8 @@ public abstract class QueryBuilderTestAbstraction { @Test(expected = NoEdgeRuleFoundException.class) public void getEdgesBetweenWithLabelsEmptyListTest() throws AAIException { - Vertex gvnf = g.addV("aai-node-type", "generic-vnf", "vnf-id", "gvnf").next(); - Vertex pserver = g.addV("aai-node-type", "pserver", "hostname", "a-name").next(); + Vertex gvnf = this.addVHelper(g, "vertex", "aai-node-type", "generic-vnf", "vnf-id", "gvnf").next(); + Vertex pserver = this.addVHelper(g, "vertex", "aai-node-type", "pserver", "hostname", "a-name").next(); testEdgeSer.addEdge(g, gvnf, pserver); testEdgeSer.addEdge(g, gvnf, pserver, "generic-vnf-pserver-B"); @@ -603,8 +636,8 @@ public abstract class QueryBuilderTestAbstraction { @Test public void getEdgesBetweenWithLabelsSingleItemTest() throws AAIException { - Vertex gvnf = g.addV("aai-node-type", "generic-vnf", "vnf-id", "gvnf").next(); - Vertex pserver = g.addV("aai-node-type", "pserver", "hostname", "a-name").next(); + Vertex gvnf = this.addVHelper(g, "vertex", "aai-node-type", "generic-vnf", "vnf-id", "gvnf").next(); + Vertex pserver = this.addVHelper(g, "vertex", "aai-node-type", "pserver", "hostname", "a-name").next(); Edge e1 = testEdgeSer.addEdge(g, gvnf, pserver); Edge e2 = testEdgeSer.addEdge(g, gvnf, pserver, "generic-vnf-pserver-B"); @@ -624,8 +657,8 @@ public abstract class QueryBuilderTestAbstraction { @Test public void getEdgesBetweenWithLabelsMultipleItemTest() throws AAIException { - Vertex gvnf = g.addV("aai-node-type", "generic-vnf", "vnf-id", "gvnf").next(); - Vertex pserver = g.addV("aai-node-type", "pserver", "hostname", "a-name").next(); + Vertex gvnf = this.addVHelper(g, "vertex", "aai-node-type", "generic-vnf", "vnf-id", "gvnf").next(); + Vertex pserver = this.addVHelper(g, "vertex", "aai-node-type", "pserver", "hostname", "a-name").next(); Edge e1 = testEdgeSer.addEdge(g, gvnf, pserver); Edge e2 = testEdgeSer.addEdge(g, gvnf, pserver, "generic-vnf-pserver-B"); @@ -656,8 +689,8 @@ public abstract class QueryBuilderTestAbstraction { } private Vertex getVertex() throws AAIException { - Vertex gvnf = g.addV("aai-node-type", "generic-vnf", "vnf-id", "gvnf").next(); - Vertex pserver = g.addV("aai-node-type", "pserver", "hostname", "a-name").next(); + Vertex gvnf = this.addVHelper(g, "vertex", "aai-node-type", "generic-vnf", "vnf-id", "gvnf").next(); + Vertex pserver = this.addVHelper(g, "vertex", "aai-node-type", "pserver", "hostname", "a-name").next(); testEdgeSer.addEdge(g, gvnf, pserver); testEdgeSer.addEdge(g, gvnf, pserver, "generic-vnf-pserver-B"); @@ -667,8 +700,8 @@ public abstract class QueryBuilderTestAbstraction { @Test public void createEdgeTraversalWithLabelsSingleItemTest() throws AAIException { - Vertex gvnf = g.addV("aai-node-type", "generic-vnf", "vnf-id", "gvnf").next(); - Vertex pserver = g.addV("aai-node-type", "pserver", "hostname", "a-name").next(); + Vertex gvnf = this.addVHelper(g, "vertex", "aai-node-type", "generic-vnf", "vnf-id", "gvnf").next(); + Vertex pserver = this.addVHelper(g, "vertex", "aai-node-type", "pserver", "hostname", "a-name").next(); Edge e1 = testEdgeSer.addEdge(g, gvnf, pserver); Edge e2 = testEdgeSer.addEdge(g, gvnf, pserver, "generic-vnf-pserver-B"); @@ -688,8 +721,8 @@ public abstract class QueryBuilderTestAbstraction { @Test public void createEdgeTraversalWithLabelsMultipleItemTest() throws AAIException { - Vertex gvnf = g.addV("aai-node-type", "generic-vnf", "vnf-id", "gvnf").next(); - Vertex pserver = g.addV("aai-node-type", "pserver", "hostname", "a-name").next(); + Vertex gvnf = this.addVHelper(g, "vertex", "aai-node-type", "generic-vnf", "vnf-id", "gvnf").next(); + Vertex pserver = this.addVHelper(g, "vertex", "aai-node-type", "pserver", "hostname", "a-name").next(); Edge e1 = testEdgeSer.addEdge(g, gvnf, pserver); Edge e2 = testEdgeSer.addEdge(g, gvnf, pserver, "generic-vnf-pserver-B"); @@ -706,6 +739,50 @@ public abstract class QueryBuilderTestAbstraction { } + @Test + public void createEdgeTraversalIfParameterIsPresentParameterExistsTest() throws AAIException { + + Vertex gvnf = this.addVHelper(g, "vertex", "aai-node-type", "generic-vnf", "vnf-id", "gvnf").next(); + Vertex pserver1 = this.addVHelper(g, "vertex", "aai-node-type", "pserver", "hostname", "a-name").next(); + Vertex pserver2 = this.addVHelper(g, "vertex", "aai-node-type", "pserver", "hostname", "b-name").next(); + Vertex optionalVce = this.addVHelper(g, "vertex", "aai-node-type", "vce", "vnf-id", "optional").next(); + + testEdgeSer.addEdge(g, gvnf, pserver1); + testEdgeSer.addEdge(g, gvnf, pserver2); + testEdgeSer.addEdge(g, optionalVce, pserver1); + + QueryBuilder<Edge> tQ = getNewEdgeTraversalWithTestEdgeRules(gvnf); + tQ.createEdgeTraversal(EdgeType.COUSIN, "generic-vnf", "pserver"); + + List<Vertex> list = tQ.createEdgeTraversalIfParameterIsPresent(EdgeType.COUSIN, "pserver", "vce", "optional").toList(); + assertEquals("Has 1 vertex ", 1, list.size()); + assertTrue("result has optional-vce vertex ", list.contains(optionalVce)); + } + + @Test + public void createEdgeTraversalIfParameterIsPresentParameterDoesNotExistTest() throws AAIException { + + Vertex gvnf = this.addVHelper(g, "vertex", "aai-node-type", "generic-vnf", "vnf-id", "gvnf").next(); + Vertex pserver1 = this.addVHelper(g, "vertex", "aai-node-type", "pserver", "hostname", "a-name").next(); + Vertex pserver2 = this.addVHelper(g, "vertex", "aai-node-type", "pserver", "hostname", "b-name").next(); + Vertex optionalVce = this.addVHelper(g, "vertex", "aai-node-type", "vce", "vnf-id", "optional").next(); + + testEdgeSer.addEdge(g, gvnf, pserver1); + testEdgeSer.addEdge(g, gvnf, pserver2); + testEdgeSer.addEdge(g, optionalVce, pserver1); + + QueryBuilder<Edge> tQ = getNewEdgeTraversalWithTestEdgeRules(gvnf); + tQ.createEdgeTraversal(EdgeType.COUSIN, "generic-vnf", "pserver"); + MissingOptionalParameter missingParameter = MissingOptionalParameter.getInstance(); + + List<Vertex> list = tQ.createEdgeTraversalIfParameterIsPresent(EdgeType.COUSIN, "pserver", "vce", missingParameter).toList(); + assertEquals("Has 2 vertices ", 2, list.size()); + assertTrue("result has pserver-1 vertex ", list.contains(pserver1)); + assertTrue("result has pserver-2 vertex ", list.contains(pserver2)); + assertTrue("result does not have optional-vce vertex ", !list.contains(optionalVce)); + } + + protected abstract QueryBuilder<Edge> getNewEdgeTraversalWithTestEdgeRules(Vertex v); protected abstract QueryBuilder<Edge> getNewEdgeTraversalWithTestEdgeRules(); diff --git a/aai-core/src/test/java/org/onap/aai/query/builder/TraversalQueryTest.java b/aai-core/src/test/java/org/onap/aai/query/builder/TraversalQueryTest.java index eb1e57c3..4eac35eb 100644 --- a/aai-core/src/test/java/org/onap/aai/query/builder/TraversalQueryTest.java +++ b/aai-core/src/test/java/org/onap/aai/query/builder/TraversalQueryTest.java @@ -20,14 +20,6 @@ package org.onap.aai.query.builder; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import java.io.UnsupportedEncodingException; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.List; - import org.apache.tinkerpop.gremlin.process.traversal.Path; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__; @@ -40,6 +32,14 @@ import org.onap.aai.db.props.AAIProperties; import org.onap.aai.edges.enums.EdgeType; import org.onap.aai.exceptions.AAIException; +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + public class TraversalQueryTest extends QueryBuilderTestAbstraction { @Override @@ -141,8 +141,8 @@ public class TraversalQueryTest extends QueryBuilderTestAbstraction { @Test public void abstractEdgeToVertexTraversalTest() throws AAIException { - Vertex gvnf = g.addV("aai-node-type", "generic-vnf", "vnf-id", "gvnf").next(); - Vertex vnfc1 = g.addV("aai-node-type", "vnfc", "vnfc-name", "a-name").next(); + Vertex gvnf = this.addVHelper(g, "vertex", "aai-node-type", "generic-vnf", "vnf-id", "gvnf").next(); + Vertex vnfc1 = this.addVHelper(g, "vertex", "aai-node-type", "vnfc", "vnfc-name", "a-name").next(); testEdgeSer.addEdge(g, gvnf, vnfc1); @@ -159,8 +159,8 @@ public class TraversalQueryTest extends QueryBuilderTestAbstraction { @Test public void abstractEdgeToVertexTraversalSingleOutRuleTest() throws AAIException { - Vertex vce = g.addV("aai-node-type", "vce", "vnf-id", "vce").next(); - Vertex vnfc1 = g.addV("aai-node-type", "vnfc", "vnfc-name", "a-name").next(); + Vertex vce = this.addVHelper(g, "vertex", "aai-node-type", "vce", "vnf-id", "vce").next(); + Vertex vnfc1 = this.addVHelper(g, "vertex", "aai-node-type", "vnfc", "vnfc-name", "a-name").next(); testEdgeSer.addEdge(g, vce, vnfc1); @@ -183,8 +183,8 @@ public class TraversalQueryTest extends QueryBuilderTestAbstraction { @Test public void abstractEdgeToVertexTraversalSingleInRuleTest() throws AAIException { - Vertex vce = g.addV("aai-node-type", "vce", "vnf-id", "vce").next(); - Vertex pserver = g.addV("aai-node-type", "pserver", "hostname", "a-name").next(); + Vertex vce = this.addVHelper(g, "vertex", "aai-node-type", "vce", "vnf-id", "vce").next(); + Vertex pserver = this.addVHelper(g, "vertex", "aai-node-type", "pserver", "hostname", "a-name").next(); testEdgeSer.addEdge(g, vce, pserver); @@ -201,9 +201,9 @@ public class TraversalQueryTest extends QueryBuilderTestAbstraction { @Test public void abstractEdgeToVertexMultiRuleTraversalTest() throws AAIException { - Vertex gvnf = g.addV("aai-node-type", "generic-vnf", "vnf-id", "gvnf").next(); - Vertex vnfc1 = g.addV("aai-node-type", "vnfc", "vnfc-name", "a-name").next(); - Vertex vnfc2 = g.addV("aai-node-type", "vnfc", "vnfc-name", "b-name").next(); + Vertex gvnf = this.addVHelper(g, "vertex", "aai-node-type", "generic-vnf", "vnf-id", "gvnf").next(); + Vertex vnfc1 = this.addVHelper(g, "vertex", "aai-node-type", "vnfc", "vnfc-name", "a-name").next(); + Vertex vnfc2 = this.addVHelper(g, "vertex", "aai-node-type", "vnfc", "vnfc-name", "b-name").next(); testEdgeSer.addEdge(g, gvnf, vnfc1); testEdgeSer.addEdge(g, gvnf, vnfc2, "re-uses"); @@ -222,8 +222,8 @@ public class TraversalQueryTest extends QueryBuilderTestAbstraction { @Test public void abstractEdgeToVertexMultiRuleOutTraversalTest() throws AAIException { - Vertex gvnf = g.addV("aai-node-type", "generic-vnf", "vnf-id", "gvnf").next(); - Vertex pserver = g.addV("aai-node-type", "pserver", "hostname", "a-name").next(); + Vertex gvnf = this.addVHelper(g, "vertex", "aai-node-type", "generic-vnf", "vnf-id", "gvnf").next(); + Vertex pserver = this.addVHelper(g, "vertex", "aai-node-type", "pserver", "hostname", "a-name").next(); testEdgeSer.addEdge(g, gvnf, pserver); testEdgeSer.addEdge(g, gvnf, pserver, "generic-vnf-pserver-B"); @@ -241,8 +241,8 @@ public class TraversalQueryTest extends QueryBuilderTestAbstraction { @Test public void abstractEdgeToVertexMultiRuleInTraversalTest() throws AAIException { - Vertex gvnf = g.addV("aai-node-type", "generic-vnf", "vnf-id", "gvnf").next(); - Vertex complex = g.addV("aai-node-type", "complex", "physical-location-id", "a-name").next(); + Vertex gvnf = this.addVHelper(g, "vertex", "aai-node-type", "generic-vnf", "vnf-id", "gvnf").next(); + Vertex complex = this.addVHelper(g, "vertex", "aai-node-type", "complex", "physical-location-id", "a-name").next(); testEdgeSer.addEdge(g, gvnf, complex); testEdgeSer.addEdge(g, gvnf, complex, "complex-generic-vnf-B"); diff --git a/aai-core/src/test/java/org/onap/aai/query/builder/optimization/AbstractGraphTraversalBuilderOptmizationTest.java b/aai-core/src/test/java/org/onap/aai/query/builder/optimization/AbstractGraphTraversalBuilderOptmizationTest.java index 911cb20c..b517ced2 100644 --- a/aai-core/src/test/java/org/onap/aai/query/builder/optimization/AbstractGraphTraversalBuilderOptmizationTest.java +++ b/aai-core/src/test/java/org/onap/aai/query/builder/optimization/AbstractGraphTraversalBuilderOptmizationTest.java @@ -20,16 +20,7 @@ package org.onap.aai.query.builder.optimization; -import static org.junit.Assert.assertEquals; - import com.google.common.base.CaseFormat; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.Arrays; -import java.util.List; -import java.util.Random; - import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; import org.apache.tinkerpop.gremlin.structure.Graph; import org.apache.tinkerpop.gremlin.structure.Vertex; @@ -38,7 +29,6 @@ import org.junit.AfterClass; import org.onap.aai.AAISetup; import org.onap.aai.db.props.AAIProperties; import org.onap.aai.dbmap.AAIGraph; -import org.onap.aai.dbmap.DBConnectionType; import org.onap.aai.introspection.Introspector; import org.onap.aai.introspection.Loader; import org.onap.aai.introspection.ModelType; @@ -50,6 +40,14 @@ import org.onap.aai.serialization.engines.QueryStyle; import org.onap.aai.serialization.engines.TransactionalGraphEngine; import org.springframework.beans.factory.annotation.Autowired; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.List; +import java.util.Random; + +import static org.junit.Assert.assertEquals; + public abstract class AbstractGraphTraversalBuilderOptmizationTest extends AAISetup { protected static final List<String> RANDOM_VALUES = Arrays.asList("A", "B", "C", "D", "E"); @@ -74,7 +72,6 @@ public abstract class AbstractGraphTraversalBuilderOptmizationTest extends AAISe private static final ModelType introspectorFactoryType = ModelType.MOXY; private static final QueryStyle queryStyle = QueryStyle.TRAVERSAL; - private static final DBConnectionType type = DBConnectionType.REALTIME; private static TransactionalGraphEngine dbEngine; private static DBSerializer dbser; protected static Loader loader; @@ -89,7 +86,7 @@ public abstract class AbstractGraphTraversalBuilderOptmizationTest extends AAISe loader = loaderFactory.createLoaderForVersion(introspectorFactoryType, schemaVersions.getDefaultVersion()); graph = AAIGraph.getInstance().getGraph(); - dbEngine = new JanusGraphDBEngine(queryStyle, type, loader); + dbEngine = new JanusGraphDBEngine(queryStyle, loader); g = dbEngine.startTransaction().traversal(); dbser = new DBSerializer(schemaVersions.getDefaultVersion(), dbEngine, introspectorFactoryType, "AAI-TEST-" + prefix); @@ -107,8 +104,12 @@ public abstract class AbstractGraphTraversalBuilderOptmizationTest extends AAISe for (int crCtr = 0; crCtr < 3; crCtr++) { crUri = String.format(crUriPattern, prefix + "cloud-owner-" + crCtr, prefix + "cloud-region-id-" + crCtr); // System.out.println(crUri); - cr = g.addV(AAIProperties.NODE_TYPE, CLOUD_REGION, CLOUD_REGION_ID, prefix + "cloud-region-id-" + crCtr, - CLOUD_OWNER, prefix + "cloud-owner-" + crCtr, AAIProperties.AAI_URI, crUri).next(); + cr = g.addV(CLOUD_REGION) + .property(AAIProperties.NODE_TYPE, CLOUD_REGION) + .property(CLOUD_REGION_ID, prefix + "cloud-region-id-" + crCtr) + .property(CLOUD_OWNER, prefix + "cloud-owner-" + crCtr) + .property(AAIProperties.AAI_URI, crUri) + .next(); for (int i = 0; i < tenantNum; i++) { Introspector intro = loader.introspectorFromName(TENANT); tenant = dbser.createNewVertex(intro); diff --git a/aai-core/src/test/java/org/onap/aai/rest/HPACapabilityTest.java b/aai-core/src/test/java/org/onap/aai/rest/HPACapabilityTest.java index a742313a..34477206 100644 --- a/aai-core/src/test/java/org/onap/aai/rest/HPACapabilityTest.java +++ b/aai-core/src/test/java/org/onap/aai/rest/HPACapabilityTest.java @@ -22,8 +22,8 @@ package org.onap.aai.rest; import static org.junit.Assert.assertEquals; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.jayway.jsonpath.JsonPath; import java.util.*; @@ -45,7 +45,7 @@ import org.skyscreamer.jsonassert.JSONAssert; @RunWith(AAIJunitRunner.class) public class HPACapabilityTest { - private static EELFLogger logger = EELFManager.getInstance().getLogger(HPACapabilityTest.class); + private static Logger logger = LoggerFactory.getLogger(HPACapabilityTest.class); private HttpTestUtil httpTestUtil; private Map<String, String> templateValuesMap; diff --git a/aai-core/src/test/java/org/onap/aai/rest/ImpliedDeleteIntegrationTest.java b/aai-core/src/test/java/org/onap/aai/rest/ImpliedDeleteIntegrationTest.java new file mode 100644 index 00000000..2b7a5818 --- /dev/null +++ b/aai-core/src/test/java/org/onap/aai/rest/ImpliedDeleteIntegrationTest.java @@ -0,0 +1,169 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 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========================================================= + */ + +package org.onap.aai.rest; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; +import org.janusgraph.core.JanusGraphTransaction; +import org.json.JSONObject; +import org.junit.After; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.mockito.Mockito; +import org.onap.aai.AAISetup; +import org.onap.aai.HttpTestUtil; +import org.onap.aai.PayloadUtil; +import org.onap.aai.db.props.AAIProperties; +import org.onap.aai.dbmap.AAIGraph; +import org.onap.aai.introspection.ModelType; +import org.onap.aai.rest.ueb.NotificationEvent; +import org.onap.aai.rest.ueb.UEBNotification; +import org.onap.aai.serialization.engines.QueryStyle; +import org.skyscreamer.jsonassert.JSONAssert; +import org.springframework.test.annotation.DirtiesContext; + +import javax.ws.rs.core.Response; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsNot.not; +import static org.junit.Assert.*; + +@RunWith(value = Parameterized.class) +@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS) +public class ImpliedDeleteIntegrationTest extends AAISetup { + + private static final Logger LOGGER = LoggerFactory.getLogger(ImpliedDeleteIntegrationTest.class); + + @Parameterized.Parameter(value = 0) + public QueryStyle queryStyle; + + @Parameterized.Parameters(name = "QueryStyle.{0}") + public static Collection<Object[]> data() { + return Arrays.asList(new Object[][] { + { QueryStyle.TRAVERSAL }, + { QueryStyle.TRAVERSAL_URI } + }); + } + + @Test + public void testPutPserverWithMultiplePInterfaceChildrenAndDoPutWithZeroChildren() throws Exception { + + String uri = "/aai/v12/cloud-infrastructure/pservers/pserver/test-pserver-implied-delete"; + + UEBNotification notification = Mockito.spy(new UEBNotification(ModelType.MOXY, loaderFactory, schemaVersions)); + HttpTestUtil httpTestUtil = new HttpTestUtil(queryStyle, notification, AAIProperties.MINIMUM_DEPTH); + + String resource = PayloadUtil.getResourcePayload("pserver-implied-delete.json"); + + Response response = httpTestUtil.doGet(uri); + assertEquals("Expecting the pserver to be not found", 404, response.getStatus()); + + response = httpTestUtil.doPut(uri, resource); + assertEquals("Expecting the pserver to be created", 201, response.getStatus()); + + response = httpTestUtil.doGet(uri); + assertEquals("Expecting the pserver to be found", 200, response.getStatus()); + + JSONObject jsonObject = new JSONObject(response.getEntity().toString()); + JSONAssert.assertEquals(resource, response.getEntity().toString(), false); + jsonObject.getJSONObject("p-interfaces").remove("p-interface"); + + notification = Mockito.spy(new UEBNotification(ModelType.MOXY, loaderFactory, schemaVersions)); + httpTestUtil = new HttpTestUtil(queryStyle, notification, AAIProperties.MINIMUM_DEPTH); + + response = httpTestUtil.doPut(uri, jsonObject.toString()); + assertEquals("Expecting the pserver to be updated and delete children", 200, response.getStatus()); + + List<NotificationEvent> notificationEvents = notification.getEvents(); + assertThat(notificationEvents.size(), is(5)); + + List<String> notificationEventHeaders = notification.getEvents() + .stream() + .map(event -> event.getEventHeader().marshal(false)) + .collect(Collectors.toList()); + + Long deletedEventsCount = notificationEventHeaders.stream().filter(e -> e.contains("\"DELETE\"")).count(); + + assertThat(deletedEventsCount, is(4L)); + + response = httpTestUtil.doGet(uri); + assertThat(response.getEntity().toString(), not(containsString("p-interface"))); + } + + @Test + public void testPutGenericVnf() throws Exception { + + String uri = "/aai/v12/network/generic-vnfs/generic-vnf/generic-vnf-implied-delete"; + HttpTestUtil httpTestUtil = new HttpTestUtil(queryStyle); + + String resource = PayloadUtil.getResourcePayload("generic-vnf-implied-delete.json"); + + Response response = httpTestUtil.doGet(uri); + assertEquals("Expecting the generic-vnf to be not found", 404, response.getStatus()); + + response = httpTestUtil.doPut(uri, resource); + assertEquals("Expecting the generic-vnf to be created", 201, response.getStatus()); + + response = httpTestUtil.doGet(uri); + assertEquals("Expecting the generic-vnf to be found", 200, response.getStatus()); + + JSONObject jsonObject = new JSONObject(response.getEntity().toString()); + JSONAssert.assertEquals(resource, response.getEntity().toString(), false); + jsonObject.getJSONObject("vf-modules").remove("vf-module"); + + response = httpTestUtil.doPut(uri, jsonObject.toString()); + assertEquals("Expecting the generic-vnf to be not deleted and fail with 403", 403, response.getStatus()); + assertThat(response.getEntity().toString(), containsString("User is not allowed to perform implicit delete")); + } + + @After + public void tearDown() { + + JanusGraphTransaction transaction = AAIGraph.getInstance().getGraph().newTransaction(); + boolean success = true; + + try { + + GraphTraversalSource g = transaction.traversal(); + + g.V().has("source-of-truth", "JUNIT").toList().forEach(v -> v.remove()); + + } catch (Exception ex) { + success = false; + LOGGER.error("Unable to remove the vertexes", ex); + } finally { + if (success) { + transaction.commit(); + } else { + transaction.rollback(); + fail("Unable to teardown the graph"); + } + } + } + +} diff --git a/aai-core/src/test/java/org/onap/aai/rest/NotificationDmaapEventTest.java b/aai-core/src/test/java/org/onap/aai/rest/NotificationDmaapEventTest.java new file mode 100644 index 00000000..16783180 --- /dev/null +++ b/aai-core/src/test/java/org/onap/aai/rest/NotificationDmaapEventTest.java @@ -0,0 +1,1028 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 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========================================================= + */ +package org.onap.aai.rest; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.janusgraph.core.JanusGraph; +import org.janusgraph.core.JanusGraphTransaction; +import org.javatuples.Pair; +import org.json.JSONObject; +import org.junit.After; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.mockito.Mockito; +import org.onap.aai.AAISetup; +import org.onap.aai.HttpTestUtil; +import org.onap.aai.PayloadUtil; +import org.onap.aai.db.props.AAIProperties; +import org.onap.aai.dbmap.AAIGraph; +import org.onap.aai.exceptions.AAIException; +import org.onap.aai.introspection.ModelType; +import org.onap.aai.rest.ueb.NotificationEvent; +import org.onap.aai.rest.ueb.UEBNotification; +import org.onap.aai.serialization.engines.QueryStyle; +import org.skyscreamer.jsonassert.JSONAssert; +import org.springframework.test.annotation.DirtiesContext; + +import javax.ws.rs.core.Response; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.util.*; + +import static org.hamcrest.CoreMatchers.*; +import static org.hamcrest.junit.MatcherAssert.assertThat; +import static org.junit.Assert.assertEquals; + +@RunWith(value = Parameterized.class) +@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS) +public class NotificationDmaapEventTest extends AAISetup { + + @Parameterized.Parameter + public QueryStyle queryStyle; + + @Parameterized.Parameters(name = "QueryStyle.{0}") + public static Collection<Object[]> data() { + return Arrays.asList(new Object[][] { + { QueryStyle.TRAVERSAL }, + { QueryStyle.TRAVERSAL_URI } + }); + } + + @Test + public void testCreateWithPserverWithAllChildrenAndVerifyMultipleNotificationsWhenNotificationDepthIsZero() throws IOException, AAIException { + + String uri = "/aai/v14/cloud-infrastructure/pservers/pserver/example-hostname-val-85598"; + UEBNotification notification = Mockito.spy(new UEBNotification(ModelType.MOXY, loaderFactory, schemaVersions)); + HttpTestUtil httpTestUtil = new HttpTestUtil(queryStyle, notification, AAIProperties.MINIMUM_DEPTH); + + String resource = PayloadUtil.getResourcePayload("pserver-with-children-for-notification.json"); + + Response response = httpTestUtil.doGet(uri); + assertEquals("Expecting the pserver to be not found", 404, response.getStatus()); + + response = httpTestUtil.doPut(uri, resource); + assertEquals("Expecting the pserver to be created", 201, response.getStatus()); + + int expectedCreateEvents = 17; + + assertThat(notification.getEvents().size(), is(expectedCreateEvents)); + + // Verify all the events are create since its a new PUT + notification.getEvents().forEach((event) -> { + + String header = event.getEventHeader().marshal(false); + + assertThat( + event.getEventHeader().marshal(false), + containsString("\"CREATE\"") + ); + + assertThat( + header, + containsString("\"top-entity-type\":\"pserver\"") + ); + + }); + + response = httpTestUtil.doGet(uri); + assertEquals("Expecting the pserver to be found", 200, response.getStatus()); + } + + // Test existing pserver create new pinterface check dmaap event for pinterface is CREATE + @Test + public void testExistingPserverCreateNewChildPInterfaceAndCheckDmaapEventForPInterfaceIsCreateWhenNotificationDepthIsZero() throws IOException, AAIException { + + String uri = "/aai/v14/cloud-infrastructure/pservers/pserver/example-hostname-val-85598"; + UEBNotification notification = Mockito.spy(new UEBNotification(ModelType.MOXY, loaderFactory, schemaVersions)); + HttpTestUtil httpTestUtil = new HttpTestUtil(queryStyle); + + String pserverResource = PayloadUtil.getResourcePayload("pserver-with-children-for-notification.json"); + + Response response = httpTestUtil.doGet(uri); + assertEquals("Expecting the pserver to be not found", 404, response.getStatus()); + + response = httpTestUtil.doPut(uri, pserverResource); + assertEquals("Expecting the pserver to be created", 201, response.getStatus()); + notification.clearEvents(); + + + response = httpTestUtil.doGet(uri , "all"); + assertEquals("Expecting the pserver to be found", 200, response.getStatus()); + + JSONObject pserverJson = new JSONObject(response.getEntity().toString()); + JSONObject pInterfaceObject = new JSONObject(); + pInterfaceObject.put("interface-name", "p-interface-1"); + + pserverJson.getJSONObject("p-interfaces").getJSONArray("p-interface").put(pInterfaceObject); + + httpTestUtil = new HttpTestUtil(queryStyle, notification, AAIProperties.MINIMUM_DEPTH); + response = httpTestUtil.doPut(uri, pserverJson.toString()); + assertEquals("Expecting the pserver to be updated with a new p-interface", 200, response.getStatus()); + + response = httpTestUtil.doGet(uri + "/p-interfaces/p-interface/p-interface-1", "0"); + assertEquals("Expecting the p-interface to be found", 200, response.getStatus()); + + List<NotificationEvent> events = notification.getEvents(); + assertThat(events.size(), is(2)); + + String notificationEventHeader = events.get(1).getEventHeader().marshal(false); + String notificationEventBody = events.get(1).getObj().marshal(false); + + assertThat(notificationEventHeader, containsString("\"action\":\"CREATE\"")); + assertThat(notificationEventHeader, containsString("\"entity-type\":\"p-interface\"")); + assertThat(notificationEventHeader, containsString("\"top-entity-type\":\"pserver\"")); + + String expectedNotificationHeader = PayloadUtil.getResourcePayload("notification-dmaap-events/depth-zero/expected-notification-header-create-child-on-existing-obj.json"); + String expectedNotificationBody = PayloadUtil.getResourcePayload("notification-dmaap-events/depth-zero/expected-notification-body-create-child-on-existing-obj.json"); + + JSONAssert.assertEquals(expectedNotificationHeader, notificationEventHeader, false); + JSONAssert.assertEquals(expectedNotificationBody, notificationEventBody, false); + } + + @Test + public void testExistingPserverCreateNewChildPInterfaceAndCheckDmaapEventForPserverIsSentWithNewPInterfaceWhenNotificationDepthIsAll() throws IOException, AAIException { + + String uri = "/aai/v14/cloud-infrastructure/pservers/pserver/example-hostname-val-85598"; + UEBNotification notification = Mockito.spy(new UEBNotification(ModelType.MOXY, loaderFactory, schemaVersions)); + HttpTestUtil httpTestUtil = new HttpTestUtil(queryStyle); + + String pserverResource = PayloadUtil.getResourcePayload("pserver-with-children-for-notification.json"); + + Response response = httpTestUtil.doGet(uri); + assertEquals("Expecting the pserver to be not found", 404, response.getStatus()); + + response = httpTestUtil.doPut(uri, pserverResource); + assertEquals("Expecting the pserver to be created", 201, response.getStatus()); + + response = httpTestUtil.doGet(uri , "all"); + assertEquals("Expecting the pserver to be found", 200, response.getStatus()); + + JSONObject pserverJson = new JSONObject(response.getEntity().toString()); + String pserverResourceVersion = pserverJson.getString("resource-version"); + + JSONObject pInterfaceObject = new JSONObject(); + pInterfaceObject.put("interface-name", "p-interface-1"); + + pserverJson.getJSONObject("p-interfaces").getJSONArray("p-interface").put(pInterfaceObject); + + httpTestUtil = new HttpTestUtil(queryStyle, notification, AAIProperties.MAXIMUM_DEPTH); + response = httpTestUtil.doPut(uri, pserverJson.toString()); + assertEquals("Expecting the pserver to be updated with a new p-interface", 200, response.getStatus()); + + response = httpTestUtil.doGet(uri + "/p-interfaces/p-interface/p-interface-1", "0"); + assertEquals("Expecting the p-interface to be found", 200, response.getStatus()); + + List<NotificationEvent> events = notification.getEvents(); + assertThat(events.size(), is(1)); + + String notificationEventHeader = events.get(0).getEventHeader().marshal(false); + String notificationEventBody = events.get(0).getObj().marshal(false); + + assertThat(notificationEventHeader, containsString("\"action\":\"UPDATE\"")); + assertThat(notificationEventHeader, containsString("\"entity-type\":\"pserver\"")); + assertThat(notificationEventHeader, containsString("\"top-entity-type\":\"pserver\"")); + + String expectedNotificationHeader = PayloadUtil.getResourcePayload("notification-dmaap-events/depth-all/expected-notification-header-create-child-on-existing-obj.json"); + String expectedNotificationBody = PayloadUtil.getResourcePayload("notification-dmaap-events/depth-all/expected-notification-body-create-child-on-existing-obj.json"); + + JSONAssert.assertEquals(expectedNotificationHeader, notificationEventHeader, false); + JSONAssert.assertEquals(expectedNotificationBody, notificationEventBody, false); + + response = httpTestUtil.doGet(uri, "0"); + pserverJson = new JSONObject(response.getEntity().toString()); + String newPserverResourceVersion = pserverJson.getString("resource-version"); + + // After an pserver's p-interface is updated on the pserver, even though + // the pserver nothing changed, expecting the pserver resource version to be changed + assertThat( + "Expecting the new pserver resource version and old resource version to be not same", + newPserverResourceVersion, + is(not(pserverResourceVersion)) + ); + assertEquals("Expecting the p-interface to be found", 200, response.getStatus()); + } + + // Test Bulk Scenario + @Test + public void testBulkScenarioWhereMultipleCreatesAndEnsureNoDuplicationInDmaapEventsWhenNotificationDepthIsZero() throws UnsupportedEncodingException, AAIException { + + String pserverUri = "/aai/v14/cloud-infrastructure/pservers/pserver/random-pserver"; + String cloudRegionUri = "/aai/v14/cloud-infrastructure/cloud-regions/cloud-region/random-cloud-region-owner/random-cloud-region-id"; + + UEBNotification notification = Mockito.spy(new UEBNotification(ModelType.MOXY, loaderFactory, schemaVersions)); + HttpTestUtil httpTestUtil = new HttpTestUtil(queryStyle, notification, AAIProperties.MINIMUM_DEPTH); + + Map<String, String> uriPayload = new LinkedHashMap<>(); + + uriPayload.put(pserverUri, "{}"); + uriPayload.put(cloudRegionUri, "{}"); + + Response response = httpTestUtil.doPut(uriPayload); + assertThat(response.getStatus(), is(201)); + + int numberOfEventsActual = notification.getEvents().size(); + int expectedEvents = 2; + + assertThat("Expecting the number of dmaap events to be 2", numberOfEventsActual, is(expectedEvents)); + + notification.getEvents().forEach((event) -> { + String notificationEventHeader = event.getEventHeader().marshal(false); + assertThat(notificationEventHeader, containsString("\"CREATE\"")); + }); + } + + + @Test + public void testBulkScenarioWhereMultipleCreatesAndEnsureNoDuplicationInDmaapEventsWhenNotificationDepthIsAll() throws UnsupportedEncodingException, AAIException { + + String pserverUri = "/aai/v14/cloud-infrastructure/pservers/pserver/random-pserver"; + String cloudRegionUri = "/aai/v14/cloud-infrastructure/cloud-regions/cloud-region/random-cloud-region-owner/random-cloud-region-id"; + + UEBNotification notification = Mockito.spy(new UEBNotification(ModelType.MOXY, loaderFactory, schemaVersions)); + HttpTestUtil httpTestUtil = new HttpTestUtil(queryStyle, notification, AAIProperties.MAXIMUM_DEPTH); + + Map<String, String> uriPayload = new LinkedHashMap<>(); + + uriPayload.put(pserverUri, "{}"); + uriPayload.put(cloudRegionUri, "{}"); + + Response response = httpTestUtil.doPut(uriPayload); + assertThat(response.getStatus(), is(201)); + + int numberOfEventsActual = notification.getEvents().size(); + int expectedEvents = 2; + + assertThat("Expecting the number of dmaap events to be 2", numberOfEventsActual, is(expectedEvents)); + + notification.getEvents().forEach((event) -> { + String notificationEventHeader = event.getEventHeader().marshal(false); + assertThat(notificationEventHeader, containsString("\"CREATE\"")); + }); + } + + @Test + public void testDeleteOnExistingPserverAndCheckIfNotificationDepthIsZeroThatAllEventsHaveDeleteAndThatDepthIsZeroOnEachNotificationEvent() throws IOException, AAIException { + String uri = "/aai/v14/cloud-infrastructure/pservers/pserver/example-hostname-val-85598"; + UEBNotification notification = Mockito.spy(new UEBNotification(ModelType.MOXY, loaderFactory, schemaVersions)); + HttpTestUtil httpTestUtil = new HttpTestUtil(queryStyle); + + String pserverResource = PayloadUtil.getResourcePayload("pserver-with-children-for-notification.json"); + + Response response = httpTestUtil.doGet(uri); + assertEquals("Expecting the pserver to be not found", 404, response.getStatus()); + + response = httpTestUtil.doPut(uri, pserverResource); + assertEquals("Expecting the pserver to be created", 201, response.getStatus()); + + response = httpTestUtil.doGet(uri , "all"); + assertEquals("Expecting the pserver to be found", 200, response.getStatus()); + + JSONObject pserverObject = new JSONObject(response.getEntity().toString()); + String resourceVersion = pserverObject.getString("resource-version"); + + httpTestUtil = new HttpTestUtil(queryStyle, notification, AAIProperties.MINIMUM_DEPTH); + response = httpTestUtil.doDelete(uri, resourceVersion); + assertEquals("Expecting the pserver to be deleted", 204, response.getStatus()); + + List<NotificationEvent> notificationEvents = notification.getEvents(); + assertThat(notificationEvents.size(), is(17)); + + notificationEvents.forEach((event) -> { + + String header = event.getEventHeader().marshal(false); + + assertThat( + event.getEventHeader().marshal(false), + containsString("\"DELETE\"") + ); + + assertThat( + header, + containsString("\"top-entity-type\":\"pserver\"") + ); + }); + } + + + @Test + public void testDeleteOnExistingResourceVersionMismatchNoEventGenerated() throws IOException, AAIException { + String uri = "/aai/v14/cloud-infrastructure/pservers/pserver/example-hostname-val-85598"; + UEBNotification notification = Mockito.spy(new UEBNotification(ModelType.MOXY, loaderFactory, schemaVersions)); + HttpTestUtil httpTestUtil = new HttpTestUtil(queryStyle); + + String pserverResource = PayloadUtil.getResourcePayload("pserver-with-children-for-notification.json"); + + Response response = httpTestUtil.doGet(uri); + assertEquals("Expecting the pserver to be not found", 404, response.getStatus()); + + response = httpTestUtil.doPut(uri, pserverResource); + assertEquals("Expecting the pserver to be created", 201, response.getStatus()); + + response = httpTestUtil.doGet(uri , "all"); + assertEquals("Expecting the pserver to be found", 200, response.getStatus()); + + JSONObject pserverObject = new JSONObject(response.getEntity().toString()); + String resourceVersion = pserverObject.getString("resource-version"); + + httpTestUtil = new HttpTestUtil(queryStyle, notification, AAIProperties.MINIMUM_DEPTH); + response = httpTestUtil.doDelete(uri, resourceVersion+"123"); + assertEquals("Resource version mismatch exception", 412, response.getStatus()); + + List<NotificationEvent> notificationEvents = notification.getEvents(); + assertThat(notificationEvents.size(), is(0)); + } + + + // Test notification depth set to all + // Scenario for testing the creation of pserver with children, grandchildren + // Default behaviour is for one event to be sent out + // which includes all the children and grandchildren, etc + @Test + public void testCreateWithPserverWithAllChildrenAndVerifyOneNotificationWhenNotificationDepthIsAll() throws IOException, AAIException { + + String uri = "/aai/v14/cloud-infrastructure/pservers/pserver/example-hostname-val-85598"; + UEBNotification notification = Mockito.spy(new UEBNotification(ModelType.MOXY, loaderFactory, schemaVersions)); + HttpTestUtil httpTestUtil = new HttpTestUtil(queryStyle, notification, AAIProperties.MAXIMUM_DEPTH); + + String resource = PayloadUtil.getResourcePayload("pserver-with-children-for-notification.json"); + + Response response = httpTestUtil.doGet(uri); + assertEquals("Expecting the pserver to be not found", 404, response.getStatus()); + + response = httpTestUtil.doPut(uri, resource); + assertEquals("Expecting the pserver to be created", 201, response.getStatus()); + + assertThat(notification.getEvents().size(), is(1)); + + NotificationEvent notificationEvent = notification.getEvents().get(0); + + // Verify all the events are create since its a new PUT + String header = notificationEvent.getEventHeader().marshal(false); + + assertThat( + header, + containsString("\"CREATE\"") + ); + + assertThat( + header, + containsString("\"entity-type\":\"pserver\"") + ); + + assertThat( + header, + containsString("\"top-entity-type\":\"pserver\"") + ); + + assertThat( + header, + containsString("\"entity-link\":\"" + uri + "\"") + ); + + response = httpTestUtil.doGet(uri); + assertEquals("Expecting the pserver to be found", 200, response.getStatus()); + + JSONAssert.assertEquals(response.getEntity().toString(), notificationEvent.getObj().marshal(false), false); + } + + @Test + public void testPatchExistingPserverWithChildrenAndModifyOnlyOneObjectAndVerifyThatOnlyOneNotificationEventNoChildrenWhenNotificationDepthIsZero() throws IOException, AAIException { + + String uri = "/aai/v14/cloud-infrastructure/pservers/pserver/example-hostname-val-85598"; + UEBNotification notification = Mockito.spy(new UEBNotification(ModelType.MOXY, loaderFactory, schemaVersions)); + HttpTestUtil httpTestUtil = new HttpTestUtil(queryStyle); + + String resource = PayloadUtil.getResourcePayload("pserver-with-children-for-notification.json"); + + Response response = httpTestUtil.doGet(uri); + assertEquals("Expecting the pserver to be not found", 404, response.getStatus()); + + response = httpTestUtil.doPut(uri, resource); + assertEquals("Expecting the pserver to be created", 201, response.getStatus()); + + response = httpTestUtil.doGet(uri); + assertEquals("Expecting the pserver to be found", 200, response.getStatus()); + + JSONObject pserverObject = new JSONObject(); + pserverObject.put("equip-type", "new-equip-patch-type"); + + httpTestUtil = new HttpTestUtil(queryStyle, notification, AAIProperties.MINIMUM_DEPTH); + response = httpTestUtil.doPatch(uri, pserverObject.toString()); + assertThat(response.getStatus(), is(200)); + + response = httpTestUtil.doGet(uri, "0"); + assertThat(response.getEntity().toString(), containsString("new-equip-patch-type")); + + assertThat(notification.getEvents().size(), is(1)); + String updateNotificationEvent = notification.getEvents().get(0).getObj().marshal(true); + + // Check that everything in notification event is also response body + // Not comparing the other way as notification only includes parents main properties + JSONAssert.assertEquals(updateNotificationEvent, response.getEntity().toString(), false); + } + + @Test + public void testPatchExistingPserverWithChildrenAndModifyOnlyOneObjectAndVerifyThatOnlyOneNotificationEventIncludeChildrenWhenNotificationDepthIsAll() throws IOException, AAIException { + + String uri = "/aai/v14/cloud-infrastructure/pservers/pserver/example-hostname-val-85598"; + UEBNotification notification = Mockito.spy(new UEBNotification(ModelType.MOXY, loaderFactory, schemaVersions)); + HttpTestUtil httpTestUtil = new HttpTestUtil(queryStyle); + + String resource = PayloadUtil.getResourcePayload("pserver-with-children-for-notification.json"); + + Response response = httpTestUtil.doGet(uri); + assertEquals("Expecting the pserver to be not found", 404, response.getStatus()); + + response = httpTestUtil.doPut(uri, resource); + assertEquals("Expecting the pserver to be created", 201, response.getStatus()); + + response = httpTestUtil.doGet(uri); + assertEquals("Expecting the pserver to be found", 200, response.getStatus()); + + JSONObject pserverObject = new JSONObject(); + pserverObject.put("equip-type", "new-equip-patch-type"); + + httpTestUtil = new HttpTestUtil(queryStyle, notification, AAIProperties.MAXIMUM_DEPTH); + response = httpTestUtil.doPatch(uri, pserverObject.toString()); + assertThat(response.getStatus(), is(200)); + + response = httpTestUtil.doGet(uri, "all"); + assertThat(response.getEntity().toString(), containsString("new-equip-patch-type")); + + assertThat(notification.getEvents().size(), is(1)); + String updateNotificationEvent = notification.getEvents().get(0).getObj().marshal(true); + + // Check that everything in notification event is also response body + // Not comparing the other way as notification only includes parents main properties + JSONAssert.assertEquals(updateNotificationEvent, response.getEntity().toString(), false); + } + + // Test notification depth set to all + // Scenario where we are only updating one field in p-interface + // Make sure the parent and children are included + @Test + public void testUpdateExistingPserverWithChildrenAndModifyOnlyOneObjectAndVerifyThatOnlyOneNotificationEventIncludingChildrenWhenNotificationDepthIsAll() throws IOException, AAIException { + + String uri = "/aai/v14/cloud-infrastructure/pservers/pserver/example-hostname-val-85598"; + UEBNotification notification = Mockito.spy(new UEBNotification(ModelType.MOXY, loaderFactory, schemaVersions)); + HttpTestUtil httpTestUtil = new HttpTestUtil(queryStyle); + + String resource = PayloadUtil.getResourcePayload("pserver-with-children-for-notification.json"); + + Response response = httpTestUtil.doGet(uri); + assertEquals("Expecting the pserver to be not found", 404, response.getStatus()); + + response = httpTestUtil.doPut(uri, resource); + assertEquals("Expecting the pserver to be created", 201, response.getStatus()); + + response = httpTestUtil.doGet(uri); + assertEquals("Expecting the pserver to be found", 200, response.getStatus()); + + response = httpTestUtil.doGet(uri + "/p-interfaces/p-interface/example-interface-name-val-46147", "0"); + assertEquals("Expecting the p-interface to be found", 200, response.getStatus()); + + JSONObject pInterfaceObject = new JSONObject(response.getEntity().toString()); + pInterfaceObject.put("equipment-identifier", "new-equipment-identifier"); + + httpTestUtil = new HttpTestUtil(queryStyle, notification, AAIProperties.MAXIMUM_DEPTH); + response = httpTestUtil.doPut(uri + "/p-interfaces/p-interface/example-interface-name-val-46147", pInterfaceObject.toString()); + assertThat(response.getStatus(), is(200)); + + // Get the parent uri as the notification event json has parent structure it makes it easy to compare + response = httpTestUtil.doGet(uri); + assertThat(response.getEntity().toString(), containsString("new-equipment-identifier")); + + assertThat(notification.getEvents().size(), is(1)); + String updateNotificationEvent = notification.getEvents().get(0).getObj().marshal(true); + + // Check that everything in notification event is also response body + // Not comparing the other way as notification only includes parents main properties + JSONAssert.assertEquals(updateNotificationEvent, response.getEntity().toString(), false); + } + + // Test notification depth set to 0 + // Scenario where we are only updating one field in p-interface + @Test + public void testUpdateExistingPserverWithChildrenAndModifyOnlyPInterfaceAndVerifyThatOnlyOneNotificationForPInterfaceIsCreatedWhenNotificationDepthIsZero() throws IOException, AAIException { + + String uri = "/aai/v14/cloud-infrastructure/pservers/pserver/example-hostname-val-85598"; + UEBNotification notification = Mockito.spy(new UEBNotification(ModelType.MOXY, loaderFactory, schemaVersions)); + HttpTestUtil httpTestUtil = new HttpTestUtil(queryStyle); + + String resource = PayloadUtil.getResourcePayload("pserver-with-children-for-notification.json"); + + Response response = httpTestUtil.doGet(uri); + assertEquals("Expecting the pserver to be not found", 404, response.getStatus()); + + response = httpTestUtil.doPut(uri, resource); + assertEquals("Expecting the pserver to be created", 201, response.getStatus()); + + response = httpTestUtil.doGet(uri); + assertEquals("Expecting the pserver to be found", 200, response.getStatus()); + + response = httpTestUtil.doGet(uri + "/p-interfaces/p-interface/example-interface-name-val-46147", "0"); + assertEquals("Expecting the p-interface to be found", 200, response.getStatus()); + + JSONObject pInterfaceObject = new JSONObject(response.getEntity().toString()); + pInterfaceObject.put("equipment-identifier", "new-equipment-identifier"); + + httpTestUtil = new HttpTestUtil(queryStyle, notification, AAIProperties.MINIMUM_DEPTH); + response = httpTestUtil.doPut(uri + "/p-interfaces/p-interface/example-interface-name-val-46147", pInterfaceObject.toString()); + assertThat(response.getStatus(), is(200)); + + response = httpTestUtil.doGet(uri); + assertThat(notification.getEvents().size(), is(1)); + String updateNotificationEvent = notification.getEvents().get(0).getObj().marshal(true); + System.out.println("Update notification " + updateNotificationEvent); + + // Check that everything in notification event is also response body + // Not comparing the other way as notification only includes parents main properties + JSONAssert.assertEquals(updateNotificationEvent, response.getEntity().toString(), false); + } + + @Test + public void testExistingPserverWithChildAndGenericVnfAndCreateEdgeBetweenThemAndCheckNoChildWhenNotificationDepthIsZero() throws IOException, AAIException { + + String hostname = "example-hostname-val-85598"; + + String pserverUri = "/aai/v14/cloud-infrastructure/pservers/pserver/" + hostname; + String genericVnfUri = "/aai/v14/network/generic-vnfs/generic-vnf/generic-vnf-notification"; + + UEBNotification notification = Mockito.spy(new UEBNotification(ModelType.MOXY, loaderFactory, schemaVersions)); + HttpTestUtil httpTestUtil = new HttpTestUtil(queryStyle); + + String resource = PayloadUtil.getResourcePayload("pserver-with-children-for-notification.json"); + String genericVnfResource = PayloadUtil.getResourcePayload("generic-vnf-notification.json"); + + Response response = httpTestUtil.doGet(pserverUri); + assertEquals("Expecting the pserver to be not found", 404, response.getStatus()); + + response = httpTestUtil.doPut(pserverUri, resource); + assertEquals("Expecting the pserver to be created", 201, response.getStatus()); + + response = httpTestUtil.doGet(pserverUri); + assertEquals("Expecting the pserver to be found", 200, response.getStatus()); + + response = httpTestUtil.doGet(genericVnfUri); + assertEquals("Expecting the generic-vnf to be not found", 404, response.getStatus()); + + response = httpTestUtil.doPut(genericVnfUri, genericVnfResource); + assertEquals("Expecting the generic-vnf to be created", 201, response.getStatus()); + + response = httpTestUtil.doGet(genericVnfUri); + assertEquals("Expecting the generic-vnf to be found", 200, response.getStatus()); + assertThat(response.getEntity().toString(), not(containsString(hostname))); + + httpTestUtil = new HttpTestUtil(queryStyle, notification, AAIProperties.MINIMUM_DEPTH); + + String relationship = PayloadUtil.getResourcePayload("pserver-to-gvnf-relationship-notification.json"); + + response = httpTestUtil.doPut(pserverUri + "/relationship-list/relationship", relationship); + assertEquals("Expecting the pserver to generic-vnf relationship to be created", 200, response.getStatus()); + + List<NotificationEvent> notificationEvents = notification.getEvents(); + assertThat(notificationEvents.size(), is(2)); + + String expectedNotificationHeader = PayloadUtil.getResourcePayload("notification-dmaap-events/depth-zero/expected-notification-header-create-edge-between-pserver-and-generic-vnf.json"); + String expectedNotificationBody = PayloadUtil.getResourcePayload("notification-dmaap-events/depth-zero/expected-notification-body-create-edge-between-pserver-and-generic-vnf.json"); + + JSONAssert.assertEquals(expectedNotificationHeader, notificationEvents.get(0).getEventHeader().marshal(false), false); + JSONAssert.assertEquals(expectedNotificationBody, notificationEvents.get(0).getObj().marshal(false), false); + + response = httpTestUtil.doGet(genericVnfUri); + + assertEquals("Expecting the generic-vnf to be found", 200, response.getStatus()); + assertThat(response.getEntity().toString(), containsString(hostname)); + } + + @Test + public void testExistingPserverWithChildAndGenericVnfAndCreateEdgeBetweenThemAndCheckChildrenIncludedWhenNotificationDepthIsAll() throws IOException, AAIException { + + String hostname = "example-hostname-val-85598"; + + String pserverUri = "/aai/v14/cloud-infrastructure/pservers/pserver/" + hostname; + String genericVnfUri = "/aai/v14/network/generic-vnfs/generic-vnf/generic-vnf-notification"; + + UEBNotification notification = Mockito.spy(new UEBNotification(ModelType.MOXY, loaderFactory, schemaVersions)); + HttpTestUtil httpTestUtil = new HttpTestUtil(queryStyle); + + String resource = PayloadUtil.getResourcePayload("pserver-with-children-for-notification.json"); + String genericVnfResource = PayloadUtil.getResourcePayload("generic-vnf-notification.json"); + + Response response = httpTestUtil.doGet(pserverUri); + assertEquals("Expecting the pserver to be not found", 404, response.getStatus()); + + response = httpTestUtil.doPut(pserverUri, resource); + assertEquals("Expecting the pserver to be created", 201, response.getStatus()); + + response = httpTestUtil.doGet(pserverUri); + assertEquals("Expecting the pserver to be found", 200, response.getStatus()); + + response = httpTestUtil.doGet(genericVnfUri); + assertEquals("Expecting the generic-vnf to be not found", 404, response.getStatus()); + + response = httpTestUtil.doPut(genericVnfUri, genericVnfResource); + assertEquals("Expecting the generic-vnf to be created", 201, response.getStatus()); + + response = httpTestUtil.doGet(genericVnfUri); + assertEquals("Expecting the generic-vnf to be found", 200, response.getStatus()); + assertThat(response.getEntity().toString(), not(containsString(hostname))); + + httpTestUtil = new HttpTestUtil(queryStyle, notification, AAIProperties.MAXIMUM_DEPTH); + + String relationship = PayloadUtil.getResourcePayload("pserver-to-gvnf-relationship-notification.json"); + + response = httpTestUtil.doPut(pserverUri + "/relationship-list/relationship", relationship); + assertEquals("Expecting the pserver to generic-vnf relationship to be created", 200, response.getStatus()); + + List<NotificationEvent> notificationEvents = notification.getEvents(); + assertThat(notificationEvents.size(), is(2)); + + String expectedNotificationHeader = PayloadUtil.getResourcePayload("notification-dmaap-events/depth-all/expected-notification-header-create-edge-between-pserver-and-generic-vnf.json"); + String expectedNotificationBody = PayloadUtil.getResourcePayload("notification-dmaap-events/depth-all/expected-notification-body-create-edge-between-pserver-and-generic-vnf.json"); + + System.out.println("Notification Body: " + notificationEvents.get(0).getObj().marshal(false)); + JSONAssert.assertEquals(expectedNotificationHeader, notificationEvents.get(0).getEventHeader().marshal(false), false); + JSONAssert.assertEquals(expectedNotificationBody, notificationEvents.get(0).getObj().marshal(false), false); + + response = httpTestUtil.doGet(genericVnfUri); + + assertEquals("Expecting the generic-vnf to be found", 200, response.getStatus()); + assertThat(response.getEntity().toString(), containsString(hostname)); + } + + @Test + public void testExistingPserverWithChildAndGenericVnfAndExistingEdgeBetweenThemAndDeleteEdgeAndCheckNoChildWhenNotificationDepthIsZero() throws IOException, AAIException { + + String hostname = "example-hostname-val-85598"; + + String pserverUri = "/aai/v14/cloud-infrastructure/pservers/pserver/" + hostname; + String genericVnfUri = "/aai/v14/network/generic-vnfs/generic-vnf/generic-vnf-notification"; + + String relationship = PayloadUtil.getResourcePayload("pserver-to-gvnf-relationship-notification.json"); + + UEBNotification notification = Mockito.spy(new UEBNotification(ModelType.MOXY, loaderFactory, schemaVersions)); + HttpTestUtil httpTestUtil = new HttpTestUtil(queryStyle); + + String resource = PayloadUtil.getResourcePayload("pserver-with-children-for-notification.json"); + String genericVnfResource = PayloadUtil.getResourcePayload("generic-vnf-notification.json"); + + Response response = httpTestUtil.doGet(pserverUri); + assertEquals("Expecting the pserver to be not found", 404, response.getStatus()); + + response = httpTestUtil.doPut(pserverUri, resource); + assertEquals("Expecting the pserver to be created", 201, response.getStatus()); + + response = httpTestUtil.doGet(pserverUri); + assertEquals("Expecting the pserver to be found", 200, response.getStatus()); + + response = httpTestUtil.doGet(genericVnfUri); + assertEquals("Expecting the generic-vnf to be not found", 404, response.getStatus()); + + response = httpTestUtil.doPut(genericVnfUri, genericVnfResource); + assertEquals("Expecting the generic-vnf to be created", 201, response.getStatus()); + + response = httpTestUtil.doGet(genericVnfUri); + assertEquals("Expecting the generic-vnf to be found", 200, response.getStatus()); + assertThat(response.getEntity().toString(), not(containsString(hostname))); + + + response = httpTestUtil.doPut(pserverUri + "/relationship-list/relationship", relationship); + assertEquals("Expecting the pserver to generic-vnf relationship to be created", 200, response.getStatus()); + + response = httpTestUtil.doGet(genericVnfUri); + + assertEquals("Expecting the generic-vnf to be found", 200, response.getStatus()); + assertThat(response.getEntity().toString(), containsString(hostname)); + + assertEquals("Expecting the generic-vnf to be found", 200, response.getStatus()); + assertThat(response.getEntity().toString(), containsString(hostname)); + + response = httpTestUtil.doGet(pserverUri); + assertEquals("Expecting the pserver to be found", 200, response.getStatus()); + + JSONObject pserverJson = new JSONObject(response.getEntity().toString()); + String resourceVersion = pserverJson.getString("resource-version"); + + httpTestUtil = new HttpTestUtil(queryStyle, notification, AAIProperties.MINIMUM_DEPTH); + + response = httpTestUtil.doDelete(pserverUri + "/relationship-list/relationship", resourceVersion, relationship); + assertThat("Expected the pserver relationship to generic-vnf to be deleted", response.getStatus(), is(204)); + + List<NotificationEvent> notificationEvents = notification.getEvents(); + + assertThat(notificationEvents.size(), is(2)); + + String expectedNotificationHeader = PayloadUtil.getResourcePayload("notification-dmaap-events/depth-zero/expected-notification-header-delete-edge-between-pserver-and-generic-vnf.json"); + String expectedNotificationBody = PayloadUtil.getResourcePayload("notification-dmaap-events/depth-zero/expected-notification-body-delete-edge-between-pserver-and-generic-vnf.json"); + + JSONAssert.assertEquals(expectedNotificationHeader, notificationEvents.get(0).getEventHeader().marshal(false), false); + JSONAssert.assertEquals(expectedNotificationBody, notificationEvents.get(0).getObj().marshal(false), false); + + } + + @Test + public void testExistingPserverWithChildAndGenericVnfAndExistingEdgeBetweenThemAndDeleteEdgeAndCheckChildrenWhenNotificationDepthIsAll() throws IOException, AAIException { + + String hostname = "example-hostname-val-85598"; + + String pserverUri = "/aai/v14/cloud-infrastructure/pservers/pserver/" + hostname; + String genericVnfUri = "/aai/v14/network/generic-vnfs/generic-vnf/generic-vnf-notification"; + + String relationship = PayloadUtil.getResourcePayload("pserver-to-gvnf-relationship-notification.json"); + + UEBNotification notification = Mockito.spy(new UEBNotification(ModelType.MOXY, loaderFactory, schemaVersions)); + HttpTestUtil httpTestUtil = new HttpTestUtil(queryStyle); + + String resource = PayloadUtil.getResourcePayload("pserver-with-children-for-notification.json"); + String genericVnfResource = PayloadUtil.getResourcePayload("generic-vnf-notification.json"); + + Response response = httpTestUtil.doGet(pserverUri); + assertEquals("Expecting the pserver to be not found", 404, response.getStatus()); + + response = httpTestUtil.doPut(pserverUri, resource); + assertEquals("Expecting the pserver to be created", 201, response.getStatus()); + + response = httpTestUtil.doGet(pserverUri); + assertEquals("Expecting the pserver to be found", 200, response.getStatus()); + + response = httpTestUtil.doGet(genericVnfUri); + assertEquals("Expecting the generic-vnf to be not found", 404, response.getStatus()); + + response = httpTestUtil.doPut(genericVnfUri, genericVnfResource); + assertEquals("Expecting the generic-vnf to be created", 201, response.getStatus()); + + response = httpTestUtil.doGet(genericVnfUri); + assertEquals("Expecting the generic-vnf to be found", 200, response.getStatus()); + assertThat(response.getEntity().toString(), not(containsString(hostname))); + + + response = httpTestUtil.doPut(pserverUri + "/relationship-list/relationship", relationship); + assertEquals("Expecting the pserver to generic-vnf relationship to be created", 200, response.getStatus()); + + response = httpTestUtil.doGet(genericVnfUri); + + assertEquals("Expecting the generic-vnf to be found", 200, response.getStatus()); + assertThat(response.getEntity().toString(), containsString(hostname)); + + assertEquals("Expecting the generic-vnf to be found", 200, response.getStatus()); + assertThat(response.getEntity().toString(), containsString(hostname)); + + response = httpTestUtil.doGet(pserverUri); + assertEquals("Expecting the pserver to be found", 200, response.getStatus()); + + JSONObject pserverJson = new JSONObject(response.getEntity().toString()); + String resourceVersion = pserverJson.getString("resource-version"); + + httpTestUtil = new HttpTestUtil(queryStyle, notification, AAIProperties.MAXIMUM_DEPTH); + + response = httpTestUtil.doDelete(pserverUri + "/relationship-list/relationship", resourceVersion, relationship); + assertThat("Expected the pserver relationship to generic-vnf to be deleted", response.getStatus(), is(204)); + + List<NotificationEvent> notificationEvents = notification.getEvents(); + assertThat(notificationEvents.size(), is(2)); + + String expectedNotificationHeader = PayloadUtil.getResourcePayload("notification-dmaap-events/depth-all/expected-notification-header-delete-edge-between-pserver-and-generic-vnf.json"); + String expectedNotificationBody = PayloadUtil.getResourcePayload("notification-dmaap-events/depth-all/expected-notification-body-delete-edge-between-pserver-and-generic-vnf.json"); + + JSONAssert.assertEquals(expectedNotificationHeader, notificationEvents.get(0).getEventHeader().marshal(false), false); + JSONAssert.assertEquals(expectedNotificationBody, notificationEvents.get(0).getObj().marshal(false), false); + + } + + @Test + public void testDeleteOnExistingResourceVersionMismatchNoEventGeneratedFullDepth() throws IOException, AAIException { + String uri = "/aai/v14/cloud-infrastructure/pservers/pserver/example-hostname-val-85598"; + UEBNotification notification = Mockito.spy(new UEBNotification(ModelType.MOXY, loaderFactory, schemaVersions)); + HttpTestUtil httpTestUtil = new HttpTestUtil(queryStyle); + + String pserverResource = PayloadUtil.getResourcePayload("pserver-with-children-for-notification.json"); + + Response response = httpTestUtil.doGet(uri); + assertEquals("Expecting the pserver to be not found", 404, response.getStatus()); + + response = httpTestUtil.doPut(uri, pserverResource); + assertEquals("Expecting the pserver to be created", 201, response.getStatus()); + + response = httpTestUtil.doGet(uri , "all"); + assertEquals("Expecting the pserver to be found", 200, response.getStatus()); + + JSONObject pserverObject = new JSONObject(response.getEntity().toString()); + String resourceVersion = pserverObject.getString("resource-version"); + + httpTestUtil = new HttpTestUtil(queryStyle, notification, AAIProperties.MAXIMUM_DEPTH); + response = httpTestUtil.doDelete(uri, resourceVersion+"123"); + assertEquals("Resource version mismatch exception", 412, response.getStatus()); + + List<NotificationEvent> notificationEvents = notification.getEvents(); + assertThat(notificationEvents.size(), is(0)); + } + + @Test + public void testCreateVnfWithChildrenCreateCustomerWithChildrenAndCousinBetweenVlanAndServiceInstanceThenDeleteCustomerVerifyingVlanRV() throws IOException, AAIException { + UEBNotification notification = Mockito.spy(new UEBNotification(ModelType.MOXY, loaderFactory, schemaVersions)); + HttpTestUtil httpTestUtil = new HttpTestUtil(queryStyle); + + JsonObject paylaods = new JsonParser().parse( + PayloadUtil.getResourcePayload("customer_with_children_and_generic-vnf_with_children_and_edge_between_service-instance_vlan.json")) + .getAsJsonObject(); + String gvnfPaylaod = paylaods.get("generic-vnf").toString(); + String custPaylaod = paylaods.get("customer").toString(); + String gvnfUri = "/aai/v14/network/generic-vnfs/generic-vnf/gvnf"; + String custUri = "/aai/v14/business/customers/customer/cust"; + String vlanUri = "/aai/v14/network/generic-vnfs/generic-vnf/gvnf/l-interfaces/l-interface/lint/vlans/vlan/vlan"; + + //Setup generic vnf + Response response = httpTestUtil.doGet(gvnfUri); + assertEquals("Expecting the generic-vnf to be not found", 404, response.getStatus()); + response = httpTestUtil.doPut(gvnfUri, gvnfPaylaod); + assertEquals("Expecting the generic-vnf to be created", 201, response.getStatus()); + response = httpTestUtil.doGet(gvnfUri , "all"); + assertEquals("Expecting the generic-vnf to be found", 200, response.getStatus()); + response = httpTestUtil.doGet(vlanUri , "all"); + assertEquals("Expecting the vlan to be found", 200, response.getStatus()); + String vlanResourceVersion = new JSONObject(response.getEntity().toString()).getString("resource-version"); + + //Setup customer with service instance relation to vlan + response = httpTestUtil.doGet(custUri); + assertEquals("Expecting the customer to be not found", 404, response.getStatus()); + response = httpTestUtil.doPut(custUri, custPaylaod); + assertEquals("Expecting the customer to be created", 201, response.getStatus()); + response = httpTestUtil.doGet(custUri , "all"); + assertEquals("Expecting the customer to be found", 200, response.getStatus()); + String custResourceVersion = new JSONObject(response.getEntity().toString()).getString("resource-version"); + + //Verify vlan rv was updated + response = httpTestUtil.doGet(vlanUri , "all"); + assertEquals("Expecting the vlan to be found", 200, response.getStatus()); + String vlanResourceVersionAfterCustPut = new JSONObject(response.getEntity().toString()).getString("resource-version"); + assertThat("Expecting the vlan resource version to be updated", vlanResourceVersionAfterCustPut, not(is(vlanResourceVersion))); + + //Delete customer + notification.clearEvents(); + httpTestUtil = new HttpTestUtil(queryStyle, notification, AAIProperties.MAXIMUM_DEPTH); + response = httpTestUtil.doDelete(custUri, custResourceVersion); + assertEquals("Expecting customer to be deleted", 204, response.getStatus()); + + //Verify vlan rv was updated + response = httpTestUtil.doGet(vlanUri , "all"); + assertEquals("Expecting the vlan to be found", 200, response.getStatus()); + String vlanResourceVersionAfterDelete = new JSONObject(response.getEntity().toString()).getString("resource-version"); + assertThat("Expecting the vlan resource version to be updated", vlanResourceVersionAfterDelete, not(is(vlanResourceVersionAfterCustPut))); + + List<NotificationEvent> notificationEvents = notification.getEvents(); + assertThat("Expect the delete to generate 4 events customer, its children and vlan", notificationEvents.size(), is(4)); + } + + + @Test + public void testBulkCreateOfComplexAndPserverWithRelationshipThenBulkDeleteBoth() throws IOException, AAIException { + UEBNotification notification = Mockito.spy(new UEBNotification(ModelType.MOXY, loaderFactory, schemaVersions)); + HttpTestUtil httpTestUtil = new HttpTestUtil(queryStyle, notification, AAIProperties.MAXIMUM_DEPTH); + + JsonObject paylaods = new JsonParser().parse( + PayloadUtil.getResourcePayload("complex_pserver_with_relation.json")) + .getAsJsonObject(); + String complexPaylaod = paylaods.get("complex").toString(); + String pserverPaylaod = paylaods.get("pserver").toString(); + String complexUri = "/aai/v14/cloud-infrastructure/complexes/complex/complex-1"; + String pserverUri = "/aai/v14/cloud-infrastructure/pservers/pserver/pserver-1"; + + Response response = httpTestUtil.doGet(complexUri); + assertEquals("Expecting the complex to be not found", 404, response.getStatus()); + response = httpTestUtil.doGet(pserverUri); + assertEquals("Expecting the pserver to be not found", 404, response.getStatus()); + + Map<String,String> puts = new LinkedHashMap<>(); + puts.put(complexUri, complexPaylaod); + puts.put(pserverUri, pserverPaylaod); + + response = httpTestUtil.doPut(puts); + assertEquals("Expecting the puts request to succeed", 201, response.getStatus()); + assertEquals("Expect 2 messages to be created", 2, notification.getEvents().size()); + response = httpTestUtil.doGet(complexUri , "all"); + assertEquals("Expecting the complex to be found", 200, response.getStatus()); + String complexRV = new JSONObject(response.getEntity().toString()).getString("resource-version"); + response = httpTestUtil.doGet(pserverUri , "all"); + assertEquals("Expecting the pserver to be found", 200, response.getStatus()); + String pserverRv = new JSONObject(response.getEntity().toString()).getString("resource-version"); + assertThat("Resource versions match", complexRV, is(pserverRv)); + + Map<String, Pair<String, String>> deletes = new LinkedHashMap<>(); + deletes.put(pserverUri, new Pair<>(pserverRv, null)); + deletes.put(complexUri, new Pair<>(complexRV, null)); + notification = Mockito.spy(new UEBNotification(ModelType.MOXY, loaderFactory, schemaVersions)); + httpTestUtil = new HttpTestUtil(queryStyle, notification, AAIProperties.MAXIMUM_DEPTH); + httpTestUtil.doDelete(deletes); + + response = httpTestUtil.doGet(complexUri); + assertEquals("Expecting the complex to be not found", 404, response.getStatus()); + response = httpTestUtil.doGet(pserverUri); + assertEquals("Expecting the pserver to be not found", 404, response.getStatus()); + } + + @Test + public void testCreateVnfWithChildrenCreateCustomerWithChildrenAndCousinBetweenVlanAndServiceInstanceThenImplicitDeleteVlanVerifyingServiceInstanceRV() throws IOException, AAIException { + UEBNotification notification = Mockito.spy(new UEBNotification(ModelType.MOXY, loaderFactory, schemaVersions)); + HttpTestUtil httpTestUtil = new HttpTestUtil(queryStyle); + + JsonObject paylaods = new JsonParser().parse( + PayloadUtil.getResourcePayload("customer_with_children_and_generic-vnf_with_children_and_edge_between_service-instance_vlan.json")) + .getAsJsonObject(); + String gvnfPaylaod = paylaods.get("generic-vnf").toString(); + String custPaylaod = paylaods.get("customer").toString(); + String custUri = "/aai/v14/business/customers/customer/cust"; + String ssUri = custUri + "/service-subscriptions/service-subscription/ss"; + String siUri = ssUri + "/service-instances/service-instance/si"; + String gvnfUri = "/aai/v14/network/generic-vnfs/generic-vnf/gvnf"; + String lintUri = gvnfUri + "/l-interfaces/l-interface/lint"; + String vlanUri = lintUri + "/vlans/vlan/vlan"; + + //Setup generic vnf + Response response = httpTestUtil.doGet(gvnfUri); + assertEquals("Expecting the generic-vnf to be not found", 404, response.getStatus()); + response = httpTestUtil.doPut(gvnfUri, gvnfPaylaod); + assertEquals("Expecting the generic-vnf to be created", 201, response.getStatus()); + response = httpTestUtil.doGet(gvnfUri , "all"); + assertEquals("Expecting the generic-vnf to be found", 200, response.getStatus()); + response = httpTestUtil.doGet(vlanUri , "all"); + assertEquals("Expecting the vlan to be found", 200, response.getStatus()); + String vlanResourceVersion = new JSONObject(response.getEntity().toString()).getString("resource-version"); + + //Setup customer with service instance relation to vlan + response = httpTestUtil.doGet(custUri); + assertEquals("Expecting the customer to be not found", 404, response.getStatus()); + response = httpTestUtil.doPut(custUri, custPaylaod); + assertEquals("Expecting the customer to be created", 201, response.getStatus()); + response = httpTestUtil.doGet(custUri , "all"); + assertEquals("Expecting the customer to be found", 200, response.getStatus()); + response = httpTestUtil.doGet(siUri , "all"); + assertEquals("Expecting the service-instance to be found", 200, response.getStatus()); + String serviceInstanceResourceVersion = new JSONObject(response.getEntity().toString()).getString("resource-version"); + + //Verify vlan rv was updated + response = httpTestUtil.doGet(vlanUri , "all"); + assertEquals("Expecting the vlan to be found", 200, response.getStatus()); + String vlanResourceVersionAfterCustPut = new JSONObject(response.getEntity().toString()).getString("resource-version"); + assertThat("Expecting the vlan resource version to be updated", vlanResourceVersionAfterCustPut, not(is(vlanResourceVersion))); + + //Get linterface, replace vlans with empty json (implicit delete) and put triggering implicit delete + response = httpTestUtil.doGet(lintUri , "all"); + assertEquals("Expecting the l-interface to be found", 200, response.getStatus()); + JSONObject lintJson = new JSONObject(response.getEntity().toString()); + lintJson.put("vlans", new JsonObject()); + notification.clearEvents(); + httpTestUtil = new HttpTestUtil(queryStyle, notification, AAIProperties.MAXIMUM_DEPTH); + response = httpTestUtil.doPut(lintUri, lintJson.toString()); + assertEquals("Expecting the l-interface to be updated", 200, response.getStatus()); + + List<NotificationEvent> notificationEvents = notification.getEvents(); + assertThat("Expect the implied delete to generate 2", notificationEvents.size(), is(2)); + + //Verify vlan is no longer there anf get service-instance and compare rv + response = httpTestUtil.doGet(vlanUri , "all"); + assertEquals("Expecting the vlan not to be found", 404, response.getStatus()); + response = httpTestUtil.doGet(siUri , "all"); + assertEquals("Expecting the service-instance to be found", 200, response.getStatus()); + String serviceInstanceResourceVersionAfterImplicitDelete = new JSONObject(response.getEntity().toString()).getString("resource-version"); + assertThat("Expecting the service-instance resource version to be updated after implicit delete of vlan", + serviceInstanceResourceVersionAfterImplicitDelete, + not(is(serviceInstanceResourceVersion))); + } + + @After + public void teardown() { + + JanusGraph janusGraph = AAIGraph.getInstance().getGraph(); + JanusGraphTransaction transaction = janusGraph.newTransaction(); + + GraphTraversalSource g = transaction.traversal(); + + g.V() + .has(AAIProperties.SOURCE_OF_TRUTH, "JUNIT") + .forEachRemaining(Vertex::remove); + + transaction.commit(); + } +} diff --git a/aai-core/src/test/java/org/onap/aai/rest/PrivateEdgeIntegrationTest.java b/aai-core/src/test/java/org/onap/aai/rest/PrivateEdgeIntegrationTest.java index d3452153..3bb017d6 100644 --- a/aai-core/src/test/java/org/onap/aai/rest/PrivateEdgeIntegrationTest.java +++ b/aai-core/src/test/java/org/onap/aai/rest/PrivateEdgeIntegrationTest.java @@ -29,8 +29,8 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.jayway.jsonpath.JsonPath; import java.util.*; @@ -55,7 +55,7 @@ import org.onap.aai.setup.SchemaVersion; @RunWith(value = Parameterized.class) public class PrivateEdgeIntegrationTest extends AAISetup { - private static EELFLogger logger = EELFManager.getInstance().getLogger(PserverTest.class); + private static Logger logger = LoggerFactory.getLogger(PserverTest.class); private HttpTestUtil httpTestUtil; private Map<String, String> relationshipMap; diff --git a/aai-core/src/test/java/org/onap/aai/rest/PserverDuplicateTest.java b/aai-core/src/test/java/org/onap/aai/rest/PserverDuplicateTest.java index 5fe3bd00..cdaf1010 100644 --- a/aai-core/src/test/java/org/onap/aai/rest/PserverDuplicateTest.java +++ b/aai-core/src/test/java/org/onap/aai/rest/PserverDuplicateTest.java @@ -24,8 +24,8 @@ import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.List; import java.util.UUID; @@ -52,7 +52,7 @@ import org.onap.aai.serialization.engines.QueryStyle; public class PserverDuplicateTest extends AAISetup { - private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(PserverDuplicateTest.class); + private static final Logger LOGGER = LoggerFactory.getLogger(PserverDuplicateTest.class); private HttpTestUtil testUtil; diff --git a/aai-core/src/test/java/org/onap/aai/rest/PserverTest.java b/aai-core/src/test/java/org/onap/aai/rest/PserverTest.java index 8ede3c32..80ced5ea 100644 --- a/aai-core/src/test/java/org/onap/aai/rest/PserverTest.java +++ b/aai-core/src/test/java/org/onap/aai/rest/PserverTest.java @@ -20,20 +20,12 @@ package org.onap.aai.rest; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; - -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.jayway.jsonpath.JsonPath; - -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; - -import javax.ws.rs.core.Response; - +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; +import org.janusgraph.core.JanusGraphTransaction; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -41,16 +33,31 @@ import org.junit.runners.Parameterized; import org.onap.aai.AAISetup; import org.onap.aai.HttpTestUtil; import org.onap.aai.PayloadUtil; -import org.onap.aai.introspection.*; +import org.onap.aai.dbmap.AAIGraph; +import org.onap.aai.introspection.Introspector; +import org.onap.aai.introspection.Loader; +import org.onap.aai.introspection.ModelType; import org.onap.aai.serialization.engines.QueryStyle; import org.skyscreamer.jsonassert.JSONAssert; import org.springframework.test.annotation.DirtiesContext; +import javax.ws.rs.core.Response; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import static junit.framework.TestCase.fail; +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + @RunWith(value = Parameterized.class) @DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS) public class PserverTest extends AAISetup { - private static EELFLogger logger = EELFManager.getInstance().getLogger(PserverTest.class); + private static Logger logger = LoggerFactory.getLogger(PserverTest.class); private HttpTestUtil httpTestUtil; private Map<String, String> relationshipMap; @@ -69,6 +76,39 @@ public class PserverTest extends AAISetup { } @Test + public void testPutPserverCreateGetInXmlForFormats() throws Exception { + httpTestUtil = new HttpTestUtil(queryStyle, "application/xml"); + String pserverUri = "/aai/v12/cloud-infrastructure/pservers/pserver/test-pserver-xml"; + String cloudRegionUri = "/aai/v12/cloud-infrastructure/cloud-regions/cloud-region/cloud-region-random1/cloud-region-random1-region"; + + Response response = httpTestUtil.doGet(pserverUri); + assertNotNull("Expected the response to be not null", response); + assertEquals("Expecting the pserver to be not found", 404, response.getStatus()); + + response = httpTestUtil.doPut(pserverUri, "{}"); + assertNotNull("Expected the response to be not null", response); + assertEquals("Expecting the pserver to be created", 201, response.getStatus()); + + response = httpTestUtil.doPut(cloudRegionUri, "{}"); + assertNotNull("Expected the response to be not null", response); + assertEquals("Expecting the cloud-region to be created", 201, response.getStatus()); + + relationshipMap.put("related-to", "pserver"); + relationshipMap.put("related-link", pserverUri); + + String pserverRelationshipPayload = PayloadUtil.getTemplatePayload("relationship.json", relationshipMap); + // Creates the relationship between cloud region and pserver + response = httpTestUtil.doPut(cloudRegionUri + "/relationship-list/relationship", pserverRelationshipPayload); + assertNotNull("Expected the response to be not null", response); + assertEquals("Expecting the cloud-region to pserver relationship to be created", 200, response.getStatus()); + + response = httpTestUtil.doGet(pserverUri , "0", "raw"); + assertNotNull("Expected the response to be not null", response); + assertEquals("Expecting the pserver to be created", 200, response.getStatus()); + assertThat(response.getEntity().toString(), containsString("<related-to><node><relationship-label>org.onap.relationships.inventory.LocatedIn</relationship-label><node-type>cloud-region</node-type>")); + } + + @Test public void testPutPServerCreateGetAndDeleteAndCreateRelationshipBetweenPserverAndCloudRegion() throws Exception { logger.info("Starting the pserver testPutServerCreateGetAndDelete"); @@ -148,4 +188,29 @@ public class PserverTest extends AAISetup { logger.info("Ending the pserver testPutServerCreateGetAndDelete"); } + @After + public void tearDown() { + + JanusGraphTransaction transaction = AAIGraph.getInstance().getGraph().newTransaction(); + boolean success = true; + + try { + + GraphTraversalSource g = transaction.traversal(); + + g.V().has("source-of-truth", "JUNIT").toList().forEach(v -> v.remove()); + + } catch (Exception ex) { + success = false; + logger.error("Unable to remove the vertexes", ex); + } finally { + if (success) { + transaction.commit(); + } else { + transaction.rollback(); + fail("Unable to teardown the graph"); + } + } + + } } diff --git a/aai-core/src/test/java/org/onap/aai/rest/RestHandlerTest.java b/aai-core/src/test/java/org/onap/aai/rest/RestHandlerTest.java index cba81d73..494d7e4e 100644 --- a/aai-core/src/test/java/org/onap/aai/rest/RestHandlerTest.java +++ b/aai-core/src/test/java/org/onap/aai/rest/RestHandlerTest.java @@ -35,7 +35,7 @@ public class RestHandlerTest { RestHandlerService secondInstance = RestHandlerService.getInstance(); assertNotNull(firstInstance); assertNotNull(secondInstance); - assertTrue(firstInstance == secondInstance); + assertSame(firstInstance, secondInstance); } } diff --git a/aai-core/src/test/java/org/onap/aai/rest/VnfcRelationshipIssueTest.java b/aai-core/src/test/java/org/onap/aai/rest/VnfcRelationshipIssueTest.java new file mode 100644 index 00000000..ae611717 --- /dev/null +++ b/aai-core/src/test/java/org/onap/aai/rest/VnfcRelationshipIssueTest.java @@ -0,0 +1,111 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 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========================================================= + */ + +package org.onap.aai.rest; + +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; +import org.janusgraph.core.JanusGraphTransaction; +import org.junit.*; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.onap.aai.AAISetup; +import org.onap.aai.HttpTestUtil; +import org.onap.aai.PayloadUtil; +import org.onap.aai.dbmap.AAIGraph; +import org.onap.aai.serialization.engines.QueryStyle; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.test.context.junit4.rules.SpringClassRule; +import org.springframework.test.context.junit4.rules.SpringMethodRule; + +import javax.ws.rs.core.Response; +import java.util.Arrays; +import java.util.Collection; + +import static junit.framework.TestCase.fail; +import static org.junit.Assert.assertEquals; + +@RunWith(value = Parameterized.class) +public class VnfcRelationshipIssueTest extends AAISetup { + + private static final Logger LOGGER = LoggerFactory.getLogger(VnfcRelationshipIssueTest.class); + private HttpTestUtil httpTestUtil; + + @ClassRule + public static final SpringClassRule SPRING_CLASS_RULE = new SpringClassRule(); + + @Rule + public final SpringMethodRule springMethodRule = new SpringMethodRule(); + + @Parameterized.Parameter(value = 0) + public QueryStyle queryStyle; + + @Parameterized.Parameters(name = "QueryStyle.{0}") + public static Collection<Object[]> data() { + return Arrays.asList(new Object[][] {{QueryStyle.TRAVERSAL}, {QueryStyle.TRAVERSAL_URI}}); + } + + @Before + public void setUp() { + httpTestUtil = new HttpTestUtil(queryStyle); + } + + @Test + public void testCreateVnfWithVfModuleAndCreateVnfcRelatedToVfModule() throws Exception { + + String genericVnfUri = "/aai/v14/network/generic-vnfs/generic-vnf/test-vnf11"; + String genericVnfPayload = PayloadUtil.getResourcePayload("generic-vnf-with-vf-module.json"); + + Response response = httpTestUtil.doPut(genericVnfUri, genericVnfPayload); + assertEquals("Expected the generic vnf to be created", 201, response.getStatus()); + + String vnfcUri = "/aai/v14/network/vnfcs/vnfc/test-vnfc11"; + String vnfcPaylaod = PayloadUtil.getResourcePayload("vnfc-related-to-vf-module.json"); + + response = httpTestUtil.doPut(vnfcUri, vnfcPaylaod); + assertEquals("Expected the generic vnf to be created", 201, response.getStatus()); + } + + @After + public void tearDown() { + + JanusGraphTransaction transaction = AAIGraph.getInstance().getGraph().newTransaction(); + boolean success = true; + + try { + + GraphTraversalSource g = transaction.traversal(); + + g.V().has("source-of-truth", "JUNIT").toList().forEach(v -> v.remove()); + + } catch (Exception ex) { + success = false; + LOGGER.error("Unable to remove the vertexes", ex); + } finally { + if (success) { + transaction.commit(); + } else { + transaction.rollback(); + fail("Unable to teardown the graph"); + } + } + + } +} diff --git a/aai-core/src/test/java/org/onap/aai/rest/db/HttpEntryTest.java b/aai-core/src/test/java/org/onap/aai/rest/db/HttpEntryTest.java index c01d270e..95220b1f 100644 --- a/aai-core/src/test/java/org/onap/aai/rest/db/HttpEntryTest.java +++ b/aai-core/src/test/java/org/onap/aai/rest/db/HttpEntryTest.java @@ -20,23 +20,8 @@ package org.onap.aai.rest.db; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.not; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; -import static org.mockito.Matchers.anyObject; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.when; - import com.google.gson.JsonObject; import com.google.gson.JsonParser; - -import java.io.UnsupportedEncodingException; -import java.net.URI; -import java.util.*; - -import javax.ws.rs.core.*; - import org.javatuples.Pair; import org.junit.Before; import org.junit.FixMethodOrder; @@ -47,11 +32,9 @@ import org.junit.runners.Parameterized; import org.mockito.Mockito; import org.onap.aai.AAISetup; import org.onap.aai.db.props.AAIProperties; -import org.onap.aai.dbmap.DBConnectionType; import org.onap.aai.exceptions.AAIException; import org.onap.aai.introspection.Introspector; import org.onap.aai.introspection.Loader; -import org.onap.aai.introspection.LoaderFactory; import org.onap.aai.introspection.ModelType; import org.onap.aai.parsers.query.QueryParser; import org.onap.aai.rest.ueb.UEBNotification; @@ -60,6 +43,19 @@ import org.onap.aai.serialization.engines.QueryStyle; import org.onap.aai.serialization.engines.TransactionalGraphEngine; import org.onap.aai.util.AAIConfig; +import javax.ws.rs.core.*; +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.util.*; + +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.not; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.mockito.Matchers.anyObject; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.when; + @RunWith(value = Parameterized.class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class HttpEntryTest extends AAISetup { @@ -139,7 +135,7 @@ public class HttpEntryTest extends AAISetup { if (uri.endsWith("relationship")) { objType = "relationship"; } - Introspector obj = null; + Introspector obj; if (method.equals(HttpMethod.GET)) { obj = loader.introspectorFromName(objType); } else { @@ -163,8 +159,7 @@ public class HttpEntryTest extends AAISetup { /* * TODO do the same with uri */ - DBConnectionType type = DBConnectionType.REALTIME; - traversalHttpEntry.setHttpEntryProperties(schemaVersions.getDefaultVersion(), type); + traversalHttpEntry.setHttpEntryProperties(schemaVersions.getDefaultVersion()); Loader loader = traversalHttpEntry.getLoader(); TransactionalGraphEngine dbEngine = traversalHttpEntry.getDbEngine(); @@ -178,8 +173,7 @@ public class HttpEntryTest extends AAISetup { @Test public void test2PutOnPserverNoPInterface() throws UnsupportedEncodingException, AAIException { - DBConnectionType type = DBConnectionType.REALTIME; - traversalHttpEntry.setHttpEntryProperties(schemaVersions.getDefaultVersion(), type); + traversalHttpEntry.setHttpEntryProperties(schemaVersions.getDefaultVersion()); Loader loader = traversalHttpEntry.getLoader(); TransactionalGraphEngine dbEngine = traversalHttpEntry.getDbEngine(); @@ -193,8 +187,7 @@ public class HttpEntryTest extends AAISetup { @Test public void test3PutOnPInterface() { try { - DBConnectionType type = DBConnectionType.REALTIME; - traversalHttpEntry.setHttpEntryProperties(schemaVersions.getDefaultVersion(), type); + traversalHttpEntry.setHttpEntryProperties(schemaVersions.getDefaultVersion()); Loader loader = traversalHttpEntry.getLoader(); TransactionalGraphEngine dbEngine = traversalHttpEntry.getDbEngine(); @@ -212,14 +205,11 @@ public class HttpEntryTest extends AAISetup { @Test public void test4GetOnPserver() throws UnsupportedEncodingException, AAIException { - DBConnectionType type = DBConnectionType.REALTIME; - traversalHttpEntry.setHttpEntryProperties(schemaVersions.getDefaultVersion(), type); + traversalHttpEntry.setHttpEntryProperties(schemaVersions.getDefaultVersion()); Loader loader = traversalHttpEntry.getLoader(); TransactionalGraphEngine dbEngine = traversalHttpEntry.getDbEngine(); - URI uriObject = UriBuilder.fromPath("/cloud-infrastructure/pservers/pserver/junit-test1").build(); - String uri = "/cloud-infrastructure/pservers/pserver/junit-test1"; String content = "{\"hostname\":\"junit-test1\", \"equip-type\":\"junit-equip-type\"}"; Response response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.GET, uri, content); @@ -230,8 +220,7 @@ public class HttpEntryTest extends AAISetup { @Test public void test5MergePatchOnPserver() throws UnsupportedEncodingException, AAIException { - DBConnectionType type = DBConnectionType.REALTIME; - traversalHttpEntry.setHttpEntryProperties(schemaVersions.getDefaultVersion(), type); + traversalHttpEntry.setHttpEntryProperties(schemaVersions.getDefaultVersion()); Loader loader = traversalHttpEntry.getLoader(); TransactionalGraphEngine dbEngine = traversalHttpEntry.getDbEngine(); @@ -246,8 +235,7 @@ public class HttpEntryTest extends AAISetup { private int doDelete(String resourceVersion, String uri, String nodeType) throws UnsupportedEncodingException, AAIException { queryParameters.add("resource-version", resourceVersion); - DBConnectionType type = DBConnectionType.REALTIME; - traversalHttpEntry.setHttpEntryProperties(schemaVersions.getDefaultVersion(), type); + traversalHttpEntry.setHttpEntryProperties(schemaVersions.getDefaultVersion()); Loader loader = traversalHttpEntry.getLoader(); TransactionalGraphEngine dbEngine = traversalHttpEntry.getDbEngine(); @@ -274,12 +262,10 @@ public class HttpEntryTest extends AAISetup { @Test public void test6DeleteOnPserver() throws UnsupportedEncodingException, AAIException { - DBConnectionType type = DBConnectionType.REALTIME; - traversalHttpEntry.setHttpEntryProperties(schemaVersions.getDefaultVersion(), type); + traversalHttpEntry.setHttpEntryProperties(schemaVersions.getDefaultVersion()); Loader loader = traversalHttpEntry.getLoader(); TransactionalGraphEngine dbEngine = traversalHttpEntry.getDbEngine(); - URI uriObject = UriBuilder.fromPath("/cloud-infrastructure/pservers/pserver/junit-test1").build(); String uri = "/cloud-infrastructure/pservers/pserver/junit-test1"; String content = ""; Response response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.GET, uri, content); @@ -297,8 +283,7 @@ public class HttpEntryTest extends AAISetup { @Test public void test7DeleteOnPserverNoPinterface() throws UnsupportedEncodingException, AAIException { - DBConnectionType type = DBConnectionType.REALTIME; - traversalHttpEntry.setHttpEntryProperties(schemaVersions.getDefaultVersion(), type); + traversalHttpEntry.setHttpEntryProperties(schemaVersions.getDefaultVersion()); // HttpEntry httpEntry = new HttpEntry(Version.getLatest(), ModelType.MOXY, queryStyle, type); Loader loader = traversalHttpEntry.getLoader(); TransactionalGraphEngine dbEngine = traversalHttpEntry.getDbEngine(); @@ -320,8 +305,7 @@ public class HttpEntryTest extends AAISetup { @Test public void test8FailedGetOnPserver() throws UnsupportedEncodingException, AAIException { - DBConnectionType type = DBConnectionType.REALTIME; - traversalHttpEntry.setHttpEntryProperties(schemaVersions.getDefaultVersion(), type); + traversalHttpEntry.setHttpEntryProperties(schemaVersions.getDefaultVersion()); // HttpEntry httpEntry = new HttpEntry(Version.getLatest(), ModelType.MOXY, queryStyle, type); Loader loader = traversalHttpEntry.getLoader(); TransactionalGraphEngine dbEngine = traversalHttpEntry.getDbEngine(); @@ -337,8 +321,7 @@ public class HttpEntryTest extends AAISetup { @Test public void putEdgeTest() throws UnsupportedEncodingException, AAIException { - DBConnectionType type = DBConnectionType.REALTIME; - traversalHttpEntry.setHttpEntryProperties(schemaVersions.getDefaultVersion(), type); + traversalHttpEntry.setHttpEntryProperties(schemaVersions.getDefaultVersion()); // HttpEntry httpEntry = new HttpEntry(Version.getLatest(), ModelType.MOXY, queryStyle, type); Loader loader = traversalHttpEntry.getLoader(); TransactionalGraphEngine dbEngine = traversalHttpEntry.getDbEngine(); @@ -368,8 +351,7 @@ public class HttpEntryTest extends AAISetup { Loader ld = loaderFactory.createLoaderForVersion(ModelType.MOXY, schemaVersions.getDefaultVersion()); UEBNotification uebNotification = Mockito.spy(new UEBNotification(ld, loaderFactory, schemaVersions)); - DBConnectionType type = DBConnectionType.REALTIME; - traversalHttpEntry.setHttpEntryProperties(schemaVersions.getDefaultVersion(), type, uebNotification); + traversalHttpEntry.setHttpEntryProperties(schemaVersions.getDefaultVersion(), uebNotification); Loader loader = traversalHttpEntry.getLoader(); TransactionalGraphEngine dbEngine = traversalHttpEntry.getDbEngine(); @@ -390,31 +372,32 @@ public class HttpEntryTest extends AAISetup { doNothing().when(uebNotification).triggerEvents(); Response response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.PUT_EDGE, uri, content); - response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.DELETE_EDGE, uri, content); - dbEngine.rollback(); - assertEquals("Expected the pserver relationship to be deleted", 204, response.getStatus()); - assertEquals("Two notifications", 2, uebNotification.getEvents().size()); + assertEquals("Expected the pserver relationship to be deleted", 200, response.getStatus()); + assertEquals("Two notifications", 2, uebNotification.getEvents().size()); assertEquals("Notification generated for PUT edge", "UPDATE", uebNotification.getEvents().get(0).getEventHeader().getValue("action").toString()); assertThat("Event body for the edge create has the related to", uebNotification.getEvents().get(0).getObj().marshal(false), containsString("cloud-infrastructure/pservers/pserver/junit-edge-test-pserver")); + response = doRequest(traversalHttpEntry, loader, dbEngine, HttpMethod.DELETE_EDGE, uri, content); + assertEquals("Expected the pserver relationship to be deleted", 204, response.getStatus()); + assertEquals("Two notifications", 2, uebNotification.getEvents().size()); assertEquals("Notification generated for DELETE edge", "UPDATE", - uebNotification.getEvents().get(1).getEventHeader().getValue("action").toString()); + uebNotification.getEvents().get(0).getEventHeader().getValue("action").toString()); assertThat("Event body for the edge delete does not have the related to", - uebNotification.getEvents().get(1).getObj().marshal(false), + uebNotification.getEvents().get(0).getObj().marshal(false), not(containsString("cloud-infrastructure/pservers/pserver/junit-edge-test-pserver"))); + dbEngine.rollback(); } @Test public void putEdgeWrongLabelTest() throws UnsupportedEncodingException, AAIException { - DBConnectionType type = DBConnectionType.REALTIME; - traversalHttpEntry.setHttpEntryProperties(schemaVersions.getDefaultVersion(), type); + traversalHttpEntry.setHttpEntryProperties(schemaVersions.getDefaultVersion()); // HttpEntry httpEntry = new HttpEntry(Version.getLatest(), ModelType.MOXY, queryStyle, type); Loader loader = traversalHttpEntry.getLoader(); TransactionalGraphEngine dbEngine = traversalHttpEntry.getDbEngine(); @@ -449,8 +432,7 @@ public class HttpEntryTest extends AAISetup { final String testName = new Object() {}.getClass().getEnclosingMethod().getName(); - DBConnectionType type = DBConnectionType.REALTIME; - traversalHttpEntry.setHttpEntryProperties(schemaVersions.getDefaultVersion(), type); + traversalHttpEntry.setHttpEntryProperties(schemaVersions.getDefaultVersion()); // HttpEntry httpEntry = new HttpEntry(schemaVersions.getDefaultVersion(), ModelType.MOXY, QueryStyle.TRAVERSAL, // type); Loader loader = traversalHttpEntry.getLoader(); @@ -496,9 +478,7 @@ public class HttpEntryTest extends AAISetup { final String testName = new Object() {}.getClass().getEnclosingMethod().getName(); - DBConnectionType type = DBConnectionType.REALTIME; - traversalHttpEntry.setHttpEntryProperties(schemaVersions.getDefaultVersion(), type); - // HttpEntry httpEntry = new HttpEntry(Version.getLatest(), ModelType.MOXY, QueryStyle.TRAVERSAL, type); + traversalHttpEntry.setHttpEntryProperties(schemaVersions.getDefaultVersion()); Loader loader = traversalHttpEntry.getLoader(); TransactionalGraphEngine dbEngine = traversalHttpEntry.getDbEngine(); @@ -532,10 +512,7 @@ public class HttpEntryTest extends AAISetup { @Test public void testSetGetPaginationMethods() { - DBConnectionType type = DBConnectionType.REALTIME; - traversalHttpEntry.setHttpEntryProperties(schemaVersions.getDefaultVersion(), type); - // HttpEntry httpEntry = new HttpEntry(schemaVersions.getDefaultVersion(), ModelType.MOXY, QueryStyle.TRAVERSAL, - // type); + traversalHttpEntry.setHttpEntryProperties(schemaVersions.getDefaultVersion()); traversalHttpEntry.setPaginationBucket(10); traversalHttpEntry.setPaginationIndex(1); traversalHttpEntry.setTotalsForPaging(101, traversalHttpEntry.getPaginationBucket()); @@ -549,9 +526,7 @@ public class HttpEntryTest extends AAISetup { @Test public void relatedToTest() throws UnsupportedEncodingException, AAIException { - DBConnectionType type = DBConnectionType.REALTIME; - traversalHttpEntry.setHttpEntryProperties(schemaVersions.getDefaultVersion(), type); - // HttpEntry httpEntry = new HttpEntry(schemaVersions.getDefaultVersion(), ModelType.MOXY, queryStyle, type); + traversalHttpEntry.setHttpEntryProperties(schemaVersions.getDefaultVersion()); Loader loader = traversalHttpEntry.getLoader(); TransactionalGraphEngine dbEngine = traversalHttpEntry.getDbEngine(); @@ -585,14 +560,12 @@ public class HttpEntryTest extends AAISetup { } @Test - public void setDepthTest() throws UnsupportedEncodingException, AAIException { + public void setDepthTest() throws AAIException { System.setProperty("AJSC_HOME", "."); System.setProperty("BUNDLECONFIG_DIR", "src/main/test/resources"); String depthParam = AAIConfig.get("aai.rest.getall.depthparam"); - DBConnectionType type = DBConnectionType.REALTIME; - traversalHttpEntry.setHttpEntryProperties(schemaVersions.getDefaultVersion(), type); - // HttpEntry httpEntry = new HttpEntry(Version.getLatest(), ModelType.MOXY, QueryStyle.TRAVERSAL, type); + traversalHttpEntry.setHttpEntryProperties(schemaVersions.getDefaultVersion()); int depth = traversalHttpEntry.setDepth(null, depthParam); assertEquals(AAIProperties.MAXIMUM_DEPTH.intValue(), depth); } @@ -600,9 +573,7 @@ public class HttpEntryTest extends AAISetup { @Test public void getAbstractTest() throws UnsupportedEncodingException, AAIException { - DBConnectionType type = DBConnectionType.REALTIME; - traversalHttpEntry.setHttpEntryProperties(schemaVersions.getDefaultVersion(), type); - // HttpEntry httpEntry = new HttpEntry(Version.getLatest(), ModelType.MOXY, queryStyle, type); + traversalHttpEntry.setHttpEntryProperties(schemaVersions.getDefaultVersion()); Loader loader = traversalHttpEntry.getLoader(); TransactionalGraphEngine dbEngine = traversalHttpEntry.getDbEngine(); diff --git a/aai-core/src/test/java/org/onap/aai/rest/ueb/UEBNotificationTest.java b/aai-core/src/test/java/org/onap/aai/rest/ueb/UEBNotificationTest.java new file mode 100644 index 00000000..58b96e49 --- /dev/null +++ b/aai-core/src/test/java/org/onap/aai/rest/ueb/UEBNotificationTest.java @@ -0,0 +1,112 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 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========================================================= + */ + +package org.onap.aai.rest.ueb; + +import org.junit.Before; +import org.junit.Test; +import org.onap.aai.AAISetup; +import org.onap.aai.edges.EdgeIngestor; +import org.onap.aai.exceptions.AAIException; +import org.onap.aai.introspection.Introspector; +import org.onap.aai.introspection.Loader; +import org.onap.aai.introspection.ModelType; +import org.onap.aai.serialization.db.EdgeSerializer; +import org.onap.aai.serialization.engines.QueryStyle; +import org.onap.aai.setup.SchemaVersion; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.annotation.DirtiesContext; + +import javax.ws.rs.core.Response; +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.HashMap; +import java.util.UUID; + +import static org.junit.Assert.assertEquals; + +@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS) +public class UEBNotificationTest extends AAISetup { + + public static final String BASE_PATH = "/aai"; + @Autowired + protected EdgeSerializer edgeSer; + @Autowired + protected EdgeIngestor ei; + + private SchemaVersion version; + private final ModelType introspectorFactoryType = ModelType.MOXY; + private Loader loader; + + public QueryStyle queryStyle = QueryStyle.TRAVERSAL_URI; + + + @Before + public void setup() throws Exception { + version = schemaVersions.getDefaultVersion(); + loader = loaderFactory.createLoaderForVersion(introspectorFactoryType, version); + } + + @Test + public void verifyUriNoIssues() throws AAIException, URISyntaxException, UnsupportedEncodingException { + + Introspector pserver = loader.introspectorFromName("pserver"); + pserver.setValue("hostname", "hn"); + URI uri = new URI("/cloud-infrastructure/pservers/pserver/hn"); + UEBNotification uebNotification = new UEBNotification(loader, loaderFactory, schemaVersions); + uebNotification.createNotificationEvent( + UUID.randomUUID().toString(), + "JUNIT-SOT", + Response.Status.CREATED, + uri, + pserver, + new HashMap<>(), + BASE_PATH); + + assertEquals("One event created", 1, uebNotification.getEvents().size()); + assertEquals( + "Uri is correct", + BASE_PATH + "/" + schemaVersions.getDefaultVersion() + "/cloud-infrastructure/pservers/pserver/hn", + uebNotification.getEvents().get(0).getEventHeader().getValue("entity-link").toString()); + } + + @Test + public void verifyUriWithBaseAndUri() throws AAIException, URISyntaxException, UnsupportedEncodingException { + + Introspector pserver = loader.introspectorFromName("pserver"); + pserver.setValue("hostname", "hn"); + URI uri = new URI(BASE_PATH + "/v12/cloud-infrastructure/pservers/pserver/hn"); + UEBNotification uebNotification = new UEBNotification(loader, loaderFactory, schemaVersions); + uebNotification.createNotificationEvent( + UUID.randomUUID().toString(), + "JUNIT-SOT", + Response.Status.CREATED, + uri, + pserver, + new HashMap<>(), BASE_PATH); + + assertEquals("One event created", 1, uebNotification.getEvents().size()); + assertEquals( + "Uri is correct", + BASE_PATH + "/" + schemaVersions.getDefaultVersion() + "/cloud-infrastructure/pservers/pserver/hn", + uebNotification.getEvents().get(0).getEventHeader().getValue("entity-link").toString()); + } +} diff --git a/aai-core/src/test/java/org/onap/aai/serialization/db/DbAliasTest.java b/aai-core/src/test/java/org/onap/aai/serialization/db/DbAliasTest.java index 944a4067..454aa218 100644 --- a/aai-core/src/test/java/org/onap/aai/serialization/db/DbAliasTest.java +++ b/aai-core/src/test/java/org/onap/aai/serialization/db/DbAliasTest.java @@ -20,20 +20,6 @@ package org.onap.aai.serialization.db; -import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.when; - -import java.io.UnsupportedEncodingException; -import java.lang.reflect.InvocationTargetException; -import java.net.MalformedURLException; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Map; - import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; import org.apache.tinkerpop.gremlin.structure.Graph; import org.apache.tinkerpop.gremlin.structure.Vertex; @@ -44,11 +30,12 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; -import org.onap.aai.AAISetup; import org.onap.aai.DataLinkSetup; -import org.onap.aai.dbmap.DBConnectionType; +import org.onap.aai.db.props.AAIProperties; import org.onap.aai.exceptions.AAIException; -import org.onap.aai.introspection.*; +import org.onap.aai.introspection.Introspector; +import org.onap.aai.introspection.Loader; +import org.onap.aai.introspection.ModelType; import org.onap.aai.parsers.query.QueryParser; import org.onap.aai.schema.enums.PropertyMetadata; import org.onap.aai.serialization.engines.JanusGraphDBEngine; @@ -57,6 +44,18 @@ import org.onap.aai.serialization.engines.TransactionalGraphEngine; import org.onap.aai.setup.SchemaVersion; import org.springframework.test.annotation.DirtiesContext; +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + @RunWith(value = Parameterized.class) @DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS) public class DbAliasTest extends DataLinkSetup { @@ -65,11 +64,10 @@ public class DbAliasTest extends DataLinkSetup { private SchemaVersion version; private final ModelType introspectorFactoryType = ModelType.MOXY; - private final DBConnectionType type = DBConnectionType.REALTIME; private Loader loader; private TransactionalGraphEngine dbEngine; - @Parameterized.Parameter(value = 0) + @Parameterized.Parameter public QueryStyle queryStyle; @Parameterized.Parameters(name = "QueryStyle.{0}") @@ -78,11 +76,11 @@ public class DbAliasTest extends DataLinkSetup { } @Before - public void setup() throws Exception { + public void setup() { version = schemaVersions.getDepthVersion(); graph = JanusGraphFactory.build().set("storage.backend", "inmemory").open(); loader = loaderFactory.createLoaderForVersion(introspectorFactoryType, version); - dbEngine = new JanusGraphDBEngine(queryStyle, type, loader); + dbEngine = new JanusGraphDBEngine(queryStyle, loader); } @After @@ -92,9 +90,7 @@ public class DbAliasTest extends DataLinkSetup { } @Test - public void checkOnWrite() throws AAIException, UnsupportedEncodingException, URISyntaxException, SecurityException, - IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException, - NoSuchMethodException, InterruptedException { + public void checkOnWrite() throws AAIException, UnsupportedEncodingException, URISyntaxException, SecurityException, IllegalArgumentException { final String property = "persona-model-customization-id"; String dbPropertyName = property; TransactionalGraphEngine spy = spy(this.dbEngine); @@ -108,6 +104,13 @@ public class DbAliasTest extends DataLinkSetup { spy.getQueryBuilder().createQueryFromURI(new URI("network/generic-vnfs/generic-vnf/key1")); Introspector obj = loader.introspectorFromName("generic-vnf"); Vertex v = g.addVertex(); + v.property("aai-uri", "abc"); + v.property("aai-uuid", "b"); + v.property(AAIProperties.CREATED_TS, 123L); + v.property(AAIProperties.SOURCE_OF_TRUTH, "sot"); + v.property(AAIProperties.RESOURCE_VERSION, "123"); + v.property(AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot"); + v.property(AAIProperties.LAST_MOD_TS, 123L); Object id = v.id(); obj.setValue("vnf-id", "key1"); obj.setValue(property, "hello"); @@ -126,14 +129,12 @@ public class DbAliasTest extends DataLinkSetup { } @Test - public void checkOnRead() throws AAIException, UnsupportedEncodingException, URISyntaxException, SecurityException, - IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException, - NoSuchMethodException, InterruptedException, MalformedURLException { + public void checkOnRead() throws AAIException, UnsupportedEncodingException, SecurityException, IllegalArgumentException { final String property = "persona-model-customization-id"; TransactionalGraphEngine spy = spy(dbEngine); TransactionalGraphEngine.Admin adminSpy = spy(dbEngine.asAdmin()); - Vertex v = graph.traversal().addV("vnf-id", "key1", "model-customization-id", "hello").next(); + Vertex v = graph.traversal().addV().property("vnf-id", "key1").property("model-customization-id", "hello").next(); graph.tx().commit(); Graph g = graph.newTransaction(); GraphTraversalSource traversal = g.traversal(); diff --git a/aai-core/src/test/java/org/onap/aai/serialization/db/DbSerializerDeltasTest.java b/aai-core/src/test/java/org/onap/aai/serialization/db/DbSerializerDeltasTest.java new file mode 100644 index 00000000..de8f2224 --- /dev/null +++ b/aai-core/src/test/java/org/onap/aai/serialization/db/DbSerializerDeltasTest.java @@ -0,0 +1,764 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 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========================================================= + */ + +package org.onap.aai.serialization.db; + +import com.google.gson.FieldNamingPolicy; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import org.apache.tinkerpop.gremlin.structure.Graph; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.janusgraph.core.JanusGraphFactory; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.onap.aai.AAISetup; +import org.onap.aai.db.props.AAIProperties; +import org.onap.aai.edges.EdgeIngestor; +import org.onap.aai.exceptions.AAIException; +import org.onap.aai.introspection.Introspector; +import org.onap.aai.introspection.Loader; +import org.onap.aai.introspection.ModelType; +import org.onap.aai.parsers.query.QueryParser; +import org.onap.aai.serialization.engines.JanusGraphDBEngine; +import org.onap.aai.serialization.engines.QueryStyle; +import org.onap.aai.serialization.engines.TransactionalGraphEngine; +import org.onap.aai.setup.SchemaVersion; +import org.onap.aai.util.delta.DeltaAction; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.TestPropertySource; + +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.*; + +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.junit.Assert.*; + +@RunWith(value = Parameterized.class) +@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS) +@TestPropertySource(properties = { + "delta.events.enabled=true", + }) +public class DbSerializerDeltasTest extends AAISetup { + + // to use, set thrown.expect to whatever your test needs + // this line establishes default of expecting no exception to be thrown + @Rule + public ExpectedException thrown = ExpectedException.none(); + + protected static Graph graph; + + @Autowired + protected EdgeSerializer edgeSer; + @Autowired + protected EdgeIngestor ei; + + private SchemaVersion version; + private final ModelType introspectorFactoryType = ModelType.MOXY; + private Loader loader; + private TransactionalGraphEngine dbEngine; + private TransactionalGraphEngine engine; // for tests that aren't mocking the engine + + @Parameterized.Parameter(value = 0) + public QueryStyle queryStyle; + + @Parameterized.Parameters(name = "QueryStyle.{0}") + public static Collection<Object[]> data() { + return Arrays.asList(new Object[][] {{QueryStyle.TRAVERSAL}, {QueryStyle.TRAVERSAL_URI}}); + } + + @BeforeClass + public static void init() throws Exception { + graph = JanusGraphFactory.build().set("storage.backend", "inmemory").open(); + + } + + @Before + public void setup() throws Exception { + // createGraph(); + version = schemaVersions.getDefaultVersion(); + loader = loaderFactory.createLoaderForVersion(introspectorFactoryType, version); + dbEngine = new JanusGraphDBEngine(queryStyle, loader); + engine = new JanusGraphDBEngine(queryStyle, loader); + } + + @Test + public void createTopLevelThenUpdateTest() throws AAIException, UnsupportedEncodingException, URISyntaxException { + engine.startTransaction(); + + DBSerializer dbserLocal = new DBSerializer(version, engine, introspectorFactoryType, "AAI-TEST", AAIProperties.MINIMUM_DEPTH); + Introspector gvnf = loader.introspectorFromName("generic-vnf"); + Vertex gvnfVert = dbserLocal.createNewVertex(gvnf); + QueryParser uriQuery = + dbEngine.getQueryBuilder().createQueryFromURI(new URI("/network/generic-vnfs/generic-vnf/myvnf")); + + gvnf.setValue("vnf-id", "myvnf"); + gvnf.setValue("vnf-type", "typo"); + dbserLocal.serializeToDb(gvnf, gvnfVert, uriQuery, "generic-vnf", gvnf.marshal(false)); + assertTrue("Original created vertex exists", engine.tx().traversal().V() + .has("aai-node-type", "generic-vnf") + .has("vnf-id", "myvnf") + .has("vnf-type", "typo") + .hasNext()); + + + assertEquals(DeltaAction.CREATE, dbserLocal.getObjectDeltas().get("/network/generic-vnfs/generic-vnf/myvnf").getAction()); + assertEquals(4L, dbserLocal.getObjectDeltas().get("/network/generic-vnfs/generic-vnf/myvnf").getPropertyDeltas().values().stream().filter(d -> d.getAction().equals(DeltaAction.STATIC)).count()); + assertEquals(5L, dbserLocal.getObjectDeltas().get("/network/generic-vnfs/generic-vnf/myvnf").getPropertyDeltas().values().stream().filter(d -> d.getAction().equals(DeltaAction.CREATE)).count()); + dbserLocal.getObjectDeltas().values().forEach(od -> { + if (!od.getPropertyDeltas().containsKey(AAIProperties.AAI_UUID) ) { + fail(od.getUri() + " is missing " + AAIProperties.AAI_UUID); + } else if (od.getPropertyDeltas().get(AAIProperties.AAI_UUID) == null) { + fail(od.getUri() + " " + AAIProperties.AAI_UUID + " is null"); + } else if (od.getPropertyDeltas().get(AAIProperties.AAI_UUID).getValue() == null) { + fail(od.getUri() + " " + AAIProperties.AAI_UUID + " value is null"); + } + }); + + gvnf = dbserLocal.getLatestVersionView(gvnfVert); + gvnf.setValue("vnf-type", "new-typo"); + dbserLocal = new DBSerializer(version, engine, introspectorFactoryType, "AAI-TEST", AAIProperties.MINIMUM_DEPTH); + dbserLocal.serializeToDb(gvnf, gvnfVert, uriQuery, "generic-vnf", gvnf.marshal(false)); + assertTrue("Vertex is updated", engine.tx().traversal().V() + .has("aai-node-type", "generic-vnf") + .has("vnf-id", "myvnf") + .has("vnf-type", "new-typo") + .hasNext()); + + + assertEquals(DeltaAction.UPDATE, dbserLocal.getObjectDeltas().get("/network/generic-vnfs/generic-vnf/myvnf").getAction()); + assertEquals(4L, dbserLocal.getObjectDeltas().get("/network/generic-vnfs/generic-vnf/myvnf").getPropertyDeltas().values().stream().filter(d -> d.getAction().equals(DeltaAction.STATIC)).count()); + assertEquals(4L, dbserLocal.getObjectDeltas().get("/network/generic-vnfs/generic-vnf/myvnf").getPropertyDeltas().values().stream().filter(d -> d.getAction().equals(DeltaAction.UPDATE)).count()); + dbserLocal.getObjectDeltas().values().forEach(od -> { + if (!od.getPropertyDeltas().containsKey(AAIProperties.AAI_UUID) ) { + fail(od.getUri() + " is missing " + AAIProperties.AAI_UUID); + } else if (od.getPropertyDeltas().get(AAIProperties.AAI_UUID) == null) { + fail(od.getUri() + " " + AAIProperties.AAI_UUID + " is null"); + } else if (od.getPropertyDeltas().get(AAIProperties.AAI_UUID).getValue() == null) { + fail(od.getUri() + " " + AAIProperties.AAI_UUID + " value is null"); + } + }); + } + + @Test + public void createTopLevelThenCreateChildTest() throws AAIException, UnsupportedEncodingException, URISyntaxException { + engine.startTransaction(); + + DBSerializer dbserLocal = new DBSerializer(version, engine, introspectorFactoryType, "AAI-TEST", AAIProperties.MINIMUM_DEPTH); + Introspector gvnf = loader.introspectorFromName("generic-vnf"); + Vertex gvnfVert = dbserLocal.createNewVertex(gvnf); + final String vnfUri = "/network/generic-vnfs/generic-vnf/myvnf"; + QueryParser uriQuery = + dbEngine.getQueryBuilder().createQueryFromURI(new URI(vnfUri)); + + gvnf.setValue("vnf-id", "myvnf"); + gvnf.setValue("vnf-type", "typo"); + dbserLocal.serializeToDb(gvnf, gvnfVert, uriQuery, "generic-vnf", gvnf.marshal(false)); + assertTrue("Original created vertex exists", engine.tx().traversal().V() + .has("aai-node-type", "generic-vnf") + .has("vnf-id", "myvnf") + .has("vnf-type", "typo") + .hasNext()); + + + assertEquals(DeltaAction.CREATE, dbserLocal.getObjectDeltas().get(vnfUri).getAction()); + assertEquals(4L, dbserLocal.getObjectDeltas().get(vnfUri).getPropertyDeltas().values().stream().filter(d -> d.getAction().equals(DeltaAction.STATIC)).count()); + assertEquals(5L, dbserLocal.getObjectDeltas().get(vnfUri).getPropertyDeltas().values().stream().filter(d -> d.getAction().equals(DeltaAction.CREATE)).count()); + dbserLocal.getObjectDeltas().values().forEach(od -> { + if (!od.getPropertyDeltas().containsKey(AAIProperties.AAI_UUID) ) { + fail(od.getUri() + " is missing " + AAIProperties.AAI_UUID); + } else if (od.getPropertyDeltas().get(AAIProperties.AAI_UUID) == null) { + fail(od.getUri() + " " + AAIProperties.AAI_UUID + " is null"); + } else if (od.getPropertyDeltas().get(AAIProperties.AAI_UUID).getValue() == null) { + fail(od.getUri() + " " + AAIProperties.AAI_UUID + " value is null"); + } + }); + + dbserLocal = new DBSerializer(version, engine, introspectorFactoryType, "AAI-TEST", AAIProperties.MINIMUM_DEPTH); + Introspector vf = loader.introspectorFromName("vf-module"); + Vertex vfVertex = dbserLocal.createNewVertex(vf); + final String vfUri = "/network/generic-vnfs/generic-vnf/myvnf/vf-modules/vf-module/myvf"; + uriQuery = engine.getQueryBuilder(gvnfVert).createQueryFromURI(new URI(vfUri)); + + vf.setValue("vf-module-id", "myvf"); + dbserLocal.serializeToDb(vf, vfVertex, uriQuery, "vf-module", vf.marshal(false)); + assertTrue("Vertex is creted", engine.tx().traversal().V() + .has("aai-node-type", "vf-module") + .has("vf-module-id", "myvf") + .hasNext()); + assertTrue("Vf module has edge to gvnf", engine.tx().traversal().V() + .has("aai-node-type", "vf-module") + .has("vf-module-id", "myvf") + .both() + .has("aai-node-type", "generic-vnf") + .has("vnf-id", "myvnf") + .hasNext()); + + + assertEquals(DeltaAction.CREATE, dbserLocal.getObjectDeltas().get(vfUri).getAction()); + assertEquals(4L, dbserLocal.getObjectDeltas().get(vfUri).getPropertyDeltas().values().stream().filter(d -> d.getAction().equals(DeltaAction.STATIC)).count()); + assertEquals(4L, dbserLocal.getObjectDeltas().get(vfUri).getPropertyDeltas().values().stream().filter(d -> d.getAction().equals(DeltaAction.CREATE)).count()); + dbserLocal.getObjectDeltas().values().forEach(od -> { + if (!od.getPropertyDeltas().containsKey(AAIProperties.AAI_UUID) ) { + fail(od.getUri() + " is missing " + AAIProperties.AAI_UUID); + } else if (od.getPropertyDeltas().get(AAIProperties.AAI_UUID) == null) { + fail(od.getUri() + " " + AAIProperties.AAI_UUID + " is null"); + } else if (od.getPropertyDeltas().get(AAIProperties.AAI_UUID).getValue() == null) { + fail(od.getUri() + " " + AAIProperties.AAI_UUID + " value is null"); + } + }); + } + + @Test + public void createTopWithChildThenDeleteTopTest() throws AAIException, UnsupportedEncodingException, URISyntaxException { + engine.startTransaction(); + + DBSerializer dbserLocal = new DBSerializer(version, engine, introspectorFactoryType, "AAI-TEST", AAIProperties.MINIMUM_DEPTH); + Introspector gvnf = loader.introspectorFromName("generic-vnf"); + Vertex gvnfVert = dbserLocal.createNewVertex(gvnf); + final String vnfUri = "/network/generic-vnfs/generic-vnf/myvnf"; + QueryParser uriQuery = + dbEngine.getQueryBuilder().createQueryFromURI(new URI(vnfUri)); + + gvnf.setValue("vnf-id", "myvnf"); + gvnf.setValue("vnf-type", "typo"); + + Introspector vf = loader.introspectorFromName("vf-module"); + vf.setValue("vf-module-id", "myvf"); + final String vfUri = "/network/generic-vnfs/generic-vnf/myvnf/vf-modules/vf-module/myvf"; + + Introspector vfs = loader.introspectorFromName("vf-modules"); + vfs.setValue("vf-module", Collections.singletonList(vf.getUnderlyingObject())); + gvnf.setValue("vf-modules", vfs.getUnderlyingObject()); + + dbserLocal.serializeToDb(gvnf, gvnfVert, uriQuery, "generic-vnf", gvnf.marshal(false)); + + Gson gson = new GsonBuilder().create(); + System.out.println(gson.toJsonTree(dbserLocal.getObjectDeltas().values())); + + assertTrue("Original created vertex exists", engine.tx().traversal().V() + .has("aai-node-type", "generic-vnf") + .has("vnf-id", "myvnf") + .has("vnf-type", "typo") + .hasNext()); + assertTrue("Vertex is creted", engine.tx().traversal().V() + .has("aai-node-type", "vf-module") + .has("vf-module-id", "myvf") + .hasNext()); + assertTrue("Vf module has edge to gvnf", engine.tx().traversal().V() + .has("aai-node-type", "vf-module") + .has("vf-module-id", "myvf") + .both() + .has("aai-node-type", "generic-vnf") + .has("vnf-id", "myvnf") + .hasNext()); + + assertEquals(DeltaAction.CREATE, dbserLocal.getObjectDeltas().get(vnfUri).getAction()); + assertEquals(4L, dbserLocal.getObjectDeltas().get(vnfUri).getPropertyDeltas().values().stream().filter(d -> d.getAction().equals(DeltaAction.STATIC)).count()); + assertEquals(5L, dbserLocal.getObjectDeltas().get(vnfUri).getPropertyDeltas().values().stream().filter(d -> d.getAction().equals(DeltaAction.CREATE)).count()); + assertEquals(DeltaAction.CREATE, dbserLocal.getObjectDeltas().get(vfUri).getAction()); + assertEquals(4L, dbserLocal.getObjectDeltas().get(vfUri).getPropertyDeltas().values().stream().filter(d -> d.getAction().equals(DeltaAction.STATIC)).count()); + assertEquals(4L, dbserLocal.getObjectDeltas().get(vfUri).getPropertyDeltas().values().stream().filter(d -> d.getAction().equals(DeltaAction.CREATE)).count()); + assertEquals(1L, dbserLocal.getObjectDeltas().get(vfUri).getRelationshipDeltas().stream().filter(d -> d.getAction().equals(DeltaAction.CREATE_REL)).count()); + dbserLocal.getObjectDeltas().values().forEach(od -> { + if (!od.getPropertyDeltas().containsKey(AAIProperties.AAI_UUID) ) { + fail(od.getUri() + " is missing " + AAIProperties.AAI_UUID); + } else if (od.getPropertyDeltas().get(AAIProperties.AAI_UUID) == null) { + fail(od.getUri() + " " + AAIProperties.AAI_UUID + " is null"); + } else if (od.getPropertyDeltas().get(AAIProperties.AAI_UUID).getValue() == null) { + fail(od.getUri() + " " + AAIProperties.AAI_UUID + " value is null"); + } + }); + + dbserLocal = new DBSerializer(version, engine, introspectorFactoryType, "AAI-TEST", AAIProperties.MINIMUM_DEPTH); + gvnf = dbserLocal.getLatestVersionView(gvnfVert); + String rv = gvnf.getValue(AAIProperties.RESOURCE_VERSION); + dbserLocal.delete(engine.tx().traversal().V(gvnfVert).next(), rv, true); + System.out.println(gson.toJsonTree(dbserLocal.getObjectDeltas().values())); + + assertFalse("generic-vnf no longer exists", engine.tx().traversal().V() + .has("aai-node-type", "generic-vnf") + .hasNext()); + assertFalse("vf-module no longer exists", engine.tx().traversal().V() + .has("aai-node-type", "vf-module") + .hasNext()); + + assertEquals(DeltaAction.DELETE, dbserLocal.getObjectDeltas().get(vnfUri).getAction()); + assertEquals(12L, dbserLocal.getObjectDeltas().get(vnfUri).getPropertyDeltas().values().stream().filter(d -> d.getAction().equals(DeltaAction.DELETE)).count());assertEquals(DeltaAction.DELETE, dbserLocal.getObjectDeltas().get(vfUri).getAction()); + assertEquals(11L, dbserLocal.getObjectDeltas().get(vfUri).getPropertyDeltas().values().stream().filter(d -> d.getAction().equals(DeltaAction.DELETE)).count()); + } + + + + @Test + public void createComplexPserverWithRelDeleteRel() throws AAIException, UnsupportedEncodingException, URISyntaxException { + engine.startTransaction(); + + DBSerializer dbserLocal = new DBSerializer(version, engine, introspectorFactoryType, "AAI-TEST", AAIProperties.MINIMUM_DEPTH); + Introspector complex = loader.introspectorFromName("complex"); + Vertex complexV = dbserLocal.createNewVertex(complex); + final String complexUri = "/cloud-infrastructure/complexes/complex/c-id"; + QueryParser uriQuery = + dbEngine.getQueryBuilder().createQueryFromURI(new URI(complexUri)); + + complex.setValue("physical-location-id", "c-id"); + complex.setValue("physical-location-type", "type"); + complex.setValue("street1", "streetA"); + complex.setValue("city", "cityA"); + complex.setValue("postal-code", "11111"); + complex.setValue("country", "abc"); + complex.setValue("region", "ef"); + dbserLocal.serializeToDb(complex, complexV, uriQuery, "complex", complex.marshal(false)); + assertTrue("Complex created", engine.tx().traversal().V() + .has("aai-node-type", "complex") + .has("physical-location-id", "c-id") + .hasNext()); + + + assertEquals(DeltaAction.CREATE, dbserLocal.getObjectDeltas().get(complexUri).getAction()); + assertEquals(4L, dbserLocal.getObjectDeltas().get(complexUri).getPropertyDeltas().values().stream().filter(d -> d.getAction().equals(DeltaAction.STATIC)).count()); + assertEquals(10L, dbserLocal.getObjectDeltas().get(complexUri).getPropertyDeltas().values().stream().filter(d -> d.getAction().equals(DeltaAction.CREATE)).count()); + dbserLocal.getObjectDeltas().values().forEach(od -> { + if (!od.getPropertyDeltas().containsKey(AAIProperties.AAI_UUID) ) { + fail(od.getUri() + " is missing " + AAIProperties.AAI_UUID); + } else if (od.getPropertyDeltas().get(AAIProperties.AAI_UUID) == null) { + fail(od.getUri() + " " + AAIProperties.AAI_UUID + " is null"); + } else if (od.getPropertyDeltas().get(AAIProperties.AAI_UUID).getValue() == null) { + fail(od.getUri() + " " + AAIProperties.AAI_UUID + " value is null"); + } + }); + + + dbserLocal = new DBSerializer(version, engine, introspectorFactoryType, "AAI-TEST", AAIProperties.MINIMUM_DEPTH); + Introspector pserver = loader.introspectorFromName("pserver"); + Vertex pserverV = dbserLocal.createNewVertex(pserver); + final String pserverUri = "/cloud-infrastructure/pservers/pserver/ps"; + uriQuery = + dbEngine.getQueryBuilder().createQueryFromURI(new URI(pserverUri)); + + Introspector relationship = loader.introspectorFromName("relationship"); + relationship.setValue("related-to", "complex"); + relationship.setValue("related-link", complexUri); + Introspector relationshipList = loader.introspectorFromName("relationship-list"); + relationshipList.setValue("relationship", Collections.singletonList(relationship.getUnderlyingObject())); + + pserver.setValue("relationship-list", relationshipList.getUnderlyingObject()); + pserver.setValue("hostname", "ps"); + + System.out.println(pserver.marshal(true)); + + dbserLocal.serializeToDb(pserver, pserverV, uriQuery, "pserver", pserver.marshal(false)); + assertTrue("Pserver created", engine.tx().traversal().V() + .has("aai-node-type", "pserver") + .has("hostname", "ps") + .hasNext()); + assertTrue("Pserver has edge to complex", engine.tx().traversal().V() + .has("aai-node-type", "pserver") + .has("hostname", "ps") + .bothE() + .otherV() + .has("aai-node-type", "complex") + .hasNext()); + + + assertEquals(DeltaAction.CREATE, dbserLocal.getObjectDeltas().get(pserverUri).getAction()); + assertEquals(4L, dbserLocal.getObjectDeltas().get(pserverUri).getPropertyDeltas().values().stream().filter(d -> d.getAction().equals(DeltaAction.STATIC)).count()); + assertEquals(4L, dbserLocal.getObjectDeltas().get(pserverUri).getPropertyDeltas().values().stream().filter(d -> d.getAction().equals(DeltaAction.CREATE)).count()); + assertEquals(1L, dbserLocal.getObjectDeltas().get(pserverUri).getRelationshipDeltas().stream().filter(d -> d.getAction().equals(DeltaAction.CREATE_REL)).count()); + dbserLocal.getObjectDeltas().values().forEach(od -> { + if (!od.getPropertyDeltas().containsKey(AAIProperties.AAI_UUID) ) { + fail(od.getUri() + " is missing " + AAIProperties.AAI_UUID); + } else if (od.getPropertyDeltas().get(AAIProperties.AAI_UUID) == null) { + fail(od.getUri() + " " + AAIProperties.AAI_UUID + " is null"); + } else if (od.getPropertyDeltas().get(AAIProperties.AAI_UUID).getValue() == null) { + fail(od.getUri() + " " + AAIProperties.AAI_UUID + " value is null"); + } + }); + + + dbserLocal = new DBSerializer(version, engine, introspectorFactoryType, "AAI-TEST", AAIProperties.MINIMUM_DEPTH); + dbserLocal.touchStandardVertexProperties(pserverV, false); + dbserLocal.deleteEdge(relationship, pserverV); + assertFalse("Pserver no longer has edge to complex", engine.tx().traversal().V() + .has("aai-node-type", "pserver") + .has("hostname", "ps") + .bothE() + .otherV() + .has("aai-node-type", "complex") + .hasNext()); + + + assertEquals(DeltaAction.UPDATE, dbserLocal.getObjectDeltas().get(pserverUri).getAction()); + assertEquals(4L, dbserLocal.getObjectDeltas().get(pserverUri).getPropertyDeltas().values().stream().filter(d -> d.getAction().equals(DeltaAction.STATIC)).count()); + assertEquals(3L, dbserLocal.getObjectDeltas().get(pserverUri).getPropertyDeltas().values().stream().filter(d -> d.getAction().equals(DeltaAction.UPDATE)).count()); + assertEquals(1L, dbserLocal.getObjectDeltas().get(pserverUri).getRelationshipDeltas().stream().filter(d -> d.getAction().equals(DeltaAction.DELETE_REL)).count()); + dbserLocal.getObjectDeltas().values().forEach(od -> { + if (!od.getPropertyDeltas().containsKey(AAIProperties.AAI_UUID) ) { + fail(od.getUri() + " is missing " + AAIProperties.AAI_UUID); + } else if (od.getPropertyDeltas().get(AAIProperties.AAI_UUID) == null) { + fail(od.getUri() + " " + AAIProperties.AAI_UUID + " is null"); + } else if (od.getPropertyDeltas().get(AAIProperties.AAI_UUID).getValue() == null) { + fail(od.getUri() + " " + AAIProperties.AAI_UUID + " value is null"); + } + }); + } + + @Test + public void createComplexPserverWithRelUpdatePserverToDeleteRelAddPinterfaceThenDeleteComplex() throws AAIException, UnsupportedEncodingException, URISyntaxException { + engine.startTransaction(); + + Gson gson = new GsonBuilder() + .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_DASHES) + .create(); + + DBSerializer dbserLocal = new DBSerializer(version, engine, introspectorFactoryType, "create-complex", AAIProperties.MINIMUM_DEPTH); + Introspector complex = loader.introspectorFromName("complex"); + Vertex complexV = dbserLocal.createNewVertex(complex); + final String complexUri = "/cloud-infrastructure/complexes/complex/c-id-b"; + QueryParser uriQuery = + dbEngine.getQueryBuilder().createQueryFromURI(new URI(complexUri)); + + complex.setValue("physical-location-id", "c-id-b"); + complex.setValue("physical-location-type", "type"); + complex.setValue("street1", "streetA"); + complex.setValue("city", "cityA"); + complex.setValue("postal-code", "11111"); + complex.setValue("country", "abc"); + complex.setValue("region", "ef"); + dbserLocal.serializeToDb(complex, complexV, uriQuery, "complex", complex.marshal(false)); + + System.out.println("Create Complex"); + System.out.println(gson.toJsonTree(dbserLocal.getObjectDeltas().values())); + + assertTrue("Complex created", engine.tx().traversal().V() + .has("aai-node-type", "complex") + .has("physical-location-id", "c-id-b") + .hasNext()); + assertEquals(DeltaAction.CREATE, dbserLocal.getObjectDeltas().get(complexUri).getAction()); + assertEquals(4L, dbserLocal.getObjectDeltas().get(complexUri).getPropertyDeltas().values().stream().filter(d -> d.getAction().equals(DeltaAction.STATIC)).count()); + assertEquals(10L, dbserLocal.getObjectDeltas().get(complexUri).getPropertyDeltas().values().stream().filter(d -> d.getAction().equals(DeltaAction.CREATE)).count()); + dbserLocal.getObjectDeltas().values().forEach(od -> { + if (!od.getPropertyDeltas().containsKey(AAIProperties.AAI_UUID) ) { + fail(od.getUri() + " is missing " + AAIProperties.AAI_UUID); + } else if (od.getPropertyDeltas().get(AAIProperties.AAI_UUID) == null) { + fail(od.getUri() + " " + AAIProperties.AAI_UUID + " is null"); + } else if (od.getPropertyDeltas().get(AAIProperties.AAI_UUID).getValue() == null) { + fail(od.getUri() + " " + AAIProperties.AAI_UUID + " value is null"); + } + }); + + + dbserLocal = new DBSerializer(version, engine, introspectorFactoryType, "create-pserver", AAIProperties.MINIMUM_DEPTH); + Introspector pserver = loader.introspectorFromName("pserver"); + Vertex pserverV = dbserLocal.createNewVertex(pserver); + final String pserverUri = "/cloud-infrastructure/pservers/pserver/ps-b"; + uriQuery = + dbEngine.getQueryBuilder().createQueryFromURI(new URI(pserverUri)); + + Introspector relationship = loader.introspectorFromName("relationship"); + relationship.setValue("related-to", "complex"); + relationship.setValue("related-link", complexUri); + Introspector relationshipList = loader.introspectorFromName("relationship-list"); + relationshipList.setValue("relationship", Collections.singletonList(relationship.getUnderlyingObject())); + + pserver.setValue("relationship-list", relationshipList.getUnderlyingObject()); + pserver.setValue("hostname", "ps-b"); + pserver.setValue("number-of-cpus", 20); + + Introspector pint = loader.introspectorFromName("p-interface"); + pint.setValue("interface-name", "pint-1"); + final String pintUri = pserverUri + "/p-interfaces/p-interface/pint-1"; + + Introspector pints = loader.introspectorFromName("p-interfaces"); + pints.setValue("p-interface", Collections.singletonList(pint.getUnderlyingObject())); + pserver.setValue("p-interfaces", pints.getUnderlyingObject()); + + dbserLocal.serializeToDb(pserver, pserverV, uriQuery, "pserver", pserver.marshal(false)); + + System.out.println("Create Pserver with pinterface and relationship to complex "); + System.out.println(gson.toJsonTree(dbserLocal.getObjectDeltas().values())); + + assertTrue("Pserver created", engine.tx().traversal().V() + .has("aai-node-type", "pserver") + .has("hostname", "ps-b") + .hasNext()); + assertTrue("Pserver has edge to complex", engine.tx().traversal().V() + .has("aai-node-type", "pserver") + .has("hostname", "ps-b") + .bothE() + .otherV() + .has("aai-node-type", "complex") + .hasNext()); + assertTrue("Pserver has edge to pinterface", engine.tx().traversal().V() + .has("aai-node-type", "pserver") + .has("hostname", "ps-b") + .bothE() + .otherV() + .has("aai-node-type", "p-interface") + .hasNext()); + + assertEquals(DeltaAction.CREATE, dbserLocal.getObjectDeltas().get(pserverUri).getAction()); + assertEquals(4L, dbserLocal.getObjectDeltas().get(pserverUri).getPropertyDeltas().values().stream().filter(d -> d.getAction().equals(DeltaAction.STATIC)).count()); + assertEquals(5L, dbserLocal.getObjectDeltas().get(pserverUri).getPropertyDeltas().values().stream().filter(d -> d.getAction().equals(DeltaAction.CREATE)).count()); + assertEquals(1L, dbserLocal.getObjectDeltas().get(pserverUri).getRelationshipDeltas().stream().filter(d -> d.getAction().equals(DeltaAction.CREATE_REL)).count()); + assertEquals(DeltaAction.CREATE, dbserLocal.getObjectDeltas().get(pintUri).getAction()); + assertEquals(4L, dbserLocal.getObjectDeltas().get(pintUri).getPropertyDeltas().values().stream().filter(d -> d.getAction().equals(DeltaAction.STATIC)).count()); + assertEquals(4L, dbserLocal.getObjectDeltas().get(pintUri).getPropertyDeltas().values().stream().filter(d -> d.getAction().equals(DeltaAction.CREATE)).count()); + assertEquals(1L, dbserLocal.getObjectDeltas().get(pintUri).getRelationshipDeltas().stream().filter(d -> d.getAction().equals(DeltaAction.CREATE_REL)).count()); + dbserLocal.getObjectDeltas().values().forEach(od -> { + if (!od.getPropertyDeltas().containsKey(AAIProperties.AAI_UUID) ) { + fail(od.getUri() + " is missing " + AAIProperties.AAI_UUID); + } else if (od.getPropertyDeltas().get(AAIProperties.AAI_UUID) == null) { + fail(od.getUri() + " " + AAIProperties.AAI_UUID + " is null"); + } else if (od.getPropertyDeltas().get(AAIProperties.AAI_UUID).getValue() == null) { + fail(od.getUri() + " " + AAIProperties.AAI_UUID + " value is null"); + } + }); + + dbserLocal = new DBSerializer(version, engine, introspectorFactoryType, "update-pserver", AAIProperties.MINIMUM_DEPTH); + pserver = dbserLocal.getLatestVersionView(pserverV); + relationshipList = loader.introspectorFromName("relationship-list"); + relationshipList.setValue("relationship", Collections.emptyList()); + pserver.setValue("relationship-list", relationshipList.getUnderlyingObject()); + pserver.setValue("equip-type", "server-a"); + pserver.setValue("number-of-cpus", 99); + + dbserLocal.serializeToDb(pserver, pserverV, uriQuery, "pserver", pserver.marshal(false)); + + System.out.println("Update pserver removing relationship to complex"); + System.out.println(gson.toJsonTree(dbserLocal.getObjectDeltas().values())); + + assertFalse("Pserver no longer has edge to complex", engine.tx().traversal().V() + .has("aai-node-type", "pserver") + .has("hostname", "ps-b") + .bothE() + .otherV() + .has("aai-node-type", "complex") + .hasNext()); + + assertEquals(DeltaAction.UPDATE, dbserLocal.getObjectDeltas().get(pserverUri).getAction()); + assertEquals(4L, dbserLocal.getObjectDeltas().get(pserverUri).getPropertyDeltas().values().stream().filter(d -> d.getAction().equals(DeltaAction.STATIC)).count()); + assertEquals(4L, dbserLocal.getObjectDeltas().get(pserverUri).getPropertyDeltas().values().stream().filter(d -> d.getAction().equals(DeltaAction.UPDATE)).count()); + assertEquals(1L, dbserLocal.getObjectDeltas().get(pserverUri).getRelationshipDeltas().stream().filter(d -> d.getAction().equals(DeltaAction.DELETE_REL)).count()); + assertFalse(dbserLocal.getObjectDeltas().containsKey(pintUri)); + dbserLocal.getObjectDeltas().values().forEach(od -> { + if (!od.getPropertyDeltas().containsKey(AAIProperties.AAI_UUID) ) { + fail(od.getUri() + " is missing " + AAIProperties.AAI_UUID); + } else if (od.getPropertyDeltas().get(AAIProperties.AAI_UUID) == null) { + fail(od.getUri() + " " + AAIProperties.AAI_UUID + " is null"); + } else if (od.getPropertyDeltas().get(AAIProperties.AAI_UUID).getValue() == null) { + fail(od.getUri() + " " + AAIProperties.AAI_UUID + " value is null"); + } + }); + + dbserLocal = new DBSerializer(version, engine, introspectorFactoryType, "delete-pserver", AAIProperties.MINIMUM_DEPTH); + pserver = dbserLocal.getLatestVersionView(pserverV); + String rv = pserver.getValue(AAIProperties.RESOURCE_VERSION); + dbserLocal.delete(engine.tx().traversal().V(pserverV).next(), rv, true); + + System.out.println("Delete pserver"); + System.out.println(gson.toJsonTree(dbserLocal.getObjectDeltas().values())); + + assertFalse("pserver no longer exists", engine.tx().traversal().V() + .has("aai-node-type", "pserver") + .hasNext()); + + assertEquals(DeltaAction.DELETE, dbserLocal.getObjectDeltas().get(pserverUri).getAction()); + assertEquals(12L, dbserLocal.getObjectDeltas().get(pserverUri).getPropertyDeltas().values().stream().filter(d -> d.getAction().equals(DeltaAction.DELETE)).count()); + assertEquals(DeltaAction.DELETE, dbserLocal.getObjectDeltas().get(pintUri).getAction()); + assertEquals(10L, dbserLocal.getObjectDeltas().get(pintUri).getPropertyDeltas().values().stream().filter(d -> d.getAction().equals(DeltaAction.DELETE)).count()); + dbserLocal.getObjectDeltas().values().forEach(od -> { + if (!od.getPropertyDeltas().containsKey(AAIProperties.AAI_UUID) ) { + fail(od.getUri() + " is missing " + AAIProperties.AAI_UUID); + } else if (od.getPropertyDeltas().get(AAIProperties.AAI_UUID) == null) { + fail(od.getUri() + " " + AAIProperties.AAI_UUID + " is null"); + } else if (od.getPropertyDeltas().get(AAIProperties.AAI_UUID).getValue() == null) { + fail(od.getUri() + " " + AAIProperties.AAI_UUID + " value is null"); + } + }); + } + + + // /network/ipsec-configurations/ipsec-configuration/{ipsec-configuration-id}/vig-servers/vig-server/{vig-address-type} + // ipaddress-v4-vig + @Test + public void createNodeWithListTest() throws AAIException, UnsupportedEncodingException, URISyntaxException { + Gson gson = new GsonBuilder() + .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_DASHES) + .create(); + + engine.startTransaction(); + + /* + * Create the parent ipsec-configuration + */ + DBSerializer dbserLocal = new DBSerializer(version, engine, introspectorFactoryType, "create-ipsec", AAIProperties.MINIMUM_DEPTH); + Introspector ipsec = loader.introspectorFromName("ipsec-configuration"); + Vertex ipsecVert = dbserLocal.createNewVertex(ipsec); + final String ipsecUri = "/network/ipsec-configurations/ipsec-configuration/ipsec"; + QueryParser uriQuery = + dbEngine.getQueryBuilder().createQueryFromURI(new URI(ipsecUri)); + + ipsec.setValue("ipsec-configuration-id", "ipsec"); + dbserLocal.serializeToDb(ipsec, ipsecVert, uriQuery, "generic-vnf", ipsec.marshal(false)); + assertTrue("Original created vertex exists", engine.tx().traversal().V() + .has("aai-node-type", "ipsec-configuration") + .has("ipsec-configuration-id", "ipsec") + .hasNext()); + + System.out.println(gson.toJsonTree(dbserLocal.getObjectDeltas().values())); + assertEquals(DeltaAction.CREATE, dbserLocal.getObjectDeltas().get(ipsecUri).getAction()); + assertEquals(4L, + dbserLocal.getObjectDeltas().get(ipsecUri).getPropertyDeltas().values().stream().filter(d -> d.getAction().equals(DeltaAction.STATIC)).count()); + assertEquals(4L, + dbserLocal.getObjectDeltas().get(ipsecUri).getPropertyDeltas().values().stream().filter(d -> d.getAction().equals(DeltaAction.CREATE)).count()); + dbserLocal.getObjectDeltas().values().forEach(od -> { + if (!od.getPropertyDeltas().containsKey(AAIProperties.AAI_UUID) ) { + fail(od.getUri() + " is missing " + AAIProperties.AAI_UUID); + } else if (od.getPropertyDeltas().get(AAIProperties.AAI_UUID) == null) { + fail(od.getUri() + " " + AAIProperties.AAI_UUID + " is null"); + } else if (od.getPropertyDeltas().get(AAIProperties.AAI_UUID).getValue() == null) { + fail(od.getUri() + " " + AAIProperties.AAI_UUID + " value is null"); + } + }); + + /* + * Create child vig-server with list property vig-address-type + */ + dbserLocal = new DBSerializer(version, engine, introspectorFactoryType, "create-child-vig-server", AAIProperties.MINIMUM_DEPTH); + Introspector vig = loader.introspectorFromName("vig-server"); + Vertex vigVertex = dbserLocal.createNewVertex(vig); + final String vigUri = "/network/ipsec-configurations/ipsec-configuration/ipsec/vig-servers/vig-server/vig"; + uriQuery = engine.getQueryBuilder(ipsecVert).createQueryFromURI(new URI(vigUri)); + + vig.setValue("vig-address-type", "vig"); + List<String> list = new ArrayList<>(); + list.add("address-1"); + list.add("address-2"); + vig.setValue("ipaddress-v4-vig", list); + dbserLocal.serializeToDb(vig, vigVertex, uriQuery, "vf-module", vig.marshal(false)); + assertTrue("Vertex is creted", engine.tx().traversal().V() + .has("aai-node-type", "vig-server") + .has("vig-address-type", "vig") + .hasNext()); + assertTrue("Vf module has edge to gvnf", engine.tx().traversal().V() + .has("aai-node-type", "vig-server") + .has("vig-address-type", "vig") + .both() + .has("aai-node-type", "ipsec-configuration") + .has("ipsec-configuration-id", "ipsec") + .hasNext()); + + System.out.println(gson.toJsonTree(dbserLocal.getObjectDeltas().values())); + assertEquals(DeltaAction.CREATE, dbserLocal.getObjectDeltas().get(vigUri).getAction()); + assertEquals(4L, + dbserLocal.getObjectDeltas().get(vigUri).getPropertyDeltas().values().stream().filter(d -> d.getAction().equals(DeltaAction.STATIC)).count()); + assertEquals(5L, + dbserLocal.getObjectDeltas().get(vigUri).getPropertyDeltas().values().stream().filter(d -> d.getAction().equals(DeltaAction.CREATE)).count()); + assertThat(dbserLocal.getObjectDeltas().get(vigUri).getPropertyDeltas().get("ipaddress-v4-vig").getValue(), instanceOf(List.class)); + dbserLocal.getObjectDeltas().values().forEach(od -> { + if (!od.getPropertyDeltas().containsKey(AAIProperties.AAI_UUID) ) { + fail(od.getUri() + " is missing " + AAIProperties.AAI_UUID); + } else if (od.getPropertyDeltas().get(AAIProperties.AAI_UUID) == null) { + fail(od.getUri() + " " + AAIProperties.AAI_UUID + " is null"); + } else if (od.getPropertyDeltas().get(AAIProperties.AAI_UUID).getValue() == null) { + fail(od.getUri() + " " + AAIProperties.AAI_UUID + " value is null"); + } + }); + + /* + * Update child vig-server with new list for vig-address-type + */ + dbserLocal = new DBSerializer(version, engine, introspectorFactoryType, "update-child-vig-server", AAIProperties.MINIMUM_DEPTH); + vig = dbserLocal.getLatestVersionView(vigVertex); + uriQuery = engine.getQueryBuilder(ipsecVert).createQueryFromURI(new URI(vigUri)); + + new ArrayList<>(); + list.add("address-3"); + list.add("address-4"); + vig.setValue("ipaddress-v4-vig", list); + dbserLocal.serializeToDb(vig, vigVertex, uriQuery, "vf-module", vig.marshal(false)); + assertTrue("Vertex is still there", engine.tx().traversal().V() + .has("aai-node-type", "vig-server") + .has("vig-address-type", "vig") + .hasNext()); + assertTrue("Vf module has edge to gvnf", engine.tx().traversal().V() + .has("aai-node-type", "vig-server") + .has("vig-address-type", "vig") + .both() + .has("aai-node-type", "ipsec-configuration") + .has("ipsec-configuration-id", "ipsec") + .hasNext()); + + System.out.println(gson.toJsonTree(dbserLocal.getObjectDeltas().values())); + assertEquals(DeltaAction.UPDATE, dbserLocal.getObjectDeltas().get(vigUri).getAction()); + assertEquals(4L, + dbserLocal.getObjectDeltas().get(vigUri).getPropertyDeltas().values().stream().filter(d -> d.getAction().equals(DeltaAction.STATIC)).count()); + assertEquals(4L, + dbserLocal.getObjectDeltas().get(vigUri).getPropertyDeltas().values().stream().filter(d -> d.getAction().equals(DeltaAction.UPDATE)).count()); + assertThat(dbserLocal.getObjectDeltas().get(vigUri).getPropertyDeltas().get("ipaddress-v4-vig").getValue(), instanceOf(List.class)); + assertThat(dbserLocal.getObjectDeltas().get(vigUri).getPropertyDeltas().get("ipaddress-v4-vig").getOldValue(), instanceOf(List.class)); + dbserLocal.getObjectDeltas().values().forEach(od -> { + if (!od.getPropertyDeltas().containsKey(AAIProperties.AAI_UUID) ) { + fail(od.getUri() + " is missing " + AAIProperties.AAI_UUID); + } else if (od.getPropertyDeltas().get(AAIProperties.AAI_UUID) == null) { + fail(od.getUri() + " " + AAIProperties.AAI_UUID + " is null"); + } else if (od.getPropertyDeltas().get(AAIProperties.AAI_UUID).getValue() == null) { + fail(od.getUri() + " " + AAIProperties.AAI_UUID + " value is null"); + } + }); + /* + * Delete top level + */ + dbserLocal = new DBSerializer(version, engine, introspectorFactoryType, "delete-ipsec", AAIProperties.MINIMUM_DEPTH); + ipsec = dbserLocal.getLatestVersionView(ipsecVert); + String rv = ipsec.getValue(AAIProperties.RESOURCE_VERSION); + dbserLocal.delete(engine.tx().traversal().V(ipsecVert).next(), rv, true); + System.out.println(gson.toJsonTree(dbserLocal.getObjectDeltas().values())); + + assertFalse("ipsec-configuration no longer exists", engine.tx().traversal().V() + .has("aai-node-type", "ipsec-configuration") + .hasNext()); + assertFalse("vig-server no longer exists", engine.tx().traversal().V() + .has("aai-node-type", "vig-server") + .hasNext()); + + assertEquals(DeltaAction.DELETE, dbserLocal.getObjectDeltas().get(ipsecUri).getAction()); + assertEquals(9L, dbserLocal.getObjectDeltas().get(ipsecUri).getPropertyDeltas().values().stream().filter(d -> d.getAction().equals(DeltaAction.DELETE)).count());assertEquals(DeltaAction.DELETE, dbserLocal.getObjectDeltas().get(vigUri).getAction()); + assertEquals(10L, dbserLocal.getObjectDeltas().get(vigUri).getPropertyDeltas().values().stream().filter(d -> d.getAction().equals(DeltaAction.DELETE)).count()); + dbserLocal.getObjectDeltas().values().forEach(od -> { + if (!od.getPropertyDeltas().containsKey(AAIProperties.AAI_UUID) ) { + fail(od.getUri() + " is missing " + AAIProperties.AAI_UUID); + } else if (od.getPropertyDeltas().get(AAIProperties.AAI_UUID) == null) { + fail(od.getUri() + " " + AAIProperties.AAI_UUID + " is null"); + } else if (od.getPropertyDeltas().get(AAIProperties.AAI_UUID).getValue() == null) { + fail(od.getUri() + " " + AAIProperties.AAI_UUID + " value is null"); + } + }); + } + +} diff --git a/aai-core/src/test/java/org/onap/aai/serialization/db/DbSerializerNotificationEventsTest.java b/aai-core/src/test/java/org/onap/aai/serialization/db/DbSerializerNotificationEventsTest.java new file mode 100644 index 00000000..cc1fc03d --- /dev/null +++ b/aai-core/src/test/java/org/onap/aai/serialization/db/DbSerializerNotificationEventsTest.java @@ -0,0 +1,330 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 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========================================================= + */ + +package org.onap.aai.serialization.db; + +import org.apache.tinkerpop.gremlin.structure.Graph; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.janusgraph.core.JanusGraphFactory; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.onap.aai.AAISetup; +import org.onap.aai.db.props.AAIProperties; +import org.onap.aai.edges.EdgeIngestor; +import org.onap.aai.exceptions.AAIException; +import org.onap.aai.introspection.Introspector; +import org.onap.aai.introspection.Loader; +import org.onap.aai.introspection.ModelType; +import org.onap.aai.parsers.query.QueryParser; +import org.onap.aai.serialization.engines.JanusGraphDBEngine; +import org.onap.aai.serialization.engines.QueryStyle; +import org.onap.aai.serialization.engines.TransactionalGraphEngine; +import org.onap.aai.setup.SchemaVersion; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.annotation.DirtiesContext; + +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.*; +import java.util.stream.Collectors; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.*; + +@RunWith(value = Parameterized.class) +@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS) +public class DbSerializerNotificationEventsTest extends AAISetup { + + // to use, set thrown.expect to whatever your test needs + // this line establishes default of expecting no exception to be thrown + @Rule + public ExpectedException thrown = ExpectedException.none(); + + protected static Graph graph; + + @Autowired + protected EdgeSerializer edgeSer; + @Autowired + protected EdgeIngestor ei; + + private SchemaVersion version; + private final ModelType introspectorFactoryType = ModelType.MOXY; + private Loader loader; + private TransactionalGraphEngine engine; // for tests that aren't mocking the engine + + @Parameterized.Parameter(value = 0) + public QueryStyle queryStyle; + + @Parameterized.Parameters(name = "QueryStyle.{0}") + public static Collection<Object[]> data() { + return Arrays.asList(new Object[][] {{QueryStyle.TRAVERSAL}, {QueryStyle.TRAVERSAL_URI}}); + } + + @BeforeClass + public static void init() throws Exception { + graph = JanusGraphFactory.build().set("storage.backend", "inmemory").open(); + + } + + @Before + public void setup() throws Exception { + // createGraph(); + version = schemaVersions.getDefaultVersion(); + loader = loaderFactory.createLoaderForVersion(introspectorFactoryType, version); + engine = new JanusGraphDBEngine(queryStyle, loader); + } + + /* + Create Complex + Create Pserver with pinterface and relationship to complex + Update pserver removing relationship to complex + Update pserver adding a second p-interface + Add l-interface directly to the 2nd p-interface + Delete pserver + */ + @Test + public void createComplexPserverWithRelUpdatePserverToDeleteRelAddPinterfaceThenDeleteComplexCheckingUpdatedListTest() throws AAIException, UnsupportedEncodingException, URISyntaxException { + engine.startTransaction(); + + System.out.println("Create Complex"); + DBSerializer dbserLocal = new DBSerializer(version, engine, introspectorFactoryType, "create-complex", AAIProperties.MINIMUM_DEPTH); + Introspector complex = loader.introspectorFromName("complex"); + Vertex complexV = dbserLocal.createNewVertex(complex); + final String complexUri = "/cloud-infrastructure/complexes/complex/c-id-b"; + QueryParser uriQuery = + engine.getQueryBuilder().createQueryFromURI(new URI(complexUri)); + + complex.setValue("physical-location-id", "c-id-b"); + complex.setValue("physical-location-type", "type"); + complex.setValue("street1", "streetA"); + complex.setValue("city", "cityA"); + complex.setValue("postal-code", "11111"); + complex.setValue("country", "abc"); + complex.setValue("region", "ef"); + dbserLocal.serializeToDb(complex, complexV, uriQuery, "complex", complex.marshal(false)); + + assertTrue("Complex created", engine.tx().traversal().V() + .has("aai-node-type", "complex") + .has("physical-location-id", "c-id-b") + .hasNext()); + Map<Vertex, Boolean> updated = getUpdatedVertexes(dbserLocal); + assertEquals("Number of updated vertexes", 1, updated.size()); + assertThat("Only modified vertexes are in the updated set", + updated.keySet().stream().map(v -> v.<String>value(AAIProperties.AAI_URI)).collect(Collectors.toSet()), + is(Collections.singleton(complexUri))); + List<String> didNotUpdateStandardVertexProps = updated.entrySet().stream() + .filter(e -> !e.getValue()) + .map(e -> e.getKey().<String>value(AAIProperties.AAI_URI)).collect(Collectors.toList()); + assertThat("Vertexes should all have their standard props updated", didNotUpdateStandardVertexProps, is(Collections.emptyList())); + + + + + System.out.println("Create Pserver with pinterface and relationship to complex "); + dbserLocal = new DBSerializer(version, engine, introspectorFactoryType, "create-pserver", AAIProperties.MINIMUM_DEPTH); + Introspector pserver = loader.introspectorFromName("pserver"); + Vertex pserverV = dbserLocal.createNewVertex(pserver); + final String pserverUri = "/cloud-infrastructure/pservers/pserver/ps-b"; + uriQuery = + engine.getQueryBuilder().createQueryFromURI(new URI(pserverUri)); + + Introspector relationship = loader.introspectorFromName("relationship"); + relationship.setValue("related-to", "complex"); + relationship.setValue("related-link", complexUri); + Introspector relationshipList = loader.introspectorFromName("relationship-list"); + relationshipList.setValue("relationship", Collections.singletonList(relationship.getUnderlyingObject())); + + pserver.setValue("relationship-list", relationshipList.getUnderlyingObject()); + pserver.setValue("hostname", "ps-b"); + pserver.setValue("number-of-cpus", 20); + + Introspector pint = loader.introspectorFromName("p-interface"); + pint.setValue("interface-name", "pint-1"); + final String pintUri = pserverUri + "/p-interfaces/p-interface/pint-1"; + + Introspector pints = loader.introspectorFromName("p-interfaces"); + pints.setValue("p-interface", Collections.singletonList(pint.getUnderlyingObject())); + pserver.setValue("p-interfaces", pints.getUnderlyingObject()); + dbserLocal.serializeToDb(pserver, pserverV, uriQuery, "pserver", pserver.marshal(false)); + + assertTrue("Pserver created", engine.tx().traversal().V() + .has("aai-node-type", "pserver") + .has("hostname", "ps-b") + .hasNext()); + assertTrue("Pserver has edge to complex", engine.tx().traversal().V() + .has("aai-node-type", "pserver") + .has("hostname", "ps-b") + .bothE() + .otherV() + .has("aai-node-type", "complex") + .hasNext()); + assertTrue("Pserver has edge to pinterface", engine.tx().traversal().V() + .has("aai-node-type", "pserver") + .has("hostname", "ps-b") + .bothE() + .otherV() + .has("aai-node-type", "p-interface") + .hasNext()); + updated = getUpdatedVertexes(dbserLocal); + assertEquals("Number of updated vertexes", 3, updated.size()); + assertThat("Only modified vertexes are in the updated set", + updated.keySet().stream().map(v -> v.<String>value(AAIProperties.AAI_URI)).collect(Collectors.toSet()), + is(new HashSet<>(Arrays.asList(pserverUri, pintUri, complexUri)))); + didNotUpdateStandardVertexProps = updated.entrySet().stream() + .filter(e -> !e.getValue()) + .map(e -> e.getKey().<String>value(AAIProperties.AAI_URI)).collect(Collectors.toList()); + assertThat("Vertexes should all have their standard props updated", didNotUpdateStandardVertexProps, is(Collections.emptyList())); + + + System.out.println("Update pserver removing relationship to complex"); + dbserLocal = new DBSerializer(version, engine, introspectorFactoryType, "update-pserver", AAIProperties.MINIMUM_DEPTH); + pserver = dbserLocal.getLatestVersionView(pserverV); + relationshipList = loader.introspectorFromName("relationship-list"); + relationshipList.setValue("relationship", Collections.emptyList()); + pserver.setValue("relationship-list", relationshipList.getUnderlyingObject()); + pserver.setValue("equip-type", "server-a"); + pserver.setValue("number-of-cpus", 99); + dbserLocal.serializeToDb(pserver, pserverV, uriQuery, "pserver", pserver.marshal(false)); + + assertFalse("Pserver no longer has edge to complex", engine.tx().traversal().V() + .has("aai-node-type", "pserver") + .has("hostname", "ps-b") + .bothE() + .otherV() + .has("aai-node-type", "complex") + .hasNext()); + updated = getUpdatedVertexes(dbserLocal); + assertEquals("Number of updated vertexes", 2, updated.size()); + assertThat("Only modified vertexes are in the updated set", + updated.keySet().stream().map(v -> v.<String>value(AAIProperties.AAI_URI)).collect(Collectors.toSet()), + is(new HashSet<>(Arrays.asList(pserverUri, complexUri)))); + didNotUpdateStandardVertexProps = updated.entrySet().stream() + .filter(e -> !e.getValue()) + .map(e -> e.getKey().<String>value(AAIProperties.AAI_URI)).collect(Collectors.toList()); + assertThat("Vertexes should all have their standard props updated", didNotUpdateStandardVertexProps, is(Collections.emptyList())); + + + + System.out.println("Update pserver adding a second p-interface"); + dbserLocal = new DBSerializer(version, engine, introspectorFactoryType, "update-pserver", AAIProperties.MINIMUM_DEPTH); + pserver = dbserLocal.getLatestVersionView(pserverV); + Introspector pint2 = loader.introspectorFromName("p-interface"); + pint2.setValue("interface-name", "pint-2"); + pints = pserver.getWrappedValue("p-interfaces"); + List<Object> pintList = pserver.getWrappedValue("p-interfaces").getWrappedListValue("p-interface") + .stream().map(Introspector::getUnderlyingObject).collect(Collectors.toList()); + pintList.add(pint2.getUnderlyingObject()); + pints.setValue("p-interface", pintList); + pserver.setValue("p-interfaces", pints.getUnderlyingObject()); + final String pint2Uri = pserverUri + "/p-interfaces/p-interface/pint-2"; + dbserLocal.serializeToDb(pserver, pserverV, uriQuery, "pserver", pserver.marshal(false)); + + assertTrue("Pserver has edge to pinterface 2", engine.tx().traversal().V() + .has("aai-node-type", "pserver") + .has("hostname", "ps-b") + .in() + .has("aai-node-type", "p-interface") + .has("interface-name","pint-2") + .hasNext()); + assertTrue("p-interface 2 created", engine.tx().traversal().V() + .has("aai-node-type", "p-interface") + .has("interface-name", "pint-2") + .has(AAIProperties.AAI_URI, pint2Uri) + .hasNext()); + updated = getUpdatedVertexes(dbserLocal); + assertEquals("Number of updated vertexes", 1, updated.size()); + assertThat("Only modified vertexes are in the updated set", + updated.keySet().stream().map(v -> v.<String>value(AAIProperties.AAI_URI)).collect(Collectors.toSet()), + is(Collections.singleton(pint2Uri))); + didNotUpdateStandardVertexProps = updated.entrySet().stream() + .filter(e -> !e.getValue()) + .map(e -> e.getKey().<String>value(AAIProperties.AAI_URI)).collect(Collectors.toList()); + assertThat("Vertexes should all have their standard props updated", didNotUpdateStandardVertexProps, is(Collections.emptyList())); + + + System.out.println("Add l-interface directly to the 2nd p-interface"); + dbserLocal = new DBSerializer(version, engine, introspectorFactoryType, "create-pserver", AAIProperties.MINIMUM_DEPTH); + Introspector lInt = loader.introspectorFromName("l-interface"); + Vertex lIntV = dbserLocal.createNewVertex(lInt); + final String lIntUri = pint2Uri + "/l-interfaces/l-interface/lint-1"; + uriQuery = + engine.getQueryBuilder().createQueryFromURI(new URI(lIntUri)); + lInt.setValue("interface-name", "lint-1"); + dbserLocal.serializeToDb(lInt, lIntV, uriQuery, "l-interface", lInt.marshal(false)); + + assertTrue("l-interface created", engine.tx().traversal().V() + .has("aai-node-type", "l-interface") + .has("interface-name", "lint-1") + .hasNext()); + + assertTrue("Pserver has edge to pinterface to l-interface", engine.tx().traversal().V() + .has("aai-node-type", "pserver") + .has("hostname", "ps-b") + .bothE() + .otherV() + .has("aai-node-type", "p-interface") + .bothE() + .otherV() + .has("aai-node-type", "l-interface") + .hasNext()); + updated = getUpdatedVertexes(dbserLocal); + assertEquals("Number of updated vertexes", 1, updated.size()); + assertThat("Only modified vertexes are in the updated set", + updated.keySet().stream().map(v -> v.<String>value(AAIProperties.AAI_URI)).collect(Collectors.toSet()), + is(new HashSet<>(Collections.singletonList(lIntUri)))); + didNotUpdateStandardVertexProps = updated.entrySet().stream() + .filter(e -> !e.getValue()) + .map(e -> e.getKey().<String>value(AAIProperties.AAI_URI)).collect(Collectors.toList()); + assertThat("Vertexes should all have their standard props updated", didNotUpdateStandardVertexProps, is(Collections.emptyList())); + + + System.out.println("Delete pserver"); + dbserLocal = new DBSerializer(version, engine, introspectorFactoryType, "delete-pserver", AAIProperties.MINIMUM_DEPTH); + pserver = dbserLocal.getLatestVersionView(pserverV); + String rv = pserver.getValue(AAIProperties.RESOURCE_VERSION); + dbserLocal.delete(engine.tx().traversal().V(pserverV).next(), rv, true); + + assertFalse("pserver no longer exists", engine.tx().traversal().V() + .has("aai-node-type", "pserver") + .hasNext()); + updated = getUpdatedVertexes(dbserLocal); + assertEquals("Number of updated vertexes", 0, updated.size()); + didNotUpdateStandardVertexProps = updated.entrySet().stream() + .filter(e -> !e.getValue()) + .map(e -> e.getKey().<String>value(AAIProperties.AAI_URI)).collect(Collectors.toList()); + assertThat("Vertexes should all have their standard props updated", didNotUpdateStandardVertexProps, is(Collections.emptyList())); + + + } + + private Map<Vertex, Boolean> getUpdatedVertexes(DBSerializer dbserLocal) { + Map<Vertex, Boolean> updated = new LinkedHashMap<>(dbserLocal.getUpdatedVertexes()); + dbserLocal.touchStandardVertexPropertiesForEdges().forEach(v -> updated.putIfAbsent(v, true)); + return updated; + } + + +} diff --git a/aai-core/src/test/java/org/onap/aai/serialization/db/DbSerializerTest.java b/aai-core/src/test/java/org/onap/aai/serialization/db/DbSerializerTest.java index b50adf2a..dd4454d5 100644 --- a/aai-core/src/test/java/org/onap/aai/serialization/db/DbSerializerTest.java +++ b/aai-core/src/test/java/org/onap/aai/serialization/db/DbSerializerTest.java @@ -20,18 +20,11 @@ package org.onap.aai.serialization.db; -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.*; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.when; - -import java.io.UnsupportedEncodingException; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.*; - import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; -import org.apache.tinkerpop.gremlin.structure.*; +import org.apache.tinkerpop.gremlin.structure.Edge; +import org.apache.tinkerpop.gremlin.structure.Graph; +import org.apache.tinkerpop.gremlin.structure.T; +import org.apache.tinkerpop.gremlin.structure.Vertex; import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph; import org.janusgraph.core.JanusGraphFactory; import org.junit.*; @@ -40,11 +33,12 @@ import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.onap.aai.AAISetup; import org.onap.aai.db.props.AAIProperties; -import org.onap.aai.dbmap.DBConnectionType; import org.onap.aai.edges.EdgeIngestor; import org.onap.aai.edges.enums.EdgeType; import org.onap.aai.exceptions.AAIException; -import org.onap.aai.introspection.*; +import org.onap.aai.introspection.Introspector; +import org.onap.aai.introspection.Loader; +import org.onap.aai.introspection.ModelType; import org.onap.aai.parsers.query.QueryParser; import org.onap.aai.serialization.engines.JanusGraphDBEngine; import org.onap.aai.serialization.engines.QueryStyle; @@ -54,6 +48,16 @@ import org.onap.aai.util.AAIConstants; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.annotation.DirtiesContext; +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.*; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.*; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + @RunWith(value = Parameterized.class) @DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS) public class DbSerializerTest extends AAISetup { @@ -72,15 +76,14 @@ public class DbSerializerTest extends AAISetup { private SchemaVersion version; private final ModelType introspectorFactoryType = ModelType.MOXY; - private final DBConnectionType type = DBConnectionType.REALTIME; private Loader loader; private TransactionalGraphEngine dbEngine; private TransactionalGraphEngine engine; // for tests that aren't mocking the engine private DBSerializer dbser; - TransactionalGraphEngine spy; - TransactionalGraphEngine.Admin adminSpy; + private TransactionalGraphEngine spy; + private TransactionalGraphEngine.Admin adminSpy; - @Parameterized.Parameter(value = 0) + @Parameterized.Parameter public QueryStyle queryStyle; @Parameterized.Parameters(name = "QueryStyle.{0}") @@ -89,7 +92,7 @@ public class DbSerializerTest extends AAISetup { } @BeforeClass - public static void init() throws Exception { + public static void init() { graph = JanusGraphFactory.build().set("storage.backend", "inmemory").open(); } @@ -99,11 +102,11 @@ public class DbSerializerTest extends AAISetup { // createGraph(); version = schemaVersions.getDefaultVersion(); loader = loaderFactory.createLoaderForVersion(introspectorFactoryType, version); - dbEngine = new JanusGraphDBEngine(queryStyle, type, loader); + dbEngine = new JanusGraphDBEngine(queryStyle, loader); spy = spy(dbEngine); adminSpy = spy(dbEngine.asAdmin()); - engine = new JanusGraphDBEngine(queryStyle, type, loader); + engine = new JanusGraphDBEngine(queryStyle, loader); dbser = new DBSerializer(version, engine, introspectorFactoryType, "AAI-TEST"); } @@ -146,7 +149,7 @@ public class DbSerializerTest extends AAISetup { } @After - public void tearDown() throws Exception { + public void tearDown() { engine.rollback(); } @@ -155,46 +158,124 @@ public class DbSerializerTest extends AAISetup { graph.close(); } - public void subnetSetup() throws AAIException { + private void subnetSetup() throws AAIException, UnsupportedEncodingException { /* * This setus up the test graph, For future junits , add more vertices * and edges */ - Vertex l3interipv4addresslist_1 = graph.traversal().addV("aai-node-type", "l3-interface-ipv4-address-list", - "l3-interface-ipv4-address", "l3-interface-ipv4-address-1").next(); - Vertex subnet_2 = graph.traversal().addV("aai-node-type", "subnet", "subnet-id", "subnet-id-2").next(); - Vertex l3interipv6addresslist_3 = graph.traversal().addV("aai-node-type", "l3-interface-ipv6-address-list", - "l3-interface-ipv6-address", "l3-interface-ipv6-address-3").next(); - Vertex subnet_4 = graph.traversal().addV("aai-node-type", "subnet", "subnet-id", "subnet-id-4").next(); - Vertex subnet_5 = graph.traversal().addV("aai-node-type", "subnet", "subnet-id", "subnet-id-5").next(); - Vertex l3network_6 = graph.traversal() - .addV("aai-node-type", "l3-network", "network-id", "network-id-6", "network-name", "network-name-6") - .next(); + Vertex l3interipv4addresslist_1 = graph.addVertex("aai-node-type", "l3-interface-ipv4-address-list", + "l3-interface-ipv4-address", "l3-interface-ipv4-address-1", + AAIProperties.AAI_UUID, UUID.randomUUID().toString(), + AAIProperties.CREATED_TS, 123L, + AAIProperties.SOURCE_OF_TRUTH, "sot", + AAIProperties.RESOURCE_VERSION, "123", + AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot", + AAIProperties.LAST_MOD_TS, 333L); + Vertex subnet_2 = graph.addVertex("aai-node-type", "subnet", "subnet-id", "subnet-id-2", + AAIProperties.AAI_UUID, UUID.randomUUID().toString(), + AAIProperties.CREATED_TS, 123L, + AAIProperties.SOURCE_OF_TRUTH, "sot", + AAIProperties.RESOURCE_VERSION, "123", + AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot", + AAIProperties.LAST_MOD_TS, 333L); + Vertex l3interipv6addresslist_3 = graph.addVertex("aai-node-type", "l3-interface-ipv6-address-list", + "l3-interface-ipv6-address", "l3-interface-ipv6-address-3", + AAIProperties.AAI_UUID, UUID.randomUUID().toString(), + AAIProperties.CREATED_TS, 123L, + AAIProperties.SOURCE_OF_TRUTH, "sot", + AAIProperties.RESOURCE_VERSION, "123", + AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot", + AAIProperties.LAST_MOD_TS, 333L); + Vertex subnet_4 = graph.addVertex("aai-node-type", "subnet", "subnet-id", "subnet-id-4", + AAIProperties.AAI_UUID, UUID.randomUUID().toString(), + AAIProperties.CREATED_TS, 123L, + AAIProperties.SOURCE_OF_TRUTH, "sot", + AAIProperties.RESOURCE_VERSION, "123", + AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot", + AAIProperties.LAST_MOD_TS, 333L); + Vertex subnet_5 = graph.addVertex("aai-node-type", "subnet", "subnet-id", "subnet-id-5", + AAIProperties.AAI_UUID, UUID.randomUUID().toString(), + AAIProperties.CREATED_TS, 123L, + AAIProperties.SOURCE_OF_TRUTH, "sot", + AAIProperties.RESOURCE_VERSION, "123", + AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot", + AAIProperties.LAST_MOD_TS, 333L); + Vertex l3network_6 = graph.addVertex("aai-node-type", "l3-network", "network-id", "network-id-6", "network-name", "network-name-6", + AAIProperties.AAI_UUID, UUID.randomUUID().toString(), + AAIProperties.CREATED_TS, 123L, + AAIProperties.SOURCE_OF_TRUTH, "sot", + AAIProperties.RESOURCE_VERSION, "123", + AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot", + AAIProperties.LAST_MOD_TS, 333L); GraphTraversalSource g = graph.traversal(); edgeSer.addEdge(g, l3interipv4addresslist_1, subnet_2); edgeSer.addEdge(g, l3interipv6addresslist_3, subnet_4); edgeSer.addTreeEdge(g, subnet_5, l3network_6); + + l3interipv4addresslist_1.property(AAIProperties.AAI_URI, dbser.getURIForVertex(l3interipv4addresslist_1).toString()); + subnet_2.property(AAIProperties.AAI_URI, dbser.getURIForVertex(subnet_2).toString()); + l3interipv6addresslist_3.property(AAIProperties.AAI_URI, dbser.getURIForVertex(l3interipv6addresslist_3).toString()); + subnet_4.property(AAIProperties.AAI_URI, dbser.getURIForVertex(subnet_4).toString()); + subnet_5.property(AAIProperties.AAI_URI, dbser.getURIForVertex(subnet_5).toString()); + l3network_6.property(AAIProperties.AAI_URI, dbser.getURIForVertex(l3network_6).toString()); + } - public void l3NetworkSetup() throws AAIException { + private void l3NetworkSetup() throws AAIException, UnsupportedEncodingException { /* * This setus up the test graph, For future junits , add more vertices * and edges */ Vertex l3network1 = graph.addVertex("aai-node-type", "l3-network", "network-id", "network-id-v1", - "network-name", "network-name-v1"); + "network-name", "network-name-v1", + AAIProperties.AAI_UUID, UUID.randomUUID().toString(), + AAIProperties.CREATED_TS, 123L, + AAIProperties.SOURCE_OF_TRUTH, "sot", + AAIProperties.RESOURCE_VERSION, "123", + AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot", + AAIProperties.LAST_MOD_TS, 333L); Vertex l3network2 = graph.addVertex("aai-node-type", "l3-network", "network-id", "network-id-v2", - "network-name", "network-name-v2"); - Vertex subnet1 = graph.addVertex("aai-node-type", "subnet", "subnet-id", "subnet-id-v1"); - Vertex subnet2 = graph.addVertex("aai-node-type", "subnet", "subnet-id", "subnet-id-v2"); + "network-name", "network-name-v2", + AAIProperties.AAI_UUID, UUID.randomUUID().toString(), + AAIProperties.CREATED_TS, 123L, + AAIProperties.SOURCE_OF_TRUTH, "sot", + AAIProperties.RESOURCE_VERSION, "123", + AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot", + AAIProperties.LAST_MOD_TS, 333L); + Vertex subnet1 = graph.addVertex("aai-node-type", "subnet", "subnet-id", "subnet-id-v1", + AAIProperties.AAI_UUID, UUID.randomUUID().toString(), + AAIProperties.CREATED_TS, 123L, + AAIProperties.SOURCE_OF_TRUTH, "sot", + AAIProperties.RESOURCE_VERSION, "123", + AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot", + AAIProperties.LAST_MOD_TS, 333L); + Vertex subnet2 = graph.addVertex("aai-node-type", "subnet", "subnet-id", "subnet-id-v2", + AAIProperties.AAI_UUID, UUID.randomUUID().toString(), + AAIProperties.CREATED_TS, 123L, + AAIProperties.SOURCE_OF_TRUTH, "sot", + AAIProperties.RESOURCE_VERSION, "123", + AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot", + AAIProperties.LAST_MOD_TS, 333L); Vertex l3interipv4addresslist_1 = graph.addVertex("aai-node-type", "l3-interface-ipv4-address-list", - "l3-interface-ipv4-address", "l3-intr-v1"); + "l3-interface-ipv4-address", "l3-intr-v1", + AAIProperties.AAI_UUID, UUID.randomUUID().toString(), + AAIProperties.CREATED_TS, 123L, + AAIProperties.SOURCE_OF_TRUTH, "sot", + AAIProperties.RESOURCE_VERSION, "123", + AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot", + AAIProperties.LAST_MOD_TS, 333L); Vertex l3interipv6addresslist_1 = graph.addVertex("aai-node-type", "l3-interface-ipv6-address-list", - "l3-interface-ipv6-address", "l3-interface-ipv6-v1"); + "l3-interface-ipv6-address", "l3-interface-ipv6-v1", + AAIProperties.AAI_UUID, UUID.randomUUID().toString(), + AAIProperties.CREATED_TS, 123L, + AAIProperties.SOURCE_OF_TRUTH, "sot", + AAIProperties.RESOURCE_VERSION, "123", + AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot", + AAIProperties.LAST_MOD_TS, 333L); GraphTraversalSource g = graph.traversal(); edgeSer.addTreeEdge(g, subnet1, l3network1); @@ -203,28 +284,77 @@ public class DbSerializerTest extends AAISetup { edgeSer.addTreeEdge(g, subnet2, l3network2); + subnet1.property(AAIProperties.AAI_URI, dbser.getURIForVertex(subnet1).toString()); + l3interipv4addresslist_1.property(AAIProperties.AAI_URI, dbser.getURIForVertex(l3interipv4addresslist_1).toString()); + l3network1.property(AAIProperties.AAI_URI, dbser.getURIForVertex(l3network1).toString()); + subnet2.property(AAIProperties.AAI_URI, dbser.getURIForVertex(subnet2).toString()); + l3network2.property(AAIProperties.AAI_URI, dbser.getURIForVertex(l3network2).toString()); + + + } - public void vserverSetup() throws AAIException { + private void vserverSetup() throws AAIException, UnsupportedEncodingException { /* * This setus up the test graph, For future junits , add more vertices * and edges */ Vertex vserver1 = graph.addVertex("aai-node-type", "vserver", "vserver-id", "vss1", - AAIProperties.AAI_URI.toString(), - "/cloud-infrastructure/cloud-regions/cloud-region/me/123/tenants/tenant/453/vservers/vserver/vss1"); - - Vertex lInterface1 = graph.addVertex("aai-node-type", "l-interface", "interface-name", "lIntr1"); - Vertex lInterface2 = graph.addVertex("aai-node-type", "l-interface", "interface-name", "lIntr2"); - - Vertex logicalLink1 = graph.addVertex("aai-node-type", "logical-link", "link-name", "logLink1"); - Vertex logicalLink2 = graph.addVertex("aai-node-type", "logical-link", "link-name", "logLink2"); + AAIProperties.AAI_URI, "/cloud-infrastructure/cloud-regions/cloud-region/me/123/tenants/tenant/453/vservers/vserver/vss1", + AAIProperties.AAI_UUID, UUID.randomUUID().toString(), + AAIProperties.CREATED_TS, 123L, + AAIProperties.SOURCE_OF_TRUTH, "sot", + AAIProperties.RESOURCE_VERSION, "123", + AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot", + AAIProperties.LAST_MOD_TS, 333L); + + Vertex lInterface1 = graph.addVertex("aai-node-type", "l-interface", "interface-name", "lIntr1", + AAIProperties.AAI_UUID, UUID.randomUUID().toString(), + AAIProperties.CREATED_TS, 123L, + AAIProperties.SOURCE_OF_TRUTH, "sot", + AAIProperties.RESOURCE_VERSION, "123", + AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot", + AAIProperties.LAST_MOD_TS, 333L); + Vertex lInterface2 = graph.addVertex("aai-node-type", "l-interface", "interface-name", "lIntr2", + AAIProperties.AAI_UUID, UUID.randomUUID().toString(), + AAIProperties.CREATED_TS, 123L, + AAIProperties.SOURCE_OF_TRUTH, "sot", + AAIProperties.RESOURCE_VERSION, "123", + AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot", + AAIProperties.LAST_MOD_TS, 333L); + + Vertex logicalLink1 = graph.addVertex("aai-node-type", "logical-link", "link-name", "logLink1", + AAIProperties.AAI_UUID, UUID.randomUUID().toString(), + AAIProperties.CREATED_TS, 123L, + AAIProperties.SOURCE_OF_TRUTH, "sot", + AAIProperties.RESOURCE_VERSION, "123", + AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot", + AAIProperties.LAST_MOD_TS, 333L); + Vertex logicalLink2 = graph.addVertex("aai-node-type", "logical-link", "link-name", "logLink2", + AAIProperties.AAI_UUID, UUID.randomUUID().toString(), + AAIProperties.CREATED_TS, 123L, + AAIProperties.SOURCE_OF_TRUTH, "sot", + AAIProperties.RESOURCE_VERSION, "123", + AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot", + AAIProperties.LAST_MOD_TS, 333L); Vertex l3interipv4addresslist_1 = graph.addVertex("aai-node-type", "l3-interface-ipv4-address-list", - "l3-interface-ipv4-address", "l3-intr-ipv4-address-1"); + "l3-interface-ipv4-address", "l3-intr-ipv4-address-1", + AAIProperties.AAI_UUID, UUID.randomUUID().toString(), + AAIProperties.CREATED_TS, 123L, + AAIProperties.SOURCE_OF_TRUTH, "sot", + AAIProperties.RESOURCE_VERSION, "123", + AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot", + AAIProperties.LAST_MOD_TS, 333L); Vertex l3interipv6addresslist_2 = graph.addVertex("aai-node-type", "l3-interface-ipv6-address-list", - "l3-interface-ipv4-address", "l3-intr-ipv6-address-1"); + "l3-interface-ipv4-address", "l3-intr-ipv6-address-1", + AAIProperties.AAI_UUID, UUID.randomUUID().toString(), + AAIProperties.CREATED_TS, 123L, + AAIProperties.SOURCE_OF_TRUTH, "sot", + AAIProperties.RESOURCE_VERSION, "123", + AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot", + AAIProperties.LAST_MOD_TS, 333L); GraphTraversalSource g = graph.traversal(); @@ -235,10 +365,18 @@ public class DbSerializerTest extends AAISetup { edgeSer.addEdge(g, lInterface1, logicalLink1); edgeSer.addEdge(g, lInterface2, logicalLink2); + + vserver1.property(AAIProperties.AAI_URI, dbser.getURIForVertex(vserver1).toString()); + lInterface1.property(AAIProperties.AAI_URI, dbser.getURIForVertex(lInterface1).toString()); + lInterface2.property(AAIProperties.AAI_URI, dbser.getURIForVertex(lInterface2).toString()); + l3interipv4addresslist_1.property(AAIProperties.AAI_URI, dbser.getURIForVertex(l3interipv4addresslist_1).toString()); + l3interipv6addresslist_2.property(AAIProperties.AAI_URI, dbser.getURIForVertex(l3interipv6addresslist_2).toString()); + logicalLink1.property(AAIProperties.AAI_URI, dbser.getURIForVertex(logicalLink1).toString()); + logicalLink2.property(AAIProperties.AAI_URI, dbser.getURIForVertex(logicalLink2).toString()); } @Test - public void subnetDelWithInEdgesIpv4Test() throws AAIException { + public void subnetDelWithInEdgesIpv4Test() throws AAIException, UnsupportedEncodingException { subnetSetup(); String expected_message = "Object is being reference by additional objects preventing it from being deleted. Please clean up references from the following types [l3-interface-ipv4-address-list]"; @@ -254,7 +392,7 @@ public class DbSerializerTest extends AAISetup { } @Test - public void subnetDelWithInEdgesIpv6Test() throws AAIException { + public void subnetDelWithInEdgesIpv6Test() throws AAIException, UnsupportedEncodingException { subnetSetup(); String expected_message = "Object is being reference by additional objects preventing it from being deleted. Please clean up references from the following types [l3-interface-ipv6-address-list]"; @@ -269,7 +407,7 @@ public class DbSerializerTest extends AAISetup { } @Test - public void subnetDelWithInEdgesL3network() throws AAIException { + public void subnetDelWithInEdgesL3network() throws AAIException, UnsupportedEncodingException { subnetSetup(); String expected_message = ""; @@ -283,7 +421,7 @@ public class DbSerializerTest extends AAISetup { } - public String testCascadeDelete(Vertex v) throws AAIException { + private String testCascadeDelete(Vertex v) throws AAIException { GraphTraversalSource traversal = graph.traversal(); when(spy.asAdmin()).thenReturn(adminSpy); @@ -297,25 +435,7 @@ public class DbSerializerTest extends AAISetup { try { serializer.delete(v, deletableVertices, "resourceVersion", false); } catch (AAIException exception) { - exceptionMessage = exception.getMessage(); - } - return exceptionMessage; - - } - - public String testDelete(Vertex v) throws AAIException { - - GraphTraversalSource traversal = graph.traversal(); - when(spy.asAdmin()).thenReturn(adminSpy); - when(adminSpy.getTraversalSource()).thenReturn(traversal); - when(adminSpy.getReadOnlyTraversalSource()).thenReturn(traversal); - - String exceptionMessage = ""; - DBSerializer serializer = new DBSerializer(version, spy, introspectorFactoryType, "AAI_TEST"); - - try { - serializer.delete(v, "resourceVersion", false); - } catch (AAIException exception) { + exception.printStackTrace(); exceptionMessage = exception.getMessage(); } return exceptionMessage; @@ -331,7 +451,7 @@ public class DbSerializerTest extends AAISetup { Vertex testVertex = dbser.createNewVertex(testObj); Vertex fromGraph = engine.tx().traversal().V().has("aai-node-type", "generic-vnf").toList().get(0); assertEquals(testVertex.id(), fromGraph.id()); - assertEquals("AAI-TEST", fromGraph.property(AAIProperties.SOURCE_OF_TRUTH.toString()).value()); + assertEquals("AAI-TEST", fromGraph.property(AAIProperties.SOURCE_OF_TRUTH).value()); } @@ -343,17 +463,17 @@ public class DbSerializerTest extends AAISetup { // different value Thread.sleep(2); DBSerializer dbser2 = new DBSerializer(version, engine, introspectorFactoryType, "AAI-TEST-2"); - Vertex vert = graph.addVertex("aai-node-type", "generic-vnf"); + Vertex vert = graph.addVertex("aai-node-type", "generic-vnf", "aai-uri", "a"); // Upon first creation of the Vertex and the DBSerializer // the source of truth and created-ts should be the same as their modified counterparts dbser2.touchStandardVertexProperties(vert, true); - String createTS = (String) vert.property(AAIProperties.CREATED_TS).value(); - String modTS = (String) vert.property(AAIProperties.LAST_MOD_TS).value(); + String createTS = String.valueOf(vert.property(AAIProperties.CREATED_TS).value()); + String modTS = String.valueOf(vert.property(AAIProperties.LAST_MOD_TS).value()); String sot = (String) vert.property(AAIProperties.SOURCE_OF_TRUTH).value(); String lastModSOT = (String) vert.property(AAIProperties.LAST_MOD_SOURCE_OF_TRUTH).value(); - assertTrue(createTS.equals(modTS)); - assertTrue(sot.equals(lastModSOT)); + assertEquals(createTS, modTS); + assertEquals(sot, lastModSOT); // if this test runs through too fast the value may not change, causing the test to fail. sleeping ensures a // different value @@ -363,12 +483,12 @@ public class DbSerializerTest extends AAISetup { // Here the vertex will be modified by a different source of truth DBSerializer dbser3 = new DBSerializer(version, engine, introspectorFactoryType, "AAI-TEST-3"); dbser3.touchStandardVertexProperties(vert, false); - createTS = (String) vert.property(AAIProperties.CREATED_TS).value(); - modTS = (String) vert.property(AAIProperties.LAST_MOD_TS).value(); + createTS = String.valueOf(vert.property(AAIProperties.CREATED_TS).value()); + modTS = String.valueOf(vert.property(AAIProperties.LAST_MOD_TS).value()); sot = (String) vert.property(AAIProperties.SOURCE_OF_TRUTH).value(); lastModSOT = (String) vert.property(AAIProperties.LAST_MOD_SOURCE_OF_TRUTH).value(); - assertFalse(createTS.equals(modTS)); - assertFalse(sot.equals(lastModSOT)); + assertNotEquals(createTS, modTS); + assertNotEquals(sot, lastModSOT); // if this test runs through too fast the value may not change, causing the test to fail. sleeping ensures a // different value @@ -380,10 +500,10 @@ public class DbSerializerTest extends AAISetup { // Using an existing vertex, but treating it as new && using an older DBSerializer dbser.touchStandardVertexProperties(vert, true); String resverStart = (String) vert.property(AAIProperties.RESOURCE_VERSION).value(); - String lastModTimeStart = (String) vert.property(AAIProperties.LAST_MOD_TS).value(); - createTS = (String) vert.property(AAIProperties.CREATED_TS).value(); - modTS = (String) vert.property(AAIProperties.LAST_MOD_TS).value(); - assertTrue(createTS.equals(modTS)); + String lastModTimeStart = String.valueOf(vert.property(AAIProperties.LAST_MOD_TS).value()); + createTS = String.valueOf(vert.property(AAIProperties.CREATED_TS).value()); + modTS = String.valueOf(vert.property(AAIProperties.LAST_MOD_TS).value()); + assertEquals(createTS, modTS); assertEquals("AAI-TEST", vert.property(AAIProperties.LAST_MOD_SOURCE_OF_TRUTH).value()); // if this test runs through too fast the value may not change, causing the test to fail. sleeping ensures a @@ -392,16 +512,16 @@ public class DbSerializerTest extends AAISetup { dbser2.touchStandardVertexProperties(vert, false); String resourceVer = (String) vert.property(AAIProperties.RESOURCE_VERSION).value(); - String lastModTs = (String) vert.property(AAIProperties.LAST_MOD_TS).value(); + String lastModTs = String.valueOf(vert.property(AAIProperties.LAST_MOD_TS).value()); String lastModSoT = (String) vert.property(AAIProperties.LAST_MOD_SOURCE_OF_TRUTH).value(); - assertFalse(resverStart.equals(resourceVer)); - assertFalse(lastModTimeStart.equals(lastModTs)); + assertNotEquals(resverStart, resourceVer); + assertNotEquals(lastModTimeStart, lastModTs); assertEquals("AAI-TEST-2", lastModSoT); } @Test - public void touchStandardVertexPropertiesAAIUUIDTest() throws AAIException, InterruptedException { + public void touchStandardVertexPropertiesAAIUUIDTest() { engine.startTransaction(); Graph graph = TinkerGraph.open(); @@ -466,7 +586,7 @@ public class DbSerializerTest extends AAISetup { } @Test - public void trimClassNameTest() throws AAIException { + public void trimClassNameTest() { assertEquals("GenericVnf", dbser.trimClassName("GenericVnf")); assertEquals("GenericVnf", dbser.trimClassName("org.onap.aai.GenericVnf")); } @@ -526,9 +646,21 @@ public class DbSerializerTest extends AAISetup { engine.startTransaction(); Vertex gvnf = engine.tx().addVertex("aai-node-type", "generic-vnf", "vnf-id", "myvnf", "aai-uri", - "/network/generic-vnfs/generic-vnf/myvnf"); + "/network/generic-vnfs/generic-vnf/myvnf", + AAIProperties.AAI_UUID, UUID.randomUUID().toString(), + AAIProperties.CREATED_TS, 123L, + AAIProperties.SOURCE_OF_TRUTH, "sot", + AAIProperties.RESOURCE_VERSION, "123", + AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot", + AAIProperties.LAST_MOD_TS, 333L); Vertex vnfc = engine.tx().addVertex("aai-node-type", "vnfc", "vnfc-name", "a-name", "aai-uri", - "/network/vnfcs/vnfc/a-name"); + "/network/vnfcs/vnfc/a-name", + AAIProperties.AAI_UUID, UUID.randomUUID().toString(), + AAIProperties.CREATED_TS, 123L, + AAIProperties.SOURCE_OF_TRUTH, "sot", + AAIProperties.RESOURCE_VERSION, "123", + AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot", + AAIProperties.LAST_MOD_TS, 333L); edgeSer.addEdge(engine.tx().traversal(), gvnf, vnfc); @@ -540,7 +672,7 @@ public class DbSerializerTest extends AAISetup { relationship.setValue("related-link", "/network/vnfcs/vnfc/a-name"); relationship.setValue("relationship-data", relData); - assertTrue(dbser.deleteEdge(relationship, gvnf)); + assertTrue(dbser.deleteEdge(relationship, gvnf).isPresent()); assertFalse(engine.tx().traversal().V(gvnf).both("uses").hasNext()); assertFalse(engine.tx().traversal().V(vnfc).both("uses").hasNext()); @@ -552,9 +684,9 @@ public class DbSerializerTest extends AAISetup { engine.startTransaction(); Vertex gvnf = engine.tx().addVertex("aai-node-type", "generic-vnf", "vnf-id", "myvnf", "aai-uri", - "/network/generic-vnfs/generic-vnf/myvnf"); + "/network/generic-vnfs/generic-vnf/myvnf", "aai-uuid", "a"); Vertex vnfc = engine.tx().addVertex("aai-node-type", "vnfc", "vnfc-name", "a-name", "aai-uri", - "/network/vnfcs/vnfc/a-name"); + "/network/vnfcs/vnfc/a-name", "aai-uuid", "b"); // sunny day case Introspector relData = loader.introspectorFromName("relationship-data"); @@ -565,7 +697,7 @@ public class DbSerializerTest extends AAISetup { relationship.setValue("related-link", "/network/vnfcs/vnfc/a-name"); relationship.setValue("relationship-data", relData); - assertTrue(dbser.createEdge(relationship, gvnf)); + assertNotNull(dbser.createEdge(relationship, gvnf)); assertTrue(engine.tx().traversal().V(gvnf).both("org.onap.relationships.inventory.BelongsTo").hasNext()); assertTrue(engine.tx().traversal().V(vnfc).both("org.onap.relationships.inventory.BelongsTo").hasNext()); @@ -634,9 +766,9 @@ public class DbSerializerTest extends AAISetup { Vertex gvnfVert = dbser.createNewVertex(gvnf); gvnf.setValue("vnf-id", "myvnf"); + gvnf.setValue("vnf-type", "typo"); dbser.serializeSingleVertex(gvnfVert, gvnf, "test"); assertTrue(engine.tx().traversal().V().has("aai-node-type", "generic-vnf").has("vnf-id", "myvnf").hasNext()); - } @Test @@ -666,19 +798,14 @@ public class DbSerializerTest extends AAISetup { engine.startTransaction(); Vertex gvnf = engine.tx().addVertex("aai-node-type", "generic-vnf", "vnf-id", "vnf-123", "aai-uri", - "/network/generic-vnfs/generic-vnf/vnf-123"); + "/network/generic-vnfs/generic-vnf/vnf-123", "aai-uuid", "a"); Vertex vnfc = engine.tx().addVertex("aai-node-type", "vnfc", "vnfc-name", "vnfc-123", "aai-uri", - "/network/vnfcs/vnfc/vnfc-123"); + "/network/vnfcs/vnfc/vnfc-123", "aai-uuid", "b"); edgeSer.addEdge(engine.tx().traversal(), gvnf, vnfc); Introspector obj = loader.introspectorFromName("generic-vnf"); - obj = this.dbser.dbToObject(Arrays.asList(gvnf), obj, AAIProperties.MAXIMUM_DEPTH, false, "false"); - - MarshallerProperties properties = - new MarshallerProperties.Builder(org.onap.aai.restcore.MediaType.getEnum("application/json")) - .formatted(true).build(); - System.out.println(obj.marshal(properties)); + obj = this.dbser.dbToObject(Collections.singletonList(gvnf), obj, AAIProperties.MAXIMUM_DEPTH, false, "false"); assertEquals("edge label between generic-vnf and vnfs is uses", "org.onap.relationships.inventory.BelongsTo", obj.getWrappedValue("relationship-list").getWrappedListValue("relationship").get(0) @@ -704,22 +831,21 @@ public class DbSerializerTest extends AAISetup { edgeSer.addEdge(engine.tx().traversal(), gvnf, vnfc); Introspector obj = loader.introspectorFromName("generic-vnf"); - obj = dbser.dbToObject(Arrays.asList(gvnf), obj, AAIProperties.MAXIMUM_DEPTH, false, "false"); + obj = dbser.dbToObject(Collections.singletonList(gvnf), obj, AAIProperties.MAXIMUM_DEPTH, false, "false"); - assertEquals("Relationship does not contain edge-property", false, obj.getWrappedValue("relationship-list") - .getWrappedListValue("relationship").get(0).hasProperty("relationship-label")); + assertFalse("Relationship does not contain edge-property", obj.getWrappedValue("relationship-list").getWrappedListValue("relationship").get(0).hasProperty("relationship-label")); } @Test public void createEdgeWithInvalidLabelTest() throws AAIException, UnsupportedEncodingException, - NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { + SecurityException, IllegalArgumentException { engine.startTransaction(); Vertex gvnf = engine.tx().addVertex("aai-node-type", "generic-vnf", "vnf-id", "myvnf", "aai-uri", - "/network/generic-vnfs/generic-vnf/myvnf"); - engine.tx().addVertex("aai-node-type", "vnfc", "vnfc-name", "a-name", "aai-uri", "/network/vnfcs/vnfc/a-name"); + "/network/generic-vnfs/generic-vnf/myvnf", "aai-uuid", "a"); + engine.tx().addVertex("aai-node-type", "vnfc", "vnfc-name", "a-name", "aai-uri", "/network/vnfcs/vnfc/a-name", "aai-uuid", "b"); Introspector relData = loader.introspectorFromName("relationship-data"); relData.setValue("relationship-key", "vnfc.vnfc-name"); @@ -738,6 +864,26 @@ public class DbSerializerTest extends AAISetup { } @Test + public void createEdgeUsingIntrospectorTest() throws AAIException, UnsupportedEncodingException, SecurityException, IllegalArgumentException { + + engine.startTransaction(); + + Vertex gvnf = engine.tx().addVertex("aai-node-type", "generic-vnf", "vnf-id", "myvnf", "aai-uri", + "/network/generic-vnfs/generic-vnf/myvnf", "aai-uuid", "a"); + engine.tx().addVertex("aai-node-type", "vnfc", "vnfc-name", "a-name", "aai-uri", "/network/vnfcs/vnfc/a-name", "aai-uuid", "b"); + + Introspector relData = loader.introspectorFromName("relationship-data"); + relData.setValue("relationship-key", "vnfc.vnfc-name"); + relData.setValue("relationship-value", "a-name"); + Introspector relationship = loader.introspectorFromName("relationship"); + relationship.setValue("related-to", "vnfc"); + relationship.setValue("related-link", "/network/vnfcs/vnfc/a-name"); + relationship.setValue("relationship-data", relData); + + dbser.createEdge(relationship, gvnf); + } + + @Test public void addRelatedToPropertyTest() throws AAIException { engine.startTransaction(); @@ -789,7 +935,7 @@ public class DbSerializerTest extends AAISetup { Introspector res = dbser.dbToObject(vertices, gvContainer, 0, true, "true"); List<Introspector> gvs = res.getWrappedListValue("generic-vnf"); - assertTrue(gvs.size() == 2); + assertEquals(2, gvs.size()); for (Introspector i : gvs) { String vnfId = i.getValue("vnf-id"); assertTrue("id1".equals(vnfId) || "id2".equals(vnfId)); @@ -814,16 +960,31 @@ public class DbSerializerTest extends AAISetup { public void deleteItemsWithTraversal() throws AAIException { DBSerializer dbser = new DBSerializer(version, engine, ModelType.MOXY, "AAI-TEST"); engine.startTransaction(); - Vertex gv = engine.tx().addVertex("aai-node-type", "generic-vnf", "vnf-id", "id1"); - Vertex lint = engine.tx().addVertex("aai-node-type", "l-interface", "interface-name", "name1"); + Vertex gv = engine.tx().addVertex("aai-node-type", "generic-vnf", "vnf-id", "id1", + AAIProperties.AAI_URI, "/network/generic-vnfs/generic-vnf/id1", + AAIProperties.AAI_UUID, UUID.randomUUID().toString(), + AAIProperties.CREATED_TS, 123L, + AAIProperties.SOURCE_OF_TRUTH, "sot", + AAIProperties.RESOURCE_VERSION, "123", + AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot", + AAIProperties.LAST_MOD_TS, 333L); + Vertex lint = engine.tx().addVertex("aai-node-type", "l-interface", "interface-name", "name1", + AAIProperties.AAI_URI, "/network/generic-vnfs/generic-vnf/id1/l-interfaces/l-interface/name1", + AAIProperties.AAI_UUID, UUID.randomUUID().toString(), + AAIProperties.CREATED_TS, 123L, + AAIProperties.SOURCE_OF_TRUTH, "sot", + AAIProperties.RESOURCE_VERSION, "123", + AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot", + AAIProperties.LAST_MOD_TS, 333L); assertTrue(engine.tx().traversal().V().has("vnf-id", "id1").hasNext()); assertTrue(engine.tx().traversal().V().has("interface-name", "name1").hasNext()); - dbser.deleteItemsWithTraversal(Arrays.asList(gv, lint)); + dbser.deleteWithTraversal(gv); + dbser.deleteWithTraversal(lint); - assertTrue(!engine.tx().traversal().V().has("vnf-id", "id1").hasNext()); - assertTrue(!engine.tx().traversal().V().has("interface-name", "name1").hasNext()); + assertFalse(engine.tx().traversal().V().has("vnf-id", "id1").hasNext()); + assertFalse(engine.tx().traversal().V().has("interface-name", "name1").hasNext()); } @@ -832,8 +993,20 @@ public class DbSerializerTest extends AAISetup { DBSerializer dbser = new DBSerializer(version, engine, ModelType.MOXY, "AAI-TEST"); engine.startTransaction(); Vertex gv = engine.tx().addVertex("aai-node-type", "generic-vnf", "vnf-id", "id1", "aai-uri", - "/network/generic-vnfs/generic-vnf/id1"); - Vertex lint = engine.tx().addVertex("aai-node-type", "l-interface"); + "/network/generic-vnfs/generic-vnf/id1", "aai-uuid", "a", + AAIProperties.CREATED_TS, 123L, + AAIProperties.SOURCE_OF_TRUTH, "sot", + AAIProperties.RESOURCE_VERSION, "123", + AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot", + AAIProperties.LAST_MOD_TS, 333L); + Vertex lint = engine.tx().addVertex("aai-node-type", "l-interface", + "aai-uri", "abc", + "aai-uuid", "b", + AAIProperties.CREATED_TS, 123L, + AAIProperties.SOURCE_OF_TRUTH, "sot", + AAIProperties.RESOURCE_VERSION, "123", + AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot", + AAIProperties.LAST_MOD_TS, 333L); edgeSer.addTreeEdge(engine.tx().traversal(), gv, lint); Introspector lintIntro = loader.introspectorFromName("l-interface"); @@ -855,13 +1028,13 @@ public class DbSerializerTest extends AAISetup { "very-fast", "service-provider-bandwidth-up-units", "things"); Introspector res = dbser.getLatestVersionView(phys); - assertTrue("zaldo".equals(res.getValue("link-name"))); - assertTrue("very-fast".equals(res.getValue("speed-value"))); - assertTrue("things".equals(res.getValue("service-provider-bandwidth-up-units"))); + assertEquals("zaldo", res.getValue("link-name")); + assertEquals("very-fast", res.getValue("speed-value")); + assertEquals("things", res.getValue("service-provider-bandwidth-up-units")); } @Test - public void cascadeVserverDeleteTest() throws AAIException { + public void cascadeVserverDeleteTest() throws AAIException, UnsupportedEncodingException { vserverSetup(); String expected_message = ""; @@ -877,7 +1050,7 @@ public class DbSerializerTest extends AAISetup { } @Test - public void cascadeL3NetworkPreventDeleteTest() throws AAIException { + public void cascadeL3NetworkPreventDeleteTest() throws AAIException, UnsupportedEncodingException { l3NetworkSetup(); ArrayList expected_messages = new ArrayList<String>(); expected_messages.add( @@ -898,7 +1071,7 @@ public class DbSerializerTest extends AAISetup { } @Test - public void cascadeL3NetworkDeleteTest() throws AAIException { + public void cascadeL3NetworkDeleteTest() throws AAIException, UnsupportedEncodingException { l3NetworkSetup(); String expected_message = ""; @@ -913,4 +1086,5 @@ public class DbSerializerTest extends AAISetup { assertEquals(expected_message, exceptionMessage); } + } diff --git a/aai-core/src/test/java/org/onap/aai/serialization/db/DbSerializer_needsFakeRulesTest.java b/aai-core/src/test/java/org/onap/aai/serialization/db/DbSerializer_needsFakeRulesTest.java index 808dd631..9a78a433 100644 --- a/aai-core/src/test/java/org/onap/aai/serialization/db/DbSerializer_needsFakeRulesTest.java +++ b/aai-core/src/test/java/org/onap/aai/serialization/db/DbSerializer_needsFakeRulesTest.java @@ -20,17 +20,10 @@ package org.onap.aai.serialization.db; -import static org.junit.Assert.*; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.when; - -import java.io.UnsupportedEncodingException; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.*; - import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; -import org.apache.tinkerpop.gremlin.structure.*; +import org.apache.tinkerpop.gremlin.structure.Direction; +import org.apache.tinkerpop.gremlin.structure.Graph; +import org.apache.tinkerpop.gremlin.structure.Vertex; import org.janusgraph.core.JanusGraphFactory; import org.junit.*; import org.junit.rules.ExpectedException; @@ -38,18 +31,20 @@ import org.junit.runner.RunWith; import org.onap.aai.config.ConfigConfiguration; import org.onap.aai.config.IntrospectionConfig; import org.onap.aai.config.SpringContextAware; +import org.onap.aai.config.XmlFormatTransformerConfiguration; import org.onap.aai.db.props.AAIProperties; -import org.onap.aai.dbmap.DBConnectionType; import org.onap.aai.edges.EdgeIngestor; import org.onap.aai.exceptions.AAIException; -import org.onap.aai.introspection.*; +import org.onap.aai.introspection.Introspector; +import org.onap.aai.introspection.Loader; +import org.onap.aai.introspection.LoaderFactory; +import org.onap.aai.introspection.ModelType; import org.onap.aai.nodes.NodeIngestor; import org.onap.aai.parsers.query.QueryParser; import org.onap.aai.serialization.engines.JanusGraphDBEngine; import org.onap.aai.serialization.engines.QueryStyle; import org.onap.aai.serialization.engines.TransactionalGraphEngine; import org.onap.aai.serialization.queryformats.QueryFormatTestHelper; -import org.onap.aai.setup.SchemaLocationsBean; import org.onap.aai.setup.SchemaVersion; import org.onap.aai.setup.SchemaVersions; import org.onap.aai.util.AAIConstants; @@ -58,11 +53,23 @@ import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.UUID; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + //@RunWith(value = Parameterized.class) TODO replace this functionality @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration( classes = {ConfigConfiguration.class, AAICoreFakeEdgesConfigTranslator.class, NodeIngestor.class, - EdgeIngestor.class, EdgeSerializer.class, SpringContextAware.class, IntrospectionConfig.class}) + EdgeIngestor.class, EdgeSerializer.class, SpringContextAware.class, IntrospectionConfig.class, XmlFormatTransformerConfiguration.class}) @TestPropertySource( properties = {"schema.translator.list = config", "schema.nodes.location=src/test/resources/onap/oxm", "schema.edges.location=src/test/resources/onap/dbedgerules"}) @@ -84,7 +91,6 @@ public class DbSerializer_needsFakeRulesTest { private SchemaVersion version; private final ModelType introspectorFactoryType = ModelType.MOXY; - private final DBConnectionType type = DBConnectionType.REALTIME; private Loader loader; private TransactionalGraphEngine dbEngine; private TransactionalGraphEngine engine; // for tests that aren't mocking the engine @@ -92,19 +98,8 @@ public class DbSerializer_needsFakeRulesTest { TransactionalGraphEngine spy; TransactionalGraphEngine.Admin adminSpy; - // @Parameterized.Parameter(value = 0) public QueryStyle queryStyle = QueryStyle.TRAVERSAL; - /* - * @Parameterized.Parameters(name = "QueryStyle.{0}") - * public static Collection<Object[]> data() { - * return Arrays.asList(new Object[][]{ - * {QueryStyle.TRAVERSAL}, - * {QueryStyle.TRAVERSAL_URI} - * }); - * } - */ - @BeforeClass public static void init() throws Exception { graph = JanusGraphFactory.build().set("storage.backend", "inmemory").open(); @@ -117,15 +112,14 @@ public class DbSerializer_needsFakeRulesTest { @Before public void setup() throws Exception { - // createGraph(); version = schemaVersions.getDefaultVersion(); loader = SpringContextAware.getBean(LoaderFactory.class).createLoaderForVersion(introspectorFactoryType, version); - dbEngine = new JanusGraphDBEngine(queryStyle, type, loader); + dbEngine = new JanusGraphDBEngine(queryStyle, loader); spy = spy(dbEngine); adminSpy = spy(dbEngine.asAdmin()); - engine = new JanusGraphDBEngine(queryStyle, type, loader); + engine = new JanusGraphDBEngine(queryStyle, loader); dbser = new DBSerializer(version, engine, introspectorFactoryType, "AAI-TEST"); } @@ -145,16 +139,14 @@ public class DbSerializer_needsFakeRulesTest { * and edges */ - Vertex l3interipv4addresslist_1 = graph.traversal().addV("aai-node-type", "l3-interface-ipv4-address-list", - "l3-interface-ipv4-address", "l3-interface-ipv4-address-1").next(); - Vertex subnet_2 = graph.traversal().addV("aai-node-type", "subnet", "subnet-id", "subnet-id-2").next(); - Vertex l3interipv6addresslist_3 = graph.traversal().addV("aai-node-type", "l3-interface-ipv6-address-list", - "l3-interface-ipv6-address", "l3-interface-ipv6-address-3").next(); - Vertex subnet_4 = graph.traversal().addV("aai-node-type", "subnet", "subnet-id", "subnet-id-4").next(); - Vertex subnet_5 = graph.traversal().addV("aai-node-type", "subnet", "subnet-id", "subnet-id-5").next(); - Vertex l3network_6 = graph.traversal() - .addV("aai-node-type", "l3-network", "network-id", "network-id-6", "network-name", "network-name-6") - .next(); + Vertex l3interipv4addresslist_1 = graph.addVertex("aai-node-type", "l3-interface-ipv4-address-list", + "l3-interface-ipv4-address", "l3-interface-ipv4-address-1"); + Vertex subnet_2 = graph.addVertex("aai-node-type", "subnet", "subnet-id", "subnet-id-2"); + Vertex l3interipv6addresslist_3 = graph.addVertex("aai-node-type", "l3-interface-ipv6-address-list", + "l3-interface-ipv6-address", "l3-interface-ipv6-address-3"); + Vertex subnet_4 = graph.addVertex("aai-node-type", "subnet", "subnet-id", "subnet-id-4"); + Vertex subnet_5 = graph.addVertex("aai-node-type", "subnet", "subnet-id", "subnet-id-5"); + Vertex l3network_6 = graph.addVertex("aai-node-type", "l3-network", "network-id", "network-id-6", "network-name", "network-name-6"); GraphTraversalSource g = graph.traversal(); edgeSer.addEdge(g, l3interipv4addresslist_1, subnet_2); @@ -190,7 +182,13 @@ public class DbSerializer_needsFakeRulesTest { engine.startTransaction(); engine.tx().addVertex("aai-node-type", "vnfc", "vnfc-name", "vnfc-" + testName, AAIProperties.AAI_URI, - "/network/vnfcs/vnfc/vnfc-" + testName); + "/network/vnfcs/vnfc/vnfc-" + testName, + AAIProperties.AAI_UUID, UUID.randomUUID().toString(), + AAIProperties.CREATED_TS, 123, + AAIProperties.SOURCE_OF_TRUTH, "sot", + AAIProperties.RESOURCE_VERSION, "123", + AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot", + AAIProperties.LAST_MOD_TS, 333); Introspector relationship = loader.introspectorFromName("relationship"); relationship.setValue("related-to", "vnfc"); @@ -222,9 +220,19 @@ public class DbSerializer_needsFakeRulesTest { engine.startTransaction(); Vertex gvnf = engine.tx().addVertex("aai-node-type", "generic-vnf", "vnf-id", "myvnf", "aai-uri", - "/network/generic-vnfs/generic-vnf/myvnf"); + "/network/generic-vnfs/generic-vnf/myvnf", "aai-uuid", "a", + AAIProperties.CREATED_TS, 123, + AAIProperties.SOURCE_OF_TRUTH, "sot", + AAIProperties.RESOURCE_VERSION, "123", + AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot", + AAIProperties.LAST_MOD_TS, 333); Vertex vnfc = engine.tx().addVertex("aai-node-type", "vnfc", "vnfc-name", "a-name", "aai-uri", - "/network/vnfcs/vnfc/a-name"); + "/network/vnfcs/vnfc/a-name", "aai-uuid", "b", + AAIProperties.CREATED_TS, 123, + AAIProperties.SOURCE_OF_TRUTH, "sot", + AAIProperties.RESOURCE_VERSION, "123", + AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot", + AAIProperties.LAST_MOD_TS, 333); // sunny day case Introspector relData = loader.introspectorFromName("relationship-data"); @@ -236,7 +244,7 @@ public class DbSerializer_needsFakeRulesTest { relationship.setValue("relationship-data", relData); relationship.setValue("relationship-label", "over-uses"); - assertTrue(localDbser.createEdge(relationship, gvnf)); + assertNotNull(dbser.createEdge(relationship, gvnf)); assertTrue(engine.tx().traversal().V(gvnf).both("over-uses").hasNext()); assertTrue(engine.tx().traversal().V(vnfc).both("over-uses").hasNext()); @@ -264,7 +272,7 @@ public class DbSerializer_needsFakeRulesTest { relationship.setValue("relationship-data", relData); relationship.setValue("relationship-label", "re-uses"); - assertTrue(localDbser.createEdge(relationship, gvnf)); + assertNotNull(dbser.createEdge(relationship, gvnf)); assertTrue(engine.tx().traversal().V(gvnf).both("re-uses").hasNext()); assertTrue(engine.tx().traversal().V(vnfc).both("re-uses").hasNext()); assertEquals("Number of edges between vertexes is 1", Long.valueOf(1), @@ -280,9 +288,21 @@ public class DbSerializer_needsFakeRulesTest { engine.startTransaction(); Vertex gvnf = engine.tx().addVertex("aai-node-type", "generic-vnf", "vnf-id", "myvnf", "aai-uri", - "/network/generic-vnfs/generic-vnf/myvnf"); + "/network/generic-vnfs/generic-vnf/myvnf", + AAIProperties.AAI_UUID, UUID.randomUUID().toString(), + AAIProperties.CREATED_TS, 123, + AAIProperties.SOURCE_OF_TRUTH, "sot", + AAIProperties.RESOURCE_VERSION, "123", + AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot", + AAIProperties.LAST_MOD_TS, 333); Vertex vnfc = engine.tx().addVertex("aai-node-type", "vnfc", "vnfc-name", "a-name", "aai-uri", - "/network/vnfcs/vnfc/a-name"); + "/network/vnfcs/vnfc/a-name", + AAIProperties.AAI_UUID, UUID.randomUUID().toString(), + AAIProperties.CREATED_TS, 123, + AAIProperties.SOURCE_OF_TRUTH, "sot", + AAIProperties.RESOURCE_VERSION, "123", + AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot", + AAIProperties.LAST_MOD_TS, 333); edgeSer.addEdge(graph.traversal(), gvnf, vnfc, "uses"); Introspector relData = loader.introspectorFromName("relationship-data"); @@ -297,7 +317,7 @@ public class DbSerializer_needsFakeRulesTest { relationship.setValue("relationship-label", "re-uses"); - assertTrue(localDbser.createEdge(relationship, gvnf)); + assertNotNull(dbser.createEdge(relationship, gvnf)); assertTrue(engine.tx().traversal().V(gvnf).both("re-uses").hasNext()); assertTrue(engine.tx().traversal().V(vnfc).both("re-uses").hasNext()); assertTrue(engine.tx().traversal().V(gvnf).both("uses").hasNext()); @@ -317,9 +337,21 @@ public class DbSerializer_needsFakeRulesTest { engine.startTransaction(); Vertex gvnf = engine.tx().addVertex("aai-node-type", "generic-vnf", "vnf-id", "myvnf", "aai-uri", - "/network/generic-vnfs/generic-vnf/myvnf"); + "/network/generic-vnfs/generic-vnf/myvnf", + AAIProperties.AAI_UUID, UUID.randomUUID().toString(), + AAIProperties.CREATED_TS, 123, + AAIProperties.SOURCE_OF_TRUTH, "sot", + AAIProperties.RESOURCE_VERSION, "123", + AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot", + AAIProperties.LAST_MOD_TS, 333); Vertex vnfc = engine.tx().addVertex("aai-node-type", "vnfc", "vnfc-name", "a-name", "aai-uri", - "/network/vnfcs/vnfc/a-name"); + "/network/vnfcs/vnfc/a-name", + AAIProperties.AAI_UUID, UUID.randomUUID().toString(), + AAIProperties.CREATED_TS, 123, + AAIProperties.SOURCE_OF_TRUTH, "sot", + AAIProperties.RESOURCE_VERSION, "123", + AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot", + AAIProperties.LAST_MOD_TS, 333); Introspector relData = loader.introspectorFromName("relationship-data"); relData.setValue("relationship-key", "vnfc.vnfc-name"); @@ -330,7 +362,7 @@ public class DbSerializer_needsFakeRulesTest { relationship.setValue("relationship-data", relData); localDbser.createEdge(relationship, gvnf); - assertTrue(localDbser.createEdge(relationship, gvnf)); + assertNotNull(dbser.createEdge(relationship, gvnf)); assertTrue(engine.tx().traversal().V(gvnf).both("uses").hasNext()); assertTrue(engine.tx().traversal().V(vnfc).both("uses").hasNext()); assertEquals("Number of edges between vertexes is 1", Long.valueOf(1), @@ -348,9 +380,21 @@ public class DbSerializer_needsFakeRulesTest { engine.startTransaction(); Vertex gvnf = engine.tx().addVertex("aai-node-type", "generic-vnf", "vnf-id", "myvnf", "aai-uri", - "/network/generic-vnfs/generic-vnf/myvnf"); + "/network/generic-vnfs/generic-vnf/myvnf", + AAIProperties.AAI_UUID, UUID.randomUUID().toString(), + AAIProperties.CREATED_TS, 123, + AAIProperties.SOURCE_OF_TRUTH, "sot", + AAIProperties.RESOURCE_VERSION, "123", + AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot", + AAIProperties.LAST_MOD_TS, 333); Vertex vnfc = engine.tx().addVertex("aai-node-type", "vnfc", "vnfc-name", "a-name", "aai-uri", - "/network/vnfcs/vnfc/a-name"); + "/network/vnfcs/vnfc/a-name", + AAIProperties.AAI_UUID, UUID.randomUUID().toString(), + AAIProperties.CREATED_TS, 123, + AAIProperties.SOURCE_OF_TRUTH, "sot", + AAIProperties.RESOURCE_VERSION, "123", + AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot", + AAIProperties.LAST_MOD_TS, 333); edgeSer.addEdge(graph.traversal(), gvnf, vnfc, "uses"); edgeSer.addEdge(graph.traversal(), gvnf, vnfc, "re-uses"); edgeSer.addEdge(graph.traversal(), gvnf, vnfc, "over-uses"); @@ -363,7 +407,7 @@ public class DbSerializer_needsFakeRulesTest { relationship.setValue("related-link", "/network/vnfcs/vnfc/a-name"); relationship.setValue("relationship-data", relData); - assertTrue(localDbser.deleteEdge(relationship, gvnf)); + assertTrue(localDbser.deleteEdge(relationship, gvnf).isPresent()); assertFalse("generic-vnf has no edge uses", engine.tx().traversal().V(gvnf).both("uses").hasNext()); assertFalse("vnfc has no edge uses", engine.tx().traversal().V(vnfc).both("uses").hasNext()); assertTrue("generic-vnf has edge re-uses", engine.tx().traversal().V(gvnf).both("re-uses").hasNext()); @@ -386,9 +430,21 @@ public class DbSerializer_needsFakeRulesTest { engine.startTransaction(); Vertex gvnf = engine.tx().addVertex("aai-node-type", "generic-vnf", "vnf-id", "myvnf", "aai-uri", - "/network/generic-vnfs/generic-vnf/myvnf"); + "/network/generic-vnfs/generic-vnf/myvnf", + AAIProperties.AAI_UUID, UUID.randomUUID().toString(), + AAIProperties.CREATED_TS, 123, + AAIProperties.SOURCE_OF_TRUTH, "sot", + AAIProperties.RESOURCE_VERSION, "123", + AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot", + AAIProperties.LAST_MOD_TS, 333); Vertex vnfc = engine.tx().addVertex("aai-node-type", "vnfc", "vnfc-name", "a-name", "aai-uri", - "/network/vnfcs/vnfc/a-name"); + "/network/vnfcs/vnfc/a-name", + AAIProperties.AAI_UUID, UUID.randomUUID().toString(), + AAIProperties.CREATED_TS, 123, + AAIProperties.SOURCE_OF_TRUTH, "sot", + AAIProperties.RESOURCE_VERSION, "123", + AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot", + AAIProperties.LAST_MOD_TS, 333); edgeSer.addEdge(graph.traversal(), gvnf, vnfc, "uses"); edgeSer.addEdge(graph.traversal(), gvnf, vnfc, "re-uses"); edgeSer.addEdge(graph.traversal(), gvnf, vnfc, "over-uses"); @@ -402,7 +458,7 @@ public class DbSerializer_needsFakeRulesTest { relationship.setValue("relationship-data", relData); relationship.setValue("relationship-label", "re-uses"); - assertTrue(localDbser.deleteEdge(relationship, gvnf)); + assertTrue(localDbser.deleteEdge(relationship, gvnf).isPresent()); assertTrue("generic-vnf has edge uses", engine.tx().traversal().V(gvnf).both("uses").hasNext()); assertTrue("vnfc has edge uses", engine.tx().traversal().V(vnfc).both("uses").hasNext()); assertFalse("generic-vnf has no edge re-uses", engine.tx().traversal().V(gvnf).both("re-uses").hasNext()); @@ -456,7 +512,12 @@ public class DbSerializer_needsFakeRulesTest { engine.startTransaction(); - engine.tx().addVertex("aai-node-type", "vnfc", "vnfc-name", "a-name", "aai-uri", "/network/vnfcs/vnfc/a-name"); + engine.tx().addVertex("aai-node-type", "vnfc", "vnfc-name", "a-name", "aai-uri", "/network/vnfcs/vnfc/a-name", "aai-uuid", "b", + AAIProperties.CREATED_TS, 123, + AAIProperties.SOURCE_OF_TRUTH, "sot", + AAIProperties.RESOURCE_VERSION, "123", + AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot", + AAIProperties.LAST_MOD_TS, 333); Introspector relationship = loader.introspectorFromName("relationship"); relationship.setValue("related-to", "vnfc"); @@ -505,7 +566,13 @@ public class DbSerializer_needsFakeRulesTest { engine.startTransaction(); - engine.tx().addVertex("aai-node-type", "vnfc", "vnfc-name", "a-name", "aai-uri", "/network/vnfcs/vnfc/a-name"); + engine.tx().addVertex("aai-node-type", "vnfc", "vnfc-name", "a-name", "aai-uri", "/network/vnfcs/vnfc/a-name", + AAIProperties.AAI_UUID, UUID.randomUUID().toString(), + AAIProperties.CREATED_TS, 123, + AAIProperties.SOURCE_OF_TRUTH, "sot", + AAIProperties.RESOURCE_VERSION, "123", + AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot", + AAIProperties.LAST_MOD_TS, 333); Introspector relationship = loader.introspectorFromName("relationship"); relationship.setValue("related-to", "vnfc"); @@ -585,7 +652,13 @@ public class DbSerializer_needsFakeRulesTest { DBSerializer localDbser = getDBSerializerWithSpecificEdgeRules(); engine.startTransaction(); - engine.tx().addVertex("aai-node-type", "vnfc", "vnfc-name", "a-name", "aai-uri", "/network/vnfcs/vnfc/a-name"); + engine.tx().addVertex("aai-node-type", "vnfc", "vnfc-name", "a-name", "aai-uri", "/network/vnfcs/vnfc/a-name", + AAIProperties.AAI_UUID, UUID.randomUUID().toString(), + AAIProperties.CREATED_TS, 123, + AAIProperties.SOURCE_OF_TRUTH, "sot", + AAIProperties.RESOURCE_VERSION, "123", + AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot", + AAIProperties.LAST_MOD_TS, 333); Introspector relationship; Introspector relationshipList; @@ -652,7 +725,13 @@ public class DbSerializer_needsFakeRulesTest { DBSerializer localDbser = getDBSerializerWithSpecificEdgeRules(); engine.startTransaction(); - engine.tx().addVertex("aai-node-type", "vnfc", "vnfc-name", "a-name", "aai-uri", "/network/vnfcs/vnfc/a-name"); + engine.tx().addVertex("aai-node-type", "vnfc", "vnfc-name", "a-name", "aai-uri", "/network/vnfcs/vnfc/a-name", + AAIProperties.AAI_UUID, UUID.randomUUID().toString(), + AAIProperties.CREATED_TS, 123, + AAIProperties.SOURCE_OF_TRUTH, "sot", + AAIProperties.RESOURCE_VERSION, "123", + AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, "lmsot", + AAIProperties.LAST_MOD_TS, 333); Introspector relationship; Introspector relationshipList; @@ -713,10 +792,8 @@ public class DbSerializer_needsFakeRulesTest { } - private DBSerializer getDBSerializerWithSpecificEdgeRules() - throws NoSuchFieldException, AAIException, IllegalAccessException { + private DBSerializer getDBSerializerWithSpecificEdgeRules() throws AAIException { - DBSerializer localDbser = new DBSerializer(version, engine, introspectorFactoryType, "AAI-TEST"); - return localDbser; + return new DBSerializer(version, engine, introspectorFactoryType, "AAI-TEST"); } } diff --git a/aai-core/src/test/java/org/onap/aai/serialization/db/EdgerPairCanBeBothCousinAndParentChildTest.java b/aai-core/src/test/java/org/onap/aai/serialization/db/EdgerPairCanBeBothCousinAndParentChildTest.java new file mode 100644 index 00000000..d00408e8 --- /dev/null +++ b/aai-core/src/test/java/org/onap/aai/serialization/db/EdgerPairCanBeBothCousinAndParentChildTest.java @@ -0,0 +1,234 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 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========================================================= + */ + +package org.onap.aai.serialization.db; + +import org.apache.tinkerpop.gremlin.structure.Graph; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.janusgraph.core.JanusGraphFactory; +import org.junit.*; +import org.junit.rules.ExpectedException; +import org.onap.aai.AAISetup; +import org.onap.aai.db.props.AAIProperties; +import org.onap.aai.edges.EdgeIngestor; +import org.onap.aai.exceptions.AAIException; +import org.onap.aai.introspection.Introspector; +import org.onap.aai.introspection.Loader; +import org.onap.aai.introspection.ModelType; +import org.onap.aai.parsers.query.QueryParser; +import org.onap.aai.serialization.engines.JanusGraphDBEngine; +import org.onap.aai.serialization.engines.QueryStyle; +import org.onap.aai.serialization.engines.TransactionalGraphEngine; +import org.onap.aai.setup.SchemaVersion; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.annotation.DirtiesContext; + +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Collections; + +import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath; +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS) +public class EdgerPairCanBeBothCousinAndParentChildTest extends AAISetup { + + // to use, set thrown.expect to whatever your test needs + // this line establishes default of expecting no exception to be thrown + @Rule + public ExpectedException thrown = ExpectedException.none(); + + protected static Graph graph; + + @Autowired + protected EdgeSerializer edgeSer; + @Autowired + protected EdgeIngestor ei; + + private SchemaVersion version; + private final ModelType introspectorFactoryType = ModelType.MOXY; + private Loader loader; + private TransactionalGraphEngine engine; + + public QueryStyle queryStyle = QueryStyle.TRAVERSAL_URI; + + public static final String SOURCE_OF_TRUTH = "EdgerPairCanBeBothCousinAndParentChildTest"; + private static final String gvnfAUri = "/network/generic-vnfs/generic-vnf/gvnf-a" + SOURCE_OF_TRUTH; + private static final String lagIntAUri = gvnfAUri + "/lag-interfaces/lag-interface/lagint-a"; + private static final String lintUri = lagIntAUri + "/l-interfaces/l-interface/lint"; + + private static final String gvnfBUri = "/network/generic-vnfs/generic-vnf/gvnf-b" + SOURCE_OF_TRUTH; + private static final String lagIntBUri = gvnfBUri + "/lag-interfaces/lag-interface/lagint-b"; + + @BeforeClass + public static void init() { + graph = JanusGraphFactory.build().set("storage.backend", "inmemory").open(); + + } + + @Before + public void setup() throws UnsupportedEncodingException, AAIException, URISyntaxException { + version = schemaVersions.getDefaultVersion(); + loader = loaderFactory.createLoaderForVersion(introspectorFactoryType, version); + engine = new JanusGraphDBEngine(queryStyle, loader); + initData(); + } + + @After + public void cleanup() { + engine.rollback(); + } + + /** + * Using latest version (see schema-ingest.properties) + * Create generic-vnf with lag-interface that has an l-interface + * Create generic-vnf with lag-interface relationship the l-interface + */ + private void initData() throws UnsupportedEncodingException, AAIException, URISyntaxException { + engine.startTransaction(); + DBSerializer serializer = new DBSerializer(version, engine, introspectorFactoryType, SOURCE_OF_TRUTH, AAIProperties.MINIMUM_DEPTH); + + + Introspector gvnf = loader.introspectorFromName("generic-vnf"); + gvnf.setValue("vnf-id", "gvnf-a" + SOURCE_OF_TRUTH); + gvnf.setValue("vnf-name", "gvnf" + SOURCE_OF_TRUTH + "-name"); + + Introspector lagInt = loader.introspectorFromName("lag-interface"); + lagInt.setValue("interface-name", "lagint-a"); + + Introspector lint = loader.introspectorFromName("l-interface"); + lint.setValue("interface-name", "lint"); + + Introspector lagints = loader.introspectorFromName("lag-interfaces"); + Introspector lints = loader.introspectorFromName("l-interfaces"); + + lints.setValue("l-interface", Collections.singletonList(lint.getUnderlyingObject())); + lagInt.setValue("l-interfaces", lints.getUnderlyingObject()); + lagints.setValue("lag-interface", Collections.singletonList(lagInt.getUnderlyingObject())); + gvnf.setValue("lag-interfaces", lagints.getUnderlyingObject()); + + + + Vertex gvnfV = serializer.createNewVertex(gvnf); + QueryParser uriQuery = engine.getQueryBuilder().createQueryFromURI(new URI(gvnfAUri)); + serializer.serializeToDb(gvnf, gvnfV, uriQuery, "generic-vnf", gvnf.marshal(false)); + + assertTrue("generic-vnf-a created", engine.tx().traversal().V() + .has(AAIProperties.AAI_URI, gvnfAUri) + .hasNext()); + assertTrue("lag-int-a created", engine.tx().traversal().V() + .has(AAIProperties.AAI_URI, lagIntAUri) + .hasNext()); + assertTrue("l-int created", engine.tx().traversal().V() + .has(AAIProperties.AAI_URI, lintUri) + .hasNext()); + + + + gvnf = loader.introspectorFromName("generic-vnf"); + gvnf.setValue("vnf-id", "gvnf-b" + SOURCE_OF_TRUTH); + gvnf.setValue("vnf-name", "gvnf" + SOURCE_OF_TRUTH + "-name"); + + lagInt = loader.introspectorFromName("lag-interface"); + lagInt.setValue("interface-name", "lagint-b"); + Introspector relationship = loader.introspectorFromName("relationship"); + relationship.setValue("related-link", lintUri); + Introspector relationshipList = loader.introspectorFromName("relationship-list"); + relationshipList.setValue("relationship", Collections.singletonList(relationship.getUnderlyingObject())); + lagInt.setValue("relationship-list", relationshipList.getUnderlyingObject()); + + lagints = loader.introspectorFromName("lag-interfaces"); + lagints.setValue("lag-interface", Collections.singletonList(lagInt.getUnderlyingObject())); + gvnf.setValue("lag-interfaces", lagints.getUnderlyingObject()); + + gvnfV = serializer.createNewVertex(gvnf); + uriQuery = engine.getQueryBuilder().createQueryFromURI(new URI(gvnfAUri)); + serializer.serializeToDb(gvnf, gvnfV, uriQuery, "generic-vnf", gvnf.marshal(false)); + + engine.tx().traversal().V().forEachRemaining(v -> System.out.println(v.<String>value(AAIProperties.AAI_URI))); + assertTrue("generic-vnf-b created", engine.tx().traversal().V() + .has(AAIProperties.AAI_URI, gvnfBUri) + .hasNext()); + assertTrue("lag-int-b created", engine.tx().traversal().V() + .has(AAIProperties.AAI_URI, lagIntBUri) + .hasNext()); + assertTrue("lag-interface relationship l-interface created", engine.tx().traversal().V() + .has(AAIProperties.AAI_URI, lagIntBUri) + .both() + .has(AAIProperties.AAI_URI, lintUri) + .hasNext()); + } + + + @Test + public void verifyReadOfGenericVnfATest() throws AAIException, UnsupportedEncodingException { + DBSerializer serializer = new DBSerializer(version, engine, introspectorFactoryType, SOURCE_OF_TRUTH, AAIProperties.MINIMUM_DEPTH); + + String gvnfALatestView = serializer.getLatestVersionView( + engine.tx().traversal().V().has(AAIProperties.AAI_URI, gvnfAUri).next()).marshal(false); + + assertThat(gvnfALatestView, + hasJsonPath( + "$.lag-interfaces.lag-interface[*]", + hasSize(1) + )); + assertThat(gvnfALatestView, + hasJsonPath( + "$.lag-interfaces.lag-interface[*].l-interfaces.l-interface[*]", + hasSize(1) + )); + assertThat(gvnfALatestView, + hasJsonPath( + "$.lag-interfaces.lag-interface[*].l-interfaces.l-interface[*].relationship-list.relationship[*].related-link", + containsInAnyOrder( + "/aai/" + schemaVersions.getDefaultVersion() + lagIntBUri + ) + )); + } + + @Test + public void verifyReadOfGenericVnfBTest() throws AAIException, UnsupportedEncodingException { + DBSerializer serializer = new DBSerializer(version, engine, introspectorFactoryType, SOURCE_OF_TRUTH, AAIProperties.MINIMUM_DEPTH); + + String gvnfBLatestView = serializer.getLatestVersionView( + engine.tx().traversal().V().has(AAIProperties.AAI_URI, gvnfBUri).next()).marshal(false); + + assertThat(gvnfBLatestView, + hasJsonPath( + "$.lag-interfaces.lag-interface[*]", + hasSize(1) + )); + assertThat(gvnfBLatestView, + not(hasJsonPath( + "$.lag-interfaces.lag-interface[*].l-interfaces.l-interface[*]" + ))); + assertThat(gvnfBLatestView, + hasJsonPath( + "$.lag-interfaces.lag-interface[*].relationship-list.relationship[*].related-link", + containsInAnyOrder( + "/aai/" + schemaVersions.getDefaultVersion() + lintUri + ) + )); + } + +} diff --git a/aai-core/src/test/java/org/onap/aai/serialization/db/ImpliedDeleteUnitTest.java b/aai-core/src/test/java/org/onap/aai/serialization/db/ImpliedDeleteUnitTest.java new file mode 100644 index 00000000..20e300a1 --- /dev/null +++ b/aai-core/src/test/java/org/onap/aai/serialization/db/ImpliedDeleteUnitTest.java @@ -0,0 +1,331 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 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========================================================= + */ +package org.onap.aai.serialization.db; + +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph; +import org.hamcrest.CoreMatchers; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.Matchers; +import org.mockito.Mockito; +import org.onap.aai.exceptions.AAIException; +import org.onap.aai.introspection.Introspector; +import org.onap.aai.serialization.engines.TransactionalGraphEngine; +import org.onap.aai.serialization.engines.query.QueryEngine; +import org.onap.aai.util.AAIConstants; +import org.springframework.boot.test.rule.OutputCapture; + +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.List; + +import static org.mockito.Matchers.eq; + +public class ImpliedDeleteUnitTest { + + private TransactionalGraphEngine mockEngine; + private DBSerializer mockSerializer; + + private ImpliedDelete impliedDelete; + + @Rule + public final OutputCapture outputCapture = new OutputCapture(); + + @Before + public void setup(){ + mockEngine = Mockito.mock(TransactionalGraphEngine.class); + mockSerializer = Mockito.mock(DBSerializer.class); + impliedDelete = Mockito.spy(new ImpliedDelete(mockEngine, mockSerializer)); + } + + // aai.implied.delete.whitelist.sdnc=* + @Test + public void testImpliedDeleteWhenUserIsAllowedToInvokeAnyMethod() throws AAIException { + + QueryEngine mockQueryEngine = Mockito.mock(QueryEngine.class); + + Mockito + .doReturn("*") + .when(impliedDelete) + .get(AAIConstants.AAI_IMPLIED_DELETE_WHITELIST + "sdnc",""); + + Mockito.when(mockEngine.getQueryEngine()).thenReturn(mockQueryEngine); + + TinkerGraph graph = TinkerGraph.open(); + + Vertex vserver = graph.addVertex("vertex"); + vserver.property("vserver-id", "some-id"); + + Vertex volume = graph.addVertex("vertex"); + volume.property("volume-id", "some-id"); + + List<Vertex> vertices = new ArrayList<>(); + vertices.add(volume); + + impliedDelete.execute(vserver.id(), "SDNC", "vserver", vertices); + + } + + // aai.implied.delete.whitelist.sdnc='vserver' + @Test + public void testImpliedDeleteWhenUserIsAllowedToInvokeCertainMethod() throws AAIException { + + QueryEngine mockQueryEngine = Mockito.mock(QueryEngine.class); + + Mockito + .doReturn("'vserver'") + .when(impliedDelete) + .get(AAIConstants.AAI_IMPLIED_DELETE_WHITELIST + "sdnc",""); + + Mockito.when(mockEngine.getQueryEngine()).thenReturn(mockQueryEngine); + + TinkerGraph graph = TinkerGraph.open(); + + Vertex vserver = graph.addVertex("vertex"); + vserver.property("vserver-id", "some-id"); + + Vertex volume = graph.addVertex("vertex"); + volume.property("volume-id", "some-id"); + + List<Vertex> vertices = new ArrayList<>(); + vertices.add(volume); + + impliedDelete.execute(vserver.id(), "SDNC", "vserver", vertices); + } + + // aai.implied.delete.whitelist.sdnc='vserver' + @Test + public void testImpliedDeleteWhenUserIsAllowedAndTryVariationsOfSOTValueSDNC() throws AAIException { + + QueryEngine mockQueryEngine = Mockito.mock(QueryEngine.class); + + Mockito + .doReturn("'vserver'") + .when(impliedDelete) + .get(AAIConstants.AAI_IMPLIED_DELETE_WHITELIST + "sdnc",""); + + Mockito.when(mockEngine.getQueryEngine()).thenReturn(mockQueryEngine); + + TinkerGraph graph = TinkerGraph.open(); + + Vertex vserver = graph.addVertex("vertex"); + vserver.property("vserver-id", "some-id"); + + Vertex volume = graph.addVertex("vertex"); + volume.property("volume-id", "some-id"); + + List<Vertex> vertices = new ArrayList<>(); + vertices.add(volume); + + impliedDelete.execute(vserver.id(), "SDNC", "vserver", vertices); + impliedDelete.execute(vserver.id(), "sDNC", "vserver", vertices); + impliedDelete.execute(vserver.id(), "sdNC", "vserver", vertices); + impliedDelete.execute(vserver.id(), "sdnC", "vserver", vertices); + impliedDelete.execute(vserver.id(), "sdnc", "vserver", vertices); + } + + // aai.implied.delete.whitelist.sdnc='vserver','vce','pserver' + @Test + public void testImpliedDeleteWhenUserIsAllowedToInvokeMultipleMethods() throws AAIException { + + QueryEngine mockQueryEngine = Mockito.mock(QueryEngine.class); + + Mockito + .doReturn("'vce','pserver','vserver','cloud-region'") + .when(impliedDelete) + .get(AAIConstants.AAI_IMPLIED_DELETE_WHITELIST + "sdnc",""); + + Mockito.when(mockEngine.getQueryEngine()).thenReturn(mockQueryEngine); + + TinkerGraph graph = TinkerGraph.open(); + + Vertex vserver = graph.addVertex("vertex"); + vserver.property("vserver-id", "some-id"); + + Vertex volume = graph.addVertex("vertex"); + volume.property("volume-id", "some-id"); + + List<Vertex> vertices = new ArrayList<>(); + vertices.add(volume); + + impliedDelete.execute(vserver.id(), "SDNC", "vserver", vertices); + } + + // aai.implied.delete.whitelist.sdnc='vserver','vce','pserver' + @Test + public void testImpliedDeleteWhenUserIsAllowedToInvokeMultipleMethodsAndDeletableReturnsMultipleVertexes() + throws AAIException, UnsupportedEncodingException { + + QueryEngine mockQueryEngine = Mockito.mock(QueryEngine.class); + + // On a spy the syntax should be doReturn => when => method to spy + // On a mock the syntax should be when => thenReturn|thenAnswer + Mockito + .doReturn("'vserver'") + .when(impliedDelete) + .get(AAIConstants.AAI_IMPLIED_DELETE_WHITELIST + "sdnc",""); + + + Introspector mockIntrospector = Mockito.mock(Introspector.class); + + Mockito.when(mockEngine.getQueryEngine()).thenReturn(mockQueryEngine); + + TinkerGraph graph = TinkerGraph.open(); + + Vertex vserver = graph.addVertex("vertex"); + vserver.property("vserver-id", "some-id"); + + Vertex volume1 = graph.addVertex("vertex"); + volume1.property("volume-id", "volume-1"); + + Vertex volume2 = graph.addVertex("vertex"); + volume1.property("volume-id", "volume-2"); + + Vertex volume3 = graph.addVertex("vertex"); + volume1.property("volume-id", "volume-3"); + + Vertex volume4 = graph.addVertex("vertex"); + volume1.property("volume-id", "volume-4"); + + List<Vertex> vertices = new ArrayList<>(); + + vertices.add(volume1); + vertices.add(volume2); + vertices.add(volume3); + vertices.add(volume4); + + Mockito + .when(mockQueryEngine.findDeletable(Mockito.anyList())) + .thenReturn(vertices); + + Mockito + .when(mockSerializer.getLatestVersionView(Mockito.anyObject())) + .thenReturn(mockIntrospector); + + Mockito + .when(mockIntrospector.marshal(false)) + .thenReturn("{\"volume-id\":\"volume-1\"}") + .thenReturn("{\"volume-id\":\"volume-2\"}") + .thenReturn("{\"volume-id\":\"volume-3\"}") + .thenReturn("{\"volume-id\":\"volume-4\"}"); + + impliedDelete.execute(vserver.id(), "SDNC", "vserver", vertices); + } + + // aai.implied.delete.whitelist.sdnc= + @Test(expected = AAIException.class) + public void testImpliedDeleteWhenUserIsNotAllowedToDelete() throws AAIException { + + QueryEngine mockQueryEngine = Mockito.mock(QueryEngine.class); + + Mockito + .doReturn("") + .when(impliedDelete) + .get(AAIConstants.AAI_IMPLIED_DELETE_WHITELIST + "sdnc",""); + + Mockito.when(mockEngine.getQueryEngine()).thenReturn(mockQueryEngine); + + TinkerGraph graph = TinkerGraph.open(); + + Vertex vserver = graph.addVertex("vertex"); + vserver.property("vserver-id", "some-id"); + + Vertex volume = graph.addVertex("vertex"); + volume.property("volume-id", "some-id"); + + List<Vertex> vertices = new ArrayList<>(); + vertices.add(volume); + + impliedDelete.execute(vserver.id(), "SDNC", "vserver", vertices); + } + + // aai.implied.delete.whitelist.sdnc='vce' + @Test(expected = AAIException.class) + public void testImpliedDeleteWhenUserIsAllowedToDeleteVceChildrenButRequestedToDeleteVserverChildren() throws AAIException { + + QueryEngine mockQueryEngine = Mockito.mock(QueryEngine.class); + + Mockito + .doReturn("'vce'") + .when(impliedDelete) + .get(AAIConstants.AAI_IMPLIED_DELETE_WHITELIST + "sdnc",""); + + Mockito.when(mockEngine.getQueryEngine()).thenReturn(mockQueryEngine); + + TinkerGraph graph = TinkerGraph.open(); + + Vertex vserver = graph.addVertex("vertex"); + vserver.property("vserver-id", "some-id"); + + Vertex volume = graph.addVertex("vertex"); + volume.property("volume-id", "some-id"); + + List<Vertex> vertices = new ArrayList<>(); + vertices.add(volume); + + impliedDelete.execute(vserver.id(), "SDNC", "vserver", vertices); + } + + @Test + public void testImpliedDeleteWhenUserIsAllowedToDeleteAndPrintingDeletingVertexItThrowsExceptionVerifyLog() throws AAIException, UnsupportedEncodingException { + + QueryEngine mockQueryEngine = Mockito.mock(QueryEngine.class); + + // On a spy the syntax should be doReturn => when => method to spy + // On a mock the syntax should be when => thenReturn|thenAnswer + Mockito + .doReturn("'vserver'") + .when(impliedDelete) + .get(AAIConstants.AAI_IMPLIED_DELETE_WHITELIST + "sdnc",""); + + + Introspector mockIntrospector = Mockito.mock(Introspector.class); + + Mockito.when(mockEngine.getQueryEngine()).thenReturn(mockQueryEngine); + + TinkerGraph graph = TinkerGraph.open(); + + Vertex vserver = graph.addVertex("vertex"); + vserver.property("vserver-id", "some-id"); + + Vertex volume1 = graph.addVertex("vertex"); + volume1.property("volume-id", "volume-1"); + + List<Vertex> vertices = new ArrayList<>(); + + vertices.add(volume1); + + Mockito + .when(mockQueryEngine.findDeletable(Mockito.anyList())) + .thenReturn(vertices); + + Mockito + .when(mockSerializer.getLatestVersionView(Mockito.anyObject())) + .thenThrow(new RuntimeException("Unable to find node")); + + impliedDelete.execute(vserver.id(), "SDNC", "vserver", vertices); + + outputCapture.expect( + CoreMatchers.containsString("Encountered an exception during retrieval of vertex properties with vertex-id " + vserver.id()) + ); + } +} diff --git a/aai-core/src/test/java/org/onap/aai/serialization/db/OneToOneEdgeUpdateTest.java b/aai-core/src/test/java/org/onap/aai/serialization/db/OneToOneEdgeUpdateTest.java new file mode 100644 index 00000000..0c90c735 --- /dev/null +++ b/aai-core/src/test/java/org/onap/aai/serialization/db/OneToOneEdgeUpdateTest.java @@ -0,0 +1,300 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 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========================================================= + */ + +package org.onap.aai.serialization.db; + +import org.apache.tinkerpop.gremlin.structure.Graph; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.janusgraph.core.JanusGraphFactory; +import org.junit.*; +import org.junit.rules.ExpectedException; +import org.onap.aai.AAISetup; +import org.onap.aai.db.props.AAIProperties; +import org.onap.aai.edges.EdgeIngestor; +import org.onap.aai.exceptions.AAIException; +import org.onap.aai.introspection.Introspector; +import org.onap.aai.introspection.Loader; +import org.onap.aai.introspection.ModelType; +import org.onap.aai.parsers.query.QueryParser; +import org.onap.aai.serialization.engines.JanusGraphDBEngine; +import org.onap.aai.serialization.engines.QueryStyle; +import org.onap.aai.serialization.engines.TransactionalGraphEngine; +import org.onap.aai.setup.SchemaVersion; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.annotation.DirtiesContext; + +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Arrays; +import java.util.Collections; + +import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath; +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; + +@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS) +public class OneToOneEdgeUpdateTest extends AAISetup { + + // to use, set thrown.expect to whatever your test needs + // this line establishes default of expecting no exception to be thrown + @Rule + public ExpectedException thrown = ExpectedException.none(); + + protected static Graph graph; + + @Autowired + protected EdgeSerializer edgeSer; + @Autowired + protected EdgeIngestor ei; + + private SchemaVersion version; + private final ModelType introspectorFactoryType = ModelType.MOXY; + private Loader loader; + private TransactionalGraphEngine engine; + + public QueryStyle queryStyle = QueryStyle.TRAVERSAL_URI; + + public static final String SOURCE_OF_TRUTH = "EdgerPairCanBeBothCousinAndParentChildTest"; + private static final String gvnfAUri = "/network/generic-vnfs/generic-vnf/gvnf-a" + SOURCE_OF_TRUTH; + private static final String lintUri = gvnfAUri + "/l-interfaces/l-interface/lint"; + private static final String lintAUri = gvnfAUri + "/l-interfaces/l-interface/lint-a"; + private static final String sriovVfUri = lintUri + "/sriov-vfs/sriov-vf/sriov-vf"; + private static final String sriovVfAUri = lintAUri + "/sriov-vfs/sriov-vf/sriov-vf-a"; + + private static final String gvnfBUri = "/network/generic-vnfs/generic-vnf/gvnf-b" + SOURCE_OF_TRUTH; + private static final String lIntBUri = gvnfBUri + "/l-interfaces/l-interface/lint-b"; + + @BeforeClass + public static void init() { + graph = JanusGraphFactory.build().set("storage.backend", "inmemory").open(); + + } + + @Before + public void setup() throws UnsupportedEncodingException, AAIException, URISyntaxException { + version = schemaVersions.getDefaultVersion(); + loader = loaderFactory.createLoaderForVersion(introspectorFactoryType, version); + engine = new JanusGraphDBEngine(queryStyle, loader); + initData(); + } + + @After + public void cleanup() { + engine.rollback(); + } + + /** + * Using latest version (see schema-ingest.properties) - sriov-vf to l-interface is one ot one + * Create generic-vnf with l-interface that has an sriov-vf + * Create generic-vnf with l-interface relationship the sriov-vf + */ + private void initData() throws UnsupportedEncodingException, AAIException, URISyntaxException { + engine.startTransaction(); + DBSerializer serializer = new DBSerializer(version, engine, introspectorFactoryType, SOURCE_OF_TRUTH, AAIProperties.MINIMUM_DEPTH); + + + Introspector gvnf = loader.introspectorFromName("generic-vnf"); + gvnf.setValue("vnf-id", "gvnf-a" + SOURCE_OF_TRUTH); + gvnf.setValue("vnf-name", "gvnf" + SOURCE_OF_TRUTH + "-name"); + + Introspector lint = loader.introspectorFromName("l-interface"); + lint.setValue("interface-name", "lint"); + + Introspector sriovVf = loader.introspectorFromName("sriov-vf"); + sriovVf.setValue("pci-id", "sriov-vf"); + + Introspector sriovVfs = loader.introspectorFromName("sriov-vfs"); + sriovVfs.setValue("sriov-vf", Collections.singletonList(sriovVf.getUnderlyingObject())); + lint.setValue("sriov-vfs", sriovVfs.getUnderlyingObject()); + + Introspector lintA = loader.introspectorFromName("l-interface"); + lintA.setValue("interface-name", "lint-a"); + + Introspector sriovVfA = loader.introspectorFromName("sriov-vf"); + sriovVfA.setValue("pci-id", "sriov-vf-a"); + + sriovVfs = loader.introspectorFromName("sriov-vfs"); + sriovVfs.setValue("sriov-vf", Collections.singletonList(sriovVfA.getUnderlyingObject())); + lintA.setValue("sriov-vfs", sriovVfs.getUnderlyingObject()); + + Introspector lints = loader.introspectorFromName("l-interfaces"); + lints.setValue("l-interface", Arrays.asList(lint.getUnderlyingObject(), lintA.getUnderlyingObject())); + gvnf.setValue("l-interfaces", lints.getUnderlyingObject()); + + + System.out.println(gvnf.marshal(true)); + Vertex gvnfV = serializer.createNewVertex(gvnf); + QueryParser uriQuery = engine.getQueryBuilder().createQueryFromURI(new URI(gvnfAUri)); + serializer.serializeToDb(gvnf, gvnfV, uriQuery, "generic-vnf", gvnf.marshal(false)); + + assertTrue("generic-vnf-a created", engine.tx().traversal().V() + .has(AAIProperties.AAI_URI, gvnfAUri) + .hasNext()); + assertTrue("l-int created", engine.tx().traversal().V() + .has(AAIProperties.AAI_URI, lintUri) + .hasNext()); + assertTrue("l-int-a created", engine.tx().traversal().V() + .has(AAIProperties.AAI_URI, lintAUri) + .hasNext()); + assertTrue("sriov-vf created", engine.tx().traversal().V() + .has(AAIProperties.AAI_URI, sriovVfUri) + .hasNext()); + assertTrue("sriov-vf-a created", engine.tx().traversal().V() + .has(AAIProperties.AAI_URI, sriovVfAUri) + .hasNext()); + + + gvnf = loader.introspectorFromName("generic-vnf"); + gvnf.setValue("vnf-id", "gvnf-b" + SOURCE_OF_TRUTH); + gvnf.setValue("vnf-name", "gvnf" + SOURCE_OF_TRUTH + "-name"); + + lint = loader.introspectorFromName("l-interface"); + lint.setValue("interface-name", "lint-b"); + Introspector relationship = loader.introspectorFromName("relationship"); + relationship.setValue("related-link", sriovVfUri); + Introspector relationshipList = loader.introspectorFromName("relationship-list"); + relationshipList.setValue("relationship", Collections.singletonList(relationship.getUnderlyingObject())); + lint.setValue("relationship-list", relationshipList.getUnderlyingObject()); + + lints = loader.introspectorFromName("l-interfaces"); + lints.setValue("l-interface", Collections.singletonList(lint.getUnderlyingObject())); + gvnf.setValue("l-interfaces", lints.getUnderlyingObject()); + + gvnfV = serializer.createNewVertex(gvnf); + uriQuery = engine.getQueryBuilder().createQueryFromURI(new URI(gvnfAUri)); + serializer.serializeToDb(gvnf, gvnfV, uriQuery, "generic-vnf", gvnf.marshal(false)); + + engine.tx().traversal().V().forEachRemaining(v -> System.out.println(v.<String>value(AAIProperties.AAI_URI))); + assertTrue("generic-vnf-b created", engine.tx().traversal().V() + .has(AAIProperties.AAI_URI, gvnfBUri) + .hasNext()); + assertTrue("l-int-b created", engine.tx().traversal().V() + .has(AAIProperties.AAI_URI, lIntBUri) + .hasNext()); + assertTrue("l-interface relationship sriov-vf created", engine.tx().traversal().V() + .has(AAIProperties.AAI_URI, lIntBUri) + .both() + .has(AAIProperties.AAI_URI, sriovVfUri) + .hasNext()); + + } + + + @Test + public void verifyReadOfGenericVnfATest() throws AAIException, UnsupportedEncodingException { + DBSerializer serializer = new DBSerializer(version, engine, introspectorFactoryType, SOURCE_OF_TRUTH, AAIProperties.MINIMUM_DEPTH); + + String gvnfALatestView = serializer.getLatestVersionView( + engine.tx().traversal().V().has(AAIProperties.AAI_URI, gvnfAUri).next()).marshal(false); + + assertThat(gvnfALatestView, + hasJsonPath( + "$.l-interfaces.l-interface[*]", + hasSize(2) + )); + assertThat(gvnfALatestView, + hasJsonPath( + "$.l-interfaces.l-interface[*].sriov-vfs.sriov-vf[*]", + hasSize(2) + )); + assertThat(gvnfALatestView, + hasJsonPath( + "$.l-interfaces.l-interface[*].sriov-vfs.sriov-vf[*].relationship-list.relationship[*].related-link", + containsInAnyOrder( + "/aai/" + schemaVersions.getDefaultVersion() + lIntBUri + ) + )); + } + + @Test + public void verifyReadOfGenericVnfBTest() throws AAIException, UnsupportedEncodingException { + DBSerializer serializer = new DBSerializer(version, engine, introspectorFactoryType, SOURCE_OF_TRUTH, AAIProperties.MINIMUM_DEPTH); + + String gvnfBLatestView = serializer.getLatestVersionView( + engine.tx().traversal().V().has(AAIProperties.AAI_URI, gvnfBUri).next()).marshal(false); + + assertThat(gvnfBLatestView, + hasJsonPath( + "$.l-interfaces.l-interface[*]", + hasSize(1) + )); + assertThat(gvnfBLatestView, + not(hasJsonPath( + "$.l-interfaces.l-interface[*].sriov-vfs.sriov-vf[*]" + ))); + assertThat(gvnfBLatestView, + hasJsonPath( + "$.l-interfaces.l-interface[*].relationship-list.relationship[*].related-link", + containsInAnyOrder( + "/aai/" + schemaVersions.getDefaultVersion() + sriovVfUri + ) + )); + } + + @Test + public void replaceRelationshipToSriovVfTest() throws AAIException, UnsupportedEncodingException, URISyntaxException { + DBSerializer serializer = new DBSerializer(version, engine, introspectorFactoryType, SOURCE_OF_TRUTH, AAIProperties.MINIMUM_DEPTH); + + Introspector lint = serializer.getLatestVersionView( + engine.tx().traversal().V().has(AAIProperties.AAI_URI, lIntBUri).next()); + String lintView = lint.marshal(false); + + assertThat(lintView, + hasJsonPath( + "$.relationship-list.relationship[*].related-link", + containsInAnyOrder( + "/aai/" + schemaVersions.getDefaultVersion() + sriovVfUri + ) + )); + + Introspector relationship = loader.introspectorFromName("relationship"); + relationship.setValue("related-link", sriovVfAUri); + Introspector relationshipList = loader.introspectorFromName("relationship-list"); + relationshipList.setValue("relationship", Collections.singletonList(relationship.getUnderlyingObject())); + lint.setValue("relationship-list", relationshipList.getUnderlyingObject()); + + QueryParser uriQuery = engine.getQueryBuilder().createQueryFromURI(new URI(lIntBUri)); + serializer.serializeToDb(lint, engine.tx().traversal().V().has(AAIProperties.AAI_URI, lIntBUri).next(), + uriQuery, "generic-vnf", lint.marshal(false)); + } + + + @Test + public void createRelationshipForNonExistentRuleTest() throws AAIException, UnsupportedEncodingException, URISyntaxException { + DBSerializer serializer = new DBSerializer(version, engine, introspectorFactoryType, SOURCE_OF_TRUTH, AAIProperties.MINIMUM_DEPTH); + + Vertex gvnfAV = engine.tx().traversal().V().has(AAIProperties.AAI_URI, gvnfAUri).next(); + Introspector gvnfA = serializer.getLatestVersionView(gvnfAV); + Introspector relationship = loader.introspectorFromName("relationship"); + relationship.setValue("related-link", gvnfBUri); + Introspector relationshipList = loader.introspectorFromName("relationship-list"); + relationshipList.setValue("relationship", Collections.singletonList(relationship.getUnderlyingObject())); + gvnfA.setValue("relationship-list", relationshipList.getUnderlyingObject()); + QueryParser uriQuery = engine.getQueryBuilder().createQueryFromURI(new URI(gvnfAUri)); + try { + serializer.serializeToDb(gvnfA, gvnfAV, uriQuery, "generic-vnf", gvnfA.marshal(false)); + } catch (AAIException e) { + assertEquals("AAI_6120", e.getCode()); + assertThat(e.getMessage(), containsString("generic-vnf")); + } + } + +} diff --git a/aai-core/src/test/java/org/onap/aai/serialization/db/VersionedScenariosTest.java b/aai-core/src/test/java/org/onap/aai/serialization/db/VersionedScenariosTest.java new file mode 100644 index 00000000..8e77c549 --- /dev/null +++ b/aai-core/src/test/java/org/onap/aai/serialization/db/VersionedScenariosTest.java @@ -0,0 +1,426 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 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========================================================= + */ + +package org.onap.aai.serialization.db; + +import org.apache.tinkerpop.gremlin.structure.Graph; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.janusgraph.core.JanusGraphFactory; +import org.junit.*; +import org.junit.rules.ExpectedException; +import org.onap.aai.AAISetup; +import org.onap.aai.db.props.AAIProperties; +import org.onap.aai.edges.EdgeIngestor; +import org.onap.aai.exceptions.AAIException; +import org.onap.aai.introspection.Introspector; +import org.onap.aai.introspection.Loader; +import org.onap.aai.introspection.ModelType; +import org.onap.aai.parsers.query.QueryParser; +import org.onap.aai.serialization.engines.JanusGraphDBEngine; +import org.onap.aai.serialization.engines.QueryStyle; +import org.onap.aai.serialization.engines.TransactionalGraphEngine; +import org.onap.aai.setup.SchemaVersion; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.annotation.DirtiesContext; + +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath; +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS) +public class VersionedScenariosTest extends AAISetup { + + // to use, set thrown.expect to whatever your test needs + // this line establishes default of expecting no exception to be thrown + @Rule + public ExpectedException thrown = ExpectedException.none(); + + protected static Graph graph; + + @Autowired + protected EdgeSerializer edgeSer; + @Autowired + protected EdgeIngestor ei; + + private SchemaVersion version; + private final ModelType introspectorFactoryType = ModelType.MOXY; + private Loader loader; + private TransactionalGraphEngine engine; + + public QueryStyle queryStyle = QueryStyle.TRAVERSAL_URI; + + public static final String SOURCE_OF_TRUTH = "VersionedScenariosTest"; + private static final String gvnfUri = "/network/generic-vnfs/generic-vnf/gvnf" + SOURCE_OF_TRUTH; + private static final String llDefaultUri = "/network/logical-links/logical-link/llDefault"; + private static final String lintSourceUri = gvnfUri + "/l-interfaces/l-interface/source"; + private static final String lintDestinationUri = gvnfUri + "/l-interfaces/l-interface/destination"; + private static final String llLabeledUri = "/network/logical-links/logical-link/llLabeled"; + + @BeforeClass + public static void init() { + graph = JanusGraphFactory.build().set("storage.backend", "inmemory").open(); + + } + + @Before + public void setup() throws UnsupportedEncodingException, AAIException, URISyntaxException { + version = schemaVersions.getDefaultVersion(); + loader = loaderFactory.createLoaderForVersion(introspectorFactoryType, version); + engine = new JanusGraphDBEngine(queryStyle, loader); + initData(); + } + + @After + public void cleanup() { + engine.rollback(); + } + + /** + * Using latest version (see schema-ingest.properties) + * Create generic-vnf with l-interfaces source, destination + * Create logical-link with relationship to interfaces source, destination (will use the default labels) + * Create logical-link with relationship to interfaces source, destination with specific labels + */ + private void initData() throws UnsupportedEncodingException, AAIException, URISyntaxException { + engine.startTransaction(); + DBSerializer serializer = new DBSerializer(version, engine, introspectorFactoryType, SOURCE_OF_TRUTH, AAIProperties.MINIMUM_DEPTH); + + + Introspector gvnf = loader.introspectorFromName("generic-vnf"); + gvnf.setValue("vnf-id", "gvnf" + SOURCE_OF_TRUTH); + gvnf.setValue("vnf-name", "gvnf" + SOURCE_OF_TRUTH + "-name"); + + Introspector lintSource = loader.introspectorFromName("l-interface"); + lintSource.setValue("interface-name", "source"); + + Introspector lintDestination = loader.introspectorFromName("l-interface"); + lintDestination.setValue("interface-name", "destination"); + + List<Object> lIntList = new ArrayList<>(); + lIntList.add(lintSource.getUnderlyingObject()); + lIntList.add(lintDestination.getUnderlyingObject()); + Introspector lints = loader.introspectorFromName("l-interfaces"); + lints.setValue("l-interface", lIntList); + gvnf.setValue("l-interfaces", lints.getUnderlyingObject()); + + Vertex gvnfV = serializer.createNewVertex(gvnf); + QueryParser uriQuery = engine.getQueryBuilder().createQueryFromURI(new URI(gvnfUri)); + serializer.serializeToDb(gvnf, gvnfV, uriQuery, "generic-vnf", gvnf.marshal(false)); + + assertTrue("generic-vnf created", engine.tx().traversal().V() + .has(AAIProperties.AAI_URI, gvnfUri) + .hasNext()); + assertTrue("source created", engine.tx().traversal().V() + .has(AAIProperties.AAI_URI, lintSourceUri) + .hasNext()); + assertTrue("destination created", engine.tx().traversal().V() + .has(AAIProperties.AAI_URI, lintDestinationUri) + .hasNext()); + + + + Introspector llDefault = loader.introspectorFromName("logical-link"); + llDefault.setValue("link-name", "llDefault"); + List<Object> relList = new ArrayList<>(); + Introspector relationship = loader.introspectorFromName("relationship"); + //relationship.setValue("related-to", "l-interface"); + relationship.setValue("related-link", lintSourceUri); + relList.add(relationship.getUnderlyingObject()); + relationship = loader.introspectorFromName("relationship"); + //relationship.setValue("related-to", "l-interface"); + relationship.setValue("related-link", lintDestinationUri); + relList.add(relationship.getUnderlyingObject()); + Introspector relationshipList = loader.introspectorFromName("relationship-list"); + relationshipList.setValue("relationship", relList); + llDefault.setValue("relationship-list", relationshipList.getUnderlyingObject()); + + Vertex llDefaultV = serializer.createNewVertex(llDefault); + uriQuery = engine.getQueryBuilder().createQueryFromURI(new URI(llDefaultUri)); + serializer.serializeToDb(llDefault, llDefaultV, uriQuery, "logical-link", llDefault.marshal(false)); + + assertTrue("logical-link created", engine.tx().traversal().V() + .has(AAIProperties.AAI_URI, llDefaultUri) + .hasNext()); + assertTrue("default source relationship created",engine.tx().traversal().V() + .has(AAIProperties.AAI_URI, llDefaultUri) + .both() + .has(AAIProperties.AAI_URI, lintSourceUri) + .hasNext()); + assertTrue("default destination relationship created", engine.tx().traversal().V() + .has(AAIProperties.AAI_URI, llDefaultUri) + .both() + .has(AAIProperties.AAI_URI, lintDestinationUri) + .hasNext()); + + + Introspector llLabeled = loader.introspectorFromName("logical-link"); + llLabeled.setValue("link-name", "llLabeled"); + relList = new ArrayList<>(); + relationship = loader.introspectorFromName("relationship"); + relationship.setValue("related-to", "l-interface"); + relationship.setValue("relationship-label", "org.onap.relationships.inventory.Source"); + relationship.setValue("related-link", lintSourceUri); + relList.add(relationship.getUnderlyingObject()); + relationship = loader.introspectorFromName("relationship"); + relationship.setValue("related-to", "l-interface"); + relationship.setValue("relationship-label", "org.onap.relationships.inventory.Destination"); + relationship.setValue("related-link", lintDestinationUri); + relList.add(relationship.getUnderlyingObject()); + relationshipList = loader.introspectorFromName("relationship-list"); + relationshipList.setValue("relationship", relList); + llLabeled.setValue("relationship-list", relationshipList.getUnderlyingObject()); + + Vertex llLabeledV = serializer.createNewVertex(llLabeled); + uriQuery = engine.getQueryBuilder().createQueryFromURI(new URI(llLabeledUri)); + serializer.serializeToDb(llLabeled, llLabeledV, uriQuery, "logical-link", llLabeled.marshal(false)); + + assertTrue("logical-link created", engine.tx().traversal().V() + .has(AAIProperties.AAI_URI, llLabeledUri) + .hasNext()); + assertTrue("labeled source relationship created",engine.tx().traversal().V() + .has(AAIProperties.AAI_URI, llLabeledUri) + .both("org.onap.relationships.inventory.Source") + .has(AAIProperties.AAI_URI, lintSourceUri) + .hasNext()); + assertTrue("labeled destination relationship created", engine.tx().traversal().V() + .has(AAIProperties.AAI_URI, llLabeledUri) + .both("org.onap.relationships.inventory.Destination") + .has(AAIProperties.AAI_URI, lintDestinationUri) + .hasNext()); + } + + + @Test + public void verifyRelsOfLatestViewOfGenericVnf() throws AAIException, UnsupportedEncodingException { + DBSerializer serializer = new DBSerializer(version, engine, introspectorFactoryType, SOURCE_OF_TRUTH, AAIProperties.MINIMUM_DEPTH); + + String gvnfLatestView = serializer.getLatestVersionView( + engine.tx().traversal().V().has(AAIProperties.AAI_URI, gvnfUri).next()).marshal(false); + assertThat(gvnfLatestView, + hasJsonPath( + "$.l-interfaces.l-interface[*].relationship-list.relationship[*]", + hasSize(4) + )); + assertThat(gvnfLatestView, + hasJsonPath( + "$.l-interfaces.l-interface[*].relationship-list.relationship[*].related-link", + containsInAnyOrder( + "/aai/" + schemaVersions.getDefaultVersion() + llDefaultUri, + "/aai/" + schemaVersions.getDefaultVersion() + llDefaultUri, + "/aai/" + schemaVersions.getDefaultVersion() + llLabeledUri, + "/aai/" + schemaVersions.getDefaultVersion() + llLabeledUri + ) + )); + assertThat(gvnfLatestView, + hasJsonPath( + "$.l-interfaces.l-interface[*].relationship-list.relationship[*].relationship-label", + containsInAnyOrder( + "tosca.relationships.network.LinksTo", + "tosca.relationships.network.LinksTo", + "org.onap.relationships.inventory.Source", + "org.onap.relationships.inventory.Destination") + )); + } + + @Test + public void verifyRelsOfLatestViewOfLLDefault() throws AAIException, UnsupportedEncodingException { + DBSerializer serializer = new DBSerializer(version, engine, introspectorFactoryType, SOURCE_OF_TRUTH, AAIProperties.MINIMUM_DEPTH); + + String llDefaultLatestView = serializer.getLatestVersionView( + engine.tx().traversal().V().has(AAIProperties.AAI_URI, llDefaultUri).next()).marshal(false); + assertThat(llDefaultLatestView, + hasJsonPath( + "$.relationship-list.relationship[*]", + hasSize(2) + )); + assertThat(llDefaultLatestView, + hasJsonPath( + "$.relationship-list.relationship[*].related-link", + containsInAnyOrder( + "/aai/" + schemaVersions.getDefaultVersion() + lintSourceUri, + "/aai/" + schemaVersions.getDefaultVersion() + lintDestinationUri + ) + )); + assertThat(llDefaultLatestView, + hasJsonPath( + "$.relationship-list.relationship[*].relationship-label", + containsInAnyOrder("tosca.relationships.network.LinksTo","tosca.relationships.network.LinksTo") + )); + assertThat(llDefaultLatestView, + hasJsonPath( + "$.relationship-list.relationship[*].relationship-label", + not(contains("org.onap.relationships.inventory.Source", "org.onap.relationships.inventory.Destination")) + )); + + } + + @Test + public void verifyRelsOfLatestViewOfLLLabeled() throws AAIException, UnsupportedEncodingException { + DBSerializer serializer = new DBSerializer(version, engine, introspectorFactoryType, SOURCE_OF_TRUTH, AAIProperties.MINIMUM_DEPTH); + + String llLabeledLatestView = serializer.getLatestVersionView( + engine.tx().traversal().V().has(AAIProperties.AAI_URI, llLabeledUri).next()).marshal(false); + assertThat(llLabeledLatestView, + hasJsonPath( + "$.relationship-list.relationship[*]", + hasSize(2) + )); + assertThat(llLabeledLatestView, + hasJsonPath( + "$.relationship-list.relationship[*].related-link", + containsInAnyOrder( + "/aai/" + schemaVersions.getDefaultVersion() + lintSourceUri, + "/aai/" + schemaVersions.getDefaultVersion() + lintDestinationUri + ) + )); + assertThat(llLabeledLatestView, + hasJsonPath( + "$.relationship-list.relationship[*].relationship-label", + not(containsInAnyOrder("tosca.relationships.network.LinksTo","tosca.relationships.network.LinksTo")) + )); + assertThat(llLabeledLatestView, + hasJsonPath( + "$.relationship-list.relationship[*].relationship-label", + contains("org.onap.relationships.inventory.Source", "org.onap.relationships.inventory.Destination") + )); + + } + + + @Test + public void verifyRelsOfOldViewOfGenericVnf() throws AAIException, UnsupportedEncodingException { + SchemaVersion oldVersion = new SchemaVersion("v11"); + Loader oldLoader = loaderFactory.getLoaderStrategy(introspectorFactoryType, oldVersion); + DBSerializer oldSerializer = new DBSerializer(oldVersion, engine, introspectorFactoryType, SOURCE_OF_TRUTH, AAIProperties.MINIMUM_DEPTH); + + String gvnfOldView = oldSerializer.dbToObject( + Collections.singletonList(engine.tx().traversal().V().has(AAIProperties.AAI_URI, gvnfUri).next()), + oldLoader.introspectorFromName("generic-vnf"), + AAIProperties.MAXIMUM_DEPTH, false, "false") + .marshal(false); + assertThat(gvnfOldView, + hasJsonPath( + "$.l-interfaces.l-interface[*].relationship-list.relationship[*]", + hasSize(2) + )); + assertThat(gvnfOldView, + hasJsonPath( + "$.l-interfaces.l-interface[*].relationship-list.relationship[*].relationship-label", + emptyCollectionOf(String.class) + )); + assertThat(gvnfOldView, + hasJsonPath( + "$.l-interfaces.l-interface[*].relationship-list.relationship[*].related-link", + containsInAnyOrder( + "/aai/" + oldVersion + llDefaultUri, + "/aai/" + oldVersion + llDefaultUri + ) + )); + } + + @Test + public void verifyRelsOfOldViewOfLLDefault() throws AAIException, UnsupportedEncodingException { + SchemaVersion oldVersion = new SchemaVersion("v11"); + Loader oldLoader = loaderFactory.getLoaderStrategy(introspectorFactoryType, oldVersion); + DBSerializer oldSerializer = new DBSerializer(oldVersion, engine, introspectorFactoryType, SOURCE_OF_TRUTH, AAIProperties.MINIMUM_DEPTH); + + String llDefaultOldView = oldSerializer.dbToObject( + Collections.singletonList(engine.tx().traversal().V().has(AAIProperties.AAI_URI, llDefaultUri).next()), + oldLoader.introspectorFromName("logical-link"), + AAIProperties.MAXIMUM_DEPTH, false, "false") + .marshal(false); + assertThat(llDefaultOldView, + hasJsonPath( + "$.relationship-list.relationship[*]", + hasSize(2) + )); + assertThat(llDefaultOldView, + hasJsonPath( + "$.relationship-list.relationship[*].relationship-label", + emptyCollectionOf(String.class) + )); + assertThat(llDefaultOldView, + hasJsonPath( + "$.relationship-list.relationship[*].related-link", + containsInAnyOrder( + "/aai/" + oldVersion + lintSourceUri, + "/aai/" + oldVersion + lintDestinationUri + ) + )); + + } + + @Test + public void verifyRelsOfOldViewOfLLLabeled() throws AAIException, UnsupportedEncodingException { + SchemaVersion oldVersion = new SchemaVersion("v11"); + Loader oldLoader = loaderFactory.getLoaderStrategy(introspectorFactoryType, oldVersion); + DBSerializer oldSerializer = new DBSerializer(oldVersion, engine, introspectorFactoryType, SOURCE_OF_TRUTH, AAIProperties.MINIMUM_DEPTH); + + String llLabeledtOldView = oldSerializer.dbToObject( + Collections.singletonList(engine.tx().traversal().V().has(AAIProperties.AAI_URI, llLabeledUri).next()), + oldLoader.introspectorFromName("logical-link"), + AAIProperties.MAXIMUM_DEPTH, false, "false") + .marshal(false); + assertThat(llLabeledtOldView, + not(hasJsonPath( + "$.relationship-list.relationship[*]" + ))); + } + + + @Test + public void useOldVersionToUpdatedGenericVnfAndVerifyLatestVersionRels() throws AAIException, UnsupportedEncodingException, URISyntaxException { + SchemaVersion oldVersion = new SchemaVersion("v11"); + Loader oldLoader = loaderFactory.getLoaderStrategy(introspectorFactoryType, oldVersion); + DBSerializer oldSerializer = new DBSerializer(oldVersion, engine, introspectorFactoryType, SOURCE_OF_TRUTH, AAIProperties.MINIMUM_DEPTH); + + Vertex oldGvnfV = engine.tx().traversal().V().has(AAIProperties.AAI_URI, gvnfUri).next(); + Introspector oldGvnf = oldSerializer.dbToObject( + Collections.singletonList(oldGvnfV), + oldLoader.introspectorFromName("generic-vnf"), + AAIProperties.MAXIMUM_DEPTH, false, "false"); + assertThat(oldGvnf.marshal(false), + hasJsonPath( + "$.l-interfaces.l-interface[*].relationship-list.relationship[*].related-link", + containsInAnyOrder( + "/aai/" + oldVersion + llDefaultUri, + "/aai/" + oldVersion + llDefaultUri + ) + )); + oldGvnf.setValue("in-maint", true); + QueryParser uriQuery = engine.getQueryBuilder().createQueryFromURI(new URI(gvnfUri)); + oldSerializer.serializeToDb(oldGvnf, oldGvnfV, uriQuery, "generic-vnf", oldGvnf.marshal(false)); + + verifyRelsOfLatestViewOfGenericVnf(); + verifyRelsOfOldViewOfGenericVnf(); + } + + + + +} diff --git a/aai-core/src/test/java/org/onap/aai/serialization/queryformats/AggregateFormatTest.java b/aai-core/src/test/java/org/onap/aai/serialization/queryformats/AggregateFormatTest.java new file mode 100644 index 00000000..0b6ffd9e --- /dev/null +++ b/aai-core/src/test/java/org/onap/aai/serialization/queryformats/AggregateFormatTest.java @@ -0,0 +1,136 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 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========================================================= + */ + +package org.onap.aai.serialization.queryformats; + +import com.google.gson.JsonObject; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; +import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ReadOnlyStrategy; +import org.apache.tinkerpop.gremlin.structure.Graph; +import org.apache.tinkerpop.gremlin.structure.T; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.onap.aai.AAISetup; +import org.onap.aai.exceptions.AAIException; +import org.onap.aai.introspection.Loader; +import org.onap.aai.introspection.ModelType; +import org.onap.aai.serialization.db.DBSerializer; +import org.onap.aai.serialization.db.EdgeSerializer; +import org.onap.aai.serialization.engines.JanusGraphDBEngine; +import org.onap.aai.serialization.engines.QueryStyle; +import org.onap.aai.serialization.engines.TransactionalGraphEngine; +import org.onap.aai.serialization.queryformats.exceptions.AAIFormatVertexException; +import org.onap.aai.serialization.queryformats.utils.UrlBuilder; +import org.onap.aai.setup.SchemaVersion; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.annotation.DirtiesContext; + +import java.util.*; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS) +public class AggregateFormatTest extends AAISetup { + + @Mock + private UrlBuilder urlBuilder; + + private Graph graph; + private TransactionalGraphEngine dbEngine; + private Loader loader; + private Aggregate aggregate; + private final ModelType factoryType = ModelType.MOXY; + + @Autowired + private EdgeSerializer rules; + + private SchemaVersion version; + private Vertex pserver; + private Vertex complex; + + @Before + public void setUp() throws Exception { + + version = schemaVersions.getDefaultVersion(); + + MockitoAnnotations.initMocks(this); + + graph = TinkerGraph.open(); + + Vertex pserver1 = + graph.addVertex(T.label, "pserver", T.id, "2", "aai-node-type", "pserver", "hostname", "hostname-1"); + Vertex complex1 = graph.addVertex(T.label, "complex", T.id, "3", "aai-node-type", "complex", + "physical-location-id", "physical-location-id-1", "country", "US"); + + GraphTraversalSource g = graph.traversal(); + rules.addEdge(g, pserver1, complex1); + + pserver = pserver1; + complex = complex1; + + System.setProperty("AJSC_HOME", "."); + System.setProperty("BUNDLECONFIG_DIR", "src/test/resources/bundleconfig-local"); + + createLoaderEngineSetup(); + } + + private void createLoaderEngineSetup() throws AAIException { + + if (loader == null) { + loader = loaderFactory.createLoaderForVersion(factoryType, version); + dbEngine = spy(new JanusGraphDBEngine(QueryStyle.TRAVERSAL, loader)); + DBSerializer serializer = new DBSerializer(version, dbEngine, factoryType, "Junit"); + aggregate = new Aggregate.Builder(loader, serializer, urlBuilder).build(); + + TransactionalGraphEngine.Admin spyAdmin = spy(dbEngine.asAdmin()); + + when(dbEngine.tx()).thenReturn(graph); + when(dbEngine.asAdmin()).thenReturn(spyAdmin); + + when(spyAdmin.getReadOnlyTraversalSource()) + .thenReturn(graph.traversal().withStrategies(ReadOnlyStrategy.instance())); + when(spyAdmin.getTraversalSource()).thenReturn(graph.traversal()); + } + } + + @Test + public void run() throws AAIFormatVertexException { + assertNotNull(dbEngine.tx()); + System.out.println(dbEngine.tx()); + assertNotNull(graph.traversal()); + JsonObject json = aggregate.createPropertiesObject(pserver).get(); + json.entrySet().forEach((System.out::println)); + assertTrue(json.has("hostname")); + assertFalse(json.has("node-type")); + Map<String, List<String>> propMap = new HashMap<>(); + List<String> selectedProps = new ArrayList<String>( Arrays.asList("'physical-location-id'")); + propMap.put("complex",selectedProps); + JsonObject json1 = aggregate.createSelectedPropertiesObject(complex, propMap).get(); + json1.entrySet().forEach((System.out::println)); + assertFalse(json1.has("country")); + assertTrue(json1.has("physical-location-id")); + } +} diff --git a/aai-core/src/test/java/org/onap/aai/serialization/queryformats/CountQuerySupportTest.java b/aai-core/src/test/java/org/onap/aai/serialization/queryformats/CountQuerySupportTest.java index a2976e0c..e128c2f6 100644 --- a/aai-core/src/test/java/org/onap/aai/serialization/queryformats/CountQuerySupportTest.java +++ b/aai-core/src/test/java/org/onap/aai/serialization/queryformats/CountQuerySupportTest.java @@ -20,15 +20,7 @@ package org.onap.aai.serialization.queryformats; -import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.when; - import com.google.gson.JsonObject; - -import java.util.Arrays; -import java.util.List; - import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ReadOnlyStrategy; import org.apache.tinkerpop.gremlin.structure.Graph; @@ -38,10 +30,8 @@ import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph; import org.junit.After; import org.junit.Before; import org.junit.Test; -import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.onap.aai.AAISetup; -import org.onap.aai.dbmap.DBConnectionType; import org.onap.aai.exceptions.AAIException; import org.onap.aai.introspection.Loader; import org.onap.aai.introspection.ModelType; @@ -52,10 +42,16 @@ import org.onap.aai.serialization.engines.QueryStyle; import org.onap.aai.serialization.engines.TransactionalGraphEngine; import org.onap.aai.serialization.queryformats.exceptions.AAIFormatQueryResultFormatNotSupported; import org.onap.aai.serialization.queryformats.exceptions.AAIFormatVertexException; -import org.onap.aai.serialization.queryformats.utils.UrlBuilder; import org.onap.aai.setup.SchemaVersion; import org.springframework.beans.factory.annotation.Autowired; +import java.util.Arrays; +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + public class CountQuerySupportTest extends AAISetup { @Autowired @@ -147,7 +143,7 @@ public class CountQuerySupportTest extends AAISetup { if (loader == null) { loader = loaderFactory.createLoaderForVersion(factoryType, version); // loader = LoaderFactory.createLoaderForVersion(factoryType, version); - dbEngine = spy(new JanusGraphDBEngine(QueryStyle.TRAVERSAL, DBConnectionType.CACHED, loader)); + dbEngine = spy(new JanusGraphDBEngine(QueryStyle.TRAVERSAL, loader)); serializer = new DBSerializer(version, dbEngine, factoryType, "Junit"); ff = new FormatFactory(loader, serializer, schemaVersions, basePath); @@ -159,7 +155,7 @@ public class CountQuerySupportTest extends AAISetup { when(dbEngine.asAdmin()).thenReturn(spyAdmin); when(spyAdmin.getReadOnlyTraversalSource()) - .thenReturn(graph.traversal(GraphTraversalSource.build().with(ReadOnlyStrategy.instance()))); + .thenReturn(graph.traversal().withStrategies(ReadOnlyStrategy.instance())); when(spyAdmin.getTraversalSource()).thenReturn(graph.traversal()); } } diff --git a/aai-core/src/test/java/org/onap/aai/serialization/queryformats/GraphSONTest.java b/aai-core/src/test/java/org/onap/aai/serialization/queryformats/GraphSONTest.java index 847a45ed..22b500f8 100644 --- a/aai-core/src/test/java/org/onap/aai/serialization/queryformats/GraphSONTest.java +++ b/aai-core/src/test/java/org/onap/aai/serialization/queryformats/GraphSONTest.java @@ -26,8 +26,8 @@ import static org.hamcrest.core.IsNot.not; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.google.gson.JsonArray; import com.google.gson.JsonObject; @@ -63,7 +63,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @DirtiesContext public class GraphSONTest { - private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(GraphSONTest.class); + private static final Logger LOGGER = LoggerFactory.getLogger(GraphSONTest.class); private Graph graph; private Vertex v1; @@ -111,7 +111,7 @@ public class GraphSONTest { /** * Case where there is only one private edge - * + * * <pre> * { * "id": 21, @@ -167,7 +167,7 @@ public class GraphSONTest { /** * Case where there is one private edge and regular edge * with the same edge label name - * + * * <pre> * { * "id": 21, @@ -230,7 +230,7 @@ public class GraphSONTest { /** * Case where there is one private edge and regular edge to same label * And another regular edge to a different label - * + * * <pre> * { * "id": 21, @@ -328,7 +328,7 @@ public class GraphSONTest { /** * Case where there is one private edge and regular edge to same label * And another regular edge to a different label - * + * * <pre> * { * "id": 21, @@ -395,7 +395,7 @@ public class GraphSONTest { /** * Case where there is one private edge and regular edge to same label * And another regular edge to a different label - * + * * <pre> * { * "id": 21, diff --git a/aai-core/src/test/java/org/onap/aai/serialization/queryformats/MultiFormatTest.java b/aai-core/src/test/java/org/onap/aai/serialization/queryformats/MultiFormatTest.java index 9ac79ca8..a59b1147 100644 --- a/aai-core/src/test/java/org/onap/aai/serialization/queryformats/MultiFormatTest.java +++ b/aai-core/src/test/java/org/onap/aai/serialization/queryformats/MultiFormatTest.java @@ -20,15 +20,8 @@ package org.onap.aai.serialization.queryformats; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.mockito.Mockito.*; - import com.google.gson.JsonObject; import com.google.gson.JsonParser; - -import java.io.UnsupportedEncodingException; - import org.apache.tinkerpop.gremlin.process.traversal.Path; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree; @@ -42,10 +35,10 @@ import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.onap.aai.AAISetup; -import org.onap.aai.dbmap.DBConnectionType; import org.onap.aai.exceptions.AAIException; import org.onap.aai.introspection.Loader; import org.onap.aai.introspection.ModelType; +import org.onap.aai.serialization.db.DBSerializer; import org.onap.aai.serialization.db.EdgeSerializer; import org.onap.aai.serialization.engines.JanusGraphDBEngine; import org.onap.aai.serialization.engines.QueryStyle; @@ -57,6 +50,13 @@ import org.onap.aai.setup.SchemaVersion; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.annotation.DirtiesContext; +import javax.ws.rs.core.MultivaluedHashMap; +import java.io.UnsupportedEncodingException; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.mockito.Mockito.*; + @DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS) public class MultiFormatTest extends AAISetup { @@ -79,7 +79,12 @@ public class MultiFormatTest extends AAISetup { private JsonObject expectedPathIdFormat = new JsonParser().parse( "{\"path\":[{\"resource-type\":\"generic-vnf\"},{\"resource-type\":\"vserver\"},{\"resource-type\":\"pserver\"},{\"resource-type\":\"complex\"}]}") .getAsJsonObject(); - + private JsonObject expectedAsTreeWithResourceFormat = new JsonParser().parse( + "{\"results\":[{\"generic-vnf\":{\"vnf-id\":\"vnf-id-1\",\"vnf-name\":\"vnf-name-1\",\"related-nodes\":[{\"vserver\":{\"vserver-id\":\"vserver-id-1\",\"vserver-name\":\"vserver-name-1\",\"related-nodes\":[{\"pserver\":{\"hostname\":\"hostname-1\"}}]}},{\"pserver\":{\"hostname\":\"hostname-2\",\"related-nodes\":[{\"complex\":{\"physical-location-id\":\"physical-location-id-2\",\"country\":\"US\"}}]}}]}}]}") + .getAsJsonObject(); + private JsonObject expectedAsTreeWithSimpleFormat = new JsonParser().parse( + "{\"results\":[{\"id\":\"0\",\"node-type\":\"generic-vnf\",\"url\":null,\"properties\":{\"vnf-id\":\"vnf-id-1\",\"vnf-name\":\"vnf-name-1\"},\"related-to\":[{\"id\":\"1\",\"relationship-label\":\"tosca.relationships.HostedOn\",\"node-type\":\"vserver\",\"url\":null},{\"id\":\"5\",\"relationship-label\":\"tosca.relationships.HostedOn\",\"node-type\":\"pserver\",\"url\":null}],\"related-nodes\":[{\"id\":\"1\",\"node-type\":\"vserver\",\"url\":null,\"properties\":{\"vserver-id\":\"vserver-id-1\",\"vserver-name\":\"vserver-name-1\"},\"related-to\":[{\"id\":\"0\",\"relationship-label\":\"tosca.relationships.HostedOn\",\"node-type\":\"generic-vnf\",\"url\":null},{\"id\":\"2\",\"relationship-label\":\"tosca.relationships.HostedOn\",\"node-type\":\"pserver\",\"url\":null}],\"related-nodes\":[{\"id\":\"2\",\"node-type\":\"pserver\",\"url\":null,\"properties\":{\"hostname\":\"hostname-1\"},\"related-to\":[{\"id\":\"1\",\"relationship-label\":\"tosca.relationships.HostedOn\",\"node-type\":\"vserver\",\"url\":null},{\"id\":\"3\",\"relationship-label\":\"org.onap.relationships.inventory.LocatedIn\",\"node-type\":\"complex\",\"url\":null}]}]},{\"id\":\"5\",\"node-type\":\"pserver\",\"url\":null,\"properties\":{\"hostname\":\"hostname-2\"},\"related-to\":[{\"id\":\"0\",\"relationship-label\":\"tosca.relationships.HostedOn\",\"node-type\":\"generic-vnf\",\"url\":null},{\"id\":\"6\",\"relationship-label\":\"org.onap.relationships.inventory.LocatedIn\",\"node-type\":\"complex\",\"url\":null}],\"related-nodes\":[{\"id\":\"6\",\"node-type\":\"complex\",\"url\":null,\"properties\":{\"physical-location-id\":\"physical-location-id-2\",\"country\":\"US\"},\"related-to\":[{\"id\":\"5\",\"relationship-label\":\"org.onap.relationships.inventory.LocatedIn\",\"node-type\":\"pserver\",\"url\":null}]}]}]}]}") + .getAsJsonObject(); @Before public void setUp() throws Exception { @@ -130,6 +135,42 @@ public class MultiFormatTest extends AAISetup { } @Test + public void testAsTreeParamAndSimpleFormat() + throws AAIFormatVertexException, AAIException, AAIFormatQueryResultFormatNotSupported { + + createLoaderEngineSetup(); + DBSerializer serializer = new DBSerializer(version, dbEngine, factoryType, "Junit"); + MultivaluedHashMap<String, String> params = new MultivaluedHashMap<>(); + params.add("as-tree", "true"); + SimpleFormat sf = new SimpleFormat(new RawFormat.Builder(loader, serializer, urlBuilder).isTree(true)); + + assertNotNull(dbEngine.tx()); + assertNotNull(dbEngine.asAdmin()); + + JsonObject json = sf.formatObject(resultTree).get(); + assertEquals(this.expectedAsTreeWithSimpleFormat, json); + + } + + @Test + public void testAsTreeParamAndResourceFormat() + throws AAIFormatVertexException, AAIException, AAIFormatQueryResultFormatNotSupported { + + createLoaderEngineSetup(); + DBSerializer serializer = new DBSerializer(version, dbEngine, factoryType, "Junit"); + MultivaluedHashMap<String, String> params = new MultivaluedHashMap<>(); + params.add("as-tree", "true"); + Resource sf = new Resource(new Resource.Builder(loader, serializer, urlBuilder, params).isTree(true)); + + assertNotNull(dbEngine.tx()); + assertNotNull(dbEngine.asAdmin()); + + JsonObject json = sf.formatObject(resultTree).get(); + assertEquals(this.expectedAsTreeWithResourceFormat, json); + } + + + @Test public void testPathResultQueryIdFormat() throws AAIFormatVertexException, AAIException, AAIFormatQueryResultFormatNotSupported { @@ -159,7 +200,7 @@ public class MultiFormatTest extends AAISetup { if (loader == null) { loader = loaderFactory.createLoaderForVersion(factoryType, version); // loader = LoaderFactory.createLoaderForVersion(factoryType, version); - dbEngine = spy(new JanusGraphDBEngine(QueryStyle.TRAVERSAL, DBConnectionType.CACHED, loader)); + dbEngine = spy(new JanusGraphDBEngine(QueryStyle.TRAVERSAL, loader)); TransactionalGraphEngine.Admin spyAdmin = spy(dbEngine.asAdmin()); @@ -167,7 +208,7 @@ public class MultiFormatTest extends AAISetup { when(dbEngine.asAdmin()).thenReturn(spyAdmin); when(spyAdmin.getReadOnlyTraversalSource()) - .thenReturn(graph.traversal(GraphTraversalSource.build().with(ReadOnlyStrategy.instance()))); + .thenReturn(graph.traversal().withStrategies(ReadOnlyStrategy.instance())); when(spyAdmin.getTraversalSource()).thenReturn(graph.traversal()); } } diff --git a/aai-core/src/test/java/org/onap/aai/serialization/queryformats/QueryFormatTestHelper.java b/aai-core/src/test/java/org/onap/aai/serialization/queryformats/QueryFormatTestHelper.java index 03990b1d..f05e36dd 100644 --- a/aai-core/src/test/java/org/onap/aai/serialization/queryformats/QueryFormatTestHelper.java +++ b/aai-core/src/test/java/org/onap/aai/serialization/queryformats/QueryFormatTestHelper.java @@ -46,7 +46,7 @@ public class QueryFormatTestHelper { public static void mockPathed(UrlBuilder mock) throws AAIFormatVertexException { Answer<String> answer = new Answer<String>() { public String answer(InvocationOnMock invocation) throws Throwable { - Vertex v = invocation.getArgument(0); + Vertex v = invocation.getArgumentAt(0, Vertex.class); return v.<String>property(AAIProperties.AAI_URI).orElse("urimissing"); } diff --git a/aai-core/src/test/java/org/onap/aai/serialization/queryformats/RawFormatTest.java b/aai-core/src/test/java/org/onap/aai/serialization/queryformats/RawFormatTest.java index 2d8c66c3..f88de4fb 100644 --- a/aai-core/src/test/java/org/onap/aai/serialization/queryformats/RawFormatTest.java +++ b/aai-core/src/test/java/org/onap/aai/serialization/queryformats/RawFormatTest.java @@ -20,10 +20,7 @@ package org.onap.aai.serialization.queryformats; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.when; - +import com.google.gson.JsonObject; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ReadOnlyStrategy; import org.apache.tinkerpop.gremlin.structure.Graph; @@ -35,7 +32,6 @@ import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.onap.aai.AAISetup; -import org.onap.aai.dbmap.DBConnectionType; import org.onap.aai.exceptions.AAIException; import org.onap.aai.introspection.Loader; import org.onap.aai.introspection.ModelType; @@ -44,13 +40,18 @@ import org.onap.aai.serialization.db.EdgeSerializer; import org.onap.aai.serialization.engines.JanusGraphDBEngine; import org.onap.aai.serialization.engines.QueryStyle; import org.onap.aai.serialization.engines.TransactionalGraphEngine; -import org.onap.aai.serialization.queryformats.exceptions.AAIFormatQueryResultFormatNotSupported; import org.onap.aai.serialization.queryformats.exceptions.AAIFormatVertexException; import org.onap.aai.serialization.queryformats.utils.UrlBuilder; import org.onap.aai.setup.SchemaVersion; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.annotation.DirtiesContext; +import java.util.*; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + @DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS) public class RawFormatTest extends AAISetup { @@ -70,8 +71,6 @@ public class RawFormatTest extends AAISetup { private Vertex pserver; private Vertex complex; - private DBSerializer serializer; - @Before public void setUp() throws Exception { @@ -100,39 +99,34 @@ public class RawFormatTest extends AAISetup { @Test public void verifyPserverRelatedToHasEdgeLabel() - throws AAIFormatVertexException, AAIException, AAIFormatQueryResultFormatNotSupported { - assertTrue(rawFormat.createRelationshipObject(pserver).get(0).getAsJsonObject().get("relationship-label") - .getAsString().equals("org.onap.relationships.inventory.LocatedIn")); + throws AAIFormatVertexException { + assertEquals("org.onap.relationships.inventory.LocatedIn", rawFormat.createRelationshipObject(pserver).get(0).getAsJsonObject().get("relationship-label").getAsString()); } @Test public void verifyPserverRelatedToComplexLabel() - throws AAIFormatVertexException, AAIException, AAIFormatQueryResultFormatNotSupported { - assertTrue(rawFormat.createRelationshipObject(pserver).get(0).getAsJsonObject().get("node-type").getAsString() - .equals("complex")); + throws AAIFormatVertexException { + assertEquals("complex", rawFormat.createRelationshipObject(pserver).get(0).getAsJsonObject().get("node-type").getAsString()); } @Test public void verifyComplexRelatedToHasEdgeLabel() - throws AAIFormatVertexException, AAIException, AAIFormatQueryResultFormatNotSupported { - assertTrue(rawFormat.createRelationshipObject(complex).get(0).getAsJsonObject().get("relationship-label") - .getAsString().equals("org.onap.relationships.inventory.LocatedIn")); + throws AAIFormatVertexException { + assertEquals("org.onap.relationships.inventory.LocatedIn", rawFormat.createRelationshipObject(complex).get(0).getAsJsonObject().get("relationship-label").getAsString()); } @Test public void verifyComplexRelatedToPserverLabel() - throws AAIFormatVertexException, AAIException, AAIFormatQueryResultFormatNotSupported { - assertTrue(rawFormat.createRelationshipObject(complex).get(0).getAsJsonObject().get("node-type").getAsString() - .equals("pserver")); + throws AAIFormatVertexException { + assertEquals("pserver", rawFormat.createRelationshipObject(complex).get(0).getAsJsonObject().get("node-type").getAsString()); } - public void createLoaderEngineSetup() throws AAIException { + private void createLoaderEngineSetup() throws AAIException { if (loader == null) { loader = loaderFactory.createLoaderForVersion(factoryType, version); - // loader = LoaderFactory.createLoaderForVersion(factoryType, version); - dbEngine = spy(new JanusGraphDBEngine(QueryStyle.TRAVERSAL, DBConnectionType.CACHED, loader)); - serializer = new DBSerializer(version, dbEngine, factoryType, "Junit"); + dbEngine = spy(new JanusGraphDBEngine(QueryStyle.TRAVERSAL, loader)); + DBSerializer serializer = new DBSerializer(version, dbEngine, factoryType, "Junit"); rawFormat = new RawFormat.Builder(loader, serializer, urlBuilder).build(); TransactionalGraphEngine.Admin spyAdmin = spy(dbEngine.asAdmin()); @@ -141,8 +135,27 @@ public class RawFormatTest extends AAISetup { when(dbEngine.asAdmin()).thenReturn(spyAdmin); when(spyAdmin.getReadOnlyTraversalSource()) - .thenReturn(graph.traversal(GraphTraversalSource.build().with(ReadOnlyStrategy.instance()))); + .thenReturn(graph.traversal().withStrategies(ReadOnlyStrategy.instance())); when(spyAdmin.getTraversalSource()).thenReturn(graph.traversal()); } } + + @Test + public void run() throws AAIFormatVertexException { + assertNotNull(dbEngine.tx()); + System.out.println(dbEngine.tx()); + assertNotNull(graph.traversal()); + JsonObject json = rawFormat.createPropertiesObject(pserver).get(); + json.entrySet().forEach((System.out::println)); + assertTrue(json.has("hostname")); + Map<String, List<String>> propMap = new HashMap<>(); + List<String> selectedProps = new ArrayList<String>( Arrays.asList("'physical-location-id'")); + propMap.put("complex",selectedProps); + JsonObject json1 = rawFormat.createSelectedPropertiesObject(complex, propMap).get(); + json1.entrySet().forEach((System.out::println)); + assertFalse(json1.has("aai-node-type")); + assertTrue(json1.has("physical-location-id")); + } + + } diff --git a/aai-core/src/test/java/org/onap/aai/serialization/queryformats/ResourceFormatTest.java b/aai-core/src/test/java/org/onap/aai/serialization/queryformats/ResourceFormatTest.java index 1a301b33..a891230c 100644 --- a/aai-core/src/test/java/org/onap/aai/serialization/queryformats/ResourceFormatTest.java +++ b/aai-core/src/test/java/org/onap/aai/serialization/queryformats/ResourceFormatTest.java @@ -20,18 +20,7 @@ package org.onap.aai.serialization.queryformats; -import static org.junit.Assert.*; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.when; - import com.google.gson.JsonObject; - -import java.util.Arrays; - -import javax.ws.rs.core.MultivaluedHashMap; -import javax.ws.rs.core.MultivaluedMap; - -import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ReadOnlyStrategy; import org.apache.tinkerpop.gremlin.structure.Graph; import org.apache.tinkerpop.gremlin.structure.T; @@ -42,7 +31,6 @@ import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.onap.aai.AAISetup; -import org.onap.aai.dbmap.DBConnectionType; import org.onap.aai.exceptions.AAIException; import org.onap.aai.introspection.Loader; import org.onap.aai.introspection.ModelType; @@ -54,6 +42,14 @@ import org.onap.aai.serialization.queryformats.exceptions.AAIFormatVertexExcepti import org.onap.aai.serialization.queryformats.utils.UrlBuilder; import org.springframework.test.annotation.DirtiesContext; +import javax.ws.rs.core.MultivaluedHashMap; +import javax.ws.rs.core.MultivaluedMap; +import java.util.Arrays; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + @DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS) public class ResourceFormatTest extends AAISetup { @@ -144,7 +140,7 @@ public class ResourceFormatTest extends AAISetup { if (loader == null) { loader = loaderFactory.createLoaderForVersion(factoryType, schemaVersions.getAppRootVersion()); - dbEngine = spy(new JanusGraphDBEngine(QueryStyle.TRAVERSAL, DBConnectionType.CACHED, loader)); + dbEngine = spy(new JanusGraphDBEngine(QueryStyle.TRAVERSAL, loader)); TransactionalGraphEngine.Admin spyAdmin = spy(dbEngine.asAdmin()); @@ -152,7 +148,7 @@ public class ResourceFormatTest extends AAISetup { when(dbEngine.asAdmin()).thenReturn(spyAdmin); when(spyAdmin.getReadOnlyTraversalSource()) - .thenReturn(graph.traversal(GraphTraversalSource.build().with(ReadOnlyStrategy.instance()))); + .thenReturn(graph.traversal().withStrategies(ReadOnlyStrategy.instance())); when(spyAdmin.getTraversalSource()).thenReturn(graph.traversal()); } } diff --git a/aai-core/src/test/java/org/onap/aai/serialization/queryformats/ResourceWithSoTTest.java b/aai-core/src/test/java/org/onap/aai/serialization/queryformats/ResourceWithSoTTest.java index 75fe6ec6..c2e5f814 100644 --- a/aai-core/src/test/java/org/onap/aai/serialization/queryformats/ResourceWithSoTTest.java +++ b/aai-core/src/test/java/org/onap/aai/serialization/queryformats/ResourceWithSoTTest.java @@ -20,15 +20,7 @@ package org.onap.aai.serialization.queryformats; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.when; - import com.google.gson.JsonObject; - -import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ReadOnlyStrategy; import org.apache.tinkerpop.gremlin.structure.Graph; import org.apache.tinkerpop.gremlin.structure.Vertex; @@ -38,7 +30,6 @@ import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.onap.aai.AAISetup; -import org.onap.aai.dbmap.DBConnectionType; import org.onap.aai.exceptions.AAIException; import org.onap.aai.introspection.Loader; import org.onap.aai.introspection.ModelType; @@ -50,6 +41,10 @@ import org.onap.aai.serialization.queryformats.exceptions.AAIFormatVertexExcepti import org.onap.aai.serialization.queryformats.utils.UrlBuilder; import org.onap.aai.setup.SchemaVersion; +import static org.junit.Assert.*; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + public class ResourceWithSoTTest extends AAISetup { @Mock private UrlBuilder urlBuilder; @@ -79,7 +74,7 @@ public class ResourceWithSoTTest extends AAISetup { graph = TinkerGraph.open(); - Long currentTimeMs = System.currentTimeMillis(); + long currentTimeMs = System.currentTimeMillis(); String timeNowInMs = Long.toString(currentTimeMs); // PUT / CREATE @@ -119,8 +114,7 @@ public class ResourceWithSoTTest extends AAISetup { // This test is to simulate a PUT request @Test public void testGetJsonFromVertexWithCreateVertex() throws AAIFormatVertexException, AAIException { - if (putVertex == null) - assertTrue("The vertex used for this test is null. Fail immediately.", false); + if (putVertex == null) fail("The vertex used for this test is null. Fail immediately."); JsonObject json = resourceWithSoT.getJsonFromVertex(putVertex).get(); assertEquals(jsonPutObj, json); @@ -129,10 +123,8 @@ public class ResourceWithSoTTest extends AAISetup { // This test is to simulate PATCH requests @Test public void testGetJsonFromVertexWithModifyVertex() throws AAIFormatVertexException, AAIException { - if (patchVertex1 == null) - assertTrue("The vertex 1 used for this test is null. Fail immediately.", false); - if (patchVertex2 == null) - assertTrue("The vertex 2 used for this test is null. Fail immediately.", false); + if (patchVertex1 == null) fail("The vertex 1 used for this test is null. Fail immediately."); + if (patchVertex2 == null) fail("The vertex 2 used for this test is null. Fail immediately."); // Differing Source of Truths will indicate that the action performed modified the vertex JsonObject json1 = resourceWithSoT.getJsonFromVertex(patchVertex1).get(); @@ -155,7 +147,7 @@ public class ResourceWithSoTTest extends AAISetup { if (loader == null) { loader = loaderFactory.createLoaderForVersion(factoryType, version); // loader = LoaderFactory.createLoaderForVersion(factoryType, version); - dbEngine = spy(new JanusGraphDBEngine(QueryStyle.TRAVERSAL, DBConnectionType.CACHED, loader)); + dbEngine = spy(new JanusGraphDBEngine(QueryStyle.TRAVERSAL, loader)); serializer = new DBSerializer(version, dbEngine, factoryType, "Junit"); resourceWithSoT = new ResourceWithSoT.Builder(loader, serializer, urlBuilder).build(); @@ -165,7 +157,7 @@ public class ResourceWithSoTTest extends AAISetup { when(dbEngine.asAdmin()).thenReturn(spyAdmin); when(spyAdmin.getReadOnlyTraversalSource()) - .thenReturn(graph.traversal(GraphTraversalSource.build().with(ReadOnlyStrategy.instance()))); + .thenReturn(graph.traversal().withStrategies(ReadOnlyStrategy.instance())); when(spyAdmin.getTraversalSource()).thenReturn(graph.traversal()); } } diff --git a/aai-core/src/test/java/org/onap/aai/serialization/queryformats/SimpleFormatTest.java b/aai-core/src/test/java/org/onap/aai/serialization/queryformats/SimpleFormatTest.java index ab899c01..886a660b 100644 --- a/aai-core/src/test/java/org/onap/aai/serialization/queryformats/SimpleFormatTest.java +++ b/aai-core/src/test/java/org/onap/aai/serialization/queryformats/SimpleFormatTest.java @@ -20,22 +20,7 @@ package org.onap.aai.serialization.queryformats; -import static org.junit.Assert.*; -import static org.mockito.Matchers.anyBoolean; -import static org.mockito.Matchers.anyInt; -import static org.mockito.Matchers.anyObject; -import static org.mockito.Matchers.anyString; -import static org.mockito.Mockito.*; - import com.google.gson.JsonObject; - -import java.io.UnsupportedEncodingException; -import java.util.Arrays; - -import javax.ws.rs.core.MultivaluedHashMap; -import javax.ws.rs.core.MultivaluedMap; - -import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; import org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ReadOnlyStrategy; import org.apache.tinkerpop.gremlin.structure.Graph; import org.apache.tinkerpop.gremlin.structure.T; @@ -47,7 +32,6 @@ import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.onap.aai.AAISetup; -import org.onap.aai.dbmap.DBConnectionType; import org.onap.aai.exceptions.AAIException; import org.onap.aai.introspection.Loader; import org.onap.aai.introspection.ModelType; @@ -60,6 +44,15 @@ import org.onap.aai.serialization.queryformats.exceptions.AAIFormatVertexExcepti import org.onap.aai.serialization.queryformats.utils.UrlBuilder; import org.springframework.test.annotation.DirtiesContext; +import javax.ws.rs.core.MultivaluedHashMap; +import javax.ws.rs.core.MultivaluedMap; +import java.io.UnsupportedEncodingException; +import java.util.Arrays; + +import static org.junit.Assert.*; +import static org.mockito.Matchers.*; +import static org.mockito.Mockito.*; + @DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS) public class SimpleFormatTest extends AAISetup { @@ -182,7 +175,7 @@ public class SimpleFormatTest extends AAISetup { if (loader == null) { loader = loaderFactory.createLoaderForVersion(factoryType, schemaVersions.getRelatedLinkVersion()); - dbEngine = spy(new JanusGraphDBEngine(QueryStyle.TRAVERSAL, DBConnectionType.CACHED, loader)); + dbEngine = spy(new JanusGraphDBEngine(QueryStyle.TRAVERSAL, loader)); TransactionalGraphEngine.Admin spyAdmin = spy(dbEngine.asAdmin()); @@ -190,7 +183,7 @@ public class SimpleFormatTest extends AAISetup { when(dbEngine.asAdmin()).thenReturn(spyAdmin); when(spyAdmin.getReadOnlyTraversalSource()) - .thenReturn(graph.traversal(GraphTraversalSource.build().with(ReadOnlyStrategy.instance()))); + .thenReturn(graph.traversal().withStrategies(ReadOnlyStrategy.instance())); when(spyAdmin.getTraversalSource()).thenReturn(graph.traversal()); } } diff --git a/aai-core/src/test/java/org/onap/aai/serialization/queryformats/utils/QueryParamInjectorTest.java b/aai-core/src/test/java/org/onap/aai/serialization/queryformats/utils/QueryParamInjectorTest.java index 0b689d88..f039d7cb 100644 --- a/aai-core/src/test/java/org/onap/aai/serialization/queryformats/utils/QueryParamInjectorTest.java +++ b/aai-core/src/test/java/org/onap/aai/serialization/queryformats/utils/QueryParamInjectorTest.java @@ -48,11 +48,11 @@ public class QueryParamInjectorTest { MockitoAnnotations.initMocks(this); QueryParamInjector injector = QueryParamInjector.getInstance(); - Builder b = new Builder(loader, serializer, urlBuilder); MultivaluedMap<String, String> params = new MultivaluedHashMap<>(); params.putSingle("nodesOnly", "true"); params.putSingle("depth", "10"); params.putSingle("invalid", "1000"); + Builder b = new Builder(loader, serializer, urlBuilder, params); injector.injectParams(b, params); assertEquals("is nodes only", true, b.isNodesOnly()); diff --git a/aai-core/src/test/java/org/onap/aai/stress/IndexStressTest.java b/aai-core/src/test/java/org/onap/aai/stress/IndexStressTest.java new file mode 100644 index 00000000..143004ac --- /dev/null +++ b/aai-core/src/test/java/org/onap/aai/stress/IndexStressTest.java @@ -0,0 +1,132 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 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========================================================= + */ + +package org.onap.aai.stress; + +import org.apache.commons.lang.RandomStringUtils; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.janusgraph.core.JanusGraphTransaction; +import org.junit.Before; +import org.junit.Test; +import org.junit.Ignore; +import org.onap.aai.AAISetup; +import org.onap.aai.dbmap.AAIGraph; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.test.annotation.DirtiesContext; + +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.Set; + +@Ignore("Run this only to test indexes limit") +@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS) +public class IndexStressTest extends AAISetup { + + private static final Logger LOGGER = LoggerFactory.getLogger(IndexStressTest.class); + + @Before + public void setup(){ + AAIGraph.getInstance().getGraph(); + } + + @Test + public void testIndexStress(){ + JanusGraphTransaction tx = AAIGraph.getInstance().getGraph().newTransaction(); + + GraphTraversalSource g = tx.traversal(); + + Set<String> linkNameSet = new HashSet<>(); + Set<String> aaiUriSet = new HashSet<>(); + + int TOTAL_LINKS = 101000; + + for(int i = 0; i <TOTAL_LINKS; i++){ + + String linkName = generateName(linkNameSet); + aaiUriSet.add("/network/logical-links/logical-link/" + linkName); + + Vertex v = g.addV() + .property("aai-node-type", "logical-link") + .property("link-name", linkName) + .property("aai-uri", "/network/logical-links/logical-link/" + linkName) + .next(); + + if(i % 1000 == 0){ + LOGGER.debug("Committing up to index {}", i); + tx.commit(); + tx = AAIGraph.getInstance().getGraph().newTransaction(); + g = tx.traversal(); + } + } + + tx.commit(); + + tx = AAIGraph.getInstance().getGraph().newTransaction(); + g = tx.traversal(); + + int totalLinks= 0; + int totalLinksWithNodeType = 0; + int totalLinksUsingUri = 0; + + int index = 0; + for (String linkName : linkNameSet) { + + if(g.V().has("aai-node-type", "logical-link").has("link-name", linkName).hasNext()){ + totalLinksWithNodeType++; + } + + if(g.V().has("link-name", linkName).hasNext()){ + totalLinks++; + } + + if(g.V().has("aai-uri", "/network/logical-links/logical-link/" + linkName).hasNext()){ + totalLinksUsingUri++; + } + + index++; + + if(index%1000 == 0){ + LOGGER.debug("Processed {} many queries and has {} many to go", index, (TOTAL_LINKS-index)); + LOGGER.debug("Total links using linkname found: {}", totalLinks); + LOGGER.debug("Total links using nodetype and linkname found: {}", totalLinksWithNodeType); + LOGGER.debug("Total links using uri found: {}", totalLinksUsingUri); + } + } + + tx.rollback(); + + LOGGER.debug("Total links using linkname found: {}", totalLinks); + LOGGER.debug("Total links using nodetype and linkname found: {}", totalLinksWithNodeType); + LOGGER.debug("Total links using uri found: {}", totalLinksUsingUri); + } + + String generateName(Set<String> uniqueKeys){ + + while(true) { + String data = RandomStringUtils.randomAlphabetic(20); + if (!uniqueKeys.contains(data)){ + uniqueKeys.add(data); + return data; + } + } + } +} diff --git a/aai-core/src/test/java/org/onap/aai/transforms/XmlFormatTransformerTest.java b/aai-core/src/test/java/org/onap/aai/transforms/XmlFormatTransformerTest.java new file mode 100644 index 00000000..6d6ae194 --- /dev/null +++ b/aai-core/src/test/java/org/onap/aai/transforms/XmlFormatTransformerTest.java @@ -0,0 +1,58 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 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========================================================= + */ +package org.onap.aai.transforms; + +import org.junit.Before; +import org.junit.Test; +import org.onap.aai.PayloadUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; + +public class XmlFormatTransformerTest { + + private static final Logger LOGGER = LoggerFactory.getLogger(XmlFormatTransformerTest.class); + + private XmlFormatTransformer xmlFormatTransformer; + + @Before + public void setup(){ + this.xmlFormatTransformer = new XmlFormatTransformer(); + } + + @Test + public void testTransformJsonToXml() throws IOException { + + String input = PayloadUtil.getResourcePayload("transform-results-to-result.json"); + String expected = PayloadUtil.getExpectedPayload("transform-json-to-xml.xml"); + // Remove all the whitespace in the xml + expected = expected.replaceAll("\\s", ""); + + LOGGER.debug("Converting the following input to xml: {}", input); + String output = xmlFormatTransformer.transform(input); + + LOGGER.debug("Converted xml payload: {}", output); + assertThat(output, is(expected)); + } +} diff --git a/aai-core/src/test/java/org/onap/aai/util/FileWatcherTest.java b/aai-core/src/test/java/org/onap/aai/util/FileWatcherTest.java deleted file mode 100644 index 2e870f6e..00000000 --- a/aai-core/src/test/java/org/onap/aai/util/FileWatcherTest.java +++ /dev/null @@ -1,79 +0,0 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aai - * ================================================================================ - * Copyright © 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========================================================= - */ - -package org.onap.aai.util; - -import static org.junit.Assert.*; - -import java.io.File; - -import org.junit.Test; -import org.mockito.Mockito; - -public class FileWatcherTest { - - class FileWatcherExtension extends FileWatcher { - - public FileWatcherExtension(File file) { - super(file); - } - - @Override - protected void onChange(File file) { - System.out.println("do nothing"); - } - } - - @Test - public void testFileWatcher() { - File file = new File("helloworld"); - file.setLastModified(new Long(123)); - FileWatcher fileWatcher = new FileWatcherExtension(file); - assertNotNull(fileWatcher); - file.deleteOnExit(); - } - - @Test(expected = NullPointerException.class) - public void testFileWatcher_nullConstructor() { - FileWatcher fileWatcher = new FileWatcherExtension(null); - assertNull(fileWatcher); - } - - @Test - public void testRun() { - // verify that code is reachable outside of conditional check in run() - File file = new File("helloworld"); - file.setLastModified(new Long(100)); - FileWatcher fileWatcher = new FileWatcherExtension(file); - fileWatcher.run(); - file.deleteOnExit(); - } - - @Test - public void testOnChange() throws Exception { - FileWatcher fileWatcher = Mockito.mock(FileWatcher.class, Mockito.CALLS_REAL_METHODS); - - File file=Mockito.mock(File.class); - fileWatcher.onChange(file); - - Mockito.verify(fileWatcher).onChange(file); - - } -} diff --git a/aai-core/src/test/java/org/onap/aai/util/StoreNotificationEventTest.java b/aai-core/src/test/java/org/onap/aai/util/StoreNotificationEventTest.java index 08cbba20..b4b8810e 100644 --- a/aai-core/src/test/java/org/onap/aai/util/StoreNotificationEventTest.java +++ b/aai-core/src/test/java/org/onap/aai/util/StoreNotificationEventTest.java @@ -66,19 +66,19 @@ public class StoreNotificationEventTest extends AAISetup { @Test(expected = AAIException.class) public void testStoreEventNullObj() throws AAIException { - sne.storeEvent(new EventHeader(), null); + sne.storeEventAndSendToJms(new EventHeader(), null); } @Test(expected = AAIException.class) public void testStoreEventInvalidObjForPojoUtils() throws AAIException { - sne.storeEvent(new EventHeader(), new Object()); + sne.storeEventAndSendToJms(new EventHeader(), new Object()); } @Test public void testStoreEventEmptyEventHeader() throws AAIException, JsonGenerationException, JsonMappingException, IOException { JsonObject object = Json.createObjectBuilder().add("hello", "world").build(); - String res = sne.storeEvent(new EventHeader(), object); + String res = sne.storeEventAndSendToJms(new EventHeader(), object); assertNotNull(res); assertTrue(res.contains("\"cambria.partition\" : \"" + AAIConstants.UEB_PUB_PARTITION_AAI + "\"")); @@ -118,7 +118,7 @@ public class StoreNotificationEventTest extends AAISetup { eh.setSeverity("ALERT"); eh.setVersion("v12"); - String res = sne.storeEvent(eh, object); + String res = sne.storeEventAndSendToJms(eh, object); assertNotNull(res); assertTrue(res.contains("\"cambria.partition\" : \"" + AAIConstants.UEB_PUB_PARTITION_AAI + "\"")); @@ -161,7 +161,7 @@ public class StoreNotificationEventTest extends AAISetup { @Test(expected = AAIException.class) public void testStoreEventIntrospectorNullObj() throws Exception { Loader loader = Mockito.mock(Loader.class); - sne.storeEvent(loader, null, null); + sne.storeEventAndSendToJms(loader, null, null); } @Ignore("Stopped working since the model driven story") @@ -180,7 +180,7 @@ public class StoreNotificationEventTest extends AAISetup { eventHeader.setValue("severity", "ALERT"); eventHeader.setValue("version", "v12"); Introspector obj = loader.introspectorFromName("notification-event"); - String res = sne.storeEvent(loader, eventHeader, obj); + String res = sne.storeEventAndSendToJms(loader, eventHeader, obj); assertNotNull(res); assertTrue(res.contains("\"cambria.partition\":\"" + AAIConstants.UEB_PUB_PARTITION_AAI + "\"")); @@ -205,7 +205,7 @@ public class StoreNotificationEventTest extends AAISetup { Introspector eventHeader = loader.introspectorFromName("notification-event-header"); Introspector obj = loader.introspectorFromName("notification-event"); - String res = sne.storeEvent(loader, eventHeader, obj); + String res = sne.storeEventAndSendToJms(loader, eventHeader, obj); assertNotNull(res); assertTrue(res.contains("\"cambria.partition\":\"" + AAIConstants.UEB_PUB_PARTITION_AAI + "\"")); diff --git a/aai-core/src/test/resources/bundleconfig-local/aaf/cadi.properties b/aai-core/src/test/resources/bundleconfig-local/aaf/cadi.properties new file mode 100644 index 00000000..8f7004ff --- /dev/null +++ b/aai-core/src/test/resources/bundleconfig-local/aaf/cadi.properties @@ -0,0 +1,14 @@ +## Location properties +## +## Localized Machine Information +## +cadi_loglevel=DEBUG +cadi_latitude=38.0 +cadi_longitude=-72.0 + +# Locate URL (which AAF Env) - Use lower case +aaf_locate_url=https://aafist.test.org:8095 +# AAF URL - Use upper case +aaf_url=https://AAF_LOCATE_URL/service:2.0 +# +cadi_prop_files=src/test/resources/bundleconfig-local/aaf/org.onap.aai.props diff --git a/aai-core/src/test/resources/bundleconfig-local/aaf/org.onap.aai.props b/aai-core/src/test/resources/bundleconfig-local/aaf/org.onap.aai.props new file mode 100644 index 00000000..3056e5f9 --- /dev/null +++ b/aai-core/src/test/resources/bundleconfig-local/aaf/org.onap.aai.props @@ -0,0 +1,4 @@ +cm_url=cm_url +hostname=hostname +aaf_env=IST +cadi_x509_issuers=CN=AAF CADI Test Issuing CA 01, OU=CSO, O=CO, C=US:CN=AAF CADI Test Issuing CA 02, OU=CSO, O=CO, C=US
\ No newline at end of file diff --git a/aai-core/src/test/resources/bundleconfig-local/etc/appprops/aaiconfig.properties b/aai-core/src/test/resources/bundleconfig-local/etc/appprops/aaiconfig.properties index 0239e2ef..f0e09d40 100644 --- a/aai-core/src/test/resources/bundleconfig-local/etc/appprops/aaiconfig.properties +++ b/aai-core/src/test/resources/bundleconfig-local/etc/appprops/aaiconfig.properties @@ -56,3 +56,4 @@ aai.rest.getall.depthparam=someuuid aaf.valid.issuer.wildcard=aaf wild card issuer|aafWildCardIssuer|OU=another +aai.implied.delete.whitelist.junit='pserver','l-interface' diff --git a/aai-core/src/test/resources/bundleconfig-local/etc/appprops/error.properties b/aai-core/src/test/resources/bundleconfig-local/etc/appprops/error.properties index 3a5671c2..d99efb5e 100644 --- a/aai-core/src/test/resources/bundleconfig-local/etc/appprops/error.properties +++ b/aai-core/src/test/resources/bundleconfig-local/etc/appprops/error.properties @@ -154,6 +154,8 @@ AAI_9105=5:0:WARN:9105:403:3300:Authorization error AAI_9106=5:0:WARN:9106:403:3300:Invalid AppId #AAI_9107=5:0:WARN:9107:403:3300:No Username in Request AAI_9107=5:0:WARN:9107:403:3300:SSL is not provided in request, please contact admin +AAI_9108=5:0:WARN:9107:403:3300:Basic auth credentials is not provided in the request +AAI_9109=5:0:WARN:9109:403:3300:User is not allowed to perform implicit delete #--- aaiinstar: 9201-9299 AAI_9201=5:4:ERROR:9201:500:3002:Unable to send notification diff --git a/aai-core/src/test/resources/bundleconfig-local/etc/appprops/janusgraph-cached.properties b/aai-core/src/test/resources/bundleconfig-local/etc/appprops/janusgraph-cached.properties index aa3c0631..a0926e7c 100644 --- a/aai-core/src/test/resources/bundleconfig-local/etc/appprops/janusgraph-cached.properties +++ b/aai-core/src/test/resources/bundleconfig-local/etc/appprops/janusgraph-cached.properties @@ -18,6 +18,7 @@ # ============LICENSE_END========================================================= query.fast-property=true +query.smart-limit=false # the following parameters are not reloaded automatically and require a manual bounce storage.backend=inmemory storage.hostname=localhost diff --git a/aai-core/src/test/resources/bundleconfig-local/etc/appprops/janusgraph-realtime.properties b/aai-core/src/test/resources/bundleconfig-local/etc/appprops/janusgraph-realtime.properties index 05394334..3f00b557 100644 --- a/aai-core/src/test/resources/bundleconfig-local/etc/appprops/janusgraph-realtime.properties +++ b/aai-core/src/test/resources/bundleconfig-local/etc/appprops/janusgraph-realtime.properties @@ -18,6 +18,7 @@ # ============LICENSE_END========================================================= query.fast-property=true +query.smart-limit=false # the following parameters are not reloaded automatically and require a manual bounce storage.backend=inmemory storage.hostname=localhost diff --git a/aai-core/src/test/resources/dbedgerules/DbEdgeRules_test.json b/aai-core/src/test/resources/dbedgerules/DbEdgeRules_test.json index b07e7783..f47925e4 100644 --- a/aai-core/src/test/resources/dbedgerules/DbEdgeRules_test.json +++ b/aai-core/src/test/resources/dbedgerules/DbEdgeRules_test.json @@ -166,7 +166,6 @@ "multiplicity": "ONE2MANY", "contains-other-v": "NONE", "delete-other-v": "${direction}", - "prevent-delete": "NONE", "description": "Hard to describe", "prevent-delete": "NONE" }, @@ -248,4 +247,4 @@ "prevent-delete": "!${direction}" } ] -}
\ No newline at end of file +} diff --git a/aai-core/src/test/resources/onap/dbedgerules/v14/DbEdgeRules_v14.json b/aai-core/src/test/resources/onap/dbedgerules/v14/DbEdgeRules_v14.json index 2eed8007..7b5c26a7 100644 --- a/aai-core/src/test/resources/onap/dbedgerules/v14/DbEdgeRules_v14.json +++ b/aai-core/src/test/resources/onap/dbedgerules/v14/DbEdgeRules_v14.json @@ -1115,7 +1115,17 @@ "prevent-delete": "NONE", "default": "true", "description":"" - }, + },{ + "from": "sriov-vf", + "to": "l-interface", + "label": "NOT.A.REAL.EDGERULE", + "direction": "OUT", + "multiplicity": "ONE2ONE", + "contains-other-v": "NONE", + "delete-other-v": "!${direction}", + "prevent-delete": "NONE", + "description":"" + }, { "from": "vlan", "to": "l-interface", @@ -3051,6 +3061,6 @@ "default": "true", "description":"" } - + ] } diff --git a/aai-core/src/test/resources/onap/oxm/v10/aai_oxm_v10.xml b/aai-core/src/test/resources/onap/oxm/v10/aai_oxm_v10.xml index e28466b7..71ab3dd5 100644 --- a/aai-core/src/test/resources/onap/oxm/v10/aai_oxm_v10.xml +++ b/aai-core/src/test/resources/onap/oxm/v10/aai_oxm_v10.xml @@ -1653,6 +1653,7 @@ <xml-property name="namespace" value="cloud-infrastructure"/> <xml-property name="uriTemplate" value="/cloud-infrastructure/pservers/pserver/{hostname}"/> <xml-property name="requiredProps" value="hostname,in-maint"/> + <xml-property name="dslStartNodeProps" value="hostname,pserver-id,pserver-name2,inv-status"/> </xml-properties> </java-type> diff --git a/aai-core/src/test/resources/onap/oxm/v14/aai_oxm_v14.xml b/aai-core/src/test/resources/onap/oxm/v14/aai_oxm_v14.xml index bb9b2eab..08a6cd52 100644 --- a/aai-core/src/test/resources/onap/oxm/v14/aai_oxm_v14.xml +++ b/aai-core/src/test/resources/onap/oxm/v14/aai_oxm_v14.xml @@ -8,9 +8,9 @@ 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. @@ -4150,7 +4150,7 @@ </xml-element> <xml-element java-attribute="relationshipList" name="relationship-list" type="inventory.aai.onap.org.v14.RelationshipList"/> <xml-element java-attribute="cps" name="cps" type="inventory.aai.onap.org.v14.Cps"/> - <xml-element container-type="java.util.ArrayList" java-attribute="l3InterfaceIpv4AddressList" name="l3-interface-ipv4-address-list" type="inventory.aai.onap.org.v14.L3InterfaceIpv4AddressList"/> + <xml-element container-type="java.util.ArrayList" java-attribute="l3InterfaceIpv4AddressList" name="l3-interface-ipv4-address-list" type="inventory.aai.onap.org.v14.L3InterfaceIpv4AddressList"/> <xml-element container-type="java.util.ArrayList" java-attribute="l3InterfaceIpv6AddressList" name="l3-interface-ipv6-address-list" type="inventory.aai.onap.org.v14.L3InterfaceIpv6AddressList"/> </java-attributes> <xml-properties> @@ -7499,7 +7499,7 @@ <xml-properties> <xml-property name="description" value="The network-technology that a cloud-region can support. Current valid values- CONTRAIL AIC_SR_IOV OVS STANDARD-SR-IOV"/> </xml-properties> - </xml-element> + </xml-element> <xml-element java-attribute="resourceVersion" name="resource-version" type="java.lang.String"> <xml-properties> <xml-property name="description" value="Used for optimistic concurrency. Must be empty on create, valid on update and delete."/> diff --git a/aai-core/src/test/resources/payloads/expected/transform-json-to-xml.xml b/aai-core/src/test/resources/payloads/expected/transform-json-to-xml.xml new file mode 100644 index 00000000..55d8854e --- /dev/null +++ b/aai-core/src/test/resources/payloads/expected/transform-json-to-xml.xml @@ -0,0 +1,59 @@ +<results> + <result> + <related-to> + <node> + <relationship-label>org.onap.relationships.inventory.LocatedIn</relationship-label> + <node-type>complex</node-type> + <id>286724232</id> + <url>/aai/v18/cloud-infrastructure/complexes/complex/testcomplex2</url> + </node> + <node> + <relationship-label>org.onap.relationships.inventory.LocatedIn</relationship-label> + <node-type>complex</node-type> + <id>286724233</id> + <url>/aai/v18/cloud-infrastructure/complexes/complex/testcomplex1</url> + </node> + </related-to> + <node-type>pserver</node-type> + <id>286724136</id> + <url>/aai/v18/cloud-infrastructure/pservers/pserver/test-pserver1</url> + <properties> + <aai-last-mod-ts>1568997029298</aai-last-mod-ts> + <ptnii-equip-name>test-pserver1</ptnii-equip-name> + <equip-type>SERVER</equip-type> + <equip-vendor>SomeVendor</equip-vendor> + <purpose>Standalone</purpose> + <fqdn>a.b.c.d</fqdn> + <aai-uri>/cloud-infrastructure/pservers/pserver/test-pserver1</aai-uri> + <pserver-id>6bf4944a-9f13-4bb8-8f49-b61060793510</pserver-id> + <aai-created-ts>1568997029298</aai-created-ts> + <ipv4-oam-address>1.2.3.4</ipv4-oam-address> + <source-of-truth>AAI</source-of-truth> + <aai-node-type>pserver</aai-node-type> + <hostname>test-pserver1</hostname> + <equip-model>SomeModel</equip-model> + <in-maint>false</in-maint> + <aai-uuid>05fa7b64-59e4-44a1-8162-e32746659c77</aai-uuid> + <resource-version>1568997029298</resource-version> + <last-mod-source-of-truth>AAIRctFeed</last-mod-source-of-truth> + </properties> + </result> + <result> + <related-to></related-to> + <node-type>pserver</node-type> + <id>286724152</id> + <url>/aai/v18/cloud-infrastructure/pservers/pserver/test-pserver2</url> + <properties> + <aai-last-mod-ts>1553805738492</aai-last-mod-ts> + <hostname>test-pserver2</hostname> + <in-maint>false</in-maint> + <aai-uuid>13a8440c-7fb4-4f41-a141-6e1d9e895b4a</aai-uuid> + <resource-version>1553805738492</resource-version> + <aai-uri>/cloud-infrastructure/pservers/pserver/test-pserver2</aai-uri> + <aai-created-ts>1553805738492</aai-created-ts> + <last-mod-source-of-truth>JUNITTESTAPP2</last-mod-source-of-truth> + <source-of-truth>JUNITTESTAPP2</source-of-truth> + <aai-node-type>pserver</aai-node-type> + </properties> + </result> +</results> diff --git a/aai-core/src/test/resources/payloads/resource/complex_pserver_with_relation.json b/aai-core/src/test/resources/payloads/resource/complex_pserver_with_relation.json new file mode 100644 index 00000000..d6b1165f --- /dev/null +++ b/aai-core/src/test/resources/payloads/resource/complex_pserver_with_relation.json @@ -0,0 +1,29 @@ +{ + "complex": { + "physical-location-id": "complex-1", + "data-center-code": "MiddletownNJ", + "complex-name": "complex-L-lisleil", + "physical-location-type": "uCPE Complex", + "street1": "4513 Western Ave", + "street2": "CU-L", + "city": "Middletown", + "state": "NJ", + "postal-code": "07748", + "country": "USA", + "region": "NA" + }, + "pserver": { + "hostname": "pserver-1", + "ptnii-equip-name": "ptnii", + "number-of-cpus": 280, + "relationship-list": { + "relationship": [ + { + "related-to": "complex", + "relationship-label": "org.onap.relationships.inventory.LocatedIn", + "related-link": "/aai/v14/cloud-infrastructure/complexes/complex/complex-1" + } + ] + } + } +} diff --git a/aai-core/src/test/resources/payloads/resource/customer_with_children_and_generic-vnf_with_children_and_edge_between_service-instance_vlan.json b/aai-core/src/test/resources/payloads/resource/customer_with_children_and_generic-vnf_with_children_and_edge_between_service-instance_vlan.json new file mode 100644 index 00000000..d4c4f65b --- /dev/null +++ b/aai-core/src/test/resources/payloads/resource/customer_with_children_and_generic-vnf_with_children_and_edge_between_service-instance_vlan.json @@ -0,0 +1,70 @@ +{ + "generic-vnf": { + "vnf-id": "gvnf", + "vnf-name": "example-vnf-name-val-28303", + "vnf-name2": "example-vnf-name2-val-14743", + "vnf-type": "example-vnf-type-val-58866", + "service-id": "example-service-id-val-24831", + "regional-resource-zone": "example-regional-resource-zone-val-33255", + "prov-status": "example-prov-status-val-47870", + "operational-state": "example-operational-state-val-8419", + "equipment-role": "example-equipment-role-val-35736", + "orchestration-status": "example-orchestration-status-val-67542", + "l-interfaces": { + "l-interface": [ + { + "interface-name": "lint", + "interface-role": "example-interface-role-val-61355", + "v6-wan-link-ip": "example-v6-wan-link-ip-val-78314", + "vlans": { + "vlan": [ + { + "vlan-interface": "vlan", + "vlan-id-inner": 90845777, + "vlan-id-outer": 23395650 + } + ] + } + } + ] + } + }, + "customer": { + "global-customer-id": "cust", + "subscriber-name": "subscriber-name-022", + "subscriber-type": "subscriber-type-022", + "service-subscriptions": { + "service-subscription": { + "service-type": "ss", + "service-instances": { + "service-instance": [ + { + "service-instance-id": "si", + "relationship-list": { + "relationship": [ + { + "related-to": "vlan", + "relationship-data": [ + { + "relationship-key": "vlan.vlan-interface", + "relationship-value": "vlan" + }, + { + "relationship-key": "l-interface.interface-name", + "relationship-value": "lint" + }, + { + "relationship-key": "generic-vnf.vnf-id", + "relationship-value": "gvnf" + } + ] + } + ] + } + } + ] + } + } + } + } +} diff --git a/aai-core/src/test/resources/payloads/resource/generic-vnf-implied-delete.json b/aai-core/src/test/resources/payloads/resource/generic-vnf-implied-delete.json new file mode 100644 index 00000000..0c83c36a --- /dev/null +++ b/aai-core/src/test/resources/payloads/resource/generic-vnf-implied-delete.json @@ -0,0 +1,26 @@ +{ + "vnf-id": "generic-vnf-implied-delete", + "vnf-type": "sometype", + "in-maint": true, + "is-closed-loop-disabled": true, + "vf-modules": { + "vf-module": [ + { + "vf-module-id": "vf-mod-id1", + "is-base-vf-module": true + }, + { + "vf-module-id": "vf-mod-id2", + "is-base-vf-module": true + }, + { + "vf-module-id": "vf-mod-id3", + "is-base-vf-module": true + }, + { + "vf-module-id": "vf-mod-id4", + "is-base-vf-module": true + } + ] + } +} diff --git a/aai-core/src/test/resources/payloads/resource/generic-vnf-notification.json b/aai-core/src/test/resources/payloads/resource/generic-vnf-notification.json new file mode 100644 index 00000000..27b38d2e --- /dev/null +++ b/aai-core/src/test/resources/payloads/resource/generic-vnf-notification.json @@ -0,0 +1,6 @@ +{ + "vnf-id": "generic-vnf-notification", + "vnf-type": "sometype", + "in-maint": true, + "is-closed-loop-disabled": true +} diff --git a/aai-core/src/test/resources/payloads/resource/generic-vnf-with-vf-module.json b/aai-core/src/test/resources/payloads/resource/generic-vnf-with-vf-module.json new file mode 100644 index 00000000..09c9b48f --- /dev/null +++ b/aai-core/src/test/resources/payloads/resource/generic-vnf-with-vf-module.json @@ -0,0 +1,17 @@ +{ + "vnf-id": "test-vnf11", + "vnf-name": "example-vnf-name-val-37069", + "vnf-name2": "example-vnf-name2-val-58382", + "vnf-type": "example-vnf-type-val-95069", + "in-maint": true, + "is-closed-loop-disabled": true, + "vf-modules": { + "vf-module": [ + { + "vf-module-id": "vf-module-test11", + "is-base-vf-module": true, + "automated-assignment": true + } + ] + } +} diff --git a/aai-core/src/test/resources/payloads/resource/notification-dmaap-events/depth-all/expected-notification-body-create-child-on-existing-obj.json b/aai-core/src/test/resources/payloads/resource/notification-dmaap-events/depth-all/expected-notification-body-create-child-on-existing-obj.json new file mode 100644 index 00000000..5cb33c82 --- /dev/null +++ b/aai-core/src/test/resources/payloads/resource/notification-dmaap-events/depth-all/expected-notification-body-create-child-on-existing-obj.json @@ -0,0 +1,273 @@ +{ + "hostname": "example-hostname-val-85598", + "ptnii-equip-name": "example-ptnii-equip-name-val-85834", + "number-of-cpus": 280, + "disk-in-gigabytes": 78521, + "ram-in-megabytes": 36975, + "equip-type": "example-equip-type-val-47930", + "equip-vendor": "example-equip-vendor-val-59512", + "equip-model": "example-equip-model-val-46076", + "fqdn": "example-fqdn-val-74486", + "pserver-selflink": "example-pserver-selflink-val-72481", + "ipv4-oam-address": "example-ipv4-oam-address-val-16616", + "serial-number": "example-serial-number-val-92800", + "ipaddress-v4-loopback-0": "example-ipaddress-v4-loopback0-val-61384", + "ipaddress-v6-loopback-0": "example-ipaddress-v6-loopback0-val-91056", + "ipaddress-v4-aim": "example-ipaddress-v4-aim-val-72233", + "ipaddress-v6-aim": "example-ipaddress-v6-aim-val-13572", + "ipaddress-v6-oam": "example-ipaddress-v6-oam-val-84518", + "inv-status": "example-inv-status-val-5042", + "pserver-id": "example-pserver-id-val-15622", + "internet-topology": "example-internet-topology-val-31234", + "in-maint": true, + "pserver-name2": "example-pserver-name2-val-93509", + "purpose": "example-purpose-val-52320", + "prov-status": "example-prov-status-val-47313", + "management-option": "example-management-option-val-72434", + "host-profile": "example-host-profile-val-84672", + "p-interfaces": { + "p-interface": [ + { + "interface-name": "example-interface-name-val-46147", + "selflink": "example-selflink-val-81029", + "speed-value": "example-speed-value-val-47874", + "speed-units": "example-speed-units-val-10396", + "port-description": "example-port-description-val-53068", + "equipment-identifier": "example-equipment-identifier-val-63234", + "interface-role": "example-interface-role-val-49232", + "interface-type": "example-interface-type-val-21757", + "prov-status": "example-prov-status-val-19117", + "in-maint": true, + "inv-status": "example-inv-status-val-48715", + "l-interfaces": { + "l-interface": [ + { + "interface-name": "example-interface-name-val-13366", + "interface-role": "example-interface-role-val-29488", + "v6-wan-link-ip": "example-v6-wan-link-ip-val-78396", + "selflink": "example-selflink-val-4757", + "interface-id": "example-interface-id-val-79486", + "macaddr": "example-macaddr-val-52194", + "network-name": "example-network-name-val-80678", + "management-option": "example-management-option-val-53535", + "interface-description": "example-interface-description-val-299", + "is-port-mirrored": true, + "in-maint": true, + "prov-status": "example-prov-status-val-9736", + "is-ip-unnumbered": true, + "allowed-address-pairs": "example-allowed-address-pairs-val-62271", + "vlans": { + "vlan": [ + { + "vlan-interface": "example-vlan-interface-val-31470", + "vlan-id-inner": 61286171, + "vlan-id-outer": 64615174, + "speed-value": "example-speed-value-val-80457", + "speed-units": "example-speed-units-val-51587", + "vlan-description": "example-vlan-description-val-97575", + "backdoor-connection": "example-backdoor-connection-val-3179", + "vpn-key": "example-vpn-key-val-50069", + "orchestration-status": "example-orchestration-status-val-34071", + "in-maint": true, + "prov-status": "example-prov-status-val-62615", + "is-ip-unnumbered": true, + "is-private": true, + "l3-interface-ipv4-address-list": [ + { + "l3-interface-ipv4-address": "example-l3-interface-ipv4-address-val-8171", + "l3-interface-ipv4-prefix-length": 39266592, + "vlan-id-inner": 91284707, + "vlan-id-outer": 80343467, + "is-floating": true, + "neutron-network-id": "example-neutron-network-id-val-52921", + "neutron-subnet-id": "example-neutron-subnet-id-val-88134" + } + ], + "l3-interface-ipv6-address-list": [ + { + "l3-interface-ipv6-address": "example-l3-interface-ipv6-address-val-70726", + "l3-interface-ipv6-prefix-length": 81422758, + "vlan-id-inner": 15099560, + "vlan-id-outer": 46643832, + "is-floating": true, + "neutron-network-id": "example-neutron-network-id-val-97954", + "neutron-subnet-id": "example-neutron-subnet-id-val-23889" + } + ] + } + ] + }, + "l-interfaces": { + "l-interface": [ + { + "interface-name": "example-interface-name-val-62086", + "interface-role": "example-interface-role-val-13107", + "v6-wan-link-ip": "example-v6-wan-link-ip-val-32015", + "selflink": "example-selflink-val-31580", + "interface-id": "example-interface-id-val-57805", + "macaddr": "example-macaddr-val-54266", + "network-name": "example-network-name-val-38517", + "management-option": "example-management-option-val-8801", + "interface-description": "example-interface-description-val-88573", + "is-port-mirrored": true, + "in-maint": true, + "prov-status": "example-prov-status-val-99164", + "is-ip-unnumbered": true, + "allowed-address-pairs": "example-allowed-address-pairs-val-14581", + "admin-status": "example-admin-status-val-29720" + } + ] + }, + "l3-interface-ipv4-address-list": [ + { + "l3-interface-ipv4-address": "example-l3-interface-ipv4-address-val-31324", + "l3-interface-ipv4-prefix-length": 36060646, + "vlan-id-inner": 62164959, + "vlan-id-outer": 93058593, + "is-floating": true, + "neutron-network-id": "example-neutron-network-id-val-39206", + "neutron-subnet-id": "example-neutron-subnet-id-val-27746" + } + ], + "l3-interface-ipv6-address-list": [ + { + "l3-interface-ipv6-address": "example-l3-interface-ipv6-address-val-72897", + "l3-interface-ipv6-prefix-length": 29592510, + "vlan-id-inner": 18402161, + "vlan-id-outer": 651158, + "is-floating": true, + "neutron-network-id": "example-neutron-network-id-val-6821", + "neutron-subnet-id": "example-neutron-subnet-id-val-11217" + } + ], + "admin-status": "example-admin-status-val-81745" + } + ] + } + }, + { + "interface-name": "p-interface-1", + "in-maint": false + } + ] + }, + "lag-interfaces": { + "lag-interface": [ + { + "interface-name": "example-interface-name-val-87366", + "interface-description": "example-interface-description-val-3722", + "speed-value": "example-speed-value-val-73546", + "speed-units": "example-speed-units-val-73658", + "interface-id": "example-interface-id-val-62385", + "interface-role": "example-interface-role-val-60746", + "prov-status": "example-prov-status-val-26239", + "in-maint": true, + "l-interfaces": { + "l-interface": [ + { + "interface-name": "example-interface-name-val-69579", + "interface-role": "example-interface-role-val-64571", + "v6-wan-link-ip": "example-v6-wan-link-ip-val-68385", + "selflink": "example-selflink-val-29611", + "interface-id": "example-interface-id-val-75464", + "macaddr": "example-macaddr-val-7285", + "network-name": "example-network-name-val-52284", + "management-option": "example-management-option-val-26028", + "interface-description": "example-interface-description-val-37641", + "is-port-mirrored": true, + "in-maint": true, + "prov-status": "example-prov-status-val-56460", + "is-ip-unnumbered": true, + "allowed-address-pairs": "example-allowed-address-pairs-val-23301", + "vlans": { + "vlan": [ + { + "vlan-interface": "example-vlan-interface-val-56661", + "vlan-id-inner": 33305644, + "vlan-id-outer": 30871600, + "speed-value": "example-speed-value-val-1929", + "speed-units": "example-speed-units-val-71630", + "vlan-description": "example-vlan-description-val-63003", + "backdoor-connection": "example-backdoor-connection-val-41834", + "vpn-key": "example-vpn-key-val-16552", + "orchestration-status": "example-orchestration-status-val-95322", + "in-maint": true, + "prov-status": "example-prov-status-val-89886", + "is-ip-unnumbered": true, + "is-private": true, + "l3-interface-ipv4-address-list": [ + { + "l3-interface-ipv4-address": "example-l3-interface-ipv4-address-val-69142", + "l3-interface-ipv4-prefix-length": 11099430, + "vlan-id-inner": 88996967, + "vlan-id-outer": 23003182, + "is-floating": true, + "neutron-network-id": "example-neutron-network-id-val-53091", + "neutron-subnet-id": "example-neutron-subnet-id-val-41571" + } + ], + "l3-interface-ipv6-address-list": [ + { + "l3-interface-ipv6-address": "example-l3-interface-ipv6-address-val-27490", + "l3-interface-ipv6-prefix-length": 20167688, + "vlan-id-inner": 40775405, + "vlan-id-outer": 75855907, + "is-floating": true, + "neutron-network-id": "example-neutron-network-id-val-9739", + "neutron-subnet-id": "example-neutron-subnet-id-val-806" + } + ] + } + ] + }, + "l-interfaces": { + "l-interface": [ + { + "interface-name": "example-interface-name-val-49266", + "interface-role": "example-interface-role-val-210", + "v6-wan-link-ip": "example-v6-wan-link-ip-val-81668", + "selflink": "example-selflink-val-6356", + "interface-id": "example-interface-id-val-99531", + "macaddr": "example-macaddr-val-25092", + "network-name": "example-network-name-val-3319", + "management-option": "example-management-option-val-79883", + "interface-description": "example-interface-description-val-54501", + "is-port-mirrored": true, + "in-maint": true, + "prov-status": "example-prov-status-val-48840", + "is-ip-unnumbered": true, + "allowed-address-pairs": "example-allowed-address-pairs-val-26846", + "admin-status": "example-admin-status-val-89244" + } + ] + }, + "l3-interface-ipv4-address-list": [ + { + "l3-interface-ipv4-address": "example-l3-interface-ipv4-address-val-61251", + "l3-interface-ipv4-prefix-length": 91875404, + "vlan-id-inner": 36470314, + "vlan-id-outer": 96344091, + "is-floating": true, + "neutron-network-id": "example-neutron-network-id-val-17339", + "neutron-subnet-id": "example-neutron-subnet-id-val-86128" + } + ], + "l3-interface-ipv6-address-list": [ + { + "l3-interface-ipv6-address": "example-l3-interface-ipv6-address-val-31476", + "l3-interface-ipv6-prefix-length": 11663872, + "vlan-id-inner": 28459412, + "vlan-id-outer": 9852622, + "is-floating": true, + "neutron-network-id": "example-neutron-network-id-val-15120", + "neutron-subnet-id": "example-neutron-subnet-id-val-36088" + } + ], + "admin-status": "example-admin-status-val-81055" + } + ] + } + } + ] + } +} diff --git a/aai-core/src/test/resources/payloads/resource/notification-dmaap-events/depth-all/expected-notification-body-create-edge-between-pserver-and-generic-vnf.json b/aai-core/src/test/resources/payloads/resource/notification-dmaap-events/depth-all/expected-notification-body-create-edge-between-pserver-and-generic-vnf.json new file mode 100644 index 00000000..79099538 --- /dev/null +++ b/aai-core/src/test/resources/payloads/resource/notification-dmaap-events/depth-all/expected-notification-body-create-edge-between-pserver-and-generic-vnf.json @@ -0,0 +1,289 @@ +{ + "hostname": "example-hostname-val-85598", + "ptnii-equip-name": "example-ptnii-equip-name-val-85834", + "number-of-cpus": 280, + "disk-in-gigabytes": 78521, + "ram-in-megabytes": 36975, + "equip-type": "example-equip-type-val-47930", + "equip-vendor": "example-equip-vendor-val-59512", + "equip-model": "example-equip-model-val-46076", + "fqdn": "example-fqdn-val-74486", + "pserver-selflink": "example-pserver-selflink-val-72481", + "ipv4-oam-address": "example-ipv4-oam-address-val-16616", + "serial-number": "example-serial-number-val-92800", + "ipaddress-v4-loopback-0": "example-ipaddress-v4-loopback0-val-61384", + "ipaddress-v6-loopback-0": "example-ipaddress-v6-loopback0-val-91056", + "ipaddress-v4-aim": "example-ipaddress-v4-aim-val-72233", + "ipaddress-v6-aim": "example-ipaddress-v6-aim-val-13572", + "ipaddress-v6-oam": "example-ipaddress-v6-oam-val-84518", + "inv-status": "example-inv-status-val-5042", + "pserver-id": "example-pserver-id-val-15622", + "internet-topology": "example-internet-topology-val-31234", + "in-maint": true, + "pserver-name2": "example-pserver-name2-val-93509", + "purpose": "example-purpose-val-52320", + "prov-status": "example-prov-status-val-47313", + "management-option": "example-management-option-val-72434", + "host-profile": "example-host-profile-val-84672", + "relationship-list": { + "relationship": [ + { + "related-to": "generic-vnf", + "relationship-label": "tosca.relationships.HostedOn", + "related-link": "/aai/v14/network/generic-vnfs/generic-vnf/generic-vnf-notification", + "relationship-data": [ + { + "relationship-key": "generic-vnf.vnf-id", + "relationship-value": "generic-vnf-notification" + } + ], + "related-to-property": [ + { + "property-key": "generic-vnf.vnf-name" + } + ] + } + ] + }, + "p-interfaces": { + "p-interface": [ + { + "interface-name": "example-interface-name-val-46147", + "selflink": "example-selflink-val-81029", + "speed-value": "example-speed-value-val-47874", + "speed-units": "example-speed-units-val-10396", + "port-description": "example-port-description-val-53068", + "equipment-identifier": "example-equipment-identifier-val-63234", + "interface-role": "example-interface-role-val-49232", + "interface-type": "example-interface-type-val-21757", + "prov-status": "example-prov-status-val-19117", + "in-maint": true, + "inv-status": "example-inv-status-val-48715", + "l-interfaces": { + "l-interface": [ + { + "interface-name": "example-interface-name-val-13366", + "interface-role": "example-interface-role-val-29488", + "v6-wan-link-ip": "example-v6-wan-link-ip-val-78396", + "selflink": "example-selflink-val-4757", + "interface-id": "example-interface-id-val-79486", + "macaddr": "example-macaddr-val-52194", + "network-name": "example-network-name-val-80678", + "management-option": "example-management-option-val-53535", + "interface-description": "example-interface-description-val-299", + "is-port-mirrored": true, + "in-maint": true, + "prov-status": "example-prov-status-val-9736", + "is-ip-unnumbered": true, + "allowed-address-pairs": "example-allowed-address-pairs-val-62271", + "vlans": { + "vlan": [ + { + "vlan-interface": "example-vlan-interface-val-31470", + "vlan-id-inner": 61286171, + "vlan-id-outer": 64615174, + "speed-value": "example-speed-value-val-80457", + "speed-units": "example-speed-units-val-51587", + "vlan-description": "example-vlan-description-val-97575", + "backdoor-connection": "example-backdoor-connection-val-3179", + "vpn-key": "example-vpn-key-val-50069", + "orchestration-status": "example-orchestration-status-val-34071", + "in-maint": true, + "prov-status": "example-prov-status-val-62615", + "is-ip-unnumbered": true, + "is-private": true, + "l3-interface-ipv4-address-list": [ + { + "l3-interface-ipv4-address": "example-l3-interface-ipv4-address-val-8171", + "l3-interface-ipv4-prefix-length": 39266592, + "vlan-id-inner": 91284707, + "vlan-id-outer": 80343467, + "is-floating": true, + "neutron-network-id": "example-neutron-network-id-val-52921", + "neutron-subnet-id": "example-neutron-subnet-id-val-88134" + } + ], + "l3-interface-ipv6-address-list": [ + { + "l3-interface-ipv6-address": "example-l3-interface-ipv6-address-val-70726", + "l3-interface-ipv6-prefix-length": 81422758, + "vlan-id-inner": 15099560, + "vlan-id-outer": 46643832, + "is-floating": true, + "neutron-network-id": "example-neutron-network-id-val-97954", + "neutron-subnet-id": "example-neutron-subnet-id-val-23889" + } + ] + } + ] + }, + "l-interfaces": { + "l-interface": [ + { + "interface-name": "example-interface-name-val-62086", + "interface-role": "example-interface-role-val-13107", + "v6-wan-link-ip": "example-v6-wan-link-ip-val-32015", + "selflink": "example-selflink-val-31580", + "interface-id": "example-interface-id-val-57805", + "macaddr": "example-macaddr-val-54266", + "network-name": "example-network-name-val-38517", + "management-option": "example-management-option-val-8801", + "interface-description": "example-interface-description-val-88573", + "is-port-mirrored": true, + "in-maint": true, + "prov-status": "example-prov-status-val-99164", + "is-ip-unnumbered": true, + "allowed-address-pairs": "example-allowed-address-pairs-val-14581", + "admin-status": "example-admin-status-val-29720" + } + ] + }, + "l3-interface-ipv4-address-list": [ + { + "l3-interface-ipv4-address": "example-l3-interface-ipv4-address-val-31324", + "l3-interface-ipv4-prefix-length": 36060646, + "vlan-id-inner": 62164959, + "vlan-id-outer": 93058593, + "is-floating": true, + "neutron-network-id": "example-neutron-network-id-val-39206", + "neutron-subnet-id": "example-neutron-subnet-id-val-27746" + } + ], + "l3-interface-ipv6-address-list": [ + { + "l3-interface-ipv6-address": "example-l3-interface-ipv6-address-val-72897", + "l3-interface-ipv6-prefix-length": 29592510, + "vlan-id-inner": 18402161, + "vlan-id-outer": 651158, + "is-floating": true, + "neutron-network-id": "example-neutron-network-id-val-6821", + "neutron-subnet-id": "example-neutron-subnet-id-val-11217" + } + ], + "admin-status": "example-admin-status-val-81745" + } + ] + } + } + ] + }, + "lag-interfaces": { + "lag-interface": [ + { + "interface-name": "example-interface-name-val-87366", + "interface-description": "example-interface-description-val-3722", + "speed-value": "example-speed-value-val-73546", + "speed-units": "example-speed-units-val-73658", + "interface-id": "example-interface-id-val-62385", + "interface-role": "example-interface-role-val-60746", + "prov-status": "example-prov-status-val-26239", + "in-maint": true, + "l-interfaces": { + "l-interface": [ + { + "interface-name": "example-interface-name-val-69579", + "interface-role": "example-interface-role-val-64571", + "v6-wan-link-ip": "example-v6-wan-link-ip-val-68385", + "selflink": "example-selflink-val-29611", + "interface-id": "example-interface-id-val-75464", + "macaddr": "example-macaddr-val-7285", + "network-name": "example-network-name-val-52284", + "management-option": "example-management-option-val-26028", + "interface-description": "example-interface-description-val-37641", + "is-port-mirrored": true, + "in-maint": true, + "prov-status": "example-prov-status-val-56460", + "is-ip-unnumbered": true, + "allowed-address-pairs": "example-allowed-address-pairs-val-23301", + "vlans": { + "vlan": [ + { + "vlan-interface": "example-vlan-interface-val-56661", + "vlan-id-inner": 33305644, + "vlan-id-outer": 30871600, + "speed-value": "example-speed-value-val-1929", + "speed-units": "example-speed-units-val-71630", + "vlan-description": "example-vlan-description-val-63003", + "backdoor-connection": "example-backdoor-connection-val-41834", + "vpn-key": "example-vpn-key-val-16552", + "orchestration-status": "example-orchestration-status-val-95322", + "in-maint": true, + "prov-status": "example-prov-status-val-89886", + "is-ip-unnumbered": true, + "is-private": true, + "l3-interface-ipv4-address-list": [ + { + "l3-interface-ipv4-address": "example-l3-interface-ipv4-address-val-69142", + "l3-interface-ipv4-prefix-length": 11099430, + "vlan-id-inner": 88996967, + "vlan-id-outer": 23003182, + "is-floating": true, + "neutron-network-id": "example-neutron-network-id-val-53091", + "neutron-subnet-id": "example-neutron-subnet-id-val-41571" + } + ], + "l3-interface-ipv6-address-list": [ + { + "l3-interface-ipv6-address": "example-l3-interface-ipv6-address-val-27490", + "l3-interface-ipv6-prefix-length": 20167688, + "vlan-id-inner": 40775405, + "vlan-id-outer": 75855907, + "is-floating": true, + "neutron-network-id": "example-neutron-network-id-val-9739", + "neutron-subnet-id": "example-neutron-subnet-id-val-806" + } + ] + } + ] + }, + "l-interfaces": { + "l-interface": [ + { + "interface-name": "example-interface-name-val-49266", + "interface-role": "example-interface-role-val-210", + "v6-wan-link-ip": "example-v6-wan-link-ip-val-81668", + "selflink": "example-selflink-val-6356", + "interface-id": "example-interface-id-val-99531", + "macaddr": "example-macaddr-val-25092", + "network-name": "example-network-name-val-3319", + "management-option": "example-management-option-val-79883", + "interface-description": "example-interface-description-val-54501", + "is-port-mirrored": true, + "in-maint": true, + "prov-status": "example-prov-status-val-48840", + "is-ip-unnumbered": true, + "allowed-address-pairs": "example-allowed-address-pairs-val-26846", + "admin-status": "example-admin-status-val-89244" + } + ] + }, + "l3-interface-ipv4-address-list": [ + { + "l3-interface-ipv4-address": "example-l3-interface-ipv4-address-val-61251", + "l3-interface-ipv4-prefix-length": 91875404, + "vlan-id-inner": 36470314, + "vlan-id-outer": 96344091, + "is-floating": true, + "neutron-network-id": "example-neutron-network-id-val-17339", + "neutron-subnet-id": "example-neutron-subnet-id-val-86128" + } + ], + "l3-interface-ipv6-address-list": [ + { + "l3-interface-ipv6-address": "example-l3-interface-ipv6-address-val-31476", + "l3-interface-ipv6-prefix-length": 11663872, + "vlan-id-inner": 28459412, + "vlan-id-outer": 9852622, + "is-floating": true, + "neutron-network-id": "example-neutron-network-id-val-15120", + "neutron-subnet-id": "example-neutron-subnet-id-val-36088" + } + ], + "admin-status": "example-admin-status-val-81055" + } + ] + } + } + ] + } +} diff --git a/aai-core/src/test/resources/payloads/resource/notification-dmaap-events/depth-all/expected-notification-body-delete-edge-between-pserver-and-generic-vnf.json b/aai-core/src/test/resources/payloads/resource/notification-dmaap-events/depth-all/expected-notification-body-delete-edge-between-pserver-and-generic-vnf.json new file mode 100644 index 00000000..cdcd3ee0 --- /dev/null +++ b/aai-core/src/test/resources/payloads/resource/notification-dmaap-events/depth-all/expected-notification-body-delete-edge-between-pserver-and-generic-vnf.json @@ -0,0 +1,269 @@ +{ + "hostname": "example-hostname-val-85598", + "ptnii-equip-name": "example-ptnii-equip-name-val-85834", + "number-of-cpus": 280, + "disk-in-gigabytes": 78521, + "ram-in-megabytes": 36975, + "equip-type": "example-equip-type-val-47930", + "equip-vendor": "example-equip-vendor-val-59512", + "equip-model": "example-equip-model-val-46076", + "fqdn": "example-fqdn-val-74486", + "pserver-selflink": "example-pserver-selflink-val-72481", + "ipv4-oam-address": "example-ipv4-oam-address-val-16616", + "serial-number": "example-serial-number-val-92800", + "ipaddress-v4-loopback-0": "example-ipaddress-v4-loopback0-val-61384", + "ipaddress-v6-loopback-0": "example-ipaddress-v6-loopback0-val-91056", + "ipaddress-v4-aim": "example-ipaddress-v4-aim-val-72233", + "ipaddress-v6-aim": "example-ipaddress-v6-aim-val-13572", + "ipaddress-v6-oam": "example-ipaddress-v6-oam-val-84518", + "inv-status": "example-inv-status-val-5042", + "pserver-id": "example-pserver-id-val-15622", + "internet-topology": "example-internet-topology-val-31234", + "in-maint": true, + "pserver-name2": "example-pserver-name2-val-93509", + "purpose": "example-purpose-val-52320", + "prov-status": "example-prov-status-val-47313", + "management-option": "example-management-option-val-72434", + "host-profile": "example-host-profile-val-84672", + "p-interfaces": { + "p-interface": [ + { + "interface-name": "example-interface-name-val-46147", + "selflink": "example-selflink-val-81029", + "speed-value": "example-speed-value-val-47874", + "speed-units": "example-speed-units-val-10396", + "port-description": "example-port-description-val-53068", + "equipment-identifier": "example-equipment-identifier-val-63234", + "interface-role": "example-interface-role-val-49232", + "interface-type": "example-interface-type-val-21757", + "prov-status": "example-prov-status-val-19117", + "in-maint": true, + "inv-status": "example-inv-status-val-48715", + "l-interfaces": { + "l-interface": [ + { + "interface-name": "example-interface-name-val-13366", + "interface-role": "example-interface-role-val-29488", + "v6-wan-link-ip": "example-v6-wan-link-ip-val-78396", + "selflink": "example-selflink-val-4757", + "interface-id": "example-interface-id-val-79486", + "macaddr": "example-macaddr-val-52194", + "network-name": "example-network-name-val-80678", + "management-option": "example-management-option-val-53535", + "interface-description": "example-interface-description-val-299", + "is-port-mirrored": true, + "in-maint": true, + "prov-status": "example-prov-status-val-9736", + "is-ip-unnumbered": true, + "allowed-address-pairs": "example-allowed-address-pairs-val-62271", + "vlans": { + "vlan": [ + { + "vlan-interface": "example-vlan-interface-val-31470", + "vlan-id-inner": 61286171, + "vlan-id-outer": 64615174, + "speed-value": "example-speed-value-val-80457", + "speed-units": "example-speed-units-val-51587", + "vlan-description": "example-vlan-description-val-97575", + "backdoor-connection": "example-backdoor-connection-val-3179", + "vpn-key": "example-vpn-key-val-50069", + "orchestration-status": "example-orchestration-status-val-34071", + "in-maint": true, + "prov-status": "example-prov-status-val-62615", + "is-ip-unnumbered": true, + "is-private": true, + "l3-interface-ipv4-address-list": [ + { + "l3-interface-ipv4-address": "example-l3-interface-ipv4-address-val-8171", + "l3-interface-ipv4-prefix-length": 39266592, + "vlan-id-inner": 91284707, + "vlan-id-outer": 80343467, + "is-floating": true, + "neutron-network-id": "example-neutron-network-id-val-52921", + "neutron-subnet-id": "example-neutron-subnet-id-val-88134" + } + ], + "l3-interface-ipv6-address-list": [ + { + "l3-interface-ipv6-address": "example-l3-interface-ipv6-address-val-70726", + "l3-interface-ipv6-prefix-length": 81422758, + "vlan-id-inner": 15099560, + "vlan-id-outer": 46643832, + "is-floating": true, + "neutron-network-id": "example-neutron-network-id-val-97954", + "neutron-subnet-id": "example-neutron-subnet-id-val-23889" + } + ] + } + ] + }, + "l-interfaces": { + "l-interface": [ + { + "interface-name": "example-interface-name-val-62086", + "interface-role": "example-interface-role-val-13107", + "v6-wan-link-ip": "example-v6-wan-link-ip-val-32015", + "selflink": "example-selflink-val-31580", + "interface-id": "example-interface-id-val-57805", + "macaddr": "example-macaddr-val-54266", + "network-name": "example-network-name-val-38517", + "management-option": "example-management-option-val-8801", + "interface-description": "example-interface-description-val-88573", + "is-port-mirrored": true, + "in-maint": true, + "prov-status": "example-prov-status-val-99164", + "is-ip-unnumbered": true, + "allowed-address-pairs": "example-allowed-address-pairs-val-14581", + "admin-status": "example-admin-status-val-29720" + } + ] + }, + "l3-interface-ipv4-address-list": [ + { + "l3-interface-ipv4-address": "example-l3-interface-ipv4-address-val-31324", + "l3-interface-ipv4-prefix-length": 36060646, + "vlan-id-inner": 62164959, + "vlan-id-outer": 93058593, + "is-floating": true, + "neutron-network-id": "example-neutron-network-id-val-39206", + "neutron-subnet-id": "example-neutron-subnet-id-val-27746" + } + ], + "l3-interface-ipv6-address-list": [ + { + "l3-interface-ipv6-address": "example-l3-interface-ipv6-address-val-72897", + "l3-interface-ipv6-prefix-length": 29592510, + "vlan-id-inner": 18402161, + "vlan-id-outer": 651158, + "is-floating": true, + "neutron-network-id": "example-neutron-network-id-val-6821", + "neutron-subnet-id": "example-neutron-subnet-id-val-11217" + } + ], + "admin-status": "example-admin-status-val-81745" + } + ] + } + } + ] + }, + "lag-interfaces": { + "lag-interface": [ + { + "interface-name": "example-interface-name-val-87366", + "interface-description": "example-interface-description-val-3722", + "speed-value": "example-speed-value-val-73546", + "speed-units": "example-speed-units-val-73658", + "interface-id": "example-interface-id-val-62385", + "interface-role": "example-interface-role-val-60746", + "prov-status": "example-prov-status-val-26239", + "in-maint": true, + "l-interfaces": { + "l-interface": [ + { + "interface-name": "example-interface-name-val-69579", + "interface-role": "example-interface-role-val-64571", + "v6-wan-link-ip": "example-v6-wan-link-ip-val-68385", + "selflink": "example-selflink-val-29611", + "interface-id": "example-interface-id-val-75464", + "macaddr": "example-macaddr-val-7285", + "network-name": "example-network-name-val-52284", + "management-option": "example-management-option-val-26028", + "interface-description": "example-interface-description-val-37641", + "is-port-mirrored": true, + "in-maint": true, + "prov-status": "example-prov-status-val-56460", + "is-ip-unnumbered": true, + "allowed-address-pairs": "example-allowed-address-pairs-val-23301", + "vlans": { + "vlan": [ + { + "vlan-interface": "example-vlan-interface-val-56661", + "vlan-id-inner": 33305644, + "vlan-id-outer": 30871600, + "speed-value": "example-speed-value-val-1929", + "speed-units": "example-speed-units-val-71630", + "vlan-description": "example-vlan-description-val-63003", + "backdoor-connection": "example-backdoor-connection-val-41834", + "vpn-key": "example-vpn-key-val-16552", + "orchestration-status": "example-orchestration-status-val-95322", + "in-maint": true, + "prov-status": "example-prov-status-val-89886", + "is-ip-unnumbered": true, + "is-private": true, + "l3-interface-ipv4-address-list": [ + { + "l3-interface-ipv4-address": "example-l3-interface-ipv4-address-val-69142", + "l3-interface-ipv4-prefix-length": 11099430, + "vlan-id-inner": 88996967, + "vlan-id-outer": 23003182, + "is-floating": true, + "neutron-network-id": "example-neutron-network-id-val-53091", + "neutron-subnet-id": "example-neutron-subnet-id-val-41571" + } + ], + "l3-interface-ipv6-address-list": [ + { + "l3-interface-ipv6-address": "example-l3-interface-ipv6-address-val-27490", + "l3-interface-ipv6-prefix-length": 20167688, + "vlan-id-inner": 40775405, + "vlan-id-outer": 75855907, + "is-floating": true, + "neutron-network-id": "example-neutron-network-id-val-9739", + "neutron-subnet-id": "example-neutron-subnet-id-val-806" + } + ] + } + ] + }, + "l-interfaces": { + "l-interface": [ + { + "interface-name": "example-interface-name-val-49266", + "interface-role": "example-interface-role-val-210", + "v6-wan-link-ip": "example-v6-wan-link-ip-val-81668", + "selflink": "example-selflink-val-6356", + "interface-id": "example-interface-id-val-99531", + "macaddr": "example-macaddr-val-25092", + "network-name": "example-network-name-val-3319", + "management-option": "example-management-option-val-79883", + "interface-description": "example-interface-description-val-54501", + "is-port-mirrored": true, + "in-maint": true, + "prov-status": "example-prov-status-val-48840", + "is-ip-unnumbered": true, + "allowed-address-pairs": "example-allowed-address-pairs-val-26846", + "admin-status": "example-admin-status-val-89244" + } + ] + }, + "l3-interface-ipv4-address-list": [ + { + "l3-interface-ipv4-address": "example-l3-interface-ipv4-address-val-61251", + "l3-interface-ipv4-prefix-length": 91875404, + "vlan-id-inner": 36470314, + "vlan-id-outer": 96344091, + "is-floating": true, + "neutron-network-id": "example-neutron-network-id-val-17339", + "neutron-subnet-id": "example-neutron-subnet-id-val-86128" + } + ], + "l3-interface-ipv6-address-list": [ + { + "l3-interface-ipv6-address": "example-l3-interface-ipv6-address-val-31476", + "l3-interface-ipv6-prefix-length": 11663872, + "vlan-id-inner": 28459412, + "vlan-id-outer": 9852622, + "is-floating": true, + "neutron-network-id": "example-neutron-network-id-val-15120", + "neutron-subnet-id": "example-neutron-subnet-id-val-36088" + } + ], + "admin-status": "example-admin-status-val-81055" + } + ] + } + } + ] + } +} diff --git a/aai-core/src/test/resources/payloads/resource/notification-dmaap-events/depth-all/expected-notification-header-create-child-on-existing-obj.json b/aai-core/src/test/resources/payloads/resource/notification-dmaap-events/depth-all/expected-notification-header-create-child-on-existing-obj.json new file mode 100644 index 00000000..2c255c1f --- /dev/null +++ b/aai-core/src/test/resources/payloads/resource/notification-dmaap-events/depth-all/expected-notification-header-create-child-on-existing-obj.json @@ -0,0 +1,9 @@ +{ + "id": "JUNIT-TRANSACTION", + "source-name": "JUNIT", + "version": "v14", + "action": "UPDATE", + "entity-type": "pserver", + "top-entity-type": "pserver", + "entity-link": "/aai/v14/cloud-infrastructure/pservers/pserver/example-hostname-val-85598" +} diff --git a/aai-core/src/test/resources/payloads/resource/notification-dmaap-events/depth-all/expected-notification-header-create-edge-between-pserver-and-generic-vnf.json b/aai-core/src/test/resources/payloads/resource/notification-dmaap-events/depth-all/expected-notification-header-create-edge-between-pserver-and-generic-vnf.json new file mode 100644 index 00000000..2c255c1f --- /dev/null +++ b/aai-core/src/test/resources/payloads/resource/notification-dmaap-events/depth-all/expected-notification-header-create-edge-between-pserver-and-generic-vnf.json @@ -0,0 +1,9 @@ +{ + "id": "JUNIT-TRANSACTION", + "source-name": "JUNIT", + "version": "v14", + "action": "UPDATE", + "entity-type": "pserver", + "top-entity-type": "pserver", + "entity-link": "/aai/v14/cloud-infrastructure/pservers/pserver/example-hostname-val-85598" +} diff --git a/aai-core/src/test/resources/payloads/resource/notification-dmaap-events/depth-all/expected-notification-header-delete-edge-between-pserver-and-generic-vnf.json b/aai-core/src/test/resources/payloads/resource/notification-dmaap-events/depth-all/expected-notification-header-delete-edge-between-pserver-and-generic-vnf.json new file mode 100644 index 00000000..2c255c1f --- /dev/null +++ b/aai-core/src/test/resources/payloads/resource/notification-dmaap-events/depth-all/expected-notification-header-delete-edge-between-pserver-and-generic-vnf.json @@ -0,0 +1,9 @@ +{ + "id": "JUNIT-TRANSACTION", + "source-name": "JUNIT", + "version": "v14", + "action": "UPDATE", + "entity-type": "pserver", + "top-entity-type": "pserver", + "entity-link": "/aai/v14/cloud-infrastructure/pservers/pserver/example-hostname-val-85598" +} diff --git a/aai-core/src/test/resources/payloads/resource/notification-dmaap-events/depth-zero/expected-notification-body-create-child-on-existing-obj.json b/aai-core/src/test/resources/payloads/resource/notification-dmaap-events/depth-zero/expected-notification-body-create-child-on-existing-obj.json new file mode 100644 index 00000000..174db245 --- /dev/null +++ b/aai-core/src/test/resources/payloads/resource/notification-dmaap-events/depth-zero/expected-notification-body-create-child-on-existing-obj.json @@ -0,0 +1,12 @@ +{ + "hostname": "example-hostname-val-85598", + "pserver-name2": "example-pserver-name2-val-93509", + "p-interfaces": { + "p-interface": [ + { + "interface-name": "p-interface-1", + "in-maint": false + } + ] + } +} diff --git a/aai-core/src/test/resources/payloads/resource/notification-dmaap-events/depth-zero/expected-notification-body-create-edge-between-pserver-and-generic-vnf.json b/aai-core/src/test/resources/payloads/resource/notification-dmaap-events/depth-zero/expected-notification-body-create-edge-between-pserver-and-generic-vnf.json new file mode 100644 index 00000000..54afd1b6 --- /dev/null +++ b/aai-core/src/test/resources/payloads/resource/notification-dmaap-events/depth-zero/expected-notification-body-create-edge-between-pserver-and-generic-vnf.json @@ -0,0 +1,48 @@ +{ + "hostname": "example-hostname-val-85598", + "ptnii-equip-name": "example-ptnii-equip-name-val-85834", + "number-of-cpus": 280, + "disk-in-gigabytes": 78521, + "ram-in-megabytes": 36975, + "equip-type": "example-equip-type-val-47930", + "equip-vendor": "example-equip-vendor-val-59512", + "equip-model": "example-equip-model-val-46076", + "fqdn": "example-fqdn-val-74486", + "pserver-selflink": "example-pserver-selflink-val-72481", + "ipv4-oam-address": "example-ipv4-oam-address-val-16616", + "serial-number": "example-serial-number-val-92800", + "ipaddress-v4-loopback-0": "example-ipaddress-v4-loopback0-val-61384", + "ipaddress-v6-loopback-0": "example-ipaddress-v6-loopback0-val-91056", + "ipaddress-v4-aim": "example-ipaddress-v4-aim-val-72233", + "ipaddress-v6-aim": "example-ipaddress-v6-aim-val-13572", + "ipaddress-v6-oam": "example-ipaddress-v6-oam-val-84518", + "inv-status": "example-inv-status-val-5042", + "pserver-id": "example-pserver-id-val-15622", + "internet-topology": "example-internet-topology-val-31234", + "in-maint": true, + "pserver-name2": "example-pserver-name2-val-93509", + "purpose": "example-purpose-val-52320", + "prov-status": "example-prov-status-val-47313", + "management-option": "example-management-option-val-72434", + "host-profile": "example-host-profile-val-84672", + "relationship-list": { + "relationship": [ + { + "related-to": "generic-vnf", + "relationship-label": "tosca.relationships.HostedOn", + "related-link": "/aai/v14/network/generic-vnfs/generic-vnf/generic-vnf-notification", + "relationship-data": [ + { + "relationship-key": "generic-vnf.vnf-id", + "relationship-value": "generic-vnf-notification" + } + ], + "related-to-property": [ + { + "property-key": "generic-vnf.vnf-name" + } + ] + } + ] + } +} diff --git a/aai-core/src/test/resources/payloads/resource/notification-dmaap-events/depth-zero/expected-notification-body-delete-edge-between-pserver-and-generic-vnf.json b/aai-core/src/test/resources/payloads/resource/notification-dmaap-events/depth-zero/expected-notification-body-delete-edge-between-pserver-and-generic-vnf.json new file mode 100644 index 00000000..369bc29b --- /dev/null +++ b/aai-core/src/test/resources/payloads/resource/notification-dmaap-events/depth-zero/expected-notification-body-delete-edge-between-pserver-and-generic-vnf.json @@ -0,0 +1,28 @@ +{ + "hostname": "example-hostname-val-85598", + "ptnii-equip-name": "example-ptnii-equip-name-val-85834", + "number-of-cpus": 280, + "disk-in-gigabytes": 78521, + "ram-in-megabytes": 36975, + "equip-type": "example-equip-type-val-47930", + "equip-vendor": "example-equip-vendor-val-59512", + "equip-model": "example-equip-model-val-46076", + "fqdn": "example-fqdn-val-74486", + "pserver-selflink": "example-pserver-selflink-val-72481", + "ipv4-oam-address": "example-ipv4-oam-address-val-16616", + "serial-number": "example-serial-number-val-92800", + "ipaddress-v4-loopback-0": "example-ipaddress-v4-loopback0-val-61384", + "ipaddress-v6-loopback-0": "example-ipaddress-v6-loopback0-val-91056", + "ipaddress-v4-aim": "example-ipaddress-v4-aim-val-72233", + "ipaddress-v6-aim": "example-ipaddress-v6-aim-val-13572", + "ipaddress-v6-oam": "example-ipaddress-v6-oam-val-84518", + "inv-status": "example-inv-status-val-5042", + "pserver-id": "example-pserver-id-val-15622", + "internet-topology": "example-internet-topology-val-31234", + "in-maint": true, + "pserver-name2": "example-pserver-name2-val-93509", + "purpose": "example-purpose-val-52320", + "prov-status": "example-prov-status-val-47313", + "management-option": "example-management-option-val-72434", + "host-profile": "example-host-profile-val-84672" +} diff --git a/aai-core/src/test/resources/payloads/resource/notification-dmaap-events/depth-zero/expected-notification-header-create-child-on-existing-obj.json b/aai-core/src/test/resources/payloads/resource/notification-dmaap-events/depth-zero/expected-notification-header-create-child-on-existing-obj.json new file mode 100644 index 00000000..e9c408af --- /dev/null +++ b/aai-core/src/test/resources/payloads/resource/notification-dmaap-events/depth-zero/expected-notification-header-create-child-on-existing-obj.json @@ -0,0 +1,9 @@ +{ + "id": "JUNIT-TRANSACTION", + "source-name": "JUNIT", + "version": "v14", + "action": "CREATE", + "entity-type": "p-interface", + "top-entity-type": "pserver", + "entity-link": "/aai/v14/cloud-infrastructure/pservers/pserver/example-hostname-val-85598/p-interfaces/p-interface/p-interface-1" +} diff --git a/aai-core/src/test/resources/payloads/resource/notification-dmaap-events/depth-zero/expected-notification-header-create-edge-between-pserver-and-generic-vnf.json b/aai-core/src/test/resources/payloads/resource/notification-dmaap-events/depth-zero/expected-notification-header-create-edge-between-pserver-and-generic-vnf.json new file mode 100644 index 00000000..2c255c1f --- /dev/null +++ b/aai-core/src/test/resources/payloads/resource/notification-dmaap-events/depth-zero/expected-notification-header-create-edge-between-pserver-and-generic-vnf.json @@ -0,0 +1,9 @@ +{ + "id": "JUNIT-TRANSACTION", + "source-name": "JUNIT", + "version": "v14", + "action": "UPDATE", + "entity-type": "pserver", + "top-entity-type": "pserver", + "entity-link": "/aai/v14/cloud-infrastructure/pservers/pserver/example-hostname-val-85598" +} diff --git a/aai-core/src/test/resources/payloads/resource/notification-dmaap-events/depth-zero/expected-notification-header-delete-edge-between-pserver-and-generic-vnf.json b/aai-core/src/test/resources/payloads/resource/notification-dmaap-events/depth-zero/expected-notification-header-delete-edge-between-pserver-and-generic-vnf.json new file mode 100644 index 00000000..2c255c1f --- /dev/null +++ b/aai-core/src/test/resources/payloads/resource/notification-dmaap-events/depth-zero/expected-notification-header-delete-edge-between-pserver-and-generic-vnf.json @@ -0,0 +1,9 @@ +{ + "id": "JUNIT-TRANSACTION", + "source-name": "JUNIT", + "version": "v14", + "action": "UPDATE", + "entity-type": "pserver", + "top-entity-type": "pserver", + "entity-link": "/aai/v14/cloud-infrastructure/pservers/pserver/example-hostname-val-85598" +} diff --git a/aai-core/src/test/resources/payloads/resource/prevalidation/failed-response-with-violations.json b/aai-core/src/test/resources/payloads/resource/prevalidation/failed-response-with-violations.json new file mode 100644 index 00000000..409516dc --- /dev/null +++ b/aai-core/src/test/resources/payloads/resource/prevalidation/failed-response-with-violations.json @@ -0,0 +1,28 @@ +{ + "validationId": "52245aa2-72a8-440d-87e2-570272aa4a83", + "validationTimestamp": "20191201T211503Z", + "entityId": { + "vnf-id": "vnf-jenkins-15903-3" + }, + "entityName": "ormfl405me3", + "entityType": "generic-vnf", + "entityLink": "network/generic-vnfs/generic-vnf/vnf-jenkins-15903-3", + "resourceVersion": "1567815933280", + "requestor": "JUNIT", + "violations": [{ + "violationId": "37d6a7ebc1fc244f9dd04b1518726a9b4cc2350e6ff478c69502e8aeb1508333", + "modelName": null, + "category": "INVALID_VALUE", + "severity": "MAJOR", + "violationType": "Dlp_rule", + "validationRule": "DLP validate generic-vnf nf-values", + "violationDetails": { + "nf-role": "vSAEGW", + "nf-naming-code": "foo", + "nf-type": "blah", + "nf-function": "blah" + }, + "errorMessage": "Invalid nf values, check nf-type, nf-role, nf-function, and nf-naming-code" + } + ] +} diff --git a/aai-core/src/test/resources/payloads/resource/prevalidation/success-request-with-no-violations.json b/aai-core/src/test/resources/payloads/resource/prevalidation/success-request-with-no-violations.json new file mode 100644 index 00000000..328f9a26 --- /dev/null +++ b/aai-core/src/test/resources/payloads/resource/prevalidation/success-request-with-no-violations.json @@ -0,0 +1,22 @@ +{ + "cambria.partition": "AAI", + "event-header": { + "severity": "NORMAL", + "entity-type": "pserver", + "top-entity-type": "pserver", + "entity-link": "/aai/v19/cloud-infrastructure/pservers/pserver/test-pserver234", + "event-type": "AAI-EVENT", + "domain": "uINT6", + "action": "CREATE", + "sequence-number": "0", + "id": "70b33094-9d60-4e49-9a42-9f9b45ef1aa6", + "source-name": "JUNIT", + "version": "v19", + "timestamp": "20191202-01:26:24:749" + }, + "entity": { + "hostname": "test-pserver234", + "in-maint": false, + "resource-version": "1575249983853" + } +} diff --git a/aai-core/src/test/resources/payloads/resource/prevalidation/success-response-with-empty-violations.json b/aai-core/src/test/resources/payloads/resource/prevalidation/success-response-with-empty-violations.json new file mode 100644 index 00000000..ecd907a1 --- /dev/null +++ b/aai-core/src/test/resources/payloads/resource/prevalidation/success-response-with-empty-violations.json @@ -0,0 +1,13 @@ +{ + "validationId": "52245aa2-72a8-440d-87e2-570272aa4a83b", + "validationTimestamp": "20191201T211503Z", + "entityId": { + "vnf-id": "vnf-jenkins-15903-3" + }, + "entityName": "ormfl405me3", + "entityType": "generic-vnf", + "entityLink": "network/generic-vnfs/generic-vnf/vnf-jenkins-15903-3", + "resourceVersion": "1567815933280", + "requestor": "JUNIT", + "violations": [] +} diff --git a/aai-core/src/test/resources/payloads/resource/prevalidation/success-response-with-exclude-violations.json b/aai-core/src/test/resources/payloads/resource/prevalidation/success-response-with-exclude-violations.json new file mode 100644 index 00000000..106b763a --- /dev/null +++ b/aai-core/src/test/resources/payloads/resource/prevalidation/success-response-with-exclude-violations.json @@ -0,0 +1,12 @@ +{ + "validationId": "52245aa2-72a8-440d-87e2-570272aa4a83b", + "validationTimestamp": "20191201T211503Z", + "entityId": { + "vnf-id": "vnf-jenkins-15903-3" + }, + "entityName": "ormfl405me3", + "entityType": "generic-vnf", + "entityLink": "network/generic-vnfs/generic-vnf/vnf-jenkins-15903-3", + "resourceVersion": "1567815933280", + "requestor": "JUNIT" +} diff --git a/aai-core/src/test/resources/payloads/resource/pserver-implied-delete.json b/aai-core/src/test/resources/payloads/resource/pserver-implied-delete.json new file mode 100644 index 00000000..5cc35713 --- /dev/null +++ b/aai-core/src/test/resources/payloads/resource/pserver-implied-delete.json @@ -0,0 +1,23 @@ +{ + "hostname": "test-pserver-implied-delete", + "p-interfaces": { + "p-interface": [ + { + "interface-name": "test-p-interface-implied-delete-1", + "selflink": "somelink" + }, + { + "interface-name": "test-p-interface-implied-delete-2", + "selflink": "somelink" + }, + { + "interface-name": "test-p-interface-implied-delete-3", + "selflink": "somelink" + }, + { + "interface-name": "test-p-interface-implied-delete-4", + "selflink": "somelink" + } + ] + } +} diff --git a/aai-core/src/test/resources/payloads/resource/pserver-to-gvnf-relationship-notification.json b/aai-core/src/test/resources/payloads/resource/pserver-to-gvnf-relationship-notification.json new file mode 100644 index 00000000..cb8ec43a --- /dev/null +++ b/aai-core/src/test/resources/payloads/resource/pserver-to-gvnf-relationship-notification.json @@ -0,0 +1,4 @@ +{ + "related-to": "generic-vnf", + "related-link": "/network/generic-vnfs/generic-vnf/generic-vnf-notification" +} diff --git a/aai-core/src/test/resources/payloads/resource/pserver-with-children-for-notification.json b/aai-core/src/test/resources/payloads/resource/pserver-with-children-for-notification.json new file mode 100644 index 00000000..f0dd071c --- /dev/null +++ b/aai-core/src/test/resources/payloads/resource/pserver-with-children-for-notification.json @@ -0,0 +1,273 @@ +{ + "hostname": "example-hostname-val-85598", + "ptnii-equip-name": "example-ptnii-equip-name-val-85834", + "number-of-cpus": 280, + "disk-in-gigabytes": 78521, + "ram-in-megabytes": 36975, + "equip-type": "example-equip-type-val-47930", + "equip-vendor": "example-equip-vendor-val-59512", + "equip-model": "example-equip-model-val-46076", + "fqdn": "example-fqdn-val-74486", + "pserver-selflink": "example-pserver-selflink-val-72481", + "ipv4-oam-address": "example-ipv4-oam-address-val-16616", + "serial-number": "example-serial-number-val-92800", + "ipaddress-v4-loopback-0": "example-ipaddress-v4-loopback0-val-61384", + "ipaddress-v6-loopback-0": "example-ipaddress-v6-loopback0-val-91056", + "ipaddress-v4-aim": "example-ipaddress-v4-aim-val-72233", + "ipaddress-v6-aim": "example-ipaddress-v6-aim-val-13572", + "ipaddress-v6-oam": "example-ipaddress-v6-oam-val-84518", + "inv-status": "example-inv-status-val-5042", + "pserver-id": "example-pserver-id-val-15622", + "internet-topology": "example-internet-topology-val-31234", + "in-maint": true, + "pserver-name2": "example-pserver-name2-val-93509", + "purpose": "example-purpose-val-52320", + "prov-status": "example-prov-status-val-47313", + "management-option": "example-management-option-val-72434", + "host-profile": "example-host-profile-val-84672", + "p-interfaces": { + "p-interface": [ + { + "interface-name": "example-interface-name-val-46147", + "selflink": "example-selflink-val-81029", + "speed-value": "example-speed-value-val-47874", + "speed-units": "example-speed-units-val-10396", + "port-description": "example-port-description-val-53068", + "equipment-identifier": "example-equipment-identifier-val-63234", + "interface-role": "example-interface-role-val-49232", + "interface-type": "example-interface-type-val-21757", + "prov-status": "example-prov-status-val-19117", + "in-maint": true, + "inv-status": "example-inv-status-val-48715", + "l-interfaces": { + "l-interface": [ + { + "interface-name": "example-interface-name-val-13366", + "interface-role": "example-interface-role-val-29488", + "v6-wan-link-ip": "example-v6-wan-link-ip-val-78396", + "selflink": "example-selflink-val-4757", + "interface-id": "example-interface-id-val-79486", + "macaddr": "example-macaddr-val-52194", + "network-name": "example-network-name-val-80678", + "management-option": "example-management-option-val-53535", + "interface-description": "example-interface-description-val-299", + "is-port-mirrored": true, + "in-maint": true, + "prov-status": "example-prov-status-val-9736", + "is-ip-unnumbered": true, + "allowed-address-pairs": "example-allowed-address-pairs-val-62271", + "priority": 82452, + "vlans": { + "vlan": [ + { + "vlan-interface": "example-vlan-interface-val-31470", + "vlan-id-inner": 61286171, + "vlan-id-outer": 64615174, + "speed-value": "example-speed-value-val-80457", + "speed-units": "example-speed-units-val-51587", + "vlan-description": "example-vlan-description-val-97575", + "backdoor-connection": "example-backdoor-connection-val-3179", + "vpn-key": "example-vpn-key-val-50069", + "orchestration-status": "example-orchestration-status-val-34071", + "in-maint": true, + "prov-status": "example-prov-status-val-62615", + "is-ip-unnumbered": true, + "is-private": true, + "l3-interface-ipv4-address-list": [ + { + "l3-interface-ipv4-address": "example-l3-interface-ipv4-address-val-8171", + "l3-interface-ipv4-prefix-length": 39266592, + "vlan-id-inner": 91284707, + "vlan-id-outer": 80343467, + "is-floating": true, + "neutron-network-id": "example-neutron-network-id-val-52921", + "neutron-subnet-id": "example-neutron-subnet-id-val-88134" + } + ], + "l3-interface-ipv6-address-list": [ + { + "l3-interface-ipv6-address": "example-l3-interface-ipv6-address-val-70726", + "l3-interface-ipv6-prefix-length": 81422758, + "vlan-id-inner": 15099560, + "vlan-id-outer": 46643832, + "is-floating": true, + "neutron-network-id": "example-neutron-network-id-val-97954", + "neutron-subnet-id": "example-neutron-subnet-id-val-23889" + } + ] + } + ] + }, + "l-interfaces": { + "l-interface": [ + { + "interface-name": "example-interface-name-val-62086", + "interface-role": "example-interface-role-val-13107", + "v6-wan-link-ip": "example-v6-wan-link-ip-val-32015", + "selflink": "example-selflink-val-31580", + "interface-id": "example-interface-id-val-57805", + "macaddr": "example-macaddr-val-54266", + "network-name": "example-network-name-val-38517", + "management-option": "example-management-option-val-8801", + "interface-description": "example-interface-description-val-88573", + "is-port-mirrored": true, + "in-maint": true, + "prov-status": "example-prov-status-val-99164", + "is-ip-unnumbered": true, + "allowed-address-pairs": "example-allowed-address-pairs-val-14581", + "priority": 80355, + "admin-status": "example-admin-status-val-29720" + } + ] + }, + "l3-interface-ipv4-address-list": [ + { + "l3-interface-ipv4-address": "example-l3-interface-ipv4-address-val-31324", + "l3-interface-ipv4-prefix-length": 36060646, + "vlan-id-inner": 62164959, + "vlan-id-outer": 93058593, + "is-floating": true, + "neutron-network-id": "example-neutron-network-id-val-39206", + "neutron-subnet-id": "example-neutron-subnet-id-val-27746" + } + ], + "l3-interface-ipv6-address-list": [ + { + "l3-interface-ipv6-address": "example-l3-interface-ipv6-address-val-72897", + "l3-interface-ipv6-prefix-length": 29592510, + "vlan-id-inner": 18402161, + "vlan-id-outer": 651158, + "is-floating": true, + "neutron-network-id": "example-neutron-network-id-val-6821", + "neutron-subnet-id": "example-neutron-subnet-id-val-11217" + } + ], + "admin-status": "example-admin-status-val-81745" + } + ] + } + } + ] + }, + "lag-interfaces": { + "lag-interface": [ + { + "interface-name": "example-interface-name-val-87366", + "interface-description": "example-interface-description-val-3722", + "speed-value": "example-speed-value-val-73546", + "speed-units": "example-speed-units-val-73658", + "interface-id": "example-interface-id-val-62385", + "interface-role": "example-interface-role-val-60746", + "prov-status": "example-prov-status-val-26239", + "in-maint": true, + "l-interfaces": { + "l-interface": [ + { + "interface-name": "example-interface-name-val-69579", + "interface-role": "example-interface-role-val-64571", + "v6-wan-link-ip": "example-v6-wan-link-ip-val-68385", + "selflink": "example-selflink-val-29611", + "interface-id": "example-interface-id-val-75464", + "macaddr": "example-macaddr-val-7285", + "network-name": "example-network-name-val-52284", + "management-option": "example-management-option-val-26028", + "interface-description": "example-interface-description-val-37641", + "is-port-mirrored": true, + "in-maint": true, + "prov-status": "example-prov-status-val-56460", + "is-ip-unnumbered": true, + "allowed-address-pairs": "example-allowed-address-pairs-val-23301", + "priority": 84739, + "vlans": { + "vlan": [ + { + "vlan-interface": "example-vlan-interface-val-56661", + "vlan-id-inner": 33305644, + "vlan-id-outer": 30871600, + "speed-value": "example-speed-value-val-1929", + "speed-units": "example-speed-units-val-71630", + "vlan-description": "example-vlan-description-val-63003", + "backdoor-connection": "example-backdoor-connection-val-41834", + "vpn-key": "example-vpn-key-val-16552", + "orchestration-status": "example-orchestration-status-val-95322", + "in-maint": true, + "prov-status": "example-prov-status-val-89886", + "is-ip-unnumbered": true, + "is-private": true, + "l3-interface-ipv4-address-list": [ + { + "l3-interface-ipv4-address": "example-l3-interface-ipv4-address-val-69142", + "l3-interface-ipv4-prefix-length": 11099430, + "vlan-id-inner": 88996967, + "vlan-id-outer": 23003182, + "is-floating": true, + "neutron-network-id": "example-neutron-network-id-val-53091", + "neutron-subnet-id": "example-neutron-subnet-id-val-41571" + } + ], + "l3-interface-ipv6-address-list": [ + { + "l3-interface-ipv6-address": "example-l3-interface-ipv6-address-val-27490", + "l3-interface-ipv6-prefix-length": 20167688, + "vlan-id-inner": 40775405, + "vlan-id-outer": 75855907, + "is-floating": true, + "neutron-network-id": "example-neutron-network-id-val-9739", + "neutron-subnet-id": "example-neutron-subnet-id-val-806" + } + ] + } + ] + }, + "l-interfaces": { + "l-interface": [ + { + "interface-name": "example-interface-name-val-49266", + "interface-role": "example-interface-role-val-210", + "v6-wan-link-ip": "example-v6-wan-link-ip-val-81668", + "selflink": "example-selflink-val-6356", + "interface-id": "example-interface-id-val-99531", + "macaddr": "example-macaddr-val-25092", + "network-name": "example-network-name-val-3319", + "management-option": "example-management-option-val-79883", + "interface-description": "example-interface-description-val-54501", + "is-port-mirrored": true, + "in-maint": true, + "prov-status": "example-prov-status-val-48840", + "is-ip-unnumbered": true, + "allowed-address-pairs": "example-allowed-address-pairs-val-26846", + "priority": 21862, + "admin-status": "example-admin-status-val-89244" + } + ] + }, + "l3-interface-ipv4-address-list": [ + { + "l3-interface-ipv4-address": "example-l3-interface-ipv4-address-val-61251", + "l3-interface-ipv4-prefix-length": 91875404, + "vlan-id-inner": 36470314, + "vlan-id-outer": 96344091, + "is-floating": true, + "neutron-network-id": "example-neutron-network-id-val-17339", + "neutron-subnet-id": "example-neutron-subnet-id-val-86128" + } + ], + "l3-interface-ipv6-address-list": [ + { + "l3-interface-ipv6-address": "example-l3-interface-ipv6-address-val-31476", + "l3-interface-ipv6-prefix-length": 11663872, + "vlan-id-inner": 28459412, + "vlan-id-outer": 9852622, + "is-floating": true, + "neutron-network-id": "example-neutron-network-id-val-15120", + "neutron-subnet-id": "example-neutron-subnet-id-val-36088" + } + ], + "admin-status": "example-admin-status-val-81055" + } + ] + } + } + ] + } +} diff --git a/aai-core/src/test/resources/payloads/resource/transform-results-to-result.json b/aai-core/src/test/resources/payloads/resource/transform-results-to-result.json new file mode 100644 index 00000000..63fa9114 --- /dev/null +++ b/aai-core/src/test/resources/payloads/resource/transform-results-to-result.json @@ -0,0 +1,61 @@ +{ + "results": [ + { + "id": "286724136", + "node-type": "pserver", + "url": "/aai/v18/cloud-infrastructure/pservers/pserver/test-pserver1", + "properties": { + "equip-type": "SERVER", + "equip-vendor": "SomeVendor", + "equip-model": "SomeModel", + "in-maint": false, + "last-mod-source-of-truth": "AAIRctFeed", + "aai-node-type": "pserver", + "aai-created-ts": 1568997029298, + "aai-last-mod-ts": 1568997029298, + "source-of-truth": "AAI", + "aai-uri": "/cloud-infrastructure/pservers/pserver/test-pserver1", + "aai-uuid": "05fa7b64-59e4-44a1-8162-e32746659c77", + "ipv4-oam-address": "1.2.3.4", + "hostname": "test-pserver1", + "pserver-id": "6bf4944a-9f13-4bb8-8f49-b61060793510", + "purpose": "Standalone", + "fqdn": "a.b.c.d", + "ptnii-equip-name": "test-pserver1", + "resource-version": "1568997029298" + }, + "related-to": [ + { + "id": "286724232", + "relationship-label": "org.onap.relationships.inventory.LocatedIn", + "node-type": "complex", + "url": "/aai/v18/cloud-infrastructure/complexes/complex/testcomplex2" + }, + { + "id": "286724233", + "relationship-label": "org.onap.relationships.inventory.LocatedIn", + "node-type": "complex", + "url": "/aai/v18/cloud-infrastructure/complexes/complex/testcomplex1" + } + ] + }, + { + "id": "286724152", + "node-type": "pserver", + "url": "/aai/v18/cloud-infrastructure/pservers/pserver/test-pserver2", + "properties": { + "in-maint": false, + "last-mod-source-of-truth": "JUNITTESTAPP2", + "aai-node-type": "pserver", + "aai-created-ts": 1553805738492, + "aai-last-mod-ts": 1553805738492, + "source-of-truth": "JUNITTESTAPP2", + "aai-uri": "/cloud-infrastructure/pservers/pserver/test-pserver2", + "aai-uuid": "13a8440c-7fb4-4f41-a141-6e1d9e895b4a", + "hostname": "test-pserver2", + "resource-version": "1553805738492" + }, + "related-to": [] + } + ] +} diff --git a/aai-core/src/test/resources/payloads/resource/vnfc-related-to-vf-module.json b/aai-core/src/test/resources/payloads/resource/vnfc-related-to-vf-module.json new file mode 100644 index 00000000..139681fa --- /dev/null +++ b/aai-core/src/test/resources/payloads/resource/vnfc-related-to-vf-module.json @@ -0,0 +1,19 @@ +{ + "vnfc-name": "test-vnfc11", + "nfc-naming-code": "testname", + "nfc-function": "test-value", + "relationship-list": { + "relationship": [{ + "related-to": "vf-module", + "relationship-data": [{ + "relationship-key": "vnf.vnf-id", + "relationship-value": "test-vnf11" + }, { + "relationship-key": "vf-module.vf-module-id", + "relationship-value": "vf-module-test11" + } + ] + } + ] + } +} diff --git a/aai-els-onap-logging/pom.xml b/aai-els-onap-logging/pom.xml new file mode 100644 index 00000000..8817adf5 --- /dev/null +++ b/aai-els-onap-logging/pom.xml @@ -0,0 +1,130 @@ +<?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.aai.aai-common</groupId> + <artifactId>aai-parent</artifactId> + <version>1.6.6-SNAPSHOT</version> + <relativePath>../aai-parent/pom.xml</relativePath> + </parent> + <artifactId>aai-els-onap-logging</artifactId> + <name>aai-els-onap-logging</name> + <packaging>jar</packaging> + <dependencies> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-aop</artifactId> + </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-context</artifactId> + </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-core</artifactId> + </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-orm</artifactId> + </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-oxm</artifactId> + </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-aspects</artifactId> + </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-tx</artifactId> + </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-web</artifactId> + </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-webmvc</artifactId> + </dependency> + <dependency> + <groupId>org.aspectj</groupId> + <artifactId>aspectjrt</artifactId> + </dependency> + <dependency> + <groupId>ch.qos.logback</groupId> + <artifactId>logback-core</artifactId> + </dependency> + <dependency> + <groupId>ch.qos.logback</groupId> + <artifactId>logback-classic</artifactId> + </dependency> + <dependency> + <groupId>ch.qos.logback</groupId> + <artifactId>logback-access</artifactId> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>javax.annotation</groupId> + <artifactId>javax.annotation-api</artifactId> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.onap.logging-analytics</groupId> + <artifactId>logging-slf4j</artifactId> + </dependency> + <dependency> + <groupId>javax.servlet</groupId> + <artifactId>javax.servlet-api</artifactId> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>javax.ws.rs</groupId> + <artifactId>javax.ws.rs-api</artifactId> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-core</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.json</groupId> + <artifactId>json</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-util</artifactId> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>com.fasterxml.jackson.module</groupId> + <artifactId>jackson-module-jaxb-annotations</artifactId> + </dependency> + <dependency> + <groupId>commons-lang</groupId> + <artifactId>commons-lang</artifactId> + </dependency> + <dependency> + <groupId>commons-io</groupId> + <artifactId>commons-io</artifactId> + </dependency> + <dependency> + <groupId>com.sun.jersey</groupId> + <artifactId>jersey-client</artifactId> + </dependency> + </dependencies> +</project> diff --git a/aai-els-onap-logging/src/main/java/org/onap/aai/aailog/filter/AaiAuditLogContainerFilter.java b/aai-els-onap-logging/src/main/java/org/onap/aai/aailog/filter/AaiAuditLogContainerFilter.java new file mode 100644 index 00000000..c826df3d --- /dev/null +++ b/aai-els-onap-logging/src/main/java/org/onap/aai/aailog/filter/AaiAuditLogContainerFilter.java @@ -0,0 +1,99 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 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========================================================= + */ + +package org.onap.aai.aailog.filter; + +import org.onap.aai.aailog.logs.ServiceName; +import org.onap.logging.filter.base.AuditLogContainerFilter; +import org.onap.logging.filter.base.Constants; +import org.onap.logging.filter.base.SimpleMap; +import org.onap.logging.ref.slf4j.ONAPLogConstants; +import org.slf4j.MDC; + +import javax.annotation.Priority; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.PreMatching; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.UriInfo; + +@PreMatching +@Priority(1) +public class AaiAuditLogContainerFilter extends AuditLogContainerFilter { + @Override + public void setMDCPartnerName(SimpleMap headers) { + logger.trace("Checking X-ONAP-PartnerName header for partnerName."); + String partnerName = headers.get(ONAPLogConstants.Headers.PARTNER_NAME); + if (partnerName == null || partnerName.isEmpty()) { + logger.trace("No valid X-ONAP-PartnerName header value. Checking X-FromAppId header for partnerName."); + partnerName = headers.get (Constants.HttpHeaders.HEADER_FROM_APP_ID); + if (partnerName == null || partnerName.isEmpty()) { + logger.trace("No valid X-FromAppId header value. Checking User-Agent header for partnerName."); + partnerName = headers.get(HttpHeaders.USER_AGENT); + if (partnerName == null || partnerName.isEmpty()) { + logger.trace("No valid User-Agent header value. Checking X-ClientID header for partnerName."); + partnerName = headers.get(Constants.HttpHeaders.CLIENT_ID); + if (partnerName == null || partnerName.isEmpty()) { + logger.trace("No valid partnerName headers. Defaulting partnerName to UNKNOWN."); + partnerName = Constants.DefaultValues.UNKNOWN; + } + } + } + } + MDC.put(ONAPLogConstants.MDCs.PARTNER_NAME, partnerName); + } + @Override + protected void setServiceName(ContainerRequestContext containerRequest) { + UriInfo uriInfo = containerRequest.getUriInfo(); + String serviceName = ServiceName.extractServiceName(uriInfo.getAbsolutePath().getRawPath()); + MDC.put(ONAPLogConstants.MDCs.SERVICE_NAME, serviceName); + } + + @Override + protected void pre(SimpleMap headers, ContainerRequestContext request, HttpServletRequest httpServletRequest) { + try { + String requestId = getRequestId(headers); + MDC.put(ONAPLogConstants.MDCs.REQUEST_ID, requestId); + // handle the case where the request ID value was invalid and we had to generate a new one + addRequestIdHeader(request, requestId); + setInvocationId(headers); + setServiceName(request); + setMDCPartnerName(headers); + setServerFQDN(); + setClientIPAddress(httpServletRequest); + setInstanceID(); + setEntryTimeStamp(); + MDC.put(ONAPLogConstants.MDCs.RESPONSE_STATUS_CODE, ONAPLogConstants.ResponseStatus.INPROGRESS.toString()); + additionalPreHandling(request); + setLogTimestamp(); + setElapsedTime(); + logger.info(ONAPLogConstants.Markers.ENTRY, "Entering"); + } catch (Exception e) { + logger.warn("Error in AaiAuditContainerFilter pre", e); + } + } + + protected void addRequestIdHeader(ContainerRequestContext containerRequest, String requestId) { + if (containerRequest.getHeaders().get(ONAPLogConstants.Headers.REQUEST_ID) != null) { + containerRequest.getHeaders().get(ONAPLogConstants.Headers.REQUEST_ID).clear(); + } + containerRequest.getHeaders().add(ONAPLogConstants.Headers.REQUEST_ID, requestId); + }; +} diff --git a/aai-els-onap-logging/src/main/java/org/onap/aai/aailog/filter/RestClientLoggingInterceptor.java b/aai-els-onap-logging/src/main/java/org/onap/aai/aailog/filter/RestClientLoggingInterceptor.java new file mode 100644 index 00000000..51824b74 --- /dev/null +++ b/aai-els-onap-logging/src/main/java/org/onap/aai/aailog/filter/RestClientLoggingInterceptor.java @@ -0,0 +1,147 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 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========================================================= + */ +package org.onap.aai.aailog.filter; + +import org.onap.aai.aailog.logs.ServiceName; +import org.onap.logging.filter.base.AbstractMetricLogFilter; +import org.onap.logging.filter.base.Constants; +import org.onap.logging.filter.base.MDCSetup; +import org.onap.logging.ref.slf4j.ONAPLogConstants; +import org.slf4j.MDC; +import org.springframework.http.HttpRequest; +import org.springframework.http.client.ClientHttpRequestExecution; +import org.springframework.http.client.ClientHttpRequestInterceptor; +import org.springframework.http.client.ClientHttpResponse; +import org.springframework.http.HttpHeaders; + +import javax.ws.rs.core.MultivaluedMap; +import java.io.IOException; +import java.util.List; +import java.util.UUID; + +public class RestClientLoggingInterceptor extends AbstractMetricLogFilter<HttpRequest, ClientHttpResponse, HttpHeaders> implements ClientHttpRequestInterceptor { + @Override + public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) + throws IOException + { + this.setInvocationId(request.getHeaders()); + pre(request, request.getHeaders()); + ClientHttpResponse resp = execution.execute(request, body); + post(request, resp); + return resp; + + } + protected void pre(HttpRequest request, HttpHeaders requestHeaders) { + try { + setupMDC(request); + setupHeaders(request, requestHeaders); + super.logInvoke(); + } catch (Exception e) { + logger.warn("Error in RestClientLoggingInterceptor pre", e); + } + } + protected void setupHeaders(HttpRequest clientRequest, HttpHeaders requestHeaders) { + String requestId = extractRequestID(requestHeaders); + addHeader(requestHeaders, ONAPLogConstants.Headers.REQUEST_ID, requestId); + addHeader(requestHeaders, Constants.HttpHeaders.HEADER_REQUEST_ID, requestId); + if (requestHeaders.getFirst(Constants.HttpHeaders.TRANSACTION_ID) == null || + requestHeaders.getFirst(Constants.HttpHeaders.TRANSACTION_ID).isEmpty()) { + addHeader(requestHeaders, Constants.HttpHeaders.TRANSACTION_ID, requestId); + } + addHeader(requestHeaders, Constants.HttpHeaders.ECOMP_REQUEST_ID, requestId); + addHeader(requestHeaders, ONAPLogConstants.Headers.INVOCATION_ID, MDC.get(ONAPLogConstants.MDCs.INVOCATION_ID)); + String pName = getProperty(Constants.Property.PARTNER_NAME); + if (pName != null && (!pName.isEmpty())) { + addHeader(requestHeaders, ONAPLogConstants.Headers.PARTNER_NAME, pName); + } + } + protected String extractRequestID(HttpHeaders requestHeaders) { + String requestId = MDC.get(ONAPLogConstants.MDCs.REQUEST_ID); + if (requestId == null || requestId.isEmpty()) { + requestId = requestHeaders.getFirst(Constants.HttpHeaders.TRANSACTION_ID); + if (requestId == null || requestId.isEmpty()) { + requestId = UUID.randomUUID().toString(); + } + MDC.put(ONAPLogConstants.MDCs.REQUEST_ID, requestId); + } + return requestId; + } + public void setInvocationId(HttpHeaders headers) { + String invocationId = null; + + List<String> headerList = headers.get(ONAPLogConstants.Headers.INVOCATION_ID); + if (headerList != null && (!headerList.isEmpty())) { + for (String h : headerList) { + if ( h != null && (!h.isEmpty()) ) { + invocationId = h; + break; + } + } + headers.remove(ONAPLogConstants.Headers.INVOCATION_ID); + } + if (invocationId == null) { + invocationId = UUID.randomUUID().toString(); + } + MDC.put(ONAPLogConstants.MDCs.INVOCATION_ID, invocationId); + } + @Override + protected void addHeader(HttpHeaders requestHeaders, String headerName, String headerValue) { + requestHeaders.add(headerName, headerValue); + } + + protected String getTargetServiceName(HttpRequest request) { + return (getServiceName(request)); + } + protected String getServiceName(HttpRequest request){ + String path = request.getURI().getRawPath(); + return(ServiceName.extractServiceName(path)); + } + + protected int getHttpStatusCode(ClientHttpResponse response) { + int result = 0; + if (response != null ) { + try { + result = response.getStatusCode().value(); + } + catch (IOException e) { + logger.warn("Error in RestClientLoggingInterceptor getHttpStatusCode {}", e.getMessage()); + } + } + return result; + } + + protected String getResponseCode(ClientHttpResponse response) { + String result = ""; + if (response != null ) { + try { + result = response.getStatusCode().toString(); + } + catch (IOException e) { + logger.warn("Error in RestClientLoggingInterceptor getResponseCode {}", e.getMessage()); + } + } + return result; + } + + protected String getTargetEntity(HttpRequest request) { + //TODO where do we get this from? + return Constants.DefaultValues.UNKNOWN_TARGET_ENTITY; + } +} diff --git a/aai-els-onap-logging/src/main/java/org/onap/aai/aailog/filter/RestControllerClientLoggingInterceptor.java b/aai-els-onap-logging/src/main/java/org/onap/aai/aailog/filter/RestControllerClientLoggingInterceptor.java new file mode 100644 index 00000000..7e332ec5 --- /dev/null +++ b/aai-els-onap-logging/src/main/java/org/onap/aai/aailog/filter/RestControllerClientLoggingInterceptor.java @@ -0,0 +1,188 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 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========================================================= + */ +package org.onap.aai.aailog.filter; + +import com.sun.jersey.api.client.ClientHandler; +import com.sun.jersey.api.client.ClientHandlerException; +import com.sun.jersey.api.client.ClientRequest; +import com.sun.jersey.api.client.ClientResponse; +import com.sun.jersey.api.client.filter.ClientFilter; +import org.onap.aai.aailog.logs.ServiceName; +import org.onap.logging.filter.base.Constants; +import org.onap.logging.filter.base.MDCSetup; +import org.onap.logging.ref.slf4j.ONAPLogConstants; +import org.slf4j.*; + +import javax.ws.rs.core.MultivaluedMap; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.UUID; + +public class RestControllerClientLoggingInterceptor extends ClientFilter { + private static final Logger logger = LoggerFactory.getLogger(RestControllerClientLoggingInterceptor.class); + private static final Marker INVOKE_RETURN = MarkerFactory.getMarker("INVOKE-RETURN"); + private final MDCSetup mdcSetup; + private final String partnerName; + + public RestControllerClientLoggingInterceptor () { + mdcSetup = new MDCSetup(); + partnerName = getPartnerName(); + } + + @Override + public ClientResponse handle(ClientRequest clientRequest) throws ClientHandlerException { + ClientResponse clientResponse = null; + pre(clientRequest); + // Call the next client handler in the filter chain + ClientHandler nextHandler = getNext(); + if (nextHandler != null) { + clientResponse = nextHandler.handle(clientRequest); + } + if (clientResponse != null) { + post(clientResponse); + } + return clientResponse; + } + + protected String getTargetServiceName(ClientRequest clientRequest) { + return getServiceName(clientRequest); + } + + protected String getServiceName(ClientRequest clientRequest) { + String path = clientRequest.getURI().getRawPath(); + return ServiceName.extractServiceName(path); + } + + protected int getHttpStatusCode(ClientResponse response) { + return response.getStatus(); + } + + protected String getResponseCode(ClientResponse clientResponse) { + return String.valueOf(clientResponse.getStatus()); + } + + + protected String getTargetEntity(ClientRequest ClientRequest) { + return Constants.DefaultValues.UNKNOWN_TARGET_ENTITY; + }; + + protected void pre(ClientRequest clientRequest) { + try { + setInvocationId(clientRequest); + setupMDC(clientRequest); + setupHeaders(clientRequest); + logger.info(ONAPLogConstants.Markers.INVOKE, "Invoke"); + } catch (Exception e) { + logger.warn("Error in RestControllerClientLoggingInterceptor pre", e.getMessage()); + } + } + public void setInvocationId(ClientRequest clientRequest) { + String invocationId = null; + MultivaluedMap<String, Object> requestHeaders = clientRequest.getHeaders(); + Object id = requestHeaders.get(ONAPLogConstants.Headers.INVOCATION_ID); + if (id != null) { + invocationId = (String)id; + } + requestHeaders.remove(ONAPLogConstants.Headers.INVOCATION_ID); + if (invocationId == null) { + invocationId = UUID.randomUUID().toString(); + } + MDC.put(ONAPLogConstants.MDCs.INVOCATION_ID, invocationId); + } + protected void setupHeaders(ClientRequest clientRequest) { + String requestId = extractRequestID(clientRequest); + MultivaluedMap<String, Object> requestHeaders = clientRequest.getHeaders(); + addHeader(requestHeaders, ONAPLogConstants.Headers.REQUEST_ID, requestId); + addHeader(requestHeaders, Constants.HttpHeaders.HEADER_REQUEST_ID, requestId); + Object requestIdObj = requestHeaders.getFirst(Constants.HttpHeaders.TRANSACTION_ID); + if (requestIdObj == null) { + addHeader(requestHeaders, Constants.HttpHeaders.TRANSACTION_ID, requestId); + } + addHeader(requestHeaders, Constants.HttpHeaders.ECOMP_REQUEST_ID, requestId); + addHeader(requestHeaders, ONAPLogConstants.Headers.INVOCATION_ID, MDC.get(ONAPLogConstants.MDCs.INVOCATION_ID)); + if (partnerName != null && (!partnerName.isEmpty())){ + addHeader(requestHeaders, ONAPLogConstants.Headers.PARTNER_NAME, partnerName); + } + } + + protected void setupMDC(ClientRequest clientRequest) { + MDC.put(ONAPLogConstants.MDCs.INVOKE_TIMESTAMP, + ZonedDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT)); + MDC.put(ONAPLogConstants.MDCs.TARGET_SERVICE_NAME, getTargetServiceName(clientRequest)); + MDC.put(ONAPLogConstants.MDCs.RESPONSE_STATUS_CODE, ONAPLogConstants.ResponseStatus.INPROGRESS.toString()); + mdcSetup.setInvocationIdFromMDC(); + + if (MDC.get(ONAPLogConstants.MDCs.TARGET_ENTITY) == null) { + String targetEntity = getTargetEntity(clientRequest); + if (targetEntity != null) { + MDC.put(ONAPLogConstants.MDCs.TARGET_ENTITY, targetEntity); + } else { + MDC.put(ONAPLogConstants.MDCs.TARGET_ENTITY, Constants.DefaultValues.UNKNOWN_TARGET_ENTITY); + } + } + + if (MDC.get(ONAPLogConstants.MDCs.SERVICE_NAME) == null) { + MDC.put(ONAPLogConstants.MDCs.SERVICE_NAME, getServiceName(clientRequest)); + } + mdcSetup.setServerFQDN(); + } + + protected String extractRequestID(ClientRequest clientRequest) { + String requestId = MDC.get(ONAPLogConstants.MDCs.REQUEST_ID); + if (requestId == null || requestId.isEmpty()) { + MultivaluedMap<String, Object> requestHeaders = clientRequest.getHeaders(); + Object requestIdObj = requestHeaders.getFirst(Constants.HttpHeaders.TRANSACTION_ID); + if (requestIdObj != null) { + requestId = (String)requestIdObj; + } + if ( requestId == null || requestId.isEmpty() ) { + requestId = UUID.randomUUID().toString(); + } + mdcSetup.setLogTimestamp(); + mdcSetup.setElapsedTimeInvokeTimestamp(); + logger.warn("No value found in MDC when checking key {} value will be set to {}", + ONAPLogConstants.MDCs.REQUEST_ID, requestId); + MDC.put(ONAPLogConstants.MDCs.REQUEST_ID, requestId); + } + return requestId; + } + + protected void post(ClientResponse clientResponse) { + try { + mdcSetup.setLogTimestamp(); + mdcSetup.setElapsedTimeInvokeTimestamp(); + mdcSetup.setResponseStatusCode(getHttpStatusCode(clientResponse)); + mdcSetup.setResponseDescription(getHttpStatusCode(clientResponse)); + MDC.put(ONAPLogConstants.MDCs.RESPONSE_CODE, getResponseCode(clientResponse)); + logger.info(INVOKE_RETURN, "InvokeReturn"); + mdcSetup.clearClientMDCs(); + } catch (Exception e) { + logger.warn("Error in RestControllerClientLoggingInterceptor post", e.getMessage()); + } + } + protected String getPartnerName() { + return mdcSetup.getProperty(Constants.Property.PARTNER_NAME); + } + + protected void addHeader(MultivaluedMap<String, Object> requestHeaders, String headerName, String headerValue) { + requestHeaders.add(headerName, headerValue); + } +} diff --git a/aai-els-onap-logging/src/main/java/org/onap/aai/aailog/logs/AaiDBMetricLog.java b/aai-els-onap-logging/src/main/java/org/onap/aai/aailog/logs/AaiDBMetricLog.java new file mode 100644 index 00000000..0269943b --- /dev/null +++ b/aai-els-onap-logging/src/main/java/org/onap/aai/aailog/logs/AaiDBMetricLog.java @@ -0,0 +1,114 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 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========================================================= + */ + +package org.onap.aai.aailog.logs; + +import org.onap.logging.filter.base.AbstractMetricLogFilter; +import org.onap.logging.filter.base.ONAPComponents; +import org.onap.logging.ref.slf4j.ONAPLogConstants; +import org.slf4j.*; + +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Response; + +public class AaiDBMetricLog + extends AbstractMetricLogFilter<DBRequestWrapper, Response, MultivaluedMap<String, Object>> { + + protected static final Logger logger = LoggerFactory.getLogger(AaiDBMetricLog.class); + private final String partnerName; + private static final Marker INVOKE_RETURN = MarkerFactory.getMarker("INVOKE-RETURN"); + private static final String TARGET_ENTITY = ONAPComponents.AAI.toString() + ".DB"; + public AaiDBMetricLog(String subcomponent) { + partnerName = getPartnerName(subcomponent); + } + + @Override + protected void addHeader(MultivaluedMap<String, Object> requestHeaders, String headerName, String headerValue) { + requestHeaders.add(headerName, headerValue); + } + + @Override + protected String getTargetServiceName(DBRequestWrapper request) { + return (getServiceName(request)); + } + + @Override + protected String getServiceName(DBRequestWrapper request) { + String path = request.getUri().getRawPath(); + return ServiceName.extractServiceName(path); + } + + @Override + protected int getHttpStatusCode(Response response) { + int intCode = response.getStatus(); + return intCode; + } + + @Override + protected String getResponseCode(Response response) { + return String.valueOf(response.getStatus()); + } + + @Override + protected String getTargetEntity(DBRequestWrapper request) { + return TARGET_ENTITY; + } + + protected String getPartnerName(String subcomponent) { + StringBuilder sb = new StringBuilder(ONAPComponents.AAI.toString()).append(subcomponent); + return (sb.toString()); + } + + public void pre(DBRequestWrapper request) { + try { + setupMDC(request); + setLogTimestamp(); + logger.info(ONAPLogConstants.Markers.INVOKE, "Invoke"); + } catch (Exception e) { + logger.warn("Error in AaiDBMetricLog pre", e); + } + } + public void post(DBRequestWrapper request, Response response) { + try { + setLogTimestamp(); + setElapsedTimeInvokeTimestamp(); + setResponseStatusCode(getHttpStatusCode(response)); + setResponseDescription(getHttpStatusCode(response)); + MDC.put(ONAPLogConstants.MDCs.RESPONSE_CODE, getResponseCode(response)); + logger.info(INVOKE_RETURN, "InvokeReturn"); + clearClientMDCs(); + } catch (Exception e) { + logger.warn("Error in AaiDBMetricLog post", e); + } + } + @Override + public void setResponseStatusCode(int code) { + String statusCode; + if (code / 100 == 2) { + statusCode = ONAPLogConstants.ResponseStatus.COMPLETE.toString(); + } + else { + statusCode = ONAPLogConstants.ResponseStatus.ERROR.toString(); + setErrorCode(code); + setErrorDesc(code); + } + MDC.put(ONAPLogConstants.MDCs.RESPONSE_STATUS_CODE, statusCode); + } +} diff --git a/aai-core/src/main/java/org/onap/aai/logging/EcompServiceName.java b/aai-els-onap-logging/src/main/java/org/onap/aai/aailog/logs/AaiDebugLog.java index 10d7a211..ef11f08e 100644 --- a/aai-core/src/main/java/org/onap/aai/logging/EcompServiceName.java +++ b/aai-els-onap-logging/src/main/java/org/onap/aai/aailog/logs/AaiDebugLog.java @@ -18,19 +18,19 @@ * ============LICENSE_END========================================================= */ -package org.onap.aai.logging; +package org.onap.aai.aailog.logs; -import ch.qos.logback.classic.pattern.ClassicConverter; -import ch.qos.logback.classic.spi.ILoggingEvent; +import org.onap.logging.filter.base.MDCSetup; +import org.onap.logging.ref.slf4j.ONAPLogConstants; +import org.slf4j.MDC; -import org.onap.aai.logging.LoggingContext.LoggingField; +import java.util.UUID; -public class EcompServiceName extends ClassicConverter { - @Override - public String convert(ILoggingEvent event) { - if (!event.getMDCPropertyMap().containsKey(LoggingField.SERVICE_NAME.toString())) { - return "AAI"; - } - return event.getMDCPropertyMap().get(LoggingField.SERVICE_NAME.toString()); +public class AaiDebugLog extends MDCSetup { + + public void setupMDC() { + String requestId = UUID.randomUUID().toString(); + MDC.put(ONAPLogConstants.MDCs.REQUEST_ID, requestId); + setLogTimestamp(); } } diff --git a/aai-els-onap-logging/src/main/java/org/onap/aai/aailog/logs/AaiDmaapMetricLog.java b/aai-els-onap-logging/src/main/java/org/onap/aai/aailog/logs/AaiDmaapMetricLog.java new file mode 100644 index 00000000..b0fb079c --- /dev/null +++ b/aai-els-onap-logging/src/main/java/org/onap/aai/aailog/logs/AaiDmaapMetricLog.java @@ -0,0 +1,92 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 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========================================================= + */ + +package org.onap.aai.aailog.logs; + +import org.onap.aai.logging.AaiElsErrorCode; +import org.onap.logging.filter.base.MDCSetup; +import org.onap.logging.ref.slf4j.ONAPLogConstants; +import org.slf4j.*; + +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.regex.PatternSyntaxException; + +public class AaiDmaapMetricLog extends MDCSetup { + + protected static final Logger logger = LoggerFactory.getLogger(AaiDmaapMetricLog.class); + private static final Marker INVOKE_RETURN = MarkerFactory.getMarker("INVOKE-RETURN"); + private static final String TARGET_ENTITY = "DMaaP"; + + public AaiDmaapMetricLog() { + } + public void pre(String targetServiceName, String event, String transactionId, String serviceName) { + + try { + MDC.put(ONAPLogConstants.MDCs.INVOKE_TIMESTAMP, + ZonedDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT)); + setLogTimestamp(); + setElapsedTimeInvokeTimestamp(); + MDC.put(ONAPLogConstants.MDCs.TARGET_SERVICE_NAME, targetServiceName); + MDC.put(ONAPLogConstants.MDCs.RESPONSE_STATUS_CODE, ONAPLogConstants.ResponseStatus.INPROGRESS.toString()); + MDC.put(ONAPLogConstants.MDCs.TARGET_ENTITY, TARGET_ENTITY); + if (transactionId != null && !(transactionId.isEmpty())) { + MDC.put(ONAPLogConstants.MDCs.REQUEST_ID, transactionId); + } + if (serviceName != null && !(serviceName.isEmpty())) { + MDC.put(ONAPLogConstants.MDCs.SERVICE_NAME, serviceName); + } + setInvocationIdFromMDC(); + logger.info(ONAPLogConstants.Markers.INVOKE, event ); + + } catch (Exception e) { + logger.warn("Error in AaiDmaapMetricLog pre", e.getMessage()); + } + } + + public void post(String responseCode, String errorDescription) { + + try { + setLogTimestamp(); + setElapsedTimeInvokeTimestamp(); + setResponseStatusCode(responseCode, errorDescription); + logger.info(INVOKE_RETURN, "InvokeReturn"); + clearClientMDCs(); + } catch (Exception e) { + logger.warn("Error in AaiDmaapMetricLog post", e.getMessage()); + } + } + + public void setResponseStatusCode(String aaiElsErrorCode, String errorDescription) { + String statusCode; + if (AaiElsErrorCode.SUCCESS.equals(aaiElsErrorCode)) { + statusCode = ONAPLogConstants.ResponseStatus.COMPLETE.toString(); + } + else { + statusCode = ONAPLogConstants.ResponseStatus.ERROR.toString(); + MDC.put(ONAPLogConstants.MDCs.ERROR_CODE, aaiElsErrorCode); + MDC.put(ONAPLogConstants.MDCs.ERROR_DESC, errorDescription); + } + MDC.put(ONAPLogConstants.MDCs.RESPONSE_STATUS_CODE, statusCode); + MDC.put(ONAPLogConstants.MDCs.RESPONSE_CODE, aaiElsErrorCode); + + } +} diff --git a/aai-els-onap-logging/src/main/java/org/onap/aai/aailog/logs/AaiScheduledTaskAuditLog.java b/aai-els-onap-logging/src/main/java/org/onap/aai/aailog/logs/AaiScheduledTaskAuditLog.java new file mode 100644 index 00000000..60460fff --- /dev/null +++ b/aai-els-onap-logging/src/main/java/org/onap/aai/aailog/logs/AaiScheduledTaskAuditLog.java @@ -0,0 +1,74 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.logging + * ================================================================================ + * Copyright © 2018 Amdocs + * 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.aai.aailog.logs; + +import org.onap.logging.filter.base.MDCSetup; +import org.onap.logging.ref.slf4j.ONAPLogConstants; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.MDC; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +import javax.ws.rs.core.Response; +import java.util.UUID; + +@Component +@Scope(scopeName = ConfigurableBeanFactory.SCOPE_PROTOTYPE) +public class AaiScheduledTaskAuditLog extends MDCSetup { + protected static Logger logger = LoggerFactory.getLogger(AaiScheduledTaskAuditLog.class); + + public void logBefore(String serviceName, String partnerName) { + try { + String requestId = UUID.randomUUID().toString(); + MDC.put(ONAPLogConstants.MDCs.REQUEST_ID, requestId); + setInvocationIdFromMDC(); + MDC.put(ONAPLogConstants.MDCs.SERVICE_NAME, serviceName); + MDC.put(ONAPLogConstants.MDCs.PARTNER_NAME, partnerName); + setServerFQDN(); + setClientIPAddress(null); + setInstanceID(); + setEntryTimeStamp(); + MDC.put(ONAPLogConstants.MDCs.RESPONSE_STATUS_CODE, ONAPLogConstants.ResponseStatus.INPROGRESS.toString()); + setLogTimestamp(); + setElapsedTime(); + logger.info(ONAPLogConstants.Markers.ENTRY, "Entering"); + } catch (Exception e) { + logger.warn("Error in AaiScheduledTaskAuditLog logBefore", e.getMessage()); + } + + } + + public void logAfter() { + try { + // TODO: how do we know if there was an error + setResponseStatusCode(Response.Status.OK.getStatusCode()); + setLogTimestamp(); + setElapsedTime(); + logger.info(ONAPLogConstants.Markers.EXIT, "Exiting."); + } catch (Exception e) { + logger.warn("Error in AaiScheduledTaskAuditLog logAfter", e.getMessage()); + } finally { + MDC.clear(); + } + } +} diff --git a/aai-rest/src/test/java/org/onap/aai/restclient/RestClientTest.java b/aai-els-onap-logging/src/main/java/org/onap/aai/aailog/logs/DBRequestWrapper.java index 36b8fb3e..2b78613d 100644 --- a/aai-rest/src/test/java/org/onap/aai/restclient/RestClientTest.java +++ b/aai-els-onap-logging/src/main/java/org/onap/aai/aailog/logs/DBRequestWrapper.java @@ -17,9 +17,10 @@ * limitations under the License. * ============LICENSE_END========================================================= */ +package org.onap.aai.aailog.logs; +import java.net.URI; -package org.onap.aai.restclient; - -public class RestClientTest { +public interface DBRequestWrapper { + public URI getUri(); } diff --git a/aai-els-onap-logging/src/main/java/org/onap/aai/aailog/logs/ServiceName.java b/aai-els-onap-logging/src/main/java/org/onap/aai/aailog/logs/ServiceName.java new file mode 100644 index 00000000..97f042f0 --- /dev/null +++ b/aai-els-onap-logging/src/main/java/org/onap/aai/aailog/logs/ServiceName.java @@ -0,0 +1,50 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 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========================================================= + */ +package org.onap.aai.aailog.logs; + +public class ServiceName { + /** + * Extract the service name from a URI path + * Service name should be the URI path up to two levels down from the version or less + * @param path the URI path + * @return the service name + */ + public static String extractServiceName (String path) { + StringBuilder sBuilder = new StringBuilder(); + String[] parts = path.split("/"); + String part = ""; + for (int i = 0; i < parts.length; i++) { + part = parts[i]; + if (i < 5) { + sBuilder.append(part).append("/"); + } else { + break; + } + } + if ((sBuilder.length() > 0) && (sBuilder.charAt(sBuilder.length()-1) == '/')) { + sBuilder.deleteCharAt(sBuilder.length()-1); + } + String serviceName = sBuilder.toString(); + if (serviceName != null && (!serviceName.isEmpty())) { + serviceName = serviceName.replaceAll(",", "\\\\,"); + } + return serviceName; + } +} diff --git a/aai-core/src/main/java/org/onap/aai/domain/restPolicyException/Fault.java b/aai-els-onap-logging/src/main/java/org/onap/aai/domain/restPolicyException/Fault.java index 55e45b64..d1403ad2 100644 --- a/aai-core/src/main/java/org/onap/aai/domain/restPolicyException/Fault.java +++ b/aai-els-onap-logging/src/main/java/org/onap/aai/domain/restPolicyException/Fault.java @@ -18,30 +18,25 @@ * ============LICENSE_END========================================================= */ // -// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2 -// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> -// Any modifications to this file will be lost upon recompilation of the source schema. -// Generated on: 2015.02.11 at 04:54:39 PM EST +// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2 +// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> +// Any modifications to this file will be lost upon recompilation of the source schema. +// Generated on: 2015.02.11 at 04:54:39 PM EST // package org.onap.aai.domain.restPolicyException; +import javax.xml.bind.annotation.*; import java.util.ArrayList; import java.util.List; -import javax.xml.bind.annotation.XmlAccessType; -import javax.xml.bind.annotation.XmlAccessorType; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; -import javax.xml.bind.annotation.XmlType; - /** * <p> * Java class for anonymous complex type. - * + * * <p> * The following schema fragment specifies the expected content contained within this class. - * + * * <pre> * <complexType> * <complexContent> @@ -85,8 +80,8 @@ import javax.xml.bind.annotation.XmlType; * </complexContent> * </complexType> * </pre> - * - * + * + * */ @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "", propOrder = {"requestError"}) @@ -98,11 +93,11 @@ public class Fault { /** * Gets the value of the requestError property. - * + * * @return * possible object is * {@link RequestError } - * + * */ public RequestError getRequestError() { return requestError; @@ -110,11 +105,11 @@ public class Fault { /** * Sets the value of the requestError property. - * + * * @param value * allowed object is * {@link RequestError } - * + * */ public void setRequestError(RequestError value) { this.requestError = value; @@ -123,10 +118,10 @@ public class Fault { /** * <p> * Java class for anonymous complex type. - * + * * <p> * The following schema fragment specifies the expected content contained within this class. - * + * * <pre> * <complexType> * <complexContent> @@ -160,8 +155,8 @@ public class Fault { * </complexContent> * </complexType> * </pre> - * - * + * + * */ @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "", propOrder = {"policyException"}) @@ -172,11 +167,11 @@ public class Fault { /** * Gets the value of the policyException property. - * + * * @return * possible object is * {@link PolicyException } - * + * */ public PolicyException getPolicyException() { return policyException; @@ -184,11 +179,11 @@ public class Fault { /** * Sets the value of the policyException property. - * + * * @param value * allowed object is * {@link PolicyException } - * + * */ public void setPolicyException(PolicyException value) { this.policyException = value; @@ -197,10 +192,10 @@ public class Fault { /** * <p> * Java class for anonymous complex type. - * + * * <p> * The following schema fragment specifies the expected content contained within this class. - * + * * <pre> * <complexType> * <complexContent> @@ -224,8 +219,8 @@ public class Fault { * </complexContent> * </complexType> * </pre> - * - * + * + * */ @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "", propOrder = {"messageId", "text", "variables"}) @@ -240,11 +235,11 @@ public class Fault { /** * Gets the value of the messageId property. - * + * * @return * possible object is * {@link String } - * + * */ public String getMessageId() { return messageId; @@ -252,11 +247,11 @@ public class Fault { /** * Sets the value of the messageId property. - * + * * @param value * allowed object is * {@link String } - * + * */ public void setMessageId(String value) { this.messageId = value; @@ -264,11 +259,11 @@ public class Fault { /** * Gets the value of the text property. - * + * * @return * possible object is * {@link String } - * + * */ public String getText() { return text; @@ -276,11 +271,11 @@ public class Fault { /** * Sets the value of the text property. - * + * * @param value * allowed object is * {@link String } - * + * */ public void setText(String value) { this.text = value; @@ -288,11 +283,11 @@ public class Fault { /** * Gets the value of the variables property. - * + * * @return * possible object is * {@link Variables } - * + * */ public Variables getVariables() { return variables; @@ -300,11 +295,11 @@ public class Fault { /** * Sets the value of the variables property. - * + * * @param value * allowed object is * {@link Variables } - * + * */ public void setVariables(Variables value) { this.variables = value; @@ -313,10 +308,10 @@ public class Fault { /** * <p> * Java class for anonymous complex type. - * + * * <p> * The following schema fragment specifies the expected content contained within this class. - * + * * <pre> * <complexType> * <complexContent> @@ -328,8 +323,8 @@ public class Fault { * </complexContent> * </complexType> * </pre> - * - * + * + * */ @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "", propOrder = {"variable"}) @@ -339,21 +334,21 @@ public class Fault { /** * Gets the value of the variable property. - * + * * <p> * This accessor method returns a reference to the live list, * not a snapshot. Therefore any modification you make to the * returned list will be present inside the JAXB object. * This is why there is not a <CODE>set</CODE> method for the variable property. - * + * * <p> * For example, to add a new item, do as follows: - * + * * <pre> * getVariable().add(newItem); * </pre> - * - * + * + * * <p> * Objects of the following type(s) are allowed in the list * {@link String } diff --git a/aai-core/src/main/java/org/onap/aai/domain/restPolicyException/ObjectFactory.java b/aai-els-onap-logging/src/main/java/org/onap/aai/domain/restPolicyException/ObjectFactory.java index f85fe748..d7837f9f 100644 --- a/aai-core/src/main/java/org/onap/aai/domain/restPolicyException/ObjectFactory.java +++ b/aai-els-onap-logging/src/main/java/org/onap/aai/domain/restPolicyException/ObjectFactory.java @@ -54,8 +54,8 @@ public class ObjectFactory { public ObjectFactory() { } - /** - * Create an instance of {@link Fault }. + /**a + * * Create an instance of {@link Fult }. * * @return the fault */ diff --git a/aai-core/src/main/java/org/onap/aai/domain/restPolicyException/PolicyException.java b/aai-els-onap-logging/src/main/java/org/onap/aai/domain/restPolicyException/PolicyException.java index 1aa2673a..ae6b6da1 100644 --- a/aai-core/src/main/java/org/onap/aai/domain/restPolicyException/PolicyException.java +++ b/aai-els-onap-logging/src/main/java/org/onap/aai/domain/restPolicyException/PolicyException.java @@ -20,20 +20,14 @@ package org.onap.aai.domain.restPolicyException; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.annotation.*; +import javax.annotation.Generated; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import javax.annotation.Generated; - @JsonInclude(JsonInclude.Include.NON_NULL) @Generated("org.jsonschema2pojo") @JsonPropertyOrder({"messageId", "text", "variables"}) diff --git a/aai-core/src/main/java/org/onap/aai/domain/restPolicyException/RESTResponse.java b/aai-els-onap-logging/src/main/java/org/onap/aai/domain/restPolicyException/RESTResponse.java index 262ca855..e1df4512 100644 --- a/aai-core/src/main/java/org/onap/aai/domain/restPolicyException/RESTResponse.java +++ b/aai-els-onap-logging/src/main/java/org/onap/aai/domain/restPolicyException/RESTResponse.java @@ -20,18 +20,12 @@ package org.onap.aai.domain.restPolicyException; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.annotation.*; +import javax.annotation.Generated; import java.util.HashMap; import java.util.Map; -import javax.annotation.Generated; - @JsonInclude(JsonInclude.Include.NON_NULL) @Generated("org.jsonschema2pojo") @JsonPropertyOrder({"requestError"}) diff --git a/aai-core/src/main/java/org/onap/aai/domain/restPolicyException/RequestError.java b/aai-els-onap-logging/src/main/java/org/onap/aai/domain/restPolicyException/RequestError.java index 54580de7..2b041840 100644 --- a/aai-core/src/main/java/org/onap/aai/domain/restPolicyException/RequestError.java +++ b/aai-els-onap-logging/src/main/java/org/onap/aai/domain/restPolicyException/RequestError.java @@ -20,18 +20,12 @@ package org.onap.aai.domain.restPolicyException; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.annotation.*; +import javax.annotation.Generated; import java.util.HashMap; import java.util.Map; -import javax.annotation.Generated; - @JsonInclude(JsonInclude.Include.NON_NULL) @Generated("org.jsonschema2pojo") @JsonPropertyOrder({"policyException"}) diff --git a/aai-core/src/main/java/org/onap/aai/domain/restResponseInfo/Info.java b/aai-els-onap-logging/src/main/java/org/onap/aai/domain/restResponseInfo/Info.java index 789fe926..268b7673 100644 --- a/aai-core/src/main/java/org/onap/aai/domain/restResponseInfo/Info.java +++ b/aai-els-onap-logging/src/main/java/org/onap/aai/domain/restResponseInfo/Info.java @@ -18,30 +18,25 @@ * ============LICENSE_END========================================================= */ // -// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2 -// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> -// Any modifications to this file will be lost upon recompilation of the source schema. -// Generated on: 2015.10.28 at 05:53:17 PM EDT +// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2 +// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> +// Any modifications to this file will be lost upon recompilation of the source schema. +// Generated on: 2015.10.28 at 05:53:17 PM EDT // package org.onap.aai.domain.restResponseInfo; +import javax.xml.bind.annotation.*; import java.util.ArrayList; import java.util.List; -import javax.xml.bind.annotation.XmlAccessType; -import javax.xml.bind.annotation.XmlAccessorType; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; -import javax.xml.bind.annotation.XmlType; - /** * <p> * Java class for anonymous complex type. - * + * * <p> * The following schema fragment specifies the expected content contained within this class. - * + * * <pre> * <complexType> * <complexContent> @@ -85,8 +80,8 @@ import javax.xml.bind.annotation.XmlType; * </complexContent> * </complexType> * </pre> - * - * + * + * */ @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "", propOrder = {"responseMessages"}) @@ -97,11 +92,11 @@ public class Info { /** * Gets the value of the responseMessages property. - * + * * @return * possible object is * {@link ResponseMessages } - * + * */ public ResponseMessages getResponseMessages() { return responseMessages; @@ -109,11 +104,11 @@ public class Info { /** * Sets the value of the responseMessages property. - * + * * @param value * allowed object is * {@link ResponseMessages } - * + * */ public void setResponseMessages(ResponseMessages value) { this.responseMessages = value; @@ -122,10 +117,10 @@ public class Info { /** * <p> * Java class for anonymous complex type. - * + * * <p> * The following schema fragment specifies the expected content contained within this class. - * + * * <pre> * <complexType> * <complexContent> @@ -159,8 +154,8 @@ public class Info { * </complexContent> * </complexType> * </pre> - * - * + * + * */ @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "", propOrder = {"responseMessage"}) @@ -170,21 +165,21 @@ public class Info { /** * Gets the value of the responseMessage property. - * + * * <p> * This accessor method returns a reference to the live list, * not a snapshot. Therefore any modification you make to the * returned list will be present inside the JAXB object. * This is why there is not a <CODE>set</CODE> method for the responseMessage property. - * + * * <p> * For example, to add a new item, do as follows: - * + * * <pre> * getResponseMessage().add(newItem); * </pre> - * - * + * + * * <p> * Objects of the following type(s) are allowed in the list * {@link ResponseMessage } @@ -201,10 +196,10 @@ public class Info { /** * <p> * Java class for anonymous complex type. - * + * * <p> * The following schema fragment specifies the expected content contained within this class. - * + * * <pre> * <complexType> * <complexContent> @@ -228,8 +223,8 @@ public class Info { * </complexContent> * </complexType> * </pre> - * - * + * + * */ @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "", propOrder = {"messageId", "text", "variables"}) @@ -244,11 +239,11 @@ public class Info { /** * Gets the value of the messageId property. - * + * * @return * possible object is * {@link String } - * + * */ public String getMessageId() { return messageId; @@ -256,11 +251,11 @@ public class Info { /** * Sets the value of the messageId property. - * + * * @param value * allowed object is * {@link String } - * + * */ public void setMessageId(String value) { this.messageId = value; @@ -268,11 +263,11 @@ public class Info { /** * Gets the value of the text property. - * + * * @return * possible object is * {@link String } - * + * */ public String getText() { return text; @@ -280,11 +275,11 @@ public class Info { /** * Sets the value of the text property. - * + * * @param value * allowed object is * {@link String } - * + * */ public void setText(String value) { this.text = value; @@ -292,11 +287,11 @@ public class Info { /** * Gets the value of the variables property. - * + * * @return * possible object is * {@link Variables } - * + * */ public Variables getVariables() { return variables; @@ -304,11 +299,11 @@ public class Info { /** * Sets the value of the variables property. - * + * * @param value * allowed object is * {@link Variables } - * + * */ public void setVariables(Variables value) { this.variables = value; @@ -317,10 +312,10 @@ public class Info { /** * <p> * Java class for anonymous complex type. - * + * * <p> * The following schema fragment specifies the expected content contained within this class. - * + * * <pre> * <complexType> * <complexContent> @@ -332,8 +327,8 @@ public class Info { * </complexContent> * </complexType> * </pre> - * - * + * + * */ @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "", propOrder = {"variable"}) @@ -343,21 +338,21 @@ public class Info { /** * Gets the value of the variable property. - * + * * <p> * This accessor method returns a reference to the live list, * not a snapshot. Therefore any modification you make to the * returned list will be present inside the JAXB object. * This is why there is not a <CODE>set</CODE> method for the variable property. - * + * * <p> * For example, to add a new item, do as follows: - * + * * <pre> * getVariable().add(newItem); * </pre> - * - * + * + * * <p> * Objects of the following type(s) are allowed in the list * {@link String } diff --git a/aai-core/src/main/java/org/onap/aai/domain/restResponseInfo/ObjectFactory.java b/aai-els-onap-logging/src/main/java/org/onap/aai/domain/restResponseInfo/ObjectFactory.java index 4efafb23..4efafb23 100644 --- a/aai-core/src/main/java/org/onap/aai/domain/restResponseInfo/ObjectFactory.java +++ b/aai-els-onap-logging/src/main/java/org/onap/aai/domain/restResponseInfo/ObjectFactory.java diff --git a/aai-core/src/main/java/org/onap/aai/domain/restServiceException/Fault.java b/aai-els-onap-logging/src/main/java/org/onap/aai/domain/restServiceException/Fault.java index 3efa13c3..09558455 100644 --- a/aai-core/src/main/java/org/onap/aai/domain/restServiceException/Fault.java +++ b/aai-els-onap-logging/src/main/java/org/onap/aai/domain/restServiceException/Fault.java @@ -18,30 +18,25 @@ * ============LICENSE_END========================================================= */ // -// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2 -// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> -// Any modifications to this file will be lost upon recompilation of the source schema. -// Generated on: 2015.02.11 at 04:54:29 PM EST +// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2 +// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> +// Any modifications to this file will be lost upon recompilation of the source schema. +// Generated on: 2015.02.11 at 04:54:29 PM EST // package org.onap.aai.domain.restServiceException; +import javax.xml.bind.annotation.*; import java.util.ArrayList; import java.util.List; -import javax.xml.bind.annotation.XmlAccessType; -import javax.xml.bind.annotation.XmlAccessorType; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; -import javax.xml.bind.annotation.XmlType; - /** * <p> * Java class for anonymous complex type. - * + * * <p> * The following schema fragment specifies the expected content contained within this class. - * + * * <pre> * <complexType> * <complexContent> @@ -85,8 +80,8 @@ import javax.xml.bind.annotation.XmlType; * </complexContent> * </complexType> * </pre> - * - * + * + * */ @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "", propOrder = {"requestError"}) @@ -98,11 +93,11 @@ public class Fault { /** * Gets the value of the requestError property. - * + * * @return * possible object is * {@link RequestError } - * + * */ public RequestError getRequestError() { return requestError; @@ -110,11 +105,11 @@ public class Fault { /** * Sets the value of the requestError property. - * + * * @param value * allowed object is * {@link RequestError } - * + * */ public void setRequestError(RequestError value) { this.requestError = value; @@ -123,10 +118,10 @@ public class Fault { /** * <p> * Java class for anonymous complex type. - * + * * <p> * The following schema fragment specifies the expected content contained within this class. - * + * * <pre> * <complexType> * <complexContent> @@ -160,8 +155,8 @@ public class Fault { * </complexContent> * </complexType> * </pre> - * - * + * + * */ @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "", propOrder = {"serviceException"}) @@ -172,11 +167,11 @@ public class Fault { /** * Gets the value of the serviceException property. - * + * * @return * possible object is * {@link ServiceException } - * + * */ public ServiceException getServiceException() { return serviceException; @@ -184,11 +179,11 @@ public class Fault { /** * Sets the value of the serviceException property. - * + * * @param value * allowed object is * {@link ServiceException } - * + * */ public void setServiceException(ServiceException value) { this.serviceException = value; @@ -197,10 +192,10 @@ public class Fault { /** * <p> * Java class for anonymous complex type. - * + * * <p> * The following schema fragment specifies the expected content contained within this class. - * + * * <pre> * <complexType> * <complexContent> @@ -224,8 +219,8 @@ public class Fault { * </complexContent> * </complexType> * </pre> - * - * + * + * */ @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "", propOrder = {"messageId", "text", "variables"}) @@ -240,11 +235,11 @@ public class Fault { /** * Gets the value of the messageId property. - * + * * @return * possible object is * {@link String } - * + * */ public String getMessageId() { return messageId; @@ -252,11 +247,11 @@ public class Fault { /** * Sets the value of the messageId property. - * + * * @param value * allowed object is * {@link String } - * + * */ public void setMessageId(String value) { this.messageId = value; @@ -264,11 +259,11 @@ public class Fault { /** * Gets the value of the text property. - * + * * @return * possible object is * {@link String } - * + * */ public String getText() { return text; @@ -276,11 +271,11 @@ public class Fault { /** * Sets the value of the text property. - * + * * @param value * allowed object is * {@link String } - * + * */ public void setText(String value) { this.text = value; @@ -288,11 +283,11 @@ public class Fault { /** * Gets the value of the variables property. - * + * * @return * possible object is * {@link Variables } - * + * */ public Variables getVariables() { return variables; @@ -300,11 +295,11 @@ public class Fault { /** * Sets the value of the variables property. - * + * * @param value * allowed object is * {@link Variables } - * + * */ public void setVariables(Variables value) { this.variables = value; @@ -313,10 +308,10 @@ public class Fault { /** * <p> * Java class for anonymous complex type. - * + * * <p> * The following schema fragment specifies the expected content contained within this class. - * + * * <pre> * <complexType> * <complexContent> @@ -328,8 +323,8 @@ public class Fault { * </complexContent> * </complexType> * </pre> - * - * + * + * */ @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "", propOrder = {"variable"}) @@ -339,21 +334,21 @@ public class Fault { /** * Gets the value of the variable property. - * + * * <p> * This accessor method returns a reference to the live list, * not a snapshot. Therefore any modification you make to the * returned list will be present inside the JAXB object. * This is why there is not a <CODE>set</CODE> method for the variable property. - * + * * <p> * For example, to add a new item, do as follows: - * + * * <pre> * getVariable().add(newItem); * </pre> - * - * + * + * * <p> * Objects of the following type(s) are allowed in the list * {@link String } diff --git a/aai-core/src/main/java/org/onap/aai/domain/restServiceException/ObjectFactory.java b/aai-els-onap-logging/src/main/java/org/onap/aai/domain/restServiceException/ObjectFactory.java index 95eb2cba..95eb2cba 100644 --- a/aai-core/src/main/java/org/onap/aai/domain/restServiceException/ObjectFactory.java +++ b/aai-els-onap-logging/src/main/java/org/onap/aai/domain/restServiceException/ObjectFactory.java diff --git a/aai-core/src/main/java/org/onap/aai/domain/restServiceException/RESTResponse.java b/aai-els-onap-logging/src/main/java/org/onap/aai/domain/restServiceException/RESTResponse.java index 09178937..d812c37b 100644 --- a/aai-core/src/main/java/org/onap/aai/domain/restServiceException/RESTResponse.java +++ b/aai-els-onap-logging/src/main/java/org/onap/aai/domain/restServiceException/RESTResponse.java @@ -20,18 +20,12 @@ package org.onap.aai.domain.restServiceException; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.annotation.*; +import javax.annotation.Generated; import java.util.HashMap; import java.util.Map; -import javax.annotation.Generated; - @JsonInclude(JsonInclude.Include.NON_NULL) @Generated("org.jsonschema2pojo") @JsonPropertyOrder({"requestError"}) diff --git a/aai-core/src/main/java/org/onap/aai/domain/restServiceException/RequestError.java b/aai-els-onap-logging/src/main/java/org/onap/aai/domain/restServiceException/RequestError.java index 38320218..79fca83f 100644 --- a/aai-core/src/main/java/org/onap/aai/domain/restServiceException/RequestError.java +++ b/aai-els-onap-logging/src/main/java/org/onap/aai/domain/restServiceException/RequestError.java @@ -20,18 +20,12 @@ package org.onap.aai.domain.restServiceException; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.annotation.*; +import javax.annotation.Generated; import java.util.HashMap; import java.util.Map; -import javax.annotation.Generated; - @JsonInclude(JsonInclude.Include.NON_NULL) @Generated("org.jsonschema2pojo") @JsonPropertyOrder({"serviceException"}) diff --git a/aai-core/src/main/java/org/onap/aai/domain/restServiceException/ServiceException.java b/aai-els-onap-logging/src/main/java/org/onap/aai/domain/restServiceException/ServiceException.java index ec658ce3..f215bd58 100644 --- a/aai-core/src/main/java/org/onap/aai/domain/restServiceException/ServiceException.java +++ b/aai-els-onap-logging/src/main/java/org/onap/aai/domain/restServiceException/ServiceException.java @@ -20,20 +20,14 @@ package org.onap.aai.domain.restServiceException; -import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonAnySetter; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.annotation.*; +import javax.annotation.Generated; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import javax.annotation.Generated; - @JsonInclude(JsonInclude.Include.NON_NULL) @Generated("org.jsonschema2pojo") @JsonPropertyOrder({"messageId", "text", "variables"}) diff --git a/aai-core/src/main/java/org/onap/aai/exceptions/AAIException.java b/aai-els-onap-logging/src/main/java/org/onap/aai/exceptions/AAIException.java index 320d5630..24228e83 100644 --- a/aai-core/src/main/java/org/onap/aai/exceptions/AAIException.java +++ b/aai-els-onap-logging/src/main/java/org/onap/aai/exceptions/AAIException.java @@ -22,13 +22,13 @@ package org.onap.aai.exceptions; -import java.util.Collection; -import java.util.LinkedList; - import org.onap.aai.logging.ErrorLogHelper; import org.onap.aai.logging.ErrorObject; import org.onap.aai.logging.ErrorObjectNotFoundException; +import java.util.Collection; +import java.util.LinkedList; + public class AAIException extends Exception { private static final String UPDATE_ERROR_PROPERTIES_BEFORE_USING_THIS_EXCEPTION_CODE = diff --git a/aai-core/src/main/java/org/onap/aai/exceptions/AAIExceptionWithInfo.java b/aai-els-onap-logging/src/main/java/org/onap/aai/exceptions/AAIExceptionWithInfo.java index e7f2901e..e7f2901e 100644 --- a/aai-core/src/main/java/org/onap/aai/exceptions/AAIExceptionWithInfo.java +++ b/aai-els-onap-logging/src/main/java/org/onap/aai/exceptions/AAIExceptionWithInfo.java diff --git a/aai-els-onap-logging/src/main/java/org/onap/aai/logging/AaiElsErrorCode.java b/aai-els-onap-logging/src/main/java/org/onap/aai/logging/AaiElsErrorCode.java new file mode 100644 index 00000000..769103ba --- /dev/null +++ b/aai-els-onap-logging/src/main/java/org/onap/aai/logging/AaiElsErrorCode.java @@ -0,0 +1,31 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - Logging + * ================================================================================ + * Copyright (C) 2019 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========================================================= + */ + +package org.onap.aai.logging; + +public class AaiElsErrorCode { + public static final String SUCCESS = "0"; + public static final String PERMISSION_ERROR = "100"; + public static final String AVAILABILITY_TIMEOUT_ERROR = "200"; + public static final String DATA_ERROR = "300"; + public static final String SCHEMA_ERROR = "400"; + public static final String BUSINESS_PROCESS_ERROR = "500"; + public static final String UNKNOWN_ERROR = "900"; +} diff --git a/aai-core/src/main/java/org/onap/aai/logging/CNName.java b/aai-els-onap-logging/src/main/java/org/onap/aai/logging/CNName.java index 5337afe3..10e4782e 100644 --- a/aai-core/src/main/java/org/onap/aai/logging/CNName.java +++ b/aai-els-onap-logging/src/main/java/org/onap/aai/logging/CNName.java @@ -20,25 +20,23 @@ package org.onap.aai.logging; -import static java.util.Base64.getDecoder; - import ch.qos.logback.access.pattern.AccessConverter; import ch.qos.logback.access.spi.IAccessEvent; - -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; - -import java.security.cert.X509Certificate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.security.auth.x500.X500Principal; import javax.servlet.http.HttpServletRequest; +import java.security.cert.X509Certificate; + +import static java.util.Base64.getDecoder; public class CNName extends AccessConverter { - private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(CNName.class); + protected static final Logger LOGGER = LoggerFactory.getLogger(CNName.class); /** * Converts access events to String response codes - * + * * @param accessEvent the IAccessEvent */ public String convert(IAccessEvent accessEvent) { diff --git a/aai-core/src/main/java/org/onap/aai/logging/CustomLogPatternLayout.java b/aai-els-onap-logging/src/main/java/org/onap/aai/logging/CustomLogPatternLayout.java index 63cc49f7..63cc49f7 100644 --- a/aai-core/src/main/java/org/onap/aai/logging/CustomLogPatternLayout.java +++ b/aai-els-onap-logging/src/main/java/org/onap/aai/logging/CustomLogPatternLayout.java diff --git a/aai-core/src/main/java/org/onap/aai/logging/CustomLogPatternLayoutEncoder.java b/aai-els-onap-logging/src/main/java/org/onap/aai/logging/CustomLogPatternLayoutEncoder.java index 010d828b..010d828b 100644 --- a/aai-core/src/main/java/org/onap/aai/logging/CustomLogPatternLayoutEncoder.java +++ b/aai-els-onap-logging/src/main/java/org/onap/aai/logging/CustomLogPatternLayoutEncoder.java diff --git a/aai-core/src/main/java/org/onap/aai/logging/DME2RestFlag.java b/aai-els-onap-logging/src/main/java/org/onap/aai/logging/DME2RestFlag.java index 768c095b..768c095b 100644 --- a/aai-core/src/main/java/org/onap/aai/logging/DME2RestFlag.java +++ b/aai-els-onap-logging/src/main/java/org/onap/aai/logging/DME2RestFlag.java diff --git a/aai-core/src/main/java/org/onap/aai/logging/ErrorLogHelper.java b/aai-els-onap-logging/src/main/java/org/onap/aai/logging/ErrorLogHelper.java index 01327606..4ef2a237 100644 --- a/aai-core/src/main/java/org/onap/aai/logging/ErrorLogHelper.java +++ b/aai-els-onap-logging/src/main/java/org/onap/aai/logging/ErrorLogHelper.java @@ -20,43 +20,36 @@ package org.onap.aai.logging; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; +import org.apache.commons.lang.StringUtils; +import org.onap.aai.exceptions.AAIException; +import org.onap.aai.util.AAIConstants; +import org.onap.aai.util.MapperUtil; +import org.onap.logging.filter.base.Constants; +import org.onap.logging.filter.base.MDCSetup; +import org.onap.logging.ref.slf4j.ONAPLogConstants; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.MDC; +import javax.ws.rs.core.MediaType; +import javax.xml.bind.JAXBContext; +import javax.xml.bind.Marshaller; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.StringWriter; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.Map.Entry; -import java.util.Properties; - -import javax.ws.rs.core.MediaType; -import javax.xml.bind.JAXBContext; -import javax.xml.bind.Marshaller; - -import org.apache.commons.lang.StringUtils; -import org.onap.aai.exceptions.AAIException; -import org.onap.aai.logging.LoggingContext.StatusCode; -import org.onap.aai.util.AAIConfig; -import org.onap.aai.util.AAIConstants; -import org.onap.aai.util.MapperUtil; -import org.slf4j.MDC; /** - * + * * This classes loads the application error properties file * and provides a method that returns an ErrorObject - * + * */ public class ErrorLogHelper { - - private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(ErrorLogHelper.class); + private static final Logger LOGGER = LoggerFactory.getLogger(ErrorLogHelper.class); private static final HashMap<String, ErrorObject> ERROR_OBJECTS = new HashMap<String, ErrorObject>(); static { @@ -71,20 +64,23 @@ public class ErrorLogHelper { /** * Load properties. - * + * @throws IOException the exception * @throws ErrorObjectFormatException - * @throws Exception the exception */ public static void loadProperties() throws IOException, ErrorObjectFormatException { final String filePath = AAIConstants.AAI_HOME_ETC_APP_PROPERTIES + "error.properties"; - final InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(filePath); + final InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("error.properties"); final Properties properties = new Properties(); - if (is != null) { - properties.load(is); - } else { - try (final FileInputStream fis = new FileInputStream(filePath)) { - properties.load(fis); + try (final FileInputStream fis = new FileInputStream(filePath)) { + LOGGER.info("Found the error.properties in the following location: {}", AAIConstants.AAI_HOME_ETC_APP_PROPERTIES); + properties.load(fis); + } catch(Exception ex){ + LOGGER.info("Unable to find the error.properties from filesystem so using file in jar"); + if (is != null) { + properties.load(is); + } else { + LOGGER.error("Expected to find the error.properties in the jar but unable to find it"); } } @@ -93,7 +89,7 @@ public class ErrorLogHelper { final String value = (String) entry.getValue(); final String[] errorProperties = value.split(":"); - if (errorProperties.length != 7) + if (errorProperties.length < 7) throw new ErrorObjectFormatException(); final ErrorObject errorObject = new ErrorObject(); @@ -105,6 +101,9 @@ public class ErrorLogHelper { errorObject.setHTTPResponseCode(errorProperties[4].trim()); errorObject.setRESTErrorCode(errorProperties[5].trim()); errorObject.setErrorText(errorProperties[6].trim()); + if (errorProperties.length > 7) { + errorObject.setAaiElsErrorCode(errorProperties[7].trim()); + } ERROR_OBJECTS.put(key, errorObject); } @@ -113,10 +112,9 @@ public class ErrorLogHelper { /** * Logs a known A&AI exception (i.e. one that can be found in error.properties) * - * @param key The key for the error in the error.properties file + * @param code for the error in the error.properties file * @throws IOException * @throws ErrorObjectNotFoundException - * @throws ErrorObjectFormatException */ public static ErrorObject getErrorObject(String code) throws ErrorObjectNotFoundException { @@ -139,12 +137,10 @@ public class ErrorLogHelper { * This allows lower level exception detail to be returned to the client to help troubleshoot the problem. * If no error object is embedded in the AAIException, one will be created using the error object from the * AAIException. - * + * * @param are must have a restError value whose numeric value must match what should be returned in the REST API * @param variables optional list of variables to flesh out text in error string * @return appropriately formatted JSON response per the REST API spec. - * @throws ErrorObjectFormatException - * @throws ErrorObjectNotFoundException * @throws IOException * @deprecated */ @@ -166,9 +162,6 @@ public class ErrorLogHelper { * @param are must have a restError value whose numeric value must match what should be returned in the REST API * @param variables optional list of variables to flesh out text in error string * @return appropriately formatted JSON response per the REST API spec. - * @throws ErrorObjectFormatException - * @throws ErrorObjectNotFoundException - * @throws IOException */ public static String getRESTAPIErrorResponse(List<MediaType> acceptHeadersOrig, AAIException are, ArrayList<String> variables) { @@ -333,7 +326,7 @@ public class ErrorLogHelper { restresp.setRequestError(reqerr); response = (MapperUtil.writeAsJSONString((Object) restresp)); } - } catch (AAIException ex) { + } catch (Exception ex) { LOGGER.error( "We were unable to create a rest exception to return on an API because of a parsing error " + ex.getMessage()); @@ -350,18 +343,11 @@ public class ErrorLogHelper { * @param acceptHeadersOrig the accept headers orig * @param are the are * @param variables the variables - * @param logline the logline - * @return the RESTAPI error response with logging - * @throws ErrorObjectFormatException - * @throws ErrorObjectNotFoundException - * @throws IOException */ public static String getRESTAPIErrorResponseWithLogging(List<MediaType> acceptHeadersOrig, AAIException are, ArrayList<String> variables) { String response = ErrorLogHelper.getRESTAPIErrorResponse(acceptHeadersOrig, are, variables); - - LOGGER.error(are.getMessage() + " " + LogFormatTools.getStackTop(are)); - + logException(are); return response; } @@ -371,9 +357,6 @@ public class ErrorLogHelper { * @param acceptHeaders the accept headers * @param areList the are list * @return the RESTAPI info response - * @throws ErrorObjectFormatException - * @throws ErrorObjectNotFoundException - * @throws IOException */ public static Object getRESTAPIInfoResponse(List<MediaType> acceptHeaders, HashMap<AAIException, ArrayList<String>> areList) { @@ -463,13 +446,10 @@ public class ErrorLogHelper { * This allows lower level exception detail to be returned to the client to help troubleshoot the problem. * If no error object is embedded in the AAIException, one will be created using the error object from the * AAIException. - * + * * @param are must have a restError value whose numeric value must match what should be returned in the REST API * @param variables optional list of variables to flesh out text in error string * @return appropriately formatted JSON response per the REST API spec. - * @throws ErrorObjectFormatException - * @throws ErrorObjectNotFoundException - * @throws IOException */ public static String getRESTAPIPolicyErrorResponseXML(AAIException are, ArrayList<String> variables) { @@ -586,16 +566,17 @@ public class ErrorLogHelper { public static void logException(AAIException e) { final ErrorObject errorObject = e.getErrorObject(); - - // MDC.put("severity", errorObject.getSeverity()); //TODO Use LoggingContext.severity(int severity) + /* String severityCode = errorObject.getSeverityCode(errorObject.getSeverity()); - if (!AAIConfig.isEmpty(severityCode)) { + Severify should be left empty per Logging Specification 2019.11 + if (!StringUtils.isEmpty(severityCode)) { int sevCode = Integer.parseInt(severityCode); if (sevCode > 0 && sevCode <= 3) { LoggingContext.severity(sevCode); } } + */ String stackTrace = ""; try { stackTrace = LogFormatTools.getStackTop(e); @@ -606,10 +587,14 @@ public class ErrorLogHelper { .append(errorObject.getRESTErrorCode()).append(":").append(errorObject.getHTTPResponseCode()) .append(":").append(e.getMessage()).toString().replaceAll("\\n", "^"); - LoggingContext.responseCode(Integer.toString(errorObject.getHTTPResponseCode().getStatusCode())); - LoggingContext.responseDescription(errorMessage); - LoggingContext.statusCode(StatusCode.ERROR); - + MDCSetup mdcSetup = new MDCSetup(); + mdcSetup.setResponseStatusCode(errorObject.getHTTPResponseCode().getStatusCode()); + mdcSetup.setErrorCode(Integer.parseInt(errorObject.getAaiElsErrorCode())); + String serviceName = MDC.get(ONAPLogConstants.MDCs.SERVICE_NAME); + if (serviceName == null || serviceName.isEmpty()) { + MDC.put(ONAPLogConstants.MDCs.SERVICE_NAME, Constants.DefaultValues.UNKNOWN); + } + MDC.put(ONAPLogConstants.MDCs.ERROR_DESC, errorMessage); final String details = new StringBuilder().append(errorObject.getErrorCodeString()).append(" ").append(stackTrace).toString(); diff --git a/aai-core/src/main/java/org/onap/aai/logging/ErrorObject.java b/aai-els-onap-logging/src/main/java/org/onap/aai/logging/ErrorObject.java index 6048c18b..2e849d25 100644 --- a/aai-core/src/main/java/org/onap/aai/logging/ErrorObject.java +++ b/aai-els-onap-logging/src/main/java/org/onap/aai/logging/ErrorObject.java @@ -38,6 +38,7 @@ public class ErrorObject { private String errorCode; private String errorText; private String details; + private String aaiElsErrorCode = AaiElsErrorCode.UNKNOWN_ERROR; /** * Instantiates a new error object. @@ -47,7 +48,7 @@ public class ErrorObject { } /** - * Creates an error object with the default HTTP Error Code (Status.INTERNAL_SERVER_ERROR) + * Creates an error object * * @param disposition the disposition * @param category the category @@ -67,13 +68,13 @@ public class ErrorObject { this.setRESTErrorCode(restErrorCode); this.setErrorCode(errorCode); this.setErrorText(errorText); + this.setAaiElsErrorCode(AaiElsErrorCode.UNKNOWN_ERROR); } // OLD STARTS HERE /** * Instantiates a new error object. - * * @param severity the severity * @param errorCode the error code * @param errorText the error text @@ -103,6 +104,7 @@ public class ErrorObject { this.setErrorText(errorText); this.setDisposition(disposition); this.setCategory(category); + this.setAaiElsErrorCode(AaiElsErrorCode.UNKNOWN_ERROR); } /** @@ -124,6 +126,7 @@ public class ErrorObject { this.setErrorText(errorText); this.setDisposition(disposition); this.setCategory(category); + this.setAaiElsErrorCode(AaiElsErrorCode.UNKNOWN_ERROR); } /** @@ -302,7 +305,22 @@ public class ErrorObject { public void setDetails(String details) { this.details = details == null ? "" : details; } - + /** + * Sets the aai els error code. + * + * @param elsErrorCode the new code + */ + public void setAaiElsErrorCode(String elsErrorCode) { + aaiElsErrorCode = elsErrorCode; + } + /** + * Gets the aai els error code. + * + * @return the code + */ + public String getAaiElsErrorCode() { + return (aaiElsErrorCode); + } /** * Gets the error code string. This is also the string * configured in Nagios to alert on diff --git a/aai-core/src/main/java/org/onap/aai/logging/ErrorObjectFormatException.java b/aai-els-onap-logging/src/main/java/org/onap/aai/logging/ErrorObjectFormatException.java index 8d53f2e3..8d53f2e3 100644 --- a/aai-core/src/main/java/org/onap/aai/logging/ErrorObjectFormatException.java +++ b/aai-els-onap-logging/src/main/java/org/onap/aai/logging/ErrorObjectFormatException.java diff --git a/aai-core/src/main/java/org/onap/aai/logging/ErrorObjectNotFoundException.java b/aai-els-onap-logging/src/main/java/org/onap/aai/logging/ErrorObjectNotFoundException.java index 3daf7137..3daf7137 100644 --- a/aai-core/src/main/java/org/onap/aai/logging/ErrorObjectNotFoundException.java +++ b/aai-els-onap-logging/src/main/java/org/onap/aai/logging/ErrorObjectNotFoundException.java diff --git a/aai-core/src/main/java/org/onap/aai/logging/LogFormatTools.java b/aai-els-onap-logging/src/main/java/org/onap/aai/logging/LogFormatTools.java index 804801f1..3f0d80ae 100644 --- a/aai-core/src/main/java/org/onap/aai/logging/LogFormatTools.java +++ b/aai-els-onap-logging/src/main/java/org/onap/aai/logging/LogFormatTools.java @@ -20,16 +20,16 @@ package org.onap.aai.logging; -import java.time.Instant; -import java.time.ZoneOffset; -import java.time.ZonedDateTime; -import java.time.format.DateTimeFormatter; - import org.apache.commons.lang.exception.ExceptionUtils; import org.onap.aai.exceptions.AAIException; import org.onap.aai.util.AAIConfig; import org.onap.aai.util.AAIConstants; +import java.time.Instant; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; + public class LogFormatTools { private static final String DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"; @@ -117,7 +117,9 @@ public class LogFormatTools { } } } - return stackMessage.toString(); + String stackMessageStr = stackMessage.toString(); + stackMessageStr = stackMessageStr.replaceAll("\\n", "^"); + return stackMessageStr; } } diff --git a/aai-els-onap-logging/src/main/java/org/onap/aai/logging/LoggingContext.java b/aai-els-onap-logging/src/main/java/org/onap/aai/logging/LoggingContext.java new file mode 100644 index 00000000..13f324ec --- /dev/null +++ b/aai-els-onap-logging/src/main/java/org/onap/aai/logging/LoggingContext.java @@ -0,0 +1,130 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 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========================================================= + */ + +package org.onap.aai.logging; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.MDC; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +public class LoggingContext { + + private static final Logger logger = LoggerFactory.getLogger(LoggingContext.class); + + // Response codes from Logging Guidelines + public static final String SUCCESS = "0"; + public static final String PERMISSION_ERROR = "100"; + public static final String AVAILABILITY_TIMEOUT_ERROR = "200"; + public static final String DATA_ERROR = "300"; + public static final String SCHEMA_ERROR = "400"; + public static final String BUSINESS_PROCESS_ERROR = "500"; + public static final String UNKNOWN_ERROR = "900"; + + public static final Map<String, String> responseMap = new HashMap(); + + + // Specific Log Event Fields + public static enum LoggingField { + START_TIME("startTime"), REQUEST_ID("requestId"), SERVICE_INSTANCE_ID("serviceInstanceId"), SERVER_NAME( + "serverName"), SERVICE_NAME("serviceName"), PARTNER_NAME("partnerName"), STATUS_CODE( + "statusCode"), RESPONSE_CODE("responseCode"), RESPONSE_DESCRIPTION( + "responseDescription"), INSTANCE_UUID("instanceUUID"), SEVERITY( + "severity"), SERVER_IP_ADDRESS( + "serverIpAddress"), ELAPSED_TIME("elapsedTime"), SERVER( + "server"), CLIENT_IP_ADDRESS("clientIpAddress"), UNUSED( + "unused"), PROCESS_KEY("processKey"), CUSTOM_FIELD_1( + "customField1"), CUSTOM_FIELD_2( + "customField2"), CUSTOM_FIELD_3( + "customField3"), CUSTOM_FIELD_4( + "customField4"), + + // Specific Metric Log Event Fields + TARGET_ENTITY("targetEntity"), TARGET_SERVICE_NAME("targetServiceName"), + // A&AI Specific Log Event Fields + COMPONENT("component"), STOP_WATCH_START("stopWatchStart"); + + private final String text; + + private LoggingField(final String text) { + this.text = text; + } + + public String toString() { + return text; + } + } + + public static void init() { + LoggingContext.clear(); + + } + + public static void elapsedTime(long elapsedTime, TimeUnit timeUnit) { + MDC.put(LoggingField.ELAPSED_TIME.toString(), + String.valueOf(TimeUnit.MILLISECONDS.convert(elapsedTime, timeUnit))); + } + + public static boolean isStopWatchStarted() { + final String rawStopWatchStart = MDC.get(LoggingField.STOP_WATCH_START.toString()); + if (rawStopWatchStart == null) { + return false; + } + return true; + } + + public static void stopWatchStart() { + MDC.put(LoggingField.STOP_WATCH_START.toString(), String.valueOf(System.nanoTime())); + } + + public static double stopWatchStop() { + final long stopWatchEnd = System.nanoTime(); + final String rawStopWatchStart = MDC.get(LoggingField.STOP_WATCH_START.toString()); + + if (rawStopWatchStart == null) + throw new StopWatchNotStartedException(); + + final Long stopWatchStart = Long.valueOf(rawStopWatchStart); + + MDC.remove(LoggingField.STOP_WATCH_START.toString()); + + final double elapsedTimeMillis = (stopWatchEnd - stopWatchStart) / 1000.0 / 1000.0; + + LoggingContext.elapsedTime((long) elapsedTimeMillis, TimeUnit.MILLISECONDS); + + return elapsedTimeMillis; + } + + public static void put(String key, String value) { + MDC.put(key, value); + } + + public static void clear() { + MDC.clear(); + } + + public static void remove(String key) { + MDC.remove(key); + } + +} diff --git a/aai-core/src/main/java/org/onap/aai/logging/LoggingContextNotExistsException.java b/aai-els-onap-logging/src/main/java/org/onap/aai/logging/LoggingContextNotExistsException.java index f1d4c59c..f1d4c59c 100644 --- a/aai-core/src/main/java/org/onap/aai/logging/LoggingContextNotExistsException.java +++ b/aai-els-onap-logging/src/main/java/org/onap/aai/logging/LoggingContextNotExistsException.java diff --git a/aai-core/src/main/java/org/onap/aai/logging/StopWatch.java b/aai-els-onap-logging/src/main/java/org/onap/aai/logging/StopWatch.java index 0d93827f..0d93827f 100644 --- a/aai-core/src/main/java/org/onap/aai/logging/StopWatch.java +++ b/aai-els-onap-logging/src/main/java/org/onap/aai/logging/StopWatch.java diff --git a/aai-core/src/main/java/org/onap/aai/logging/StopWatchNotStartedException.java b/aai-els-onap-logging/src/main/java/org/onap/aai/logging/StopWatchNotStartedException.java index e4819c5c..e4819c5c 100644 --- a/aai-core/src/main/java/org/onap/aai/logging/StopWatchNotStartedException.java +++ b/aai-els-onap-logging/src/main/java/org/onap/aai/logging/StopWatchNotStartedException.java diff --git a/aai-els-onap-logging/src/main/java/org/onap/aai/util/AAIApplicationConfig.java b/aai-els-onap-logging/src/main/java/org/onap/aai/util/AAIApplicationConfig.java new file mode 100644 index 00000000..7de6af28 --- /dev/null +++ b/aai-els-onap-logging/src/main/java/org/onap/aai/util/AAIApplicationConfig.java @@ -0,0 +1,362 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 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========================================================= + */ + +package org.onap.aai.util; + +import org.apache.commons.io.IOUtils; +import org.eclipse.jetty.util.security.Password; +import org.onap.aai.exceptions.AAIException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.Charset; +import java.util.Properties; +import java.util.UUID; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class AAIApplicationConfig { + + private static final Logger LOGGER = LoggerFactory.getLogger(AAIApplicationConfig.class); + private static String GLOBAL_PROP_FILE_NAME = "application.properties"; + private static final String SERVER_CERTS_LOCATION_PROP_NAME = "server.certs.location"; + private static final String PASSPHRASSES_FILENAME = ".passphrases"; + private static final String PASSWORD_FILENAME = ".password"; + private static final String TRUSTSTORE_PASSWORD_PROP_NAME = "cadi_truststore_password"; + private static final String SERVER_SSL_KEYSTORE_PROP_NAME = "server.ssl.key-store"; + private static final String SERVER_SSL_KEYSTORE_PKCS12_PROP_NAME = "server.ssl.key-store.pkcs12"; + private static final String SERVER_SSL_TRUSTSTORE_PROP_NAME = "server.ssl.trust-store"; + private static Properties serverProps; + private static boolean propsInitialized = false; + private static String TRUSTSTORE_PASSWORD = null; + private static String KEYSTORE_PASSWORD = null; + private static final String PROPERTY_REGEX = "\\$\\{([^\\$\\{\\}]+)\\}"; + + /** + * Instantiates a new AAI config. + */ + // Don't instantiate + private AAIApplicationConfig() { + } + + /** + * Inits the. + * + * @throws AAIException the AAI exception + */ + public synchronized static void init() { + /*LoggingContext.save(); + LoggingContext.component("config"); + LoggingContext.partnerName("NA"); + LoggingContext.targetEntity("AAI"); + LoggingContext.requestId(UUID.randomUUID().toString()); + LoggingContext.serviceName("AAI"); + LoggingContext.targetServiceName("init"); + LoggingContext.statusCode(StatusCode.COMPLETE);*/ + + LOGGER.info("Initializing AAIApplicationConfig"); + + AAIApplicationConfig.reloadConfig(); + + //LoggingContext.restore(); + } + + /** + * Reload config. + */ + public synchronized static void reloadConfig() { + + Properties newServerProps = new Properties(); + LOGGER.debug("Reloading config from " + GLOBAL_PROP_FILE_NAME); + + try { + InputStream is = AAIApplicationConfig.class.getClassLoader().getResourceAsStream(GLOBAL_PROP_FILE_NAME); + newServerProps.load(is); + propsInitialized = true; + serverProps = newServerProps; + TRUSTSTORE_PASSWORD = retrieveTruststorePassword(); + KEYSTORE_PASSWORD = retrieveKeystorePassword(); + } catch (Exception fnfe) { + final InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("application.properties"); + LOGGER.info("Unable to find the application.properties from filesystem so using file in jar"); + if (is != null) { + try { + newServerProps.load(is); + serverProps = newServerProps; + TRUSTSTORE_PASSWORD = retrieveTruststorePassword(); + KEYSTORE_PASSWORD = retrieveKeystorePassword(); + } catch (IOException e) { + LOGGER.warn("Encountered IO Exception during loading of props from inputstream", e); + } + } else { + LOGGER.error("Expected to find the properties file in the jar but unable to find it"); + } + } + } + + /** + * Gets the key value + * + * @param key the key + * @param defaultValue the default value + * @return the string + */ + public static String get(String key, String defaultValue) { + String result = defaultValue; + try { + result = get(key); + } catch (AAIException a) { + } + if (result == null || result.isEmpty()) { + result = defaultValue; + } + return (result); + } + + /** + * Gets the key value + * + * @param key the key + * @return the string + * @throws AAIException the AAI exception + */ + public static String get(String key) throws AAIException { + String response = null; + + if (!propsInitialized || (serverProps == null)) { + reloadConfig(); + } + + if ((key.endsWith("password") || key.endsWith("passwd") || key.endsWith("apisecret")) + && serverProps.containsKey(key + ".x")) { + String valx = serverProps.getProperty(key + ".x"); + return Password.deobfuscate(valx); + } + + if (!serverProps.containsKey(key)) { + throw new AAIException("AAI_4005", "Property key " + key + " cannot be found"); + } else { + response = serverProps.getProperty(key); + if (response == null || response.isEmpty()) { + throw new AAIException("AAI_4005", "Property key " + key + " is null or empty"); + } + response = replaceProperties(response); + } + return response; + } + + /** + * Gets the keystore path + * + * @return the string + * @throws AAIException the AAI exception + */ + public static String getKeystore() throws AAIException { + return (get(SERVER_SSL_KEYSTORE_PROP_NAME)); + } + /** + * Gets the PKCS12 keystore path + * + * @return the string + * @throws AAIException the AAI exception + */ + public static String getKeystorePkcs12() throws AAIException { + return (get(SERVER_SSL_KEYSTORE_PKCS12_PROP_NAME)); + } + /** + * Gets the keystore path + * + * @return the string + * @throws AAIException the AAI exception + */ + public static String getTruststore() throws AAIException { + return (get(SERVER_SSL_TRUSTSTORE_PROP_NAME)); + } + + /** + * Retrieve the keystore password + * + * @return the password + */ + private static String retrieveKeystorePassword() { + String certPath = serverProps.getProperty(SERVER_CERTS_LOCATION_PROP_NAME); + if (certPath == null) { + return null; + } + try { + certPath = replaceProperties(certPath); + } + catch (AAIException e) { + return null; + } + + File passwordFile = null; + InputStream passwordStream = null; + String keystorePassword = null; + + // Override the passwords from application.properties if we find AAF certman files + try { + passwordFile = new File(certPath + PASSWORD_FILENAME); + passwordStream = new FileInputStream(passwordFile); + keystorePassword = IOUtils.toString(passwordStream, Charset.defaultCharset()); + if (keystorePassword != null) { + keystorePassword = keystorePassword.trim(); + } + + } catch (IOException e) { + LOGGER.warn("Not using AAF Certman password file, e=" + e.getMessage()); + } catch (NullPointerException n) { + LOGGER.warn("Not using AAF Certman passphrases file, e=" + n.getMessage()); + } finally { + if (passwordStream != null) { + try { + passwordStream.close(); + } catch (Exception e) { + } + } + } + return keystorePassword; + } + + /** + * Get the keystore password + * + * @return the password + */ + public static String getKeystorePassword() { + return (KEYSTORE_PASSWORD); + } + + /** + * Gets the truststore password + * + * @return the password + */ + private static String retrieveTruststorePassword() { + String certPath = serverProps.getProperty(SERVER_CERTS_LOCATION_PROP_NAME); + if (certPath == null) { + return null; + } + try { + certPath = replaceProperties(certPath); + } + catch (AAIException e) { + return null; + } + File passphrasesFile = null; + InputStream passphrasesStream = null; + String truststorePassword = null; + try { + passphrasesFile = new File(certPath + PASSPHRASSES_FILENAME); + passphrasesStream = new FileInputStream(passphrasesFile); + + + Properties passphrasesProps = new Properties(); + passphrasesProps.load(passphrasesStream); + truststorePassword = passphrasesProps.getProperty(TRUSTSTORE_PASSWORD_PROP_NAME); + if (truststorePassword != null) { + truststorePassword = truststorePassword.trim(); + } + + } catch (IOException e) { + LOGGER.warn("Not using AAF Certman passphrases file, e=" + e.getMessage()); + } catch (NullPointerException n) { + LOGGER.warn("Not using AAF Certman passphrases file, e=" + n.getMessage()); + } finally { + if (passphrasesStream != null) { + try { + passphrasesStream.close(); + } catch (Exception e) { + } + } + } + + return truststorePassword; + } + + /** + * Get the trustore password + * + * @return the password + */ + public static String getTruststorePassword() { + return (TRUSTSTORE_PASSWORD); + } + + /** + * Gets the int value for the key. + * + * @param key the key + * @return the int + * @throws AAIException the AAI exception + */ + public static int getInt(String key) throws AAIException { + return Integer.parseInt(AAIApplicationConfig.get(key)); + } + + /** + * Gets the int. + * + * @param key the key + * @return the int + */ + public static int getInt(String key, String value) { + return Integer.parseInt(AAIApplicationConfig.get(key, value)); + } + + /** + * Gets the server props. + * + * @return the server props + */ + public static Properties getServerProps() { + return serverProps; + } + + /** + * Check if a null or an Empty string is passed in. + * + * @param s the s + * @return boolean + */ + public static boolean isEmpty(String s) { + return (s == null || s.length() == 0); + } + + private static String replaceProperties(String originalValue) throws AAIException { + final Pattern p = Pattern.compile(PROPERTY_REGEX); + Matcher m = p.matcher(originalValue); + /*if (!m.matches()) { + return originalValue; + }*/ + StringBuffer sb = new StringBuffer(); + while(m.find()) { + String text = m.group(1); + String replacement = get(text); + m.appendReplacement(sb, replacement); + } + m.appendTail(sb); + return(sb.toString()); + } +} diff --git a/aai-core/src/main/java/org/onap/aai/util/AAIConfig.java b/aai-els-onap-logging/src/main/java/org/onap/aai/util/AAIConfig.java index c2103071..8d3e2cc8 100644 --- a/aai-core/src/main/java/org/onap/aai/util/AAIConfig.java +++ b/aai-els-onap-logging/src/main/java/org/onap/aai/util/AAIConfig.java @@ -20,26 +20,21 @@ package org.onap.aai.util; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; +import org.eclipse.jetty.util.security.Password; +import org.onap.aai.exceptions.AAIException; +import org.onap.aai.logging.ErrorLogHelper; import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.net.InetAddress; import java.util.Properties; -import java.util.UUID; - -import org.eclipse.jetty.util.security.Password; -import org.onap.aai.exceptions.AAIException; -import org.onap.aai.logging.ErrorLogHelper; -import org.onap.aai.logging.LoggingContext; -import org.onap.aai.logging.LoggingContext.StatusCode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class AAIConfig { - private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(AAIConfig.class); + private static final Logger LOGGER = LoggerFactory.getLogger(AAIConfig.class); private static final String GLOBAL_PROP_FILE_NAME = AAIConstants.AAI_CONFIG_FILENAME; private static Properties serverProps; private static boolean propsInitialized = false; @@ -58,15 +53,6 @@ public class AAIConfig { */ public synchronized static void init() throws AAIException { - LoggingContext.save(); - LoggingContext.component("config"); - LoggingContext.partnerName("NA"); - LoggingContext.targetEntity("AAI"); - LoggingContext.requestId(UUID.randomUUID().toString()); - LoggingContext.serviceName("AAI"); - LoggingContext.targetServiceName("init"); - LoggingContext.statusCode(StatusCode.COMPLETE); - LOGGER.info("Initializing AAIConfig"); AAIConfig.getConfigFile(); @@ -77,7 +63,6 @@ public class AAIConfig { } else { LOGGER.info("A&AI Server Node Name = " + AAIConstants.AAI_NODENAME); } - LoggingContext.restore(); } /** @@ -95,19 +80,28 @@ public class AAIConfig { public synchronized static void reloadConfig() { String propFileName = GLOBAL_PROP_FILE_NAME; - Properties newServerProps = null; + Properties newServerProps = new Properties(); LOGGER.debug("Reloading config from " + propFileName); try (InputStream is = new FileInputStream(propFileName)) { - newServerProps = new Properties(); + LOGGER.info("Found the aaiconfig.properties in the following location: {}", GLOBAL_PROP_FILE_NAME); newServerProps.load(is); propsInitialized = true; serverProps = newServerProps; - } catch (FileNotFoundException fnfe) { - ErrorLogHelper.logError("AAI_4001", " " + propFileName + ". Exception: " + fnfe.getMessage()); - } catch (IOException e) { - ErrorLogHelper.logError("AAI_4002", " " + propFileName + ". IOException: " + e.getMessage()); + } catch (Exception fnfe) { + final InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("aaiconfig.properties"); + LOGGER.info("Unable to find the aaiconfig.properties from filesystem so using file in jar"); + if (is != null) { + try { + newServerProps.load(is); + serverProps = newServerProps; + } catch (IOException e) { + LOGGER.warn("Encountered IO Exception during loading of aaiconfig props from inputstream", e); + } + } else { + LOGGER.error("Expected to find the error.properties in the jar but unable to find it"); + } } } diff --git a/aai-core/src/test/java/org/onap/aai/logging/EcompErrorCategoryTest.java b/aai-els-onap-logging/src/main/java/org/onap/aai/util/AAIConfigProxy.java index 65c78121..faacc527 100644 --- a/aai-core/src/test/java/org/onap/aai/logging/EcompErrorCategoryTest.java +++ b/aai-els-onap-logging/src/main/java/org/onap/aai/util/AAIConfigProxy.java @@ -17,34 +17,25 @@ * limitations under the License. * ============LICENSE_END========================================================= */ +package org.onap.aai.util; -package org.onap.aai.logging; - -import static org.junit.Assert.*; -import static org.mockito.Mockito.*; - -import ch.qos.logback.classic.Level; -import ch.qos.logback.classic.spi.ILoggingEvent; - -import org.junit.*; - -public class EcompErrorCategoryTest { - - EcompErrorCategory _ecompErrorCategory; - ILoggingEvent mockEvent; - - @Before - public void setUp() throws Exception { - - mockEvent = mock(ILoggingEvent.class); - _ecompErrorCategory = spy(EcompErrorCategory.class); +/** + * <b>AAIConfigProxy</b> is a interface trying to proxy calls + * to the AAIConfig class in which there are only static methods + * The main reason for this interface existence is to simplify + * unit testing edge cases in which it is harder to simulate + * + * Note: If there is a better way to do this, + * it is encouraged to change this early on + */ +// TODO - Find an better name for this interface name +public interface AAIConfigProxy { + default String get(String key, String defaultValue){ + return AAIConfig.get(key, defaultValue); } - @Test - public void warn() { - String defaultCategory = "WARN"; - assertEquals(_ecompErrorCategory.convert(mockEvent), defaultCategory); + default int getInt(String key, String defaultValue){ + return AAIConfig.getInt(key, defaultValue); } - } diff --git a/aai-core/src/main/java/org/onap/aai/util/AAIConstants.java b/aai-els-onap-logging/src/main/java/org/onap/aai/util/AAIConstants.java index e906c280..3ddd008f 100644 --- a/aai-core/src/main/java/org/onap/aai/util/AAIConstants.java +++ b/aai-els-onap-logging/src/main/java/org/onap/aai/util/AAIConstants.java @@ -51,6 +51,8 @@ public final class AAIConstants { public static final String AAI_HOME_ETC_OXM = AAI_HOME_ETC + "oxm" + AAI_FILESEP; public static final String AAI_EVENT_DMAAP_PROPS = AAI_HOME_ETC_APP_PROPERTIES + "aaiEventDMaaPPublisher.properties"; + public static final String DELTA_EVENT_DMAAP_PROPS = + AAI_HOME_ETC_APP_PROPERTIES + "delta-event-publisher.properties"; public static final String AAI_HOME_ETC_SCRIPT = AAI_HOME_ETC + AAI_FILESEP + "scriptdata" + AAI_FILESEP; public static final String AAI_LOGBACK_PROPS = "logback.xml"; @@ -89,6 +91,39 @@ public final class AAIConstants { */ public static final String AAI_IMPLIED_DELETE_LOG_LIMIT = "aai.implied.delete.log.limit"; + /** + * Specifies which clients should the implied delete be allowed + * + * If the aaiconfig properties has the below property: + * + * <code> + * aai.implied.delete.whitelist.sdnc=* + * aai.implied.delete.whitelist.sdc='pserver','vserver' + * </code> + * + * Then SDNC can do implied delete on any object and could potentially delete any children + * and SDC is allowed to do implicit delete on any child of pserver + * + * So the following request would return 200 and ends up deleting p-interfaces + * since the X-FromAppId is SDC and they are allowed to delete any child of pserver + * + * PUT /aai/v$/cloud-infrastructure/pservers/pserver + * + * Headers: + * + * X-FromAppId: SDC + * X-TransactionId: Some-Transaction-Id + * Content-Type: application/json + * + * <code> + * { + * "hostname": "pserver", + * "p-interfaces":{} + * } + * </code> + */ + public static final String AAI_IMPLIED_DELETE_WHITELIST = "aai.implied.delete.whitelist."; + public static final String AAI_BULKCONSUMER_LIMIT = "aai.bulkconsumer.payloadlimit"; public static final String AAI_BULKCONSUMER_OVERRIDE_LIMIT = "aai.bulkconsumer.payloadoverride"; diff --git a/aai-core/src/main/java/org/onap/aai/util/FormatDate.java b/aai-els-onap-logging/src/main/java/org/onap/aai/util/FormatDate.java index 9ee2b71d..9ee2b71d 100644 --- a/aai-core/src/main/java/org/onap/aai/util/FormatDate.java +++ b/aai-els-onap-logging/src/main/java/org/onap/aai/util/FormatDate.java diff --git a/aai-core/src/main/java/org/onap/aai/util/HbaseSaltPrefixer.java b/aai-els-onap-logging/src/main/java/org/onap/aai/util/HbaseSaltPrefixer.java index a41ad27b..a41ad27b 100644 --- a/aai-core/src/main/java/org/onap/aai/util/HbaseSaltPrefixer.java +++ b/aai-els-onap-logging/src/main/java/org/onap/aai/util/HbaseSaltPrefixer.java diff --git a/aai-core/src/main/java/org/onap/aai/util/MapperUtil.java b/aai-els-onap-logging/src/main/java/org/onap/aai/util/MapperUtil.java index 47a937d4..d856999e 100644 --- a/aai-core/src/main/java/org/onap/aai/util/MapperUtil.java +++ b/aai-els-onap-logging/src/main/java/org/onap/aai/util/MapperUtil.java @@ -23,9 +23,10 @@ package org.onap.aai.util; import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.databind.*; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.module.jaxb.JaxbAnnotationModule; - import org.onap.aai.exceptions.AAIException; public class MapperUtil { diff --git a/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/AbstractAuditLogFilter.java b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/AbstractAuditLogFilter.java new file mode 100644 index 00000000..ce2f4489 --- /dev/null +++ b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/AbstractAuditLogFilter.java @@ -0,0 +1,82 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - Logging + * ================================================================================ + * Copyright (C) 2019 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========================================================= + */ + +package org.onap.logging.filter.base; + +import javax.servlet.http.HttpServletRequest; +import org.onap.logging.ref.slf4j.ONAPLogConstants; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.MDC; + +public abstract class AbstractAuditLogFilter<GenericRequest, GenericResponse> extends MDCSetup { + protected static final Logger logger = LoggerFactory.getLogger(AbstractAuditLogFilter.class); + + protected void pre(SimpleMap headers, GenericRequest request, HttpServletRequest httpServletRequest) { + try { + String requestId = getRequestId(headers); + MDC.put(ONAPLogConstants.MDCs.REQUEST_ID, requestId); + setInvocationId(headers); + setServiceName(request); + setMDCPartnerName(headers); + setServerFQDN(); + setClientIPAddress(httpServletRequest); + setInstanceID(); + setEntryTimeStamp(); + MDC.put(ONAPLogConstants.MDCs.RESPONSE_STATUS_CODE, ONAPLogConstants.ResponseStatus.INPROGRESS.toString()); + additionalPreHandling(request); + setLogTimestamp(); + setElapsedTime(); + logger.info(ONAPLogConstants.Markers.ENTRY, "Entering"); + } catch (Exception e) { + logger.warn("Error in AbstractInboundFilter pre", e); + } + } + + protected void post(GenericResponse response) { + try { + int responseCode = getResponseCode(response); + setResponseStatusCode(responseCode); + MDC.put(ONAPLogConstants.MDCs.RESPONSE_CODE, String.valueOf(responseCode)); + setResponseDescription(responseCode); + setLogTimestamp(); + setElapsedTime(); + logger.info(ONAPLogConstants.Markers.EXIT, "Exiting."); + additionalPostHandling(response); + } catch (Exception e) { + logger.warn("Error in AbstractInboundFilter post", e); + } finally { + MDC.clear(); + } + } + + protected abstract int getResponseCode(GenericResponse response); + + protected abstract void setServiceName(GenericRequest request); + + protected void additionalPreHandling(GenericRequest request) { + // override to add additional pre handling + } + + protected void additionalPostHandling(GenericResponse response) { + // override to add additional post handling + } + +} diff --git a/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/AbstractMetricLogFilter.java b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/AbstractMetricLogFilter.java new file mode 100644 index 00000000..ab1daab5 --- /dev/null +++ b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/AbstractMetricLogFilter.java @@ -0,0 +1,135 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - Logging + * ================================================================================ + * Copyright (C) 2019 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========================================================= + */ + +package org.onap.logging.filter.base; + +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.UUID; +import org.onap.logging.ref.slf4j.ONAPLogConstants; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.MDC; +import org.slf4j.Marker; +import org.slf4j.MarkerFactory; + +public abstract class AbstractMetricLogFilter<Request, Response, RequestHeaders> extends MDCSetup { + protected static final Logger logger = LoggerFactory.getLogger(AbstractMetricLogFilter.class); + private final String partnerName; + private static final Marker INVOKE_RETURN = MarkerFactory.getMarker("INVOKE-RETURN"); + + public AbstractMetricLogFilter() { + partnerName = getPartnerName(); + } + + protected abstract void addHeader(RequestHeaders requestHeaders, String headerName, String headerValue); + + protected abstract String getTargetServiceName(Request request); + + protected abstract String getServiceName(Request request); + + protected abstract int getHttpStatusCode(Response response); + + protected abstract String getResponseCode(Response response); + + protected abstract String getTargetEntity(Request request); + + protected void pre(Request request, RequestHeaders requestHeaders) { + try { + setupMDC(request); + setupHeaders(request, requestHeaders); + logger.info(ONAPLogConstants.Markers.INVOKE, "Invoke"); + } catch (Exception e) { + logger.warn("Error in AbstractMetricLogFilter pre", e); + } + } + + protected void setupHeaders(Request clientRequest, RequestHeaders requestHeaders) { + String requestId = extractRequestID(); + addHeader(requestHeaders, ONAPLogConstants.Headers.REQUEST_ID, requestId); + addHeader(requestHeaders, Constants.HttpHeaders.HEADER_REQUEST_ID, requestId); + addHeader(requestHeaders, Constants.HttpHeaders.TRANSACTION_ID, requestId); + addHeader(requestHeaders, Constants.HttpHeaders.ECOMP_REQUEST_ID, requestId); + addHeader(requestHeaders, ONAPLogConstants.Headers.INVOCATION_ID, MDC.get(ONAPLogConstants.MDCs.INVOCATION_ID)); + addHeader(requestHeaders, ONAPLogConstants.Headers.PARTNER_NAME, partnerName); + } + + protected void setupMDC(Request request) { + MDC.put(ONAPLogConstants.MDCs.INVOKE_TIMESTAMP, + ZonedDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT)); + // setup time stamp defaults + setLogTimestamp(); + setElapsedTimeInvokeTimestamp(); + MDC.put(ONAPLogConstants.MDCs.TARGET_SERVICE_NAME, getTargetServiceName(request)); + MDC.put(ONAPLogConstants.MDCs.RESPONSE_STATUS_CODE, ONAPLogConstants.ResponseStatus.INPROGRESS.toString()); + setInvocationIdFromMDC(); + + if (MDC.get(ONAPLogConstants.MDCs.TARGET_ENTITY) == null) { + String targetEntity = getTargetEntity(request); + if (targetEntity != null) { + MDC.put(ONAPLogConstants.MDCs.TARGET_ENTITY, targetEntity); + } else { + MDC.put(ONAPLogConstants.MDCs.TARGET_ENTITY, Constants.DefaultValues.UNKNOWN_TARGET_ENTITY); + } + } + + if (MDC.get(ONAPLogConstants.MDCs.SERVICE_NAME) == null) { + MDC.put(ONAPLogConstants.MDCs.SERVICE_NAME, getServiceName(request)); + } + setServerFQDN(); + } + + protected String extractRequestID() { + String requestId = MDC.get(ONAPLogConstants.MDCs.REQUEST_ID); + if (requestId == null || requestId.isEmpty()) { + requestId = UUID.randomUUID().toString(); + setLogTimestamp(); + setElapsedTimeInvokeTimestamp(); + logger.warn("No value found in MDC when checking key {} value will be set to {}", + ONAPLogConstants.MDCs.REQUEST_ID, requestId); + MDC.put(ONAPLogConstants.MDCs.REQUEST_ID, requestId); + } + return requestId; + } + + protected void post(Request request, Response response) { + try { + setLogTimestamp(); + setElapsedTimeInvokeTimestamp(); + setResponseStatusCode(getHttpStatusCode(response)); + setResponseDescription(getHttpStatusCode(response)); + MDC.put(ONAPLogConstants.MDCs.RESPONSE_CODE, getResponseCode(response)); + logger.info(INVOKE_RETURN, "InvokeReturn"); + clearClientMDCs(); + } catch (Exception e) { + logger.warn("Error in AbstractMetricLogFilter post", e); + } + } + + protected String getPartnerName() { + return getProperty(Constants.Property.PARTNER_NAME); + } + + protected void logInvoke() { + logger.info(ONAPLogConstants.Markers.INVOKE, "Invoke"); + } + +} diff --git a/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/AbstractServletFilter.java b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/AbstractServletFilter.java new file mode 100644 index 00000000..28495c84 --- /dev/null +++ b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/AbstractServletFilter.java @@ -0,0 +1,57 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - Logging + * ================================================================================ + * Copyright (C) 2019 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========================================================= + */ + +package org.onap.logging.filter.base; + +import java.util.Enumeration; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.core.HttpHeaders; + +public abstract class AbstractServletFilter { + + protected String getSecureRequestHeaders(HttpServletRequest httpRequest) { + StringBuilder sb = new StringBuilder(); + String header; + for (Enumeration<String> e = httpRequest.getHeaderNames(); e.hasMoreElements();) { + header = e.nextElement(); + sb.append(header); + sb.append(":"); + if (header.equalsIgnoreCase(HttpHeaders.AUTHORIZATION)) { + sb.append(Constants.REDACTED); + } else { + sb.append(httpRequest.getHeader(header)); + } + sb.append(";"); + } + return sb.toString(); + } + + protected String formatResponseHeaders(HttpServletResponse response) { + StringBuilder sb = new StringBuilder(); + for (String headerName : response.getHeaderNames()) { + sb.append(headerName); + sb.append(":"); + sb.append(response.getHeader(headerName)); + sb.append(";"); + } + return sb.toString(); + } +} diff --git a/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/AuditLogContainerFilter.java b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/AuditLogContainerFilter.java new file mode 100644 index 00000000..a0194850 --- /dev/null +++ b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/AuditLogContainerFilter.java @@ -0,0 +1,67 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - Logging + * ================================================================================ + * Copyright (C) 2019 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========================================================= + */ + +package org.onap.logging.filter.base; + +import java.io.IOException; +import javax.annotation.Priority; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.container.*; +import javax.ws.rs.core.Context; +import javax.ws.rs.ext.Provider; +import javax.ws.rs.ext.Providers; +import org.onap.logging.ref.slf4j.ONAPLogConstants; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.MDC; + +@Priority(1) +public class AuditLogContainerFilter extends AbstractAuditLogFilter<ContainerRequestContext, ContainerResponseContext> + implements ContainerRequestFilter, ContainerResponseFilter { + + @Context + private HttpServletRequest httpServletRequest; + + @Context + private Providers providers; + + @Override + public void filter(ContainerRequestContext containerRequest) { + SimpleMap headers = new SimpleJaxrsHeadersMap(containerRequest.getHeaders()); + pre(headers, containerRequest, httpServletRequest); + } + + @Override + public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) + throws IOException { + post(responseContext); + } + + @Override + protected void setServiceName(ContainerRequestContext containerRequest) { + MDC.put(ONAPLogConstants.MDCs.SERVICE_NAME, containerRequest.getUriInfo().getPath()); + } + + @Override + protected int getResponseCode(ContainerResponseContext response) { + return response.getStatus(); + } + +} diff --git a/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/AuditLogServletFilter.java b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/AuditLogServletFilter.java new file mode 100644 index 00000000..a8f5eae9 --- /dev/null +++ b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/AuditLogServletFilter.java @@ -0,0 +1,85 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - Logging + * ================================================================================ + * Copyright (C) 2019 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.logging.filter.base; + +import java.io.IOException; +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.onap.logging.ref.slf4j.ONAPLogConstants; +import org.slf4j.MDC; + +public class AuditLogServletFilter extends AbstractAuditLogFilter<HttpServletRequest, HttpServletResponse> + implements Filter { + + @Override + public void destroy() { + // this method does nothing + } + + @Override + public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain filterChain) + throws IOException, ServletException { + try { + if (request != null && request instanceof HttpServletRequest) { + pre((HttpServletRequest) request); + } + filterChain.doFilter(request, response); + } finally { + if (request != null && request instanceof HttpServletRequest) { + post((HttpServletRequest) request, (HttpServletResponse) response); + } + MDC.clear(); + } + } + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + // this method does nothing + } + + protected void pre(HttpServletRequest request) { + SimpleMap headers = new SimpleServletHeadersMap(request); + pre(headers, request, request); + } + + @Override + protected void setServiceName(HttpServletRequest request) { + MDC.put(ONAPLogConstants.MDCs.SERVICE_NAME, request.getRequestURI()); + } + + private void post(HttpServletRequest request, HttpServletResponse response) { + post(response); + } + + @Override + protected int getResponseCode(HttpServletResponse response) { + return response.getStatus(); + } + +} diff --git a/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/Constants.java b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/Constants.java new file mode 100644 index 00000000..be28f0bc --- /dev/null +++ b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/Constants.java @@ -0,0 +1,46 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - Logging + * ================================================================================ + * Copyright (C) 2019 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========================================================= + */ + +package org.onap.logging.filter.base; + +public class Constants { + protected static final String REDACTED = "***REDACTED***"; + + public static final class DefaultValues { + public static final String UNKNOWN = "UNKNOWN"; + public static final String UNKNOWN_TARGET_ENTITY = "Unknown-Target-Entity"; + } + + public static final class HttpHeaders { + public static final String HEADER_FROM_APP_ID = "X-FromAppId"; + public static final String ONAP_PARTNER_NAME = "X-ONAP-PartnerName"; + public static final String HEADER_REQUEST_ID = "X-RequestID"; + public static final String TRANSACTION_ID = "X-TransactionID"; + public static final String ECOMP_REQUEST_ID = "X-ECOMP-RequestID"; + public static final String ONAP_REQUEST_ID = "X-ONAP-RequestID"; + public static final String CLIENT_ID = "X-ClientID"; + public static final String INVOCATION_ID_HEADER = "X-InvocationID"; + public static final String TARGET_ENTITY_HEADER = "X-Target-Entity"; + } + + public static final class Property { + public static final String PARTNER_NAME = "partnerName"; + } +} diff --git a/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/MDCSetup.java b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/MDCSetup.java new file mode 100644 index 00000000..369a9f20 --- /dev/null +++ b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/MDCSetup.java @@ -0,0 +1,238 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - Logging + * ================================================================================ + * Copyright (C) 2019 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========================================================= + */ + +package org.onap.logging.filter.base; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; +import java.util.UUID; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.Response; +import org.onap.logging.ref.slf4j.ONAPLogConstants; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.MDC; + +public class MDCSetup { + + protected static Logger logger = LoggerFactory.getLogger(MDCSetup.class); + + private static final String INSTANCE_UUID = UUID.randomUUID().toString(); + + public void setInstanceID() { + MDC.put(ONAPLogConstants.MDCs.INSTANCE_UUID, INSTANCE_UUID); + } + + public void setServerFQDN() { + String serverFQDN = ""; + InetAddress addr = null; + try { + addr = InetAddress.getLocalHost(); + serverFQDN = addr.getCanonicalHostName(); + MDC.put(ONAPLogConstants.MDCs.SERVER_IP_ADDRESS, addr.getHostAddress()); + } catch (UnknownHostException e) { + logger.warn("Cannot Resolve Host Name"); + serverFQDN = ""; + } + MDC.put(ONAPLogConstants.MDCs.SERVER_FQDN, serverFQDN); + } + + public void setClientIPAddress(HttpServletRequest httpServletRequest) { + String clientIpAddress = ""; + if (httpServletRequest != null) { + // This logic is to avoid setting the client ip address to that of the load + // balancer in front of the application + String getForwadedFor = httpServletRequest.getHeader("X-Forwarded-For"); + if (getForwadedFor != null) { + clientIpAddress = getForwadedFor; + } else { + clientIpAddress = httpServletRequest.getRemoteAddr(); + } + } + MDC.put(ONAPLogConstants.MDCs.CLIENT_IP_ADDRESS, clientIpAddress); + } + + public void setEntryTimeStamp() { + MDC.put(ONAPLogConstants.MDCs.ENTRY_TIMESTAMP, + ZonedDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT)); + } + + public String getRequestId(SimpleMap headers) { + logger.trace("Checking X-ONAP-RequestID header for requestId."); + String requestId = headers.get(ONAPLogConstants.Headers.REQUEST_ID); + if (requestId != null && !requestId.isEmpty() && isValidUUID(requestId)) { + return requestId; + } + if (requestId != null && !requestId.isEmpty()) { + //invalid + return UUID.randomUUID().toString(); + } + logger.trace("No valid X-ONAP-RequestID header value. Checking X-RequestID header for requestId."); + requestId = headers.get(Constants.HttpHeaders.HEADER_REQUEST_ID); + if (requestId != null && !requestId.isEmpty() && isValidUUID(requestId)) { + return requestId; + } + if (requestId != null && !requestId.isEmpty()) { + //invalid + return UUID.randomUUID().toString(); + } + logger.trace("No valid X-RequestID header value. Checking X-TransactionID header for requestId."); + requestId = headers.get(Constants.HttpHeaders.TRANSACTION_ID); + if (requestId != null && !requestId.isEmpty() && isValidUUID(requestId)) { + return requestId; + } + if (requestId != null && !requestId.isEmpty()) { + //invalid + return UUID.randomUUID().toString(); + } + logger.trace("No valid X-TransactionID header value. Checking X-ECOMP-RequestID header for requestId."); + requestId = headers.get(Constants.HttpHeaders.ECOMP_REQUEST_ID); + if (requestId != null && !requestId.isEmpty() && isValidUUID(requestId)) { + return requestId; + } + if (requestId != null && !requestId.isEmpty()) { + //invalid + return UUID.randomUUID().toString(); + } + return requestId; + } + protected boolean isValidUUID(String transId) { + try { + UUID.fromString(transId); + } catch (IllegalArgumentException e) { + return false; + } + return true; + } + public void setInvocationId(SimpleMap headers) { + String invocationId = headers.get(ONAPLogConstants.Headers.INVOCATION_ID); + if (invocationId == null || invocationId.isEmpty()) + invocationId = UUID.randomUUID().toString(); + MDC.put(ONAPLogConstants.MDCs.INVOCATION_ID, invocationId); + } + + public void setInvocationIdFromMDC() { + String invocationId = MDC.get(ONAPLogConstants.MDCs.INVOCATION_ID); + if (invocationId == null || invocationId.isEmpty()) + invocationId = UUID.randomUUID().toString(); + MDC.put(ONAPLogConstants.MDCs.INVOCATION_ID, invocationId); + } + + public void setMDCPartnerName(SimpleMap headers) { + logger.trace("Checking X-ONAP-PartnerName header for partnerName."); + String partnerName = headers.get(ONAPLogConstants.Headers.PARTNER_NAME); + if (partnerName == null || partnerName.isEmpty()) { + logger.trace("No valid X-ONAP-PartnerName header value. Checking User-Agent header for partnerName."); + partnerName = headers.get(HttpHeaders.USER_AGENT); + if (partnerName == null || partnerName.isEmpty()) { + logger.trace("No valid User-Agent header value. Checking X-ClientID header for partnerName."); + partnerName = headers.get(Constants.HttpHeaders.CLIENT_ID); + if (partnerName == null || partnerName.isEmpty()) { + logger.trace("No valid partnerName headers. Defaulting partnerName to UNKNOWN."); + partnerName = Constants.DefaultValues.UNKNOWN; + } + } + } + MDC.put(ONAPLogConstants.MDCs.PARTNER_NAME, partnerName); + } + + public void setLogTimestamp() { + MDC.put(ONAPLogConstants.MDCs.LOG_TIMESTAMP, + ZonedDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT)); + } + + public void setElapsedTime() { + DateTimeFormatter timeFormatter = DateTimeFormatter.ISO_ZONED_DATE_TIME; + ZonedDateTime entryTimestamp = + ZonedDateTime.parse(MDC.get(ONAPLogConstants.MDCs.ENTRY_TIMESTAMP), timeFormatter); + ZonedDateTime endTimestamp = ZonedDateTime.parse(MDC.get(ONAPLogConstants.MDCs.LOG_TIMESTAMP), timeFormatter); + + MDC.put(ONAPLogConstants.MDCs.ELAPSED_TIME, + Long.toString(ChronoUnit.MILLIS.between(entryTimestamp, endTimestamp))); + } + + public void setElapsedTimeInvokeTimestamp() { + DateTimeFormatter timeFormatter = DateTimeFormatter.ISO_ZONED_DATE_TIME; + ZonedDateTime entryTimestamp = + ZonedDateTime.parse(MDC.get(ONAPLogConstants.MDCs.INVOKE_TIMESTAMP), timeFormatter); + ZonedDateTime endTimestamp = ZonedDateTime.parse(MDC.get(ONAPLogConstants.MDCs.LOG_TIMESTAMP), timeFormatter); + + MDC.put(ONAPLogConstants.MDCs.ELAPSED_TIME, + Long.toString(ChronoUnit.MILLIS.between(entryTimestamp, endTimestamp))); + } + + public void setResponseStatusCode(int code) { + String statusCode; + if (Response.Status.Family.familyOf(code).equals(Response.Status.Family.SUCCESSFUL)) { + statusCode = ONAPLogConstants.ResponseStatus.COMPLETE.toString(); + } else { + statusCode = ONAPLogConstants.ResponseStatus.ERROR.toString(); + setErrorCode(code); + setErrorDesc(code); + } + MDC.put(ONAPLogConstants.MDCs.RESPONSE_STATUS_CODE, statusCode); + } + + public void setTargetEntity(ONAPComponentsList targetEntity) { + MDC.put(ONAPLogConstants.MDCs.TARGET_ENTITY, targetEntity.toString()); + } + + public void clearClientMDCs() { + //MDC.remove(ONAPLogConstants.MDCs.INVOCATION_ID); + MDC.remove(ONAPLogConstants.MDCs.RESPONSE_DESCRIPTION); + MDC.remove(ONAPLogConstants.MDCs.RESPONSE_STATUS_CODE); + MDC.remove(ONAPLogConstants.MDCs.RESPONSE_CODE); + MDC.remove(ONAPLogConstants.MDCs.TARGET_ENTITY); + MDC.remove(ONAPLogConstants.MDCs.TARGET_SERVICE_NAME); + MDC.remove(ONAPLogConstants.MDCs.INVOKE_TIMESTAMP); + MDC.remove(ONAPLogConstants.MDCs.ERROR_CODE); + MDC.remove(ONAPLogConstants.MDCs.ERROR_DESC); + } + + public void setResponseDescription(int statusCode) { + MDC.put(ONAPLogConstants.MDCs.RESPONSE_DESCRIPTION, Response.Status.fromStatusCode(statusCode).toString()); + } + + public void setErrorCode(int statusCode) { + MDC.put(ONAPLogConstants.MDCs.ERROR_CODE, String.valueOf(statusCode)); + } + + public void setErrorDesc(int statusCode) { + MDC.put(ONAPLogConstants.MDCs.ERROR_DESC, Response.Status.fromStatusCode(statusCode).toString()); + } + + public String getProperty(String property) { + logger.info("Checking for system property [{}]", property); + String propertyValue = System.getProperty(property); + if (propertyValue == null || propertyValue.isEmpty()) { + logger.info("System property was null or empty. Checking environment variable for: {}", property); + propertyValue = System.getenv(property); + if (propertyValue == null || propertyValue.isEmpty()) { + logger.info("Environment variable: {} was null or empty", property ); + } + } + return propertyValue; + } +} diff --git a/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/MetricLogClientFilter.java b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/MetricLogClientFilter.java new file mode 100644 index 00000000..da4d9827 --- /dev/null +++ b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/MetricLogClientFilter.java @@ -0,0 +1,82 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - Logging + * ================================================================================ + * Copyright (C) 2019 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========================================================= + */ + +package org.onap.logging.filter.base; + +import javax.annotation.Priority; +import javax.ws.rs.client.ClientRequestContext; +import javax.ws.rs.client.ClientRequestFilter; +import javax.ws.rs.client.ClientResponseContext; +import javax.ws.rs.client.ClientResponseFilter; +import javax.ws.rs.container.PreMatching; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.ext.Provider; +import javax.ws.rs.ext.Providers; + +@Priority(0) +public class MetricLogClientFilter + extends AbstractMetricLogFilter<ClientRequestContext, ClientResponseContext, MultivaluedMap<String, Object>> + implements ClientRequestFilter, ClientResponseFilter { + + @Context + private Providers providers; + + @Override + public void filter(ClientRequestContext clientRequest) { + pre(clientRequest, clientRequest.getHeaders()); + } + + @Override + public void filter(ClientRequestContext requestContext, ClientResponseContext responseContext) { + post(requestContext, responseContext); + } + + @Override + protected void addHeader(MultivaluedMap<String, Object> requestHeaders, String headerName, String headerValue) { + requestHeaders.add(headerName, headerValue); + } + + @Override + protected String getTargetServiceName(ClientRequestContext request) { + return request.getUri().toString(); + } + + @Override + protected String getServiceName(ClientRequestContext request) { + return request.getUri().getPath(); + } + + @Override + protected int getHttpStatusCode(ClientResponseContext response) { + return response.getStatus(); + } + + @Override + protected String getResponseCode(ClientResponseContext response) { + return String.valueOf(response.getStatus()); + } + + @Override + protected String getTargetEntity(ClientRequestContext request) { + return Constants.DefaultValues.UNKNOWN_TARGET_ENTITY; + } + +} diff --git a/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/ONAPComponents.java b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/ONAPComponents.java new file mode 100644 index 00000000..06fbba9a --- /dev/null +++ b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/ONAPComponents.java @@ -0,0 +1,80 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - Logging + * ================================================================================ + * Copyright (C) 2019 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========================================================= + */ + +package org.onap.logging.filter.base; + +import java.util.EnumSet; +import java.util.Set; + +public enum ONAPComponents implements ONAPComponentsList { + OPENSTACK_ADAPTER, + BPMN, + GRM, + AAI, + DMAAP, + POLICY, + CATALOG_DB, + REQUEST_DB, + SNIRO, + SDC, + EXTERNAL, + VNF_ADAPTER, + SDNC_ADAPTER, + MULTICLOUD, + CLAMP, + PORTAL, + VID, + APPC, + DCAE, + HOLMES, + SDNC, + SO, + VFC, + ESR, + DBC, + DR, + MR, + OPTF; + + + public static Set<ONAPComponents> getSOInternalComponents() { + return EnumSet.of(OPENSTACK_ADAPTER, BPMN, CATALOG_DB, REQUEST_DB, VNF_ADAPTER, SDNC_ADAPTER); + } + + public static Set<ONAPComponents> getDMAAPInternalComponents() { + return EnumSet.of(DBC, DR, MR); + } + + public static Set<ONAPComponents> getAAIInternalComponents() { + return EnumSet.of(ESR); + } + + @Override + public String toString() { + if (getSOInternalComponents().contains(this)) + return SO + "." + this.name(); + else if (getDMAAPInternalComponents().contains(this)) + return DMAAP + "." + this.name(); + else if (getAAIInternalComponents().contains(this)) + return AAI + "." + this.name(); + else + return this.name(); + } +} diff --git a/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/ONAPComponentsList.java b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/ONAPComponentsList.java new file mode 100644 index 00000000..7ffc2517 --- /dev/null +++ b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/ONAPComponentsList.java @@ -0,0 +1,25 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - Logging + * ================================================================================ + * Copyright (C) 2019 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========================================================= + */ + +package org.onap.logging.filter.base; + +public interface ONAPComponentsList { + +} diff --git a/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/PayloadLoggingClientFilter.java b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/PayloadLoggingClientFilter.java new file mode 100644 index 00000000..88c95aa4 --- /dev/null +++ b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/PayloadLoggingClientFilter.java @@ -0,0 +1,162 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - Logging + * ================================================================================ + * Copyright (C) 2019 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========================================================= + */ + +package org.onap.logging.filter.base; + +import java.io.BufferedInputStream; +import java.io.ByteArrayOutputStream; +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.client.ClientRequestContext; +import javax.ws.rs.client.ClientRequestFilter; +import javax.ws.rs.client.ClientResponseContext; +import javax.ws.rs.client.ClientResponseFilter; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MultivaluedHashMap; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.ext.WriterInterceptor; +import javax.ws.rs.ext.WriterInterceptorContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class PayloadLoggingClientFilter implements ClientRequestFilter, ClientResponseFilter, WriterInterceptor { + + private static final Logger logger = LoggerFactory.getLogger(PayloadLoggingClientFilter.class); + private static final String ENTITY_STREAM_PROPERTY = "LoggingFilter.entityStream"; + private static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8; + private final int maxEntitySize; + + public PayloadLoggingClientFilter() { + maxEntitySize = 1024 * 1024; + } + + public PayloadLoggingClientFilter(int maxPayloadSize) { + this.maxEntitySize = Integer.min(maxPayloadSize, 1024 * 1024); + } + + protected InputStream logInboundEntity(final StringBuilder b, InputStream stream, final Charset charset) + throws IOException { + if (!stream.markSupported()) { + stream = new BufferedInputStream(stream); + } + stream.mark(maxEntitySize + 1); + final byte[] entity = new byte[maxEntitySize + 1]; + final int entitySize = stream.read(entity); + if (entitySize != -1) { + b.append(new String(entity, 0, Math.min(entitySize, maxEntitySize), charset)); + } + if (entitySize > maxEntitySize) { + b.append("...more..."); + } + b.append('\n'); + stream.reset(); + return stream; + } + + @Override + public void filter(ClientRequestContext requestContext) throws IOException { + if (requestContext.hasEntity()) { + final OutputStream stream = new LoggingStream(requestContext.getEntityStream()); + requestContext.setEntityStream(stream); + requestContext.setProperty(ENTITY_STREAM_PROPERTY, stream); + } + String method = formatMethod(requestContext); + logger.debug("Sending HTTP {} to:{} with request headers:{}", method, requestContext.getUri(), + getHeaders(requestContext.getHeaders())); + } + + protected String getHeaders(MultivaluedMap<String, Object> headers) { + MultivaluedMap<String, Object> printHeaders = new MultivaluedHashMap<>(); + for (String header : headers.keySet()) { + if (!header.equals(HttpHeaders.AUTHORIZATION)) { + printHeaders.add(header, headers.getFirst(header)); + } else { + printHeaders.add(header, Constants.REDACTED);; + } + } + return printHeaders.toString(); + } + + @Override + public void filter(ClientRequestContext requestContext, ClientResponseContext responseContext) throws IOException { + String method = formatMethod(requestContext); + logger.debug("Response from method:{} performed on uri:{} has http status code:{} and response headers:{}", + method, requestContext.getUri(), responseContext.getStatus(), responseContext.getHeaders().toString()); + if (responseContext.hasEntity()) { + final StringBuilder sb = new StringBuilder(); + responseContext.setEntityStream(logInboundEntity(sb, responseContext.getEntityStream(), DEFAULT_CHARSET)); + logger.debug(sb.toString()); + } + } + + @Override + public void aroundWriteTo(WriterInterceptorContext context) throws IOException, WebApplicationException { + final LoggingStream stream = (LoggingStream) context.getProperty(ENTITY_STREAM_PROPERTY); + context.proceed(); + if (stream != null) { + logger.debug(stream.getStringBuilder(DEFAULT_CHARSET).toString()); + } + } + + private class LoggingStream extends FilterOutputStream { + + private final StringBuilder sb = new StringBuilder(); + private final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + LoggingStream(OutputStream out) { + super(out); + } + + StringBuilder getStringBuilder(Charset charset) { + // write entity to the builder + final byte[] entity = baos.toByteArray(); + + sb.append(new String(entity, 0, entity.length, charset)); + if (entity.length > maxEntitySize) { + sb.append("...more..."); + } + sb.append('\n'); + + return sb; + } + + @Override + public void write(final int i) throws IOException { + if (baos.size() <= maxEntitySize) { + baos.write(i); + } + out.write(i); + } + } + + protected String formatMethod(ClientRequestContext requestContext) { + String httpMethodOverride = requestContext.getHeaderString("X-HTTP-Method-Override"); + if (httpMethodOverride == null) { + return requestContext.getMethod(); + } else { + return requestContext.getMethod() + " (overridden to " + httpMethodOverride + ")"; + } + } +} diff --git a/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/PayloadLoggingServletFilter.java b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/PayloadLoggingServletFilter.java new file mode 100644 index 00000000..fa8533a7 --- /dev/null +++ b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/PayloadLoggingServletFilter.java @@ -0,0 +1,330 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - Logging + * ================================================================================ + * Copyright (C) 2019 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.logging.filter.base; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.util.zip.GZIPInputStream; +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ReadListener; +import javax.servlet.ServletException; +import javax.servlet.ServletInputStream; +import javax.servlet.ServletOutputStream; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.WriteListener; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpServletResponseWrapper; + +public class PayloadLoggingServletFilter extends AbstractServletFilter implements Filter { + + private static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(PayloadLoggingServletFilter.class); + + private static class ByteArrayServletStream extends ServletOutputStream { + ByteArrayOutputStream baos; + + ByteArrayServletStream(ByteArrayOutputStream baos) { + this.baos = baos; + } + + @Override + public void write(int param) throws IOException { + baos.write(param); + } + + @Override + public boolean isReady() { + return true; + } + + @Override + public void setWriteListener(WriteListener arg0) { + // this method does nothing + } + } + + private static class ByteArrayPrintWriter extends PrintWriter { + private ByteArrayOutputStream baos; + private int errorCode = -1; + private String errorMsg = ""; + private boolean errored = false; + + public ByteArrayPrintWriter(ByteArrayOutputStream out) { + super(out); + this.baos = out; + } + + public ServletOutputStream getStream() { + return new ByteArrayServletStream(baos); + } + + public Boolean hasErrored() { + return errored; + } + + public int getErrorCode() { + return errorCode; + } + + public String getErrorMsg() { + return errorMsg; + } + + public void setError(int code) { + errorCode = code; + errored = true; + } + + public void setError(int code, String msg) { + errorMsg = msg; + errorCode = code; + errored = true; + } + + } + + private class BufferedServletInputStream extends ServletInputStream { + ByteArrayInputStream bais; + + public BufferedServletInputStream(ByteArrayInputStream bais) { + this.bais = bais; + } + + @Override + public int available() { + return bais.available(); + } + + @Override + public int read() { + return bais.read(); + } + + @Override + public int read(byte[] buf, int off, int len) { + return bais.read(buf, off, len); + } + + @Override + public boolean isFinished() { + return available() < 1; + } + + @Override + public boolean isReady() { + return true; + } + + @Override + public void setReadListener(ReadListener arg0) { + // this method does nothing + } + + } + + private class BufferedRequestWrapper extends HttpServletRequestWrapper { + ByteArrayInputStream bais; + ByteArrayOutputStream baos; + BufferedServletInputStream bsis; + byte[] buffer; + + public BufferedRequestWrapper(HttpServletRequest req) throws IOException { + super(req); + + InputStream is = req.getInputStream(); + baos = new ByteArrayOutputStream(); + byte[] buf = new byte[1024]; + int letti; + while ((letti = is.read(buf)) > 0) { + baos.write(buf, 0, letti); + } + buffer = baos.toByteArray(); + } + + @Override + public ServletInputStream getInputStream() { + try { + bais = new ByteArrayInputStream(buffer); + bsis = new BufferedServletInputStream(bais); + } catch (Exception ex) { + log.error("Exception in getInputStream", ex); + } + return bsis; + } + + public byte[] getBuffer() { + return buffer; + } + } + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + // this method does nothing + } + + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) + throws IOException, ServletException { + final HttpServletRequest httpRequest = (HttpServletRequest) servletRequest; + BufferedRequestWrapper bufferedRequest = new BufferedRequestWrapper(httpRequest); + + StringBuilder requestHeaders = new StringBuilder("REQUEST|"); + requestHeaders.append(httpRequest.getMethod()); + requestHeaders.append(":"); + requestHeaders.append(httpRequest.getRequestURL().toString()); + requestHeaders.append("|"); + requestHeaders.append(getSecureRequestHeaders(httpRequest)); + log.info(requestHeaders.toString()); + + log.info("REQUEST BODY|" + new String(bufferedRequest.getBuffer())); + + final HttpServletResponse response = (HttpServletResponse) servletResponse; + final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + final ByteArrayPrintWriter pw = new ByteArrayPrintWriter(baos); + + HttpServletResponse wrappedResp = new HttpServletResponseWrapper(response) { + @Override + public PrintWriter getWriter() { + return pw; + } + + @Override + public ServletOutputStream getOutputStream() { + return pw.getStream(); + } + + @Override + public void sendError(int sc) throws IOException { + super.sendError(sc); + pw.setError(sc); + + } + + @Override + public void sendError(int sc, String msg) throws IOException { + super.sendError(sc, msg); + pw.setError(sc, msg); + } + }; + + try { + filterChain.doFilter(bufferedRequest, wrappedResp); + } catch (Exception e) { + log.error("Chain Exception", e); + throw e; + } finally { + try { + byte[] bytes = baos.toByteArray(); + StringBuilder responseHeaders = new StringBuilder("RESPONSE HEADERS|"); + responseHeaders.append(formatResponseHeaders(response)); + responseHeaders.append("Status:"); + responseHeaders.append(response.getStatus()); + responseHeaders.append(";IsCommited:" + wrappedResp.isCommitted()); + + log.info(responseHeaders.toString()); + + if ("gzip".equals(response.getHeader("Content-Encoding"))) { + log.info("UNGZIPED RESPONSE BODY|" + decompressGZIPByteArray(bytes)); + } else { + log.info("RESPONSE BODY|" + new String(bytes)); + } + + if (pw.hasErrored()) { + log.info("ERROR RESPONSE|" + pw.getErrorCode() + ":" + pw.getErrorMsg()); + } else { + if (!wrappedResp.isCommitted()) { + response.getOutputStream().write(bytes); + response.getOutputStream().flush(); + } + } + } catch (Exception e) { + log.error("Exception in response filter", e); + } + } + } + + @Override + public void destroy() { + // this method does nothing + } + + private String decompressGZIPByteArray(byte[] bytes) { + BufferedReader in = null; + InputStreamReader inR = null; + ByteArrayInputStream byteS = null; + GZIPInputStream gzS = null; + StringBuilder str = new StringBuilder(); + try { + byteS = new ByteArrayInputStream(bytes); + gzS = new GZIPInputStream(byteS); + inR = new InputStreamReader(gzS); + in = new BufferedReader(inR); + + if (in != null) { + String content; + while ((content = in.readLine()) != null) { + str.append(content); + } + } + + } catch (Exception e) { + log.error("Failed get read GZIPInputStream", e); + } finally { + if (byteS != null) + try { + byteS.close(); + } catch (IOException e1) { + log.error("Failed to close ByteStream", e1); + } + if (gzS != null) + try { + gzS.close(); + } catch (IOException e2) { + log.error("Failed to close GZStream", e2); + } + if (inR != null) + try { + inR.close(); + } catch (IOException e3) { + log.error("Failed to close InputReader", e3); + } + if (in != null) + try { + in.close(); + } catch (IOException e) { + log.error("Failed to close BufferedReader", e); + } + } + return str.toString(); + } + +} diff --git a/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/SimpleHashMap.java b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/SimpleHashMap.java new file mode 100644 index 00000000..1e9cedb7 --- /dev/null +++ b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/SimpleHashMap.java @@ -0,0 +1,37 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - Logging + * ================================================================================ + * Copyright (C) 2019 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========================================================= + */ + +package org.onap.logging.filter.base; + +import java.util.HashMap; + +public class SimpleHashMap implements SimpleMap { + private HashMap<String, String> map; + + public SimpleHashMap(HashMap<String, String> map) { + this.map = map; + } + + @Override + public String get(String key) { + return map.get(key); + } + +} diff --git a/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/SimpleJaxrsHeadersMap.java b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/SimpleJaxrsHeadersMap.java new file mode 100644 index 00000000..50074782 --- /dev/null +++ b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/SimpleJaxrsHeadersMap.java @@ -0,0 +1,37 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - Logging + * ================================================================================ + * Copyright (C) 2019 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========================================================= + */ + +package org.onap.logging.filter.base; + +import javax.ws.rs.core.MultivaluedMap; + +public class SimpleJaxrsHeadersMap implements SimpleMap { + MultivaluedMap<String, String> map; + + public SimpleJaxrsHeadersMap(MultivaluedMap<String, String> map) { + this.map = map; + } + + @Override + public String get(String key) { + return map.getFirst(key); + } + +} diff --git a/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/SimpleMap.java b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/SimpleMap.java new file mode 100644 index 00000000..9543721f --- /dev/null +++ b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/SimpleMap.java @@ -0,0 +1,25 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - Logging + * ================================================================================ + * Copyright (C) 2019 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========================================================= + */ + +package org.onap.logging.filter.base; + +public interface SimpleMap { + String get(String key); +} diff --git a/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/SimpleServletHeadersMap.java b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/SimpleServletHeadersMap.java new file mode 100644 index 00000000..e6a91fbe --- /dev/null +++ b/aai-els-onap-logging/src/main/java/org/onap/logging/filter/base/SimpleServletHeadersMap.java @@ -0,0 +1,37 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - Logging + * ================================================================================ + * Copyright (C) 2019 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========================================================= + */ + +package org.onap.logging.filter.base; + +import javax.servlet.http.HttpServletRequest; + +public class SimpleServletHeadersMap implements SimpleMap { + private HttpServletRequest request; + + public SimpleServletHeadersMap(HttpServletRequest request) { + this.request = request; + } + + @Override + public String get(String key) { + return request.getHeader(key); + } + +} diff --git a/aai-els-onap-logging/src/main/java/org/onap/logging/ref/slf4j/ONAPLogAdapter.java b/aai-els-onap-logging/src/main/java/org/onap/logging/ref/slf4j/ONAPLogAdapter.java new file mode 100644 index 00000000..aafc74d4 --- /dev/null +++ b/aai-els-onap-logging/src/main/java/org/onap/logging/ref/slf4j/ONAPLogAdapter.java @@ -0,0 +1,616 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.logging + * ================================================================================ + * Copyright © 2018 Amdocs + * 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.logging.ref.slf4j; + +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.UUID; + +import javax.servlet.http.HttpServletRequest; + +import org.slf4j.Logger; +import org.slf4j.MDC; +import org.slf4j.Marker; +import org.slf4j.event.Level; + +/** + * Extensible adapter for cheaply meeting ONAP logging obligations using + * an SLF4J facade. + * + * <p>This can be used with any SLF4J-compatible logging provider, with + * appropriate provider configuration.</p> + * + * <p>The basics are that: + * <ul> + * <li>{@link #entering} sets all MDCs.</li> + * <li>{@link #exiting} unsets all MDCs *and* logs response information.</li> + * <li>{@link #invoke} logs and returns a UUID to passed during invocation, + * and optionally sets these for you on your downstream request by way of + * an adapter.</li> + * <li>Call {@link #getServiceDescriptor()} and its setters to set service-related MDCs.</li> + * <li>Call {@link #getResponseDescriptor()} and its setters to set response-related MDCs.</li> + * </ul> + * </p> + * + * <p>Minimal usage is: + * <ol> + * <li>#entering(RequestAdapter)</li> + * <li>#invoke, #invoke, ...</li> + * <li>#getResponse + setters (or #setResponse)</li> + * <li>#exiting</li> + * </ol> + * </p> + * + * <p> ... if you're happy for service information to be automatically derived as follows: + * <ul> + * <li><tt>ServiceName</tt> - from <tt>HttpServletRequest#getRequestURI()</tt></li> + * <li><tt>InstanceUUID</tt> - classloader-scope UUID.</li> + * </ul> + * </p> + * + * <p>... and if those defaults don't suit, then you can override using properties on + * {@link #getServiceDescriptor()}, or by injecting your own adapter using + * {@link #setServiceDescriptor(ServiceDescriptor)}, or by overriding + * a <tt>protected</tt> methods like{@link #setEnteringMDCs}.</p> + * + * <p>For everything else: + * <ul> + * <li>The underlying SLF4J {@link Logger} can be retrieved using {@link #unwrap}. + * Use this or create your own using the usual SLF4J factor.</li> + * <li>Set whatever MDCs you like.</li> + * <li>Log whatever else you like.</li> + * </ul> + * </p> + */ +public class ONAPLogAdapter { + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // + // Constants. + // + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + /** String constant for messages <tt>ENTERING</tt>, <tt>EXITING</tt>, etc. */ + private static final String EMPTY_MESSAGE = ""; + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // + // Fields. + // + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + /** Automatic UUID, overrideable per adapter or per invocation. */ + private static UUID sInstanceUUID = UUID.randomUUID(); + + /** Logger delegate. */ + private Logger mLogger; + + /** Overrideable descriptor for the service doing the logging. */ + private ServiceDescriptor mServiceDescriptor = new ServiceDescriptor(); + + /** Overrideable descriptor for the response returned by the service doing the logging. */ + private ResponseDescriptor mResponseDescriptor = new ResponseDescriptor(); + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // + // Constructors. + // + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Construct adapter. + * + * @param logger non-null logger. + */ + public ONAPLogAdapter(final Logger logger) { + this.mLogger = checkNotNull(logger); + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // + // Public methods. + // + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Get logger. + * + * @return unwrapped logger. + */ + public Logger unwrap() { + return this.mLogger; + } + + /** + * Report <tt>ENTERING</tt> marker. + * + * @param request non-null incoming request (wrapper). + * @return this. + */ + public ONAPLogAdapter entering(final RequestAdapter request) { + + checkNotNull(request); + + // Default the service name. + + this.setEnteringMDCs(request); + this.mLogger.info(ONAPLogConstants.Markers.ENTRY, EMPTY_MESSAGE); + + return this; + } + + /** + * Report <tt>ENTERING</tt> marker. + * + * @param request non-null incoming request. + * @return this. + */ + public ONAPLogAdapter entering(final HttpServletRequest request) { + return this.entering(new HttpServletRequestAdapter(checkNotNull(request))); + } + + /** + * Report <tt>EXITING</tt> marker. + * + * @return this. + */ + public ONAPLogAdapter exiting() { + try { + this.mResponseDescriptor.setMDCs(); + this.mLogger.info(ONAPLogConstants.Markers.EXIT, EMPTY_MESSAGE); + } + finally { + MDC.clear(); + } + return this; + } + + /** + * Report pending invocation with <tt>INVOKE</tt> marker. + * + * <p>If you call this variant, then YOU are assuming responsibility for + * setting the requisite ONAP headers.</p> + * + * @param sync whether synchronous. + * @return invocation ID to be passed with invocation. + */ + public UUID invoke(final ONAPLogConstants.InvocationMode sync) { + + final UUID invocationID = UUID.randomUUID(); + + // Derive SYNC/ASYNC marker. + + final Marker marker = (sync == null) ? ONAPLogConstants.Markers.INVOKE : sync.getMarker(); + + // Log INVOKE*, with the invocationID as the message body. + // (We didn't really want this kind of behavior in the standard, + // but is it worse than new, single-message MDC?) + + this.mLogger.info(marker, "{}", invocationID); + return invocationID; + } + + /** + * Report pending invocation with <tt>INVOKE</tt> marker, + * setting standard ONAP logging headers automatically. + * + * @param builder request builder, for setting headers. + * @param sync whether synchronous, nullable. + * @return invocation ID to be passed with invocation. + */ + public UUID invoke(final RequestBuilder builder, + final ONAPLogConstants.InvocationMode sync) { + + // Sync can be defaulted. Builder cannot. + + checkNotNull(builder); + + // Log INVOKE, and retain invocation ID for header + return. + + final UUID invocationID = this.invoke(sync); + + // Set standard HTTP headers on (southbound request) builder. + + builder.setHeader(ONAPLogConstants.Headers.REQUEST_ID, + defaultToEmpty(MDC.get(ONAPLogConstants.MDCs.REQUEST_ID))); + builder.setHeader(ONAPLogConstants.Headers.INVOCATION_ID, + defaultToEmpty(invocationID)); + builder.setHeader(ONAPLogConstants.Headers.PARTNER_NAME, + defaultToEmpty(MDC.get(ONAPLogConstants.MDCs.PARTNER_NAME))); + + return invocationID; + } + + /** + * Report vanilla <tt>INVOKE</tt> marker. + * + * @param builder builder for downstream requests, if you want the + * standard ONAP headers to be added automatically. + * @return invocation ID to be passed with invocation. + */ + public UUID invoke(final RequestBuilder builder) { + return this.invoke(builder, (ONAPLogConstants.InvocationMode)null); + } + + /** + * Get descriptor, for overriding service details. + * @return non-null descriptor. + */ + public ServiceDescriptor getServiceDescriptor() { + return checkNotNull(this.mServiceDescriptor); + } + + /** + * Override {@link ServiceDescriptor}. + * @param d non-null override. + * @return this. + */ + public ONAPLogAdapter setServiceDescriptor(final ServiceDescriptor d) { + this.mServiceDescriptor = checkNotNull(d); + return this; + } + + /** + * Get descriptor, for setting response details. + * @return non-null descriptor. + */ + public ResponseDescriptor getResponseDescriptor() { + return checkNotNull(this.mResponseDescriptor); + } + + /** + * Override {@link ResponseDescriptor}. + * @param d non-null override. + * @return this. + */ + public ONAPLogAdapter setResponseDescriptor(final ResponseDescriptor d) { + this.mResponseDescriptor = checkNotNull(d); + return this; + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // + // Protected methods. + // + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Set MDCs that persist for the duration of an invocation. + * + * <p>It would be better to roll this into {@link #entering}, like + * with {@link #exiting}. Then it would be easier to do, but it + * would mean more work. </p> + * + * @param request incoming HTTP request. + * @return this. + */ + protected ONAPLogAdapter setEnteringMDCs(final RequestAdapter<?> request) { + + // Extract MDC values from standard HTTP headers. + + final String requestID = defaultToUUID(request.getHeader(ONAPLogConstants.Headers.REQUEST_ID)); + final String invocationID = defaultToUUID(request.getHeader(ONAPLogConstants.Headers.INVOCATION_ID)); + final String partnerName = defaultToEmpty(request.getHeader(ONAPLogConstants.Headers.PARTNER_NAME)); + + // Set standard MDCs. Override this entire method if you want to set + // others, OR set them BEFORE or AFTER the invocation of #entering, + // depending on where you need them to appear, OR extend the + // ServiceDescriptor to add them. + + MDC.put(ONAPLogConstants.MDCs.INVOKE_TIMESTAMP, + ZonedDateTime.now(ZoneOffset.UTC) + .format(DateTimeFormatter.ISO_INSTANT)); + MDC.put(ONAPLogConstants.MDCs.REQUEST_ID, requestID); + MDC.put(ONAPLogConstants.MDCs.INVOCATION_ID, invocationID); + MDC.put(ONAPLogConstants.MDCs.PARTNER_NAME, partnerName); + MDC.put(ONAPLogConstants.MDCs.CLIENT_IP_ADDRESS, defaultToEmpty(request.getClientAddress())); + MDC.put(ONAPLogConstants.MDCs.SERVER_FQDN, defaultToEmpty(request.getServerAddress())); + + // Delegate to the service adapter, for service-related DMCs. + + this.mServiceDescriptor.setMDCs(); + + // Default the service name to the requestURI, in the event that + // no value has been provided. + + if (MDC.get(ONAPLogConstants.MDCs.SERVICE_NAME) == null || + MDC.get(ONAPLogConstants.MDCs.SERVICE_NAME).equalsIgnoreCase(EMPTY_MESSAGE)) { + MDC.put(ONAPLogConstants.MDCs.SERVICE_NAME, request.getRequestURI()); + } + + return this; + } + + /** + * Dependency-free nullcheck. + * + * @param in to be checked. + * @param <T> argument (and return) type. + * @return input arg. + */ + protected static <T> T checkNotNull(final T in) { + if (in == null) { + throw new NullPointerException(); + } + return in; + } + + /** + * Dependency-free string default. + * + * @param in to be filtered. + * @return input string or null. + */ + protected static String defaultToEmpty(final Object in) { + if (in == null) { + return ""; + } + return in.toString(); + } + + /** + * Dependency-free string default. + * + * @param in to be filtered. + * @return input string or null. + */ + protected static String defaultToUUID(final String in) { + if (in == null) { + return UUID.randomUUID().toString(); + } + return in; + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // + // Inner classes. + // + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Extensible descriptor for reporting service details. + * + * <p>In most cases extension isn't required. </p> + */ + public static class ServiceDescriptor { + + /** <tt>ServiceName</tt>. */ + protected String mName; + + /** <tt>InstanceUUID</tt>. */ + protected String mUUID = sInstanceUUID.toString(); + + /** + * Set name. + * @param name <tt>ServiceName</tt>. + * @return this. + */ + public ServiceDescriptor setServiceName(final String name) { + this.mName = name; + return this; + } + + /** + * Set name. + * @param uuid <tt>InstanceUUID</tt>. + * @return this. + */ + public ServiceDescriptor setServiceUUID(final String uuid) { + this.mUUID = uuid; + return this; + } + + /** + * Set MDCs. Once set they remain set until everything is cleared. + */ + protected void setMDCs() { + MDC.put(ONAPLogConstants.MDCs.SERVICE_NAME, defaultToEmpty(this.mName)); + MDC.put(ONAPLogConstants.MDCs.INSTANCE_UUID, defaultToEmpty(this.mUUID)); + } + } + + /** + * Response is different in that response MDCs are normally only + * reported once, for a single log message. (But there's no method + * for clearing them, because this is only expected to be called + * during <tt>#exiting</tt>.) + */ + public static class ResponseDescriptor { + + /** Response errorcode. */ + protected String mCode; + + /** Response description. */ + protected String mDescription; + + /** Response severity. */ + protected Level mSeverity; + + /** Response status, of {<tt>COMPLETED</tt>, <tt>ERROR</tt>}. */ + protected ONAPLogConstants.ResponseStatus mStatus; + + /** + * Setter. + * + * @param code response (error) code. + * @return this. + */ + public ResponseDescriptor setResponseCode(final String code) { + this.mCode = code; + return this; + } + + /** + * Setter. + * + * @param description response description. + * @return this. + */ + public ResponseDescriptor setResponseDescription(final String description) { + this.mDescription = description; + return this; + } + + /** + * Setter. + * + * @param severity response outcome severity. + * @return this. + */ + public ResponseDescriptor setResponseSeverity(final Level severity) { + this.mSeverity = severity; + return this; + } + + /** + * Setter. + * + * @param status response overall status. + * @return this. + */ + public ResponseDescriptor setResponseStatus(final ONAPLogConstants.ResponseStatus status) { + this.mStatus = status; + return this; + } + + /** + * Overrideable method to set MDCs based on property values. + */ + protected void setMDCs() { + MDC.put(ONAPLogConstants.MDCs.RESPONSE_CODE, defaultToEmpty(this.mCode)); + MDC.put(ONAPLogConstants.MDCs.RESPONSE_DESCRIPTION, defaultToEmpty(this.mDescription)); + MDC.put(ONAPLogConstants.MDCs.RESPONSE_SEVERITY, defaultToEmpty(this.mSeverity)); + MDC.put(ONAPLogConstants.MDCs.RESPONSE_STATUS_CODE, defaultToEmpty(this.mStatus)); + } + } + + /** + * Adapter for reading information from an incoming HTTP request. + * + * <p>Incoming is generally easy, because in most cases you'll be able to + * get your hands on the <tt>HttpServletRequest</tt>.</p> + * + * <p>Perhaps should be generalized to refer to constants instead of + * requiring the implementation of specific methods.</p> + * + * @param <T> type, for chaining. + */ + public interface RequestAdapter<T extends RequestAdapter> { + + /** + * Get header by name. + * @param name header name. + * @return header value, or null. + */ + String getHeader(String name); + + /** + * Get client address. + * @return address, if available. + */ + String getClientAddress(); + + /** + * Get server address. + * @return address, if available. + */ + String getServerAddress(); + + /** + * Get default service name, from service URI. + * @return service name default. + */ + String getRequestURI(); + } + + /** + * Default {@link RequestBuilder} impl for {@link HttpServletRequest}, which + * will should available for most incoming REST requests. + */ + public static class HttpServletRequestAdapter implements RequestAdapter<HttpServletRequestAdapter> { + + /** Wrapped HTTP request. */ + private final HttpServletRequest mRequest; + + /** + * Construct adapter for HTTP request. + * @param request to be wrapped; + */ + public HttpServletRequestAdapter(final HttpServletRequest request) { + this.mRequest = checkNotNull(request); + } + + /** + * {@inheritDoc} + */ + @Override + public String getHeader(final String name) { + return this.mRequest.getHeader(name); + } + + /** + * {@inheritDoc} + */ + @Override + public String getClientAddress() { + return this.mRequest.getRemoteAddr(); + } + + /** + * {@inheritDoc} + */ + @Override + public String getServerAddress() { + return this.mRequest.getServerName(); + } + + /** + * {@inheritDoc} + */ + @Override + public String getRequestURI() { + return this.mRequest.getRequestURI(); + } + } + + /** + * Header builder, which (unlike {@link RequestAdapter} will tend to + * vary a lot from caller to caller, since they each get to choose their + * own REST (or HTTP, or whatever) client APIs. + * + * <p>No default implementation, because there's no HTTP client that's + * sufficiently ubiquitous to warrant incurring a mandatory dependency.</p> + * + * @param <T> type, for chaining. + */ + public interface RequestBuilder<T extends RequestBuilder> { + + /** + * Set HTTP header. + * @param name header name. + * @param value header value. + * @return this. + */ + T setHeader(String name, String value); + } +} diff --git a/aai-els-onap-logging/src/main/java/org/onap/logging/ref/slf4j/ONAPLogConstants.java b/aai-els-onap-logging/src/main/java/org/onap/logging/ref/slf4j/ONAPLogConstants.java new file mode 100644 index 00000000..77ca084d --- /dev/null +++ b/aai-els-onap-logging/src/main/java/org/onap/logging/ref/slf4j/ONAPLogConstants.java @@ -0,0 +1,289 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.logging + * ================================================================================ + * Copyright © 2018 Amdocs + * 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.logging.ref.slf4j; + +import org.slf4j.Marker; +import org.slf4j.MarkerFactory; + +/** + * Constants for standard ONAP headers, MDCs, etc. + * + * <p>See <tt>package-info.java</tt>.</p> + */ +public final class ONAPLogConstants { + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // + // Constructors. + // + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Hide and forbid construction. + */ + private ONAPLogConstants() { + throw new UnsupportedOperationException(); + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // + // Inner classes. + // + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Marker constants. + */ + public static final class Markers { + + /** Marker reporting invocation. */ + public static final Marker INVOKE = MarkerFactory.getMarker("INVOKE"); + + /** Marker reporting invocation return. */ + public static final Marker INVOKE_RETURN = MarkerFactory.getMarker("INVOKE_RETURN"); + + /** Marker reporting synchronous invocation. */ + public static final Marker INVOKE_SYNCHRONOUS = build("INVOKE", "SYNCHRONOUS"); + + /** Marker reporting asynchronous invocation. */ + public static final Marker INVOKE_ASYNCHRONOUS = build("INVOKE", "ASYNCHRONOUS"); + + /** Marker reporting entry into a component. */ + public static final Marker ENTRY = MarkerFactory.getMarker("ENTRY"); + + /** Marker reporting exit from a component. */ + public static final Marker EXIT = MarkerFactory.getMarker("EXIT"); + + /** + * Build nested, detached marker. + * @param m1 top token. + * @param m2 sub-token. + * @return detached Marker. + */ + private static Marker build(final String m1, final String m2) { + final Marker marker = MarkerFactory.getDetachedMarker(m1); + marker.add(MarkerFactory.getDetachedMarker(m2)); + return marker; + } + + /** + * Hide and forbid construction. + */ + private Markers() { + throw new UnsupportedOperationException(); + } + } + + /** + * MDC name constants. + */ + public static final class MDCs { + + // Tracing. //////////////////////////////////////////////////////////// + + /** MDC correlating messages for an invocation. */ + public static final String INVOCATION_ID = "InvocationID"; + + /** MDC correlating messages for a logical transaction. */ + public static final String REQUEST_ID = "RequestID"; + + /** MDC recording calling partner name. */ + public static final String PARTNER_NAME = "PartnerName"; + + /** MDC recording current service. */ + public static final String SERVICE_NAME = "ServiceName"; + + /** MDC recording target service. */ + public static final String TARGET_SERVICE_NAME = "TargetServiceName"; + + /** MDC recording target entity. */ + public static final String TARGET_ENTITY = "TargetEntity"; + + /** MDC recording target element. */ + public static final String TARGET_ELEMENT = "TargetElement"; + + /** MDC recording current service instance id. */ + public static final String SERVICE_INSTANCE_ID = "ServiceInstanceID"; + + /** MDC recording current instance id. */ + public static final String INSTANCE_UUID = "InstanceID"; + + // Network. //////////////////////////////////////////////////////////// + + /** MDC recording caller address. */ + public static final String CLIENT_IP_ADDRESS = "ClientIPAddress"; + + /** MDC recording server IP address. */ + public static final String SERVER_IP_ADDRESS = "ServerIPAddress"; + + /** MDC recording server FQDN. */ + public static final String SERVER_FQDN = "ServerFQDN"; + + /** MDC recording virtual server name. */ + public static final String VIRTUAL_SERVER_NAME = "VirtualServerName"; + + /** MDC recording context name. */ + public static final String CONTEXT_NAME = "ContextName"; + + /** + * MDC recording timestamp at the start of the current request, + * with the same scope as {@link #REQUEST_ID}. + * + * <p>Open issues: + * <ul> + * <ul>Easily confused with {@link #INVOKE_TIMESTAMP}.</ul> + * <ul>No mechanism for propagation between components, e.g. via HTTP headers.</ul> + * <ul>Whatever mechanism we define, it's going to be costly.</ul> + * </ul> + * </p> + * */ + public static final String ENTRY_TIMESTAMP = "EntryTimestamp"; + + /** MDC recording timestamp at the start of the current invocation. */ + public static final String INVOKE_TIMESTAMP = "InvokeTimestamp"; + + /** MDC recording elapsed time. */ + public static final String ELAPSED_TIME = "ElapsedTime"; + + /** MDC recording log timestamp. */ + public static final String LOG_TIMESTAMP = "LogTimestamp"; + + // Outcomes. /////////////////////////////////////////////////////////// + + /** MDC reporting outcome code. */ + public static final String RESPONSE_CODE = "ResponseCode"; + + /** MDC reporting outcome description. */ + public static final String RESPONSE_DESCRIPTION = "ResponseDesc"; + + /** MDC reporting severity */ + public static final String RESPONSE_SEVERITY = "Severity"; + + /** MDC reporting response status code */ + public static final String RESPONSE_STATUS_CODE = "StatusCode"; + + /** MDC recording error code. */ + public static final String ERROR_CODE = "ErrorCode"; + + /** MDC recording error description. */ + public static final String ERROR_DESC = "ErrorDesc"; + + // Unsorted. /////////////////////////////////////////////////////////// + + /** + * Hide and forbid construction. + */ + private MDCs() { + throw new UnsupportedOperationException(); + } + } + + /** + * Header name constants. + */ + public static final class Headers { + + /** HTTP <tt>X-ONAP-RequestID</tt> header. */ + public static final String REQUEST_ID = "X-ONAP-RequestID"; + + /** HTTP <tt>X-ONAP-InvocationID</tt> header. */ + public static final String INVOCATION_ID = "X-ONAP-InvocationID"; + + /** HTTP <tt>X-ONAP-PartnerName</tt> header. */ + public static final String PARTNER_NAME = "X-ONAP-PartnerName"; + + /** + * Hide and forbid construction. + */ + private Headers() { + throw new UnsupportedOperationException(); + } + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // + // Enums. + // + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Response success or not, for setting <tt>StatusCode</tt>. + */ + public enum ResponseStatus { + + /** Success. */ + COMPLETE, + + /** Not. */ + ERROR, + + /** In Progress. */ + INPROGRESS + } + + /** + * Synchronous or asynchronous execution, for setting invocation marker. + */ + public enum InvocationMode { + + /** Synchronous, blocking. */ + SYNCHRONOUS("SYNCHRONOUS", Markers.INVOKE_SYNCHRONOUS), + + /** Asynchronous, non-blocking. */ + ASYNCHRONOUS("ASYNCHRONOUS", Markers.INVOKE_ASYNCHRONOUS); + + /** Enum value. */ + private String mString; + + /** Corresponding marker. */ + private Marker mMarker; + + /** + * Construct enum. + * + * @param s enum value. + * @param m corresponding Marker. + */ + InvocationMode(final String s, final Marker m) { + this.mString = s; + this.mMarker = m; + } + + /** + * Get Marker for enum. + * + * @return Marker. + */ + public Marker getMarker() { + return this.mMarker; + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return this.mString; + } + } + +} diff --git a/aai-els-onap-logging/src/main/java/org/onap/logging/ref/slf4j/package-info.java b/aai-els-onap-logging/src/main/java/org/onap/logging/ref/slf4j/package-info.java new file mode 100644 index 00000000..d9a62472 --- /dev/null +++ b/aai-els-onap-logging/src/main/java/org/onap/logging/ref/slf4j/package-info.java @@ -0,0 +1,32 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.logging + * ================================================================================ + * Copyright © 2018 Amdocs + * 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.logging.ref.slf4j; + +/** + * <p>Code in here has potential application outside this reference + * example, and accordingly: + * <ul> + * <li>Packaged in <tt>common</tt>.</li> + * <li>Has minimal dependencies.</li> + * </ul> + * </p> + */
\ No newline at end of file diff --git a/aai-core/src/test/java/org/onap/aai/util/MapperUtilTest.java b/aai-els-onap-logging/src/test/java/org/onap/aai/util/MapperUtilTest.java index 33da9c04..14d80020 100644 --- a/aai-core/src/test/java/org/onap/aai/util/MapperUtilTest.java +++ b/aai-els-onap-logging/src/test/java/org/onap/aai/util/MapperUtilTest.java @@ -25,6 +25,7 @@ package org.onap.aai.util; import static org.junit.Assert.assertEquals; import org.json.JSONObject; +import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -44,7 +45,7 @@ public class MapperUtilTest { expectedJson.put("color", "black"); expectedJson.put("shape", "box"); SampleClass sample = new SampleClass("black", "box"); - assertEquals(expectedJson.toString(), MapperUtil.writeAsJSONString(sample)); + Assert.assertEquals(expectedJson.toString(), MapperUtil.writeAsJSONString(sample)); } @Test diff --git a/aai-parent/pom.xml b/aai-parent/pom.xml index 1f44f747..7f4d4a2d 100644 --- a/aai-parent/pom.xml +++ b/aai-parent/pom.xml @@ -59,6 +59,7 @@ limitations under the License. <commons.text.version>1.8</commons.text.version> <docker.fabric.version>0.31.0</docker.fabric.version> <dmaap.client.version>1.1.9</dmaap.client.version> + <easy.mock.version>4.0.2</easy.mock.version> <eclipse.persistence.version>2.6.2</eclipse.persistence.version> <eelf.core.version>1.0.1-oss</eelf.core.version> <freemarker.version>2.3.29</freemarker.version> @@ -80,12 +81,24 @@ limitations under the License. <jopt.simple.version>5.0.4</jopt.simple.version> <jsonassert.version>1.5.0</jsonassert.version> <json.patch.version>1.9</json.patch.version> - <json.path.version>2.4.0</json.path.version> + <!-- + JSONPath has an bug when it tries to parse an expression + when nesting reaches three levels so an junit was failing + when it was moving to an library of 2.3.0 or above + There seems to be no new releases since 2017 so not sure if + this library is still active or not + We might need to move away from this library but its in the core logic + and would take some time to refactor + Please don't upgrade to 2.3.0 or above for nexus iq or security scans + as it could potentially break our code + --> + <json.path.version>2.2.0</json.path.version> <json.version>20190722</json.version> <junit.version>4.12</junit.version> <httpclient.version>4.5.10</httpclient.version> <io.swagger.version>1.5.24</io.swagger.version> <logback.version>1.2.3</logback.version> + <slf4j.version>1.7.25</slf4j.version> <log4j.version>1.2.17</log4j.version> <mockito.all.version>1.10.19</mockito.all.version> <mockito.core.version>2.15.0</mockito.core.version> @@ -98,11 +111,13 @@ limitations under the License. <snakeyaml.version>1.25</snakeyaml.version> <spring.boot.version>1.5.22.RELEASE</spring.boot.version> + <javax.servlet.version>3.1.0</javax.servlet.version> + <javax.annotation.version>1.2</javax.annotation.version> <sonar.jacoco.reportPath /> <sonar.jacoco.itReportPath /> <sonar.jacoco.reportMissing.force.zero /> - + <!-- we let things pass by default, set custom level for each child project --> <jacoco.line.coverage.limit>0.00</jacoco.line.coverage.limit> @@ -114,20 +129,21 @@ limitations under the License. <sonar.scanner.version>3.7.0.1746</sonar.scanner.version> - <spring.web.version>4.3.25.RELEASE</spring.web.version> + <spring.version>4.3.25.RELEASE</spring.version> <spring.jms.version>4.3.25.RELEASE</spring.jms.version> <spring.test.version>4.3.25.RELEASE</spring.test.version> <spring.security.rsa.version>1.0.8.RELEASE</spring.security.rsa.version> <json.simple.version>1.1.1</json.simple.version> <powermock.api.mockito2.version>2.0.4</powermock.api.mockito2.version> - + <aspectj.version>1.9.1</aspectj.version> + <logging.analytics.version>1.5.1</logging.analytics.version> </properties> <profiles> <profile> <id>spring-boot-2-1</id> <properties> - <spring.boot.version>2.1.12.RELEASE</spring.boot.version> + <spring.boot.version>1.5.22.RELEASE</spring.boot.version> </properties> </profile> </profiles> @@ -153,6 +169,18 @@ limitations under the License. <version>${aai.release.version}</version> </dependency> + <dependency> + <groupId>org.onap.aai.aai-common</groupId> + <artifactId>aai-aaf-auth</artifactId> + <version>${aai.release.version}</version> + </dependency> + + <dependency> + <groupId>org.onap.aai.aai-common</groupId> + <artifactId>aai-els-onap-logging</artifactId> + <version>${aai.release.version}</version> + </dependency> + <dependency> <groupId>org.onap.aai.aai-common</groupId> <artifactId>aai-annotations</artifactId> @@ -251,6 +279,12 @@ limitations under the License. <version>${logback.version}</version> </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + <version>${slf4j.version}</version> + </dependency> + <dependency> <groupId>org.hamcrest</groupId> <artifactId>java-hamcrest</artifactId> @@ -269,10 +303,24 @@ limitations under the License. <version>${hamcrest.junit.version}</version> </dependency> + <dependency> + <groupId>javax.servlet</groupId> + <artifactId>javax.servlet-api</artifactId> + <version>${javax.servlet.version}</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>javax.annotation</groupId> + <artifactId>javax.annotation-api</artifactId> + <version>${javax.annotation.version}</version> + <scope>provided</scope> + </dependency> + <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> + <scope>test</scope> </dependency> <dependency> @@ -340,8 +388,12 @@ limitations under the License. <version>${mockito.all.version}</version> </dependency> - <!-- <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> - <version>${mockito.core.version}</version> </dependency> --> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-core</artifactId> + <version>${mockito.core.version}</version> + <scope>test</scope> + </dependency> <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-module-junit4</artifactId> @@ -424,8 +476,22 @@ limitations under the License. <dependency> <groupId>org.onap.aaf.authz</groupId> + <artifactId>aaf-cadi-core</artifactId> + <version>${aaf.version}</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>org.onap.aaf.authz</groupId> <artifactId>aaf-cadi-aaf</artifactId> <version>${aaf.version}</version> + <scope>compile</scope> + </dependency> + + <dependency> + <groupId>org.easymock</groupId> + <artifactId>easymock</artifactId> + <version>${easy.mock.version}</version> + <scope>test</scope> </dependency> <dependency> @@ -457,6 +523,11 @@ limitations under the License. <artifactId>json-path</artifactId> <version>${json.path.version}</version> </dependency> + <dependency> + <groupId>com.jayway.jsonpath</groupId> + <artifactId>json-path-assert</artifactId> + <version>${json.path.version}</version> + </dependency> <dependency> <groupId>org.javatuples</groupId> @@ -543,6 +614,46 @@ limitations under the License. <version>${commons.io.version}</version> </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-web</artifactId> + <version>${spring.version}</version> + </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-context</artifactId> + <version>${spring.version}</version> + </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-core</artifactId> + <version>${spring.version}</version> + </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-orm</artifactId> + <version>${spring.version}</version> + </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-oxm</artifactId> + <version>${spring.version}</version> + </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-aspects</artifactId> + <version>${spring.version}</version> + </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-tx</artifactId> + <version>${spring.version}</version> + </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-webmvc</artifactId> + <version>${spring.version}</version> + </dependency> <dependency> <groupId>org.springframework.security</groupId> @@ -568,6 +679,12 @@ limitations under the License. <version>${aai.common.logging.version}</version> </dependency> + <dependency> + <groupId>org.onap.logging-analytics</groupId> + <artifactId>logging-slf4j</artifactId> + <version>${logging.analytics.version}</version> + </dependency> + <dependency> <groupId>org.onap.aai</groupId> <artifactId>rest-client</artifactId> @@ -586,6 +703,12 @@ limitations under the License. <version>${io.swagger.version}</version> </dependency> + <dependency> + <groupId>org.aspectj</groupId> + <artifactId>aspectjrt</artifactId> + <version>${aspectj.version}</version> + </dependency> + <dependency> <groupId>io.swagger</groupId> <artifactId>swagger-annotations</artifactId> @@ -688,7 +811,7 @@ limitations under the License. <artifactId>jacoco-maven-plugin</artifactId> <version>${jacoco.version}</version> <configuration> - <!-- Note: This exclusion list should match <sonar.exclusions> property + <!-- Note: This exclusion list should match <sonar.exclusions> property above --> <excludes> <exclude>**/gen/**</exclude> @@ -698,7 +821,7 @@ limitations under the License. </excludes> </configuration> <executions> - <!-- Prepares the property pointing to the JaCoCo runtime agent which + <!-- Prepares the property pointing to the JaCoCo runtime agent which is passed as VM argument when Maven the Surefire plugin is executed. --> <execution> <id>pre-unit-test</id> @@ -706,15 +829,15 @@ limitations under the License. <goal>prepare-agent</goal> </goals> <configuration> - <!-- Sets the path to the file which contains the execution data + <!-- Sets the path to the file which contains the execution data . --> <destFile>${project.build.directory}/code-coverage/jacoco-ut.exec</destFile> - <!-- Sets the name of the property containing the settings for JaCoCo + <!-- Sets the name of the property containing the settings for JaCoCo runtime agent. --> <propertyName>surefireArgLine</propertyName> </configuration> </execution> - <!-- Ensures that the code coverage report for unit tests is created + <!-- Ensures that the code coverage report for unit tests is created after unit tests have been run. --> <execution> <id>post-unit-test</id> @@ -723,7 +846,7 @@ limitations under the License. <goal>report</goal> </goals> <configuration> - <!-- Sets the path to the file which contains the execution data + <!-- Sets the path to the file which contains the execution data . --> <dataFile>${project.build.directory}/code-coverage/jacoco-ut.exec</dataFile> <!-- Sets the output directory for the code coverage report. --> @@ -737,15 +860,15 @@ limitations under the License. <goal>prepare-agent</goal> </goals> <configuration> - <!-- Sets the path to the file which contains the execution data + <!-- Sets the path to the file which contains the execution data . --> <destFile>${project.build.directory}/code-coverage/jacoco-it.exec</destFile> - <!-- Sets the name of the property containing the settings for JaCoCo + <!-- Sets the name of the property containing the settings for JaCoCo runtime agent. --> <propertyName>failsafeArgLine</propertyName> </configuration> </execution> - <!-- Ensures that the code coverage report for integration tests after + <!-- Ensures that the code coverage report for integration tests after integration tests have been run. --> <execution> <id>post-integration-test</id> @@ -754,7 +877,7 @@ limitations under the License. <goal>report</goal> </goals> <configuration> - <!-- Sets the path to the file which contains the execution data + <!-- Sets the path to the file which contains the execution data . --> <dataFile>${project.build.directory}/code-coverage/jacoco-it.exec</dataFile> <!-- Sets the output directory for the code coverage report. --> @@ -802,7 +925,7 @@ limitations under the License. <artifactId>maven-failsafe-plugin</artifactId> <version>3.0.0-M4</version> <executions> - <!-- Ensures that both integration-test and verify goals of the Failsafe + <!-- Ensures that both integration-test and verify goals of the Failsafe Maven plugin are executed. --> <execution> <id>integration-tests</id> diff --git a/aai-rest/pom.xml b/aai-rest/pom.xml index 91fc7e48..d176212f 100644 --- a/aai-rest/pom.xml +++ b/aai-rest/pom.xml @@ -106,6 +106,17 @@ <artifactId>spring-boot-test</artifactId> <scope>test</scope> </dependency> + <dependency> + <groupId>org.onap.aai.aai-common</groupId> + <artifactId>aai-els-onap-logging</artifactId> + <scope>compile</scope> + <exclusions> + <exclusion> + <groupId>javax.ws.rs</groupId> + <artifactId>javax.ws.rs-api</artifactId> + </exclusion> + </exclusions> + </dependency> </dependencies> </project> diff --git a/aai-rest/src/main/java/org/onap/aai/restclient/AAIRestClient.java b/aai-rest/src/main/java/org/onap/aai/restclient/AAIRestClient.java index b9fe87f1..3470de9d 100644 --- a/aai-rest/src/main/java/org/onap/aai/restclient/AAIRestClient.java +++ b/aai-rest/src/main/java/org/onap/aai/restclient/AAIRestClient.java @@ -20,8 +20,8 @@ package org.onap.aai.restclient; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.Collections; import java.util.Map; @@ -35,7 +35,7 @@ import org.springframework.util.MultiValueMap; @Component(value = ClientType.AAI) public class AAIRestClient extends TwoWaySSLRestClient { - private static EELFLogger logger = EELFManager.getInstance().getLogger(AAIRestClient.class); + private static Logger logger = LoggerFactory.getLogger(AAIRestClient.class); @Value("${aai.base.url}") private String baseUrl; diff --git a/aai-rest/src/main/java/org/onap/aai/restclient/NoAuthRestClient.java b/aai-rest/src/main/java/org/onap/aai/restclient/NoAuthRestClient.java index 31dd0c92..68ff3e5e 100644 --- a/aai-rest/src/main/java/org/onap/aai/restclient/NoAuthRestClient.java +++ b/aai-rest/src/main/java/org/onap/aai/restclient/NoAuthRestClient.java @@ -20,30 +20,40 @@ package org.onap.aai.restclient; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; - -import javax.annotation.PostConstruct; - +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.apache.http.client.HttpClient; import org.apache.http.impl.client.HttpClients; +import org.onap.aai.aailog.filter.RestClientLoggingInterceptor; import org.springframework.boot.web.client.RestTemplateBuilder; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.web.client.RestTemplate; +import javax.annotation.PostConstruct; + public abstract class NoAuthRestClient extends RestClient { - private static EELFLogger logger = EELFManager.getInstance().getLogger(NoAuthRestClient.class); + private static Logger logger = LoggerFactory.getLogger(NoAuthRestClient.class); protected RestTemplate restTemplate; @PostConstruct public void init() throws Exception { - HttpClient client = HttpClients.createDefault(); restTemplate = - new RestTemplateBuilder().requestFactory(() -> new HttpComponentsClientHttpRequestFactory(client)).build(); - + new RestTemplateBuilder().requestFactory(this.getHttpRequestFactory()).build(); restTemplate.setErrorHandler(new RestClientResponseErrorHandler()); + RestClientLoggingInterceptor loggingInterceptor = new RestClientLoggingInterceptor(); + restTemplate.getInterceptors().add(loggingInterceptor); + + } + + protected HttpComponentsClientHttpRequestFactory getHttpRequestFactory() throws Exception { + return new HttpComponentsClientHttpRequestFactory(this.getClient()); + } + + protected HttpClient getClient() throws Exception { + HttpClient client = HttpClients.createDefault(); + return client; } @Override diff --git a/aai-rest/src/main/java/org/onap/aai/restclient/OneWaySSLRestClient.java b/aai-rest/src/main/java/org/onap/aai/restclient/OneWaySSLRestClient.java index aa672575..b2534f57 100644 --- a/aai-rest/src/main/java/org/onap/aai/restclient/OneWaySSLRestClient.java +++ b/aai-rest/src/main/java/org/onap/aai/restclient/OneWaySSLRestClient.java @@ -20,49 +20,55 @@ package org.onap.aai.restclient; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; - -import java.io.File; -import java.io.FileInputStream; -import java.io.InputStream; -import java.security.KeyStore; - -import javax.annotation.PostConstruct; -import javax.net.ssl.SSLContext; - +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.apache.http.client.HttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.ssl.SSLContextBuilder; +import org.onap.aai.aailog.filter.RestClientLoggingInterceptor; import org.springframework.boot.web.client.RestTemplateBuilder; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.util.ResourceUtils; import org.springframework.web.client.RestTemplate; +import javax.annotation.PostConstruct; +import javax.net.ssl.SSLContext; + public abstract class OneWaySSLRestClient extends RestClient { - private static EELFLogger logger = EELFManager.getInstance().getLogger(OneWaySSLRestClient.class); + private static Logger logger = LoggerFactory.getLogger(OneWaySSLRestClient.class); private RestTemplate restTemplate; @PostConstruct public void init() throws Exception { + restTemplate = + new RestTemplateBuilder().requestFactory(this.getHttpRequestFactory()).build(); + + restTemplate.setErrorHandler(new RestClientResponseErrorHandler()); + RestClientLoggingInterceptor loggingInterceptor = new RestClientLoggingInterceptor(); + restTemplate.getInterceptors().add(loggingInterceptor); + + } + + protected HttpComponentsClientHttpRequestFactory getHttpRequestFactory() throws Exception { + return new HttpComponentsClientHttpRequestFactory(this.getClient()); + } + + protected HttpClient getClient() throws Exception { char[] trustStorePassword = getTruststorePassword(); String trustStore = getTruststorePath(); - SSLContext sslContext = SSLContextBuilder.create() + SSLContext sslContext = + SSLContextBuilder.create() .loadTrustMaterial(ResourceUtils.getFile(trustStore), trustStorePassword).build(); HttpClient client = - HttpClients.custom().setSSLContext(sslContext).setSSLHostnameVerifier((s, sslSession) -> true).build(); - - restTemplate = - new RestTemplateBuilder().requestFactory(() -> new HttpComponentsClientHttpRequestFactory(client)).build(); - - restTemplate.setErrorHandler(new RestClientResponseErrorHandler()); + HttpClients.custom().setSSLContext(sslContext).setSSLHostnameVerifier((s, sslSession) -> true).build(); + return client; } protected abstract String getTruststorePath(); diff --git a/aai-rest/src/main/java/org/onap/aai/restclient/PropertyPasswordConfiguration.java b/aai-rest/src/main/java/org/onap/aai/restclient/PropertyPasswordConfiguration.java index 3160469a..29d9506f 100644 --- a/aai-rest/src/main/java/org/onap/aai/restclient/PropertyPasswordConfiguration.java +++ b/aai-rest/src/main/java/org/onap/aai/restclient/PropertyPasswordConfiguration.java @@ -17,14 +17,11 @@ * limitations under the License. * ============LICENSE_END========================================================= */ - package org.onap.aai.restclient; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - +import org.apache.commons.io.IOUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.core.env.ConfigurableEnvironment; @@ -32,23 +29,103 @@ import org.springframework.core.env.EnumerablePropertySource; import org.springframework.core.env.MapPropertySource; import org.springframework.core.env.PropertySource; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Properties; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + public class PropertyPasswordConfiguration implements ApplicationContextInitializer<ConfigurableApplicationContext> { private static final Pattern decodePasswordPattern = Pattern.compile("password\\((.*?)\\)"); - private PasswordDecoder passwordDecoder = new JettyPasswordDecoder(); + private static final Logger logger = LoggerFactory.getLogger(PropertyPasswordConfiguration.class.getName()); @Override public void initialize(ConfigurableApplicationContext applicationContext) { ConfigurableEnvironment environment = applicationContext.getEnvironment(); + String certPath = environment.getProperty("server.certs.location"); + File passwordFile = null; + File passphrasesFile = null; + InputStream passwordStream = null; + InputStream passphrasesStream = null; + Map<String, Object> sslProps = new LinkedHashMap<>(); + + // Override the passwords from application.properties if we find AAF certman files + if (certPath != null) { + try { + passwordFile = new File(certPath + ".password"); + passwordStream = new FileInputStream(passwordFile); + + if (passwordStream != null) { + String keystorePassword = null; + + keystorePassword = IOUtils.toString(passwordStream); + if (keystorePassword != null) { + keystorePassword = keystorePassword.trim(); + } + sslProps.put("server.ssl.key-store-password", keystorePassword); + sslProps.put("schema.service.ssl.key-store-password", keystorePassword); + sslProps.put("validation.service.ssl.key-store-password", keystorePassword); + } else { + logger.info("Not using AAF Certman password file"); + } + } catch (IOException e) { + logger.warn("Not using AAF Certman password file, e=" + e.getMessage()); + } finally { + if (passwordStream != null) { + try { + passwordStream.close(); + } catch (Exception e) { + } + } + } + try { + passphrasesFile = new File(certPath + ".passphrases"); + passphrasesStream = new FileInputStream(passphrasesFile); + + if (passphrasesStream != null) { + String truststorePassword = null; + Properties passphrasesProps = new Properties(); + passphrasesProps.load(passphrasesStream); + truststorePassword = passphrasesProps.getProperty("cadi_truststore_password"); + if (truststorePassword != null) { + truststorePassword = truststorePassword.trim(); + } + sslProps.put("server.ssl.trust-store-password", truststorePassword); + sslProps.put("schema.service.ssl.trust-store-password", truststorePassword); + sslProps.put("validation.service.ssl.trust-store-password", truststorePassword); + } else { + logger.info("Not using AAF Certman passphrases file"); + } + } catch (IOException e) { + logger.warn("Not using AAF Certman passphrases file, e=" + e.getMessage()); + } finally { + if (passphrasesStream != null) { + try { + passphrasesStream.close(); + } catch (Exception e) { + } + } + } + } for (PropertySource<?> propertySource : environment.getPropertySources()) { Map<String, Object> propertyOverrides = new LinkedHashMap<>(); decodePasswords(propertySource, propertyOverrides); if (!propertyOverrides.isEmpty()) { - PropertySource<?> decodedProperties = - new MapPropertySource("decoded " + propertySource.getName(), propertyOverrides); + PropertySource<?> decodedProperties = new MapPropertySource("decoded "+ propertySource.getName(), propertyOverrides); environment.getPropertySources().addBefore(propertySource.getName(), decodedProperties); } + + } + if (!sslProps.isEmpty()) { + logger.info("Using AAF Certman files"); + PropertySource<?> additionalProperties = new MapPropertySource("additionalProperties", sslProps); + environment.getPropertySources().addFirst(additionalProperties); } } @@ -66,8 +143,7 @@ public class PropertyPasswordConfiguration implements ApplicationContextInitiali } private String decodePasswordsInString(String input) { - if (input == null) - return null; + if (input == null) return null; StringBuffer output = new StringBuffer(); Matcher matcher = decodePasswordPattern.matcher(input); while (matcher.find()) { diff --git a/aai-rest/src/main/java/org/onap/aai/restclient/RestClient.java b/aai-rest/src/main/java/org/onap/aai/restclient/RestClient.java index f5fc074b..67fb01e1 100644 --- a/aai-rest/src/main/java/org/onap/aai/restclient/RestClient.java +++ b/aai-rest/src/main/java/org/onap/aai/restclient/RestClient.java @@ -22,8 +22,8 @@ package org.onap.aai.restclient; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.net.URI; import java.net.URISyntaxException; @@ -40,13 +40,13 @@ import org.springframework.web.client.RestTemplate; public abstract class RestClient { - private static EELFLogger log = EELFManager.getInstance().getLogger(RestClient.class); + private static Logger log = LoggerFactory.getLogger(RestClient.class); @Value("${spring.application.name}") protected String appName; /** * Execute the given http method against the uri with passed headers - * + * * @param uri properly encoded, can include query params also properly encoded * @param method http method of the request * @param headers headers for the request @@ -58,7 +58,7 @@ public abstract class RestClient { throws RestClientException { HttpEntity<String> httpEntity; - log.debug("Headers: {}", headers); + log.debug("Request Headers: {}", headers); if (body == null) { httpEntity = new HttpEntity<>(getHeaders(headers)); } else { @@ -79,16 +79,15 @@ public abstract class RestClient { log.error("URL syntax error with url {}{}", getBaseUrl(), uri); throw new RestClientException(e.getMessage()); } - log.debug("METHOD={},URL={},HEADERS={}", method, url, httpEntity); - + log.debug("METHOD={}, URL={}, BODY={}", method, url, httpEntity.getBody()); ResponseEntity responseEntity = getRestTemplate().exchange(url, method, httpEntity, String.class); - log.debug("RESPONSE={}", responseEntity); + log.trace("RESPONSE={}", responseEntity); return responseEntity; } /** * Execute the given http method against the uri with passed headers - * + * * @param uri properly encoded, can include query params also properly encoded * @param method http method of the request * @param headers headers for the request @@ -103,7 +102,7 @@ public abstract class RestClient { /** * Execute the given http method against the uri with passed headers - * + * * @param uri properly encoded, can include query params also properly encoded * @param method http method of the request * @param headers headers for the request @@ -117,7 +116,7 @@ public abstract class RestClient { /** * Execute the given http method against the uri with passed headers - * + * * @param uri properly encoded, can include query params also properly encoded * @param method http method of the request * @param headers headers for the request diff --git a/aai-rest/src/main/java/org/onap/aai/restclient/RestClientResponseErrorHandler.java b/aai-rest/src/main/java/org/onap/aai/restclient/RestClientResponseErrorHandler.java index 9c4876d4..9945275a 100644 --- a/aai-rest/src/main/java/org/onap/aai/restclient/RestClientResponseErrorHandler.java +++ b/aai-rest/src/main/java/org/onap/aai/restclient/RestClientResponseErrorHandler.java @@ -20,8 +20,8 @@ package org.onap.aai.restclient; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.IOException; @@ -31,7 +31,7 @@ import org.springframework.web.client.ResponseErrorHandler; public class RestClientResponseErrorHandler implements ResponseErrorHandler { - private static EELFLogger logger = EELFManager.getInstance().getLogger(RestClientResponseErrorHandler.class); + private static Logger logger = LoggerFactory.getLogger(RestClientResponseErrorHandler.class); @Override public boolean hasError(ClientHttpResponse clientHttpResponse) throws IOException { diff --git a/aai-rest/src/main/java/org/onap/aai/restclient/TwoWaySSLRestClient.java b/aai-rest/src/main/java/org/onap/aai/restclient/TwoWaySSLRestClient.java index 58f2106c..58ee79f1 100644 --- a/aai-rest/src/main/java/org/onap/aai/restclient/TwoWaySSLRestClient.java +++ b/aai-rest/src/main/java/org/onap/aai/restclient/TwoWaySSLRestClient.java @@ -20,8 +20,8 @@ package org.onap.aai.restclient; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.File; import java.io.FileInputStream; @@ -38,15 +38,30 @@ import org.springframework.boot.web.client.RestTemplateBuilder; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.util.ResourceUtils; import org.springframework.web.client.RestTemplate; +import org.onap.aai.aailog.filter.RestClientLoggingInterceptor; public abstract class TwoWaySSLRestClient extends RestClient { - private static EELFLogger logger = EELFManager.getInstance().getLogger(TwoWaySSLRestClient.class); + private static Logger logger = LoggerFactory.getLogger(TwoWaySSLRestClient.class); private RestTemplate restTemplate; @PostConstruct public void init() throws Exception { + restTemplate = + new RestTemplateBuilder().requestFactory(this.getHttpRequestFactory()).build(); + + restTemplate.setErrorHandler(new RestClientResponseErrorHandler()); + RestClientLoggingInterceptor loggingInterceptor = new RestClientLoggingInterceptor(); + restTemplate.getInterceptors().add(loggingInterceptor); + + } + + protected HttpComponentsClientHttpRequestFactory getHttpRequestFactory() throws Exception { + return new HttpComponentsClientHttpRequestFactory(this.getClient()); + } + + protected HttpClient getClient() throws Exception { char[] keyStorePassword = getKeystorePassword(); char[] trustStorePassword = getTruststorePassword(); @@ -55,17 +70,13 @@ public abstract class TwoWaySSLRestClient extends RestClient { String trustStore = getTruststorePath(); SSLContext sslContext = - SSLContextBuilder.create().loadKeyMaterial(loadPfx(keyStore, keyStorePassword), keyStorePassword) - .loadTrustMaterial(ResourceUtils.getFile(trustStore), trustStorePassword).build(); + SSLContextBuilder.create().loadKeyMaterial(loadPfx(keyStore, keyStorePassword), keyStorePassword) + .loadTrustMaterial(ResourceUtils.getFile(trustStore), trustStorePassword).build(); HttpClient client = - HttpClients.custom().setSSLContext(sslContext).setSSLHostnameVerifier((s, sslSession) -> true).build(); - - restTemplate = - new RestTemplateBuilder().requestFactory(() -> new HttpComponentsClientHttpRequestFactory(client)).build(); - - restTemplate.setErrorHandler(new RestClientResponseErrorHandler()); + HttpClients.custom().setSSLContext(sslContext).setSSLHostnameVerifier((s, sslSession) -> true).build(); + return client; } private KeyStore loadPfx(String file, char[] password) throws Exception { diff --git a/aai-schema-abstraction/pom.xml b/aai-schema-abstraction/pom.xml index 4f216fc4..38318101 100644 --- a/aai-schema-abstraction/pom.xml +++ b/aai-schema-abstraction/pom.xml @@ -31,13 +31,12 @@ <version>1.6.6-SNAPSHOT</version> <relativePath>../aai-parent/pom.xml</relativePath> </parent> - + <artifactId>aai-schema-abstraction</artifactId> <name>aai-schema-abstraction</name> <properties> <onap.nexus.url>https://nexus.onap.org</onap.nexus.url> - <logback.version>1.2.3</logback.version> </properties> <dependencies> @@ -102,7 +101,6 @@ <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> - <version>${mockito.core.version}</version> <scope>test</scope> </dependency> </dependencies> diff --git a/aai-schema-ingest/pom.xml b/aai-schema-ingest/pom.xml index 1717ad41..76b11f42 100644 --- a/aai-schema-ingest/pom.xml +++ b/aai-schema-ingest/pom.xml @@ -1,13 +1,24 @@ -<!-- ============LICENSE_START======================================================= - org.onap.aai ================================================================================ - Copyright © 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========================================================= --> +<!-- + +============LICENSE_START====================================================== +org.onap.aai +=============================================================================== +Copyright © 2019 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========================================================= + +--> <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"> @@ -34,7 +45,7 @@ <artifactId>maven-source-plugin</artifactId> </plugin> <plugin> - <!-- explicitly define maven-deploy-plugin after other to force exec + <!-- explicitly define maven-deploy-plugin after other to force exec order --> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-deploy-plugin</artifactId> diff --git a/aai-schema-ingest/src/main/java/org/onap/aai/config/NodesConfiguration.java b/aai-schema-ingest/src/main/java/org/onap/aai/config/NodesConfiguration.java index a6675d43..0bb36a2d 100644 --- a/aai-schema-ingest/src/main/java/org/onap/aai/config/NodesConfiguration.java +++ b/aai-schema-ingest/src/main/java/org/onap/aai/config/NodesConfiguration.java @@ -22,8 +22,8 @@ package org.onap.aai.config; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.Arrays; import java.util.HashSet; @@ -49,7 +49,7 @@ public class NodesConfiguration { private static final String CONFIG_TRANSLATOR = "config"; private static final String SCHEMA_SERVICE_TRANSLATOR = "schema-service"; - private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(NodesConfiguration.class); + private static final Logger LOGGER = LoggerFactory.getLogger(NodesConfiguration.class); @Autowired(required = false) SchemaServiceConfiguration schemaConfiguration; diff --git a/aai-schema-ingest/src/main/java/org/onap/aai/config/RestConfiguration.java b/aai-schema-ingest/src/main/java/org/onap/aai/config/RestConfiguration.java index 4074b425..529c0684 100644 --- a/aai-schema-ingest/src/main/java/org/onap/aai/config/RestConfiguration.java +++ b/aai-schema-ingest/src/main/java/org/onap/aai/config/RestConfiguration.java @@ -44,21 +44,6 @@ public class RestConfiguration { @Value("${schema.service.client:one-way-ssl}") private String schemaServiceClient; - @Autowired - private RestClient restClient; - - @Bean - public RestClientFactory restClientFactory() { - - return new RestClientFactory() { - @Override - public RestClient getRestClient(String clientType) { - return restClient; - - } - }; - } - /* * In the below cases bean name and method names are different because all of them qualify as restClient */ diff --git a/aai-schema-ingest/src/main/java/org/onap/aai/config/SchemaServiceConfiguration.java b/aai-schema-ingest/src/main/java/org/onap/aai/config/SchemaServiceConfiguration.java index 245dce97..cdd87492 100644 --- a/aai-schema-ingest/src/main/java/org/onap/aai/config/SchemaServiceConfiguration.java +++ b/aai-schema-ingest/src/main/java/org/onap/aai/config/SchemaServiceConfiguration.java @@ -44,7 +44,7 @@ public class SchemaServiceConfiguration { return schemaVersionsBean().getSchemaVersions(); } - @Bean(name = "schemaVersions2") + @Bean(name = "schemaVersions") public SchemaVersions schemaVersions() { return schemaServiceVersions(); } diff --git a/aai-schema-ingest/src/main/java/org/onap/aai/edges/EdgeIngestor.java b/aai-schema-ingest/src/main/java/org/onap/aai/edges/EdgeIngestor.java index 3cf67052..002ec1ee 100644 --- a/aai-schema-ingest/src/main/java/org/onap/aai/edges/EdgeIngestor.java +++ b/aai-schema-ingest/src/main/java/org/onap/aai/edges/EdgeIngestor.java @@ -23,8 +23,8 @@ package org.onap.aai.edges; import static com.jayway.jsonpath.Criteria.where; import static com.jayway.jsonpath.Filter.filter; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; @@ -60,7 +60,7 @@ import org.springframework.stereotype.Component; */ @Component public class EdgeIngestor { - private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(EdgeIngestor.class); + private static final Logger LOGGER = LoggerFactory.getLogger(EdgeIngestor.class); private Map<SchemaVersion, List<DocumentContext>> versionJsonFilesMap = new TreeMap<>(); private static final String READ_START = "$.rules.[?]"; private static final String READ_ALL_START = "$.rules.*"; diff --git a/aai-schema-ingest/src/main/java/org/onap/aai/edges/EdgeRule.java b/aai-schema-ingest/src/main/java/org/onap/aai/edges/EdgeRule.java index d3c9a599..68def753 100644 --- a/aai-schema-ingest/src/main/java/org/onap/aai/edges/EdgeRule.java +++ b/aai-schema-ingest/src/main/java/org/onap/aai/edges/EdgeRule.java @@ -20,13 +20,13 @@ package org.onap.aai.edges; +import org.apache.tinkerpop.gremlin.structure.Direction; +import org.onap.aai.edges.enums.*; + import java.util.EnumMap; import java.util.HashMap; import java.util.Map; -import org.apache.tinkerpop.gremlin.structure.Direction; -import org.onap.aai.edges.enums.*; - /** * Container for A&AI edge rule information */ @@ -43,7 +43,7 @@ public class EdgeRule { /** * Instantiates a new edge rule. - * + * * @param fieldVals - Map<String, String> where first string is * an EdgeField value and second string is the * value of that field @@ -56,14 +56,14 @@ public class EdgeRule { label = fieldVals.get(EdgeField.LABEL.toString()); direction = Direction.valueOf(fieldVals.get(EdgeField.DIRECTION.toString())); multiplicityRule = MultiplicityRule.getValue(fieldVals.get(EdgeField.MULTIPLICITY.toString())); - isPrivateEdge = Boolean.valueOf(fieldVals.getOrDefault(EdgeField.PRIVATE.toString(), "false")); + isPrivateEdge = Boolean.parseBoolean(fieldVals.getOrDefault(EdgeField.PRIVATE.toString(), "false")); for (EdgeProperty prop : EdgeProperty.values()) { String rawVal = fieldVals.get(prop.toString()); edgeFields.put(prop, convertNotation(direction, rawVal)); } - isDefaultEdge = Boolean.valueOf(fieldVals.get(EdgeField.DEFAULT.toString())); + isDefaultEdge = Boolean.parseBoolean(fieldVals.get(EdgeField.DEFAULT.toString())); description = fieldVals.get(EdgeField.DESCRIPTION.toString()); if (description == null) { // bc description is optional and not in v12 and earlier description = ""; @@ -86,7 +86,7 @@ public class EdgeRule { /** * Converts whatever string was in the json for an edge property value into * the appropriate AAIDirection - * + * * @param Direction dir - the edge direction * @param String rawVal - property value from the json, may be * IN, OUT, BOTH, NONE, ${direction}, or !${direction} @@ -114,7 +114,7 @@ public class EdgeRule { /** * Gets the name of the node type in the "from" field - * + * * @return String nodetype */ public String getFrom() { @@ -123,7 +123,7 @@ public class EdgeRule { /** * Gets the name of the node type in the "to" field - * + * * @return String nodetype */ public String getTo() { @@ -177,7 +177,7 @@ public class EdgeRule { /** * Gets the value of the prevent-delete property - * + * * @return String prevent-delete property value */ public String getPreventDelete() { @@ -186,7 +186,7 @@ public class EdgeRule { /** * Returns if this rule is a default or not - * + * * @return boolean */ public boolean isDefault() { @@ -195,7 +195,7 @@ public class EdgeRule { /** * Gets the description on the edge rule (if there is one) - * + * * @return String description */ public String getDescription() { diff --git a/aai-schema-ingest/src/main/java/org/onap/aai/edges/JsonIngestor.java b/aai-schema-ingest/src/main/java/org/onap/aai/edges/JsonIngestor.java index b686b3a6..9b1f0bd9 100644 --- a/aai-schema-ingest/src/main/java/org/onap/aai/edges/JsonIngestor.java +++ b/aai-schema-ingest/src/main/java/org/onap/aai/edges/JsonIngestor.java @@ -20,8 +20,8 @@ package org.onap.aai.edges; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.jayway.jsonpath.DocumentContext; import com.jayway.jsonpath.JsonPath; @@ -40,7 +40,7 @@ import org.onap.aai.setup.SchemaVersion; * JsonIngestor produces DocumentContexts from json files */ public class JsonIngestor { - private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(JsonIngestor.class); + private static final Logger LOGGER = LoggerFactory.getLogger(JsonIngestor.class); /** * Reads in given json files to queryable DocumentContexts. diff --git a/aai-schema-ingest/src/main/java/org/onap/aai/nodes/NodeIngestor.java b/aai-schema-ingest/src/main/java/org/onap/aai/nodes/NodeIngestor.java index 6016fcca..139eb625 100644 --- a/aai-schema-ingest/src/main/java/org/onap/aai/nodes/NodeIngestor.java +++ b/aai-schema-ingest/src/main/java/org/onap/aai/nodes/NodeIngestor.java @@ -22,8 +22,8 @@ package org.onap.aai.nodes; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.google.common.base.CaseFormat; import java.io.*; @@ -62,7 +62,7 @@ import org.xml.sax.SAXException; @PropertySource(value = "file:${schema.ingest.file}", ignoreResourceNotFound = true) public class NodeIngestor { - private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(NodeIngestor.class); + private static final Logger LOGGER = LoggerFactory.getLogger(NodeIngestor.class); private static final Pattern classNamePattern = Pattern.compile("\\.(v\\d+)\\."); private Map<SchemaVersion, DynamicJAXBContext> versionContextMap = new HashMap<>(); private Map<SchemaVersion, Set<String>> typesPerVersion = new HashMap<>(); diff --git a/aai-schema-ingest/src/main/java/org/onap/aai/restclient/SchemaServiceNoAuthClient.java b/aai-schema-ingest/src/main/java/org/onap/aai/restclient/SchemaServiceNoAuthClient.java index cc88edef..a92005ea 100644 --- a/aai-schema-ingest/src/main/java/org/onap/aai/restclient/SchemaServiceNoAuthClient.java +++ b/aai-schema-ingest/src/main/java/org/onap/aai/restclient/SchemaServiceNoAuthClient.java @@ -20,34 +20,24 @@ package org.onap.aai.restclient; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; - -import java.util.Collections; -import java.util.Map; -import java.util.UUID; - -import javax.annotation.PostConstruct; - +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; -import org.springframework.stereotype.Component; import org.springframework.util.MultiValueMap; -@Component(value = "no-auth-service-rest-client") +import java.util.Collections; +import java.util.Map; +import java.util.UUID; + public class SchemaServiceNoAuthClient extends NoAuthRestClient { - private static EELFLogger logger = EELFManager.getInstance().getLogger(SchemaServiceNoAuthClient.class); + private static Logger logger = LoggerFactory.getLogger(SchemaServiceNoAuthClient.class); @Value("${schema.service.base.url}") private String baseUrl; - @PostConstruct - public void init() throws Exception { - super.init(); - } - @Override public String getBaseUrl() { return baseUrl; diff --git a/aai-schema-ingest/src/main/java/org/onap/aai/restclient/SchemaServiceOneWayClient.java b/aai-schema-ingest/src/main/java/org/onap/aai/restclient/SchemaServiceOneWayClient.java index 6b107285..1ab0999e 100644 --- a/aai-schema-ingest/src/main/java/org/onap/aai/restclient/SchemaServiceOneWayClient.java +++ b/aai-schema-ingest/src/main/java/org/onap/aai/restclient/SchemaServiceOneWayClient.java @@ -20,25 +20,20 @@ package org.onap.aai.restclient; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; - -import java.util.Collections; -import java.util.Map; -import java.util.UUID; - -import javax.annotation.PostConstruct; - +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; -import org.springframework.stereotype.Component; import org.springframework.util.MultiValueMap; -@Component(value = "schema-service-one-way-rest-client") +import java.util.Collections; +import java.util.Map; +import java.util.UUID; + public class SchemaServiceOneWayClient extends OneWaySSLRestClient { - private static EELFLogger logger = EELFManager.getInstance().getLogger(SchemaServiceOneWayClient.class); + private static Logger logger = LoggerFactory.getLogger(SchemaServiceOneWayClient.class); @Value("${schema.service.base.url}") private String baseUrl; diff --git a/aai-schema-ingest/src/main/java/org/onap/aai/restclient/SchemaServiceRestClient.java b/aai-schema-ingest/src/main/java/org/onap/aai/restclient/SchemaServiceRestClient.java index 56ddd744..62f4b68b 100644 --- a/aai-schema-ingest/src/main/java/org/onap/aai/restclient/SchemaServiceRestClient.java +++ b/aai-schema-ingest/src/main/java/org/onap/aai/restclient/SchemaServiceRestClient.java @@ -22,22 +22,19 @@ package org.onap.aai.restclient; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; - -import java.util.Collections; -import java.util.Map; -import java.util.UUID; - +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; -import org.springframework.stereotype.Component; import org.springframework.util.MultiValueMap; -@Component(value = "schema-service-rest-client") +import java.util.Collections; +import java.util.Map; +import java.util.UUID; + public class SchemaServiceRestClient extends TwoWaySSLRestClient { - private static EELFLogger logger = EELFManager.getInstance().getLogger(SchemaServiceRestClient.class); + private static Logger logger = LoggerFactory.getLogger(SchemaServiceRestClient.class); @Value("${schema.service.base.url}") private String baseUrl; diff --git a/aai-schema-ingest/src/main/java/org/onap/aai/setup/ConfigTranslator.java b/aai-schema-ingest/src/main/java/org/onap/aai/setup/ConfigTranslator.java index 1c49e1de..a62dd17b 100644 --- a/aai-schema-ingest/src/main/java/org/onap/aai/setup/ConfigTranslator.java +++ b/aai-schema-ingest/src/main/java/org/onap/aai/setup/ConfigTranslator.java @@ -20,8 +20,8 @@ package org.onap.aai.setup; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.*; import java.nio.charset.Charset; @@ -40,7 +40,7 @@ import org.springframework.beans.factory.annotation.Autowired; * */ public abstract class ConfigTranslator extends Translator { - private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(ConfigTranslator.class); + private static final Logger LOGGER = LoggerFactory.getLogger(ConfigTranslator.class); protected SchemaLocationsBean bean; diff --git a/aai-schema-ingest/src/main/java/org/onap/aai/setup/SchemaServiceTranslator.java b/aai-schema-ingest/src/main/java/org/onap/aai/setup/SchemaServiceTranslator.java index 8c29f96d..4ee93fad 100644 --- a/aai-schema-ingest/src/main/java/org/onap/aai/setup/SchemaServiceTranslator.java +++ b/aai-schema-ingest/src/main/java/org/onap/aai/setup/SchemaServiceTranslator.java @@ -20,8 +20,8 @@ package org.onap.aai.setup; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.*; import java.util.*; @@ -29,8 +29,8 @@ import java.util.*; import javax.ws.rs.HttpMethod; import org.onap.aai.restclient.RestClient; -import org.onap.aai.restclient.RestClientFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.io.Resource; import org.springframework.http.HttpHeaders; @@ -45,7 +45,7 @@ import org.springframework.http.ResponseEntity; */ public class SchemaServiceTranslator extends Translator { - private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(SchemaServiceTranslator.class); + private static final Logger LOGGER = LoggerFactory.getLogger(SchemaServiceTranslator.class); private static final String SchemaServiceClientType = "schema.service"; @@ -55,8 +55,9 @@ public class SchemaServiceTranslator extends Translator { @Value("${schema.service.edges.endpoint}") private String edgeSchemaUri; + @Qualifier("restClient") @Autowired - private RestClientFactory restClientFactory; + private RestClient restClient; public SchemaServiceTranslator(SchemaVersions schemaVersions) { super(schemaVersions); @@ -64,7 +65,7 @@ public class SchemaServiceTranslator extends Translator { /* * (non-Javadoc) - * + * * @see org.onap.aai.setup.ConfigTranslator#getNodeFiles() */ @@ -78,7 +79,6 @@ public class SchemaServiceTranslator extends Translator { headersMap.put(HttpHeaders.ACCEPT, MediaType.APPLICATION_XML.toString()); headersMap.put(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_XML.toString()); - RestClient restClient = restClientFactory.getRestClient(SchemaServiceClientType); ResponseEntity<Resource> schemaResponse = restClient.getGetResource(content, uri, headersMap); verifySchemaServiceResponse(schemaResponse.getStatusCode()); LOGGER.debug("SchemaResponse Status code" + schemaResponse.getStatusCode()); @@ -96,8 +96,6 @@ public class SchemaServiceTranslator extends Translator { String uri = edgeSchemaUri + version.toString(); Map<String, String> headersMap = new HashMap<>(); - RestClient restClient = restClientFactory.getRestClient(SchemaServiceClientType); - ResponseEntity<String> schemaResponse = restClient.getGetRequest(content, uri, headersMap); verifySchemaServiceResponse(schemaResponse.getStatusCode()); LOGGER.debug("SchemaResponse Status code" + schemaResponse.getStatusCode()); diff --git a/aai-schema-ingest/src/main/java/org/onap/aai/setup/SchemaVersionsBean.java b/aai-schema-ingest/src/main/java/org/onap/aai/setup/SchemaVersionsBean.java index 68678b83..90b05e38 100644 --- a/aai-schema-ingest/src/main/java/org/onap/aai/setup/SchemaVersionsBean.java +++ b/aai-schema-ingest/src/main/java/org/onap/aai/setup/SchemaVersionsBean.java @@ -31,8 +31,8 @@ import java.util.Map; import javax.annotation.PostConstruct; import org.onap.aai.restclient.RestClient; -import org.onap.aai.restclient.RestClientFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.ResponseEntity; @@ -47,12 +47,13 @@ public class SchemaVersionsBean { @Value("${schema.service.versions.override:false}") private String overrideSchemaService; - @Autowired - private RestClientFactory restClientFactory; - @Autowired(required = false) private SchemaConfigVersions schemaConfigVersions; + @Qualifier("restClient") + @Autowired + private RestClient restClient; + @PostConstruct public void initialize() { // Call SchemaService to get versions @@ -65,7 +66,6 @@ public class SchemaVersionsBean { */ String content = ""; Map<String, String> headersMap = new HashMap<>(); - RestClient restClient = restClientFactory.getRestClient(SCHEMA_SERVICE); ResponseEntity<String> schemaResponse = restClient.getGetRequest(content, versionsUri, headersMap); Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_DASHES).create(); diff --git a/aai-schema-ingest/src/main/java/org/onap/aai/validation/CheckEverythingStrategy.java b/aai-schema-ingest/src/main/java/org/onap/aai/validation/CheckEverythingStrategy.java index 3f0ee41f..d16e3cc7 100644 --- a/aai-schema-ingest/src/main/java/org/onap/aai/validation/CheckEverythingStrategy.java +++ b/aai-schema-ingest/src/main/java/org/onap/aai/validation/CheckEverythingStrategy.java @@ -59,7 +59,7 @@ public class CheckEverythingStrategy implements SchemaErrorStrategy { if (errorMsgs.isEmpty()) { return "No errors found."; } else { - return StringUtils.join(errorMsgs, "\n"); + return StringUtils.join(errorMsgs.iterator(), "\n"); } } diff --git a/aai-schema-ingest/src/test/java/org/onap/aai/restclient/MockProvider.java b/aai-schema-ingest/src/test/java/org/onap/aai/restclient/MockProvider.java index f0fed324..09b8d3a7 100644 --- a/aai-schema-ingest/src/test/java/org/onap/aai/restclient/MockProvider.java +++ b/aai-schema-ingest/src/test/java/org/onap/aai/restclient/MockProvider.java @@ -35,21 +35,6 @@ public class MockProvider { @Value("${mock.filename}") private String fileName; - @Autowired - private RestClient restClient; - - @Bean - public RestClientFactory restClientFactory() { - - return new RestClientFactory() { - @Override - public RestClient getRestClient(String clientType) { - return restClient; - - } - }; - } - @Bean(name = "restClient") @ConditionalOnProperty(name = "schema.service.client", havingValue = "mock-no-auth") public RestClient getSchemaServiceNoAuthClient() { diff --git a/aai-schema-ingest/src/test/java/org/onap/aai/restclient/MockRestClient.java b/aai-schema-ingest/src/test/java/org/onap/aai/restclient/MockRestClient.java index 52e6364b..6c23301b 100644 --- a/aai-schema-ingest/src/test/java/org/onap/aai/restclient/MockRestClient.java +++ b/aai-schema-ingest/src/test/java/org/onap/aai/restclient/MockRestClient.java @@ -24,7 +24,8 @@ import static org.junit.Assert.assertNotNull; import static org.springframework.test.web.client.match.MockRestRequestMatchers.*; import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus; -import com.att.eelf.configuration.EELFLogger; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.google.gson.JsonArray; import com.google.gson.JsonObject; import com.google.gson.JsonParser; @@ -288,7 +289,7 @@ public class MockRestClient extends RestClient { return null; } - protected EELFLogger getLogger() { + protected Logger getLogger() { return null; } diff --git a/aai-schema-ingest/src/test/java/org/onap/aai/setup/SchemaLocationsBeanXMLSetterWithPropFileTest.java b/aai-schema-ingest/src/test/java/org/onap/aai/setup/SchemaLocationsBeanXMLSetterWithPropFileTest.java index b7688472..af94765f 100644 --- a/aai-schema-ingest/src/test/java/org/onap/aai/setup/SchemaLocationsBeanXMLSetterWithPropFileTest.java +++ b/aai-schema-ingest/src/test/java/org/onap/aai/setup/SchemaLocationsBeanXMLSetterWithPropFileTest.java @@ -27,12 +27,10 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = {"classpath:forWiringTests/testUsingPropFileContext.xml"}) -@TestPropertySource(locations="classpath:forWiringTests/schema-ingest-for-xml-test.properties") public class SchemaLocationsBeanXMLSetterWithPropFileTest { @Autowired SchemaLocationsBean bean; diff --git a/aai-schema-ingest/src/test/resources/edgeRules/test_v16.json b/aai-schema-ingest/src/test/resources/edgeRules/test_v16.json new file mode 100644 index 00000000..0932014c --- /dev/null +++ b/aai-schema-ingest/src/test/resources/edgeRules/test_v16.json @@ -0,0 +1,275 @@ +{ + "rules": [ + { + "from": "foo", + "to": "bar", + "label": "eats", + "direction": "OUT", + "multiplicity": "One2Many", + "contains-other-v": "NONE", + "delete-other-v": "${direction}", + "prevent-delete": "NONE", + "description": "Hard to describe" + }, + { + "from": "foo", + "to": "bar", + "label": "eatz", + "direction": "IN", + "multiplicity": "One2Many", + "contains-other-v": "NONE", + "delete-other-v": "${direction}", + "prevent-delete": "NONE", + "description": "Hard to describe" + }, + { + "from": "foo", + "to": "baz", + "label": "isVeryHappyAbout", + "direction": "OUT", + "multiplicity": "One2Many", + "contains-other-v": "${direction}", + "delete-other-v": "${direction}", + "prevent-delete": "NONE", + "description": "Hard to describe" + }, + { + "from": "quux", + "to": "foo", + "label": "dancesWith", + "direction": "IN", + "multiplicity": "One2Many", + "contains-other-v": "!${direction}", + "delete-other-v": "${direction}", + "prevent-delete": "NONE", + "description": "Hard to describe" + }, + { + "from": "foo", + "to": "dog", + "label": "pets", + "direction": "OUT", + "multiplicity": "One2Many", + "contains-other-v": "NONE", + "delete-other-v": "${direction}", + "prevent-delete": "NONE", + "description": "Hard to describe" + }, + { + "from": "dog", + "to": "puppy", + "label": "caresFor", + "direction": "OUT", + "multiplicity": "One2Many", + "contains-other-v": "NONE", + "delete-other-v": "${direction}", + "prevent-delete": "NONE", + "description": "Hard to describe", + "default": "true" + }, + { + "from": "l-interface", + "to": "logical-link", + "label": "tosca.relationships.network.LinksTo", + "direction": "OUT", + "multiplicity": "MANY2MANY", + "contains-other-v": "NONE", + "delete-other-v": "${direction}", + "prevent-delete": "NONE", + "default": "true", + "description":"" + }, + { + "from": "logical-link", + "to": "l-interface", + "label": "org.onap.relationships.inventory.Source", + "direction": "OUT", + "multiplicity": "ONE2MANY", + "contains-other-v": "NONE", + "delete-other-v": "!${direction}", + "prevent-delete": "NONE", + "default": "false", + "description":"" + }, + { + "from": "logical-link", + "to": "l-interface", + "label": "org.onap.relationships.inventory.Destination", + "direction": "OUT", + "multiplicity": "ONE2MANY", + "contains-other-v": "NONE", + "delete-other-v": "!${direction}", + "prevent-delete": "NONE", + "default": "false", + "description":"" + }, + { + "from": "l-interface", + "to": "lag-interface", + "label": "org.onap.relationships.inventory.BelongsTo", + "direction": "OUT", + "multiplicity": "MANY2ONE", + "contains-other-v": "!${direction}", + "delete-other-v": "!${direction}", + "prevent-delete": "NONE", + "default": "true", + "description":"" + }, + { + "from": "lag-interface", + "to": "logical-link", + "label": "org.onap.relationships.inventory.Uses", + "direction": "OUT", + "multiplicity": "MANY2MANY", + "contains-other-v": "NONE", + "delete-other-v": "${direction}", + "prevent-delete": "NONE", + "default": "true", + "description":"" + }, + { + "from": "bloop", + "to": "bloop", + "label": "links", + "direction": "OUT", + "multiplicity": "ONE2ONE", + "contains-other-v": "IN", + "delete-other-v": "NONE", + "prevent-delete": "NONE", + "default": "true", + "description": "for testing same type direction flip requirement" + }, + { + "from": "parent", + "to": "notation", + "label": "has", + "direction": "OUT", + "multiplicity": "Many2Many", + "contains-other-v": "${direction}", + "delete-other-v": "NONE", + "prevent-delete": "NONE", + "description": "parent contains notation" + }, + { + "from": "not-notation", + "to": "parent", + "label": "contains", + "direction": "OUT", + "multiplicity": "Many2Many", + "contains-other-v": "!${direction}", + "delete-other-v": "NONE", + "prevent-delete": "NONE", + "description": "parent contains not-notation" + }, + { + "from": "parent", + "to": "out-out", + "label": "eats", + "direction": "OUT", + "multiplicity": "Many2Many", + "contains-other-v": "OUT", + "delete-other-v": "NONE", + "prevent-delete": "NONE", + "description": "parent contains out-out" + }, + { + "from": "parent", + "to": "in-in", + "label": "verbs", + "direction": "IN", + "multiplicity": "Many2Many", + "contains-other-v": "IN", + "delete-other-v": "NONE", + "prevent-delete": "NONE", + "description": "parent contains in-in" + }, + { + "from": "out-in", + "to": "parent", + "label": "alarms", + "direction": "OUT", + "multiplicity": "Many2Many", + "contains-other-v": "IN", + "delete-other-v": "NONE", + "prevent-delete": "NONE", + "description": "parent contains out-in" + }, + { + "from": "in-out", + "to": "parent", + "label": "befriends", + "direction": "IN", + "multiplicity": "Many2Many", + "contains-other-v": "OUT", + "delete-other-v": "NONE", + "prevent-delete": "NONE", + "description": "parent contains in-out" + }, + { + "from": "parent", + "to": "grandparent1", + "label": "has", + "direction": "OUT", + "multiplicity": "Many2Many", + "contains-other-v": "!${direction}", + "delete-other-v": "NONE", + "prevent-delete": "NONE", + "description": "parent contained by grandparent1" + }, + { + "from": "grandparent2", + "to": "parent", + "label": "contains", + "direction": "OUT", + "multiplicity": "Many2Many", + "contains-other-v": "${direction}", + "delete-other-v": "NONE", + "prevent-delete": "NONE", + "description": "parent contained by grandparent2" + }, + { + "from": "parent", + "to": "grandparent3", + "label": "eats", + "direction": "OUT", + "multiplicity": "Many2Many", + "contains-other-v": "IN", + "delete-other-v": "NONE", + "prevent-delete": "NONE", + "description": "parent contained by grandparent3" + }, + { + "from": "parent", + "to": "grandparent4", + "label": "verbs", + "direction": "IN", + "multiplicity": "Many2Many", + "contains-other-v": "OUT", + "delete-other-v": "NONE", + "prevent-delete": "NONE", + "description": "parent contained by grandparent4" + }, + { + "from": "grandparent5", + "to": "parent", + "label": "alarms", + "direction": "OUT", + "multiplicity": "Many2Many", + "contains-other-v": "OUT", + "delete-other-v": "NONE", + "prevent-delete": "NONE", + "description": "parent contained by grandparent5" + }, + { + "from": "grandparent6", + "to": "parent", + "label": "befriends", + "direction": "IN", + "multiplicity": "Many2Many", + "contains-other-v": "IN", + "delete-other-v": "NONE", + "prevent-delete": "NONE", + "description": "parent contained by grandparent6" + } + ] +} diff --git a/aai-schema-ingest/src/test/resources/oxm/test_combined_network_business_v16.xml b/aai-schema-ingest/src/test/resources/oxm/test_combined_network_business_v16.xml new file mode 100644 index 00000000..b167ce55 --- /dev/null +++ b/aai-schema-ingest/src/test/resources/oxm/test_combined_network_business_v16.xml @@ -0,0 +1,101 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- + ============LICENSE_START======================================================= + org.openecomp.aai + ================================================================================ + 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========================================================= + --> + +<xml-bindings xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm" package-name="inventory.aai.onap.org.v16" xml-mapping-metadata-complete="true"> + <xml-schema element-form-default="QUALIFIED"> + <xml-ns namespace-uri="http://org.onap.aai.inventory/v16" /> + </xml-schema> + <java-types> + + <java-type name="Foo"> + <xml-root-element name="foo" /> + <java-attributes> + <xml-element java-attribute="fooId" name="foo-id" required="true" type="java.lang.String" xml-key="true"> + <xml-properties> + <xml-property name="description" value="Unique id of Foo. This is unique across the graph." /> + </xml-properties> + </xml-element> + <xml-element java-attribute="fooName" name="foo-name" required="true" type="java.lang.String"> + <xml-properties> + <xml-property name="description" value="Name of Foo." /> + </xml-properties> + </xml-element> + <xml-element java-attribute="quantity" name="quantity" required="false" type="java.lang.String"> + <xml-properties> + <xml-property name="description" value="How many." /> + </xml-properties> + </xml-element> + + </java-attributes> + <xml-properties> + <xml-property name="description" value="General purpose metasyntactic variable" /> + <xml-property name="nameProps" value="foo-name" /> + <xml-property name="uniqueProps" value="foo-id" /> + </xml-properties> + </java-type> + + <java-type name="Quux"> + <xml-root-element name="quux" /> + <java-attributes> + <xml-element java-attribute="qManagerName" name="q-manager-name" required="true" type="java.lang.String" xml-key="true"> + <xml-properties> + <xml-property name="description" value="Unique id of Quux owner. This is unique across the graph." /> + </xml-properties> + </xml-element> + <xml-element java-attribute="color" name="color" required="false" type="java.lang.String"> + <xml-properties> + <xml-property name="description" value="color" /> + </xml-properties> + </xml-element> + + </java-attributes> + <xml-properties> + <xml-property name="description" value="General purpose metasyntactic variable" /> + </xml-properties> + </java-type> + + <java-type name="Bar"> + <xml-root-element name="bar" /> + <java-attributes> + <xml-element java-attribute="barId" name="bar-id" required="true" type="java.lang.String" xml-key="true"> + <xml-properties> + <xml-property name="description" value="Unique id of Bar This is unique across the graph." /> + </xml-properties> + </xml-element> + <xml-element java-attribute="quantity" name="quantity" required="false" type="java.lang.Integer"> + <xml-properties> + <xml-property name="description" value="How many." /> + </xml-properties> + </xml-element> + + </java-attributes> + <xml-properties> + <xml-property name="description" value="General purpose metasyntactic variable" /> + <xml-property name="uniqueProps" value="bar-id" /> + </xml-properties> + </java-type> + + + </java-types> +</xml-bindings> + + + @@ -40,8 +40,10 @@ <module>aai-rest</module> <module>aai-schema-ingest</module> <module>aai-annotations</module> + <module>aai-aaf-auth</module> <module>aai-core</module> <module>aai-auth</module> + <module>aai-els-onap-logging</module> <module>aai-utils</module> <module>aai-schema-abstraction</module> </modules> |