diff options
34 files changed, 5911 insertions, 2365 deletions
diff --git a/aai-core/pom.xml.versionsBackup b/aai-core/pom.xml.versionsBackup new file mode 100644 index 00000000..55c5d712 --- /dev/null +++ b/aai-core/pom.xml.versionsBackup @@ -0,0 +1,1063 @@ +<?xml version="1.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========================================================= + +--> +<project + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" + xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.onap.aai.aai-common</groupId> + <artifactId>aai-common</artifactId> + <version>1.3.1-SNAPSHOT</version> + </parent> + <artifactId>aai-core</artifactId> + <name>aai-core</name> + <version>1.3.1-SNAPSHOT</version> + <packaging>jar</packaging> + <properties> + <sonar.language>java</sonar.language> + <sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin> + <sonar.surefire.reportsPath>${project.build.directory}/surefire-reports</sonar.surefire.reportsPath> + <sonar.jacoco.reportPath>${project.build.directory}/coverage-reports/jacoco.exec</sonar.jacoco.reportPath> + <sonar.jacoco.reportMissing.force.zero>false</sonar.jacoco.reportMissing.force.zero> + <sonar.projectVersion>${project.version}</sonar.projectVersion> + <httpclient.version>4.5.5</httpclient.version> + <jackson.version>2.2.3</jackson.version> + <eelf.core.version>1.0.0</eelf.core.version> + <logback.version>1.2.3</logback.version> + <freemarker.version>2.3.21</freemarker.version> + <activemq.version>5.15.6</activemq.version> + <jacoco.line.coverage.limit>0.50</jacoco.line.coverage.limit> + <gremlin.version>3.2.2</gremlin.version> + <groovy.version>2.4.15</groovy.version> + <jetty.version>9.4.11.v20180605</jetty.version> + + <!-- Start of Default ONAP Schema Properties --> + <aai.wiki.link>https://wiki.onap.org/</aai.wiki.link> + <gendoc.version>v14</gendoc.version> + <aai.release>onap</aai.release> + <schema.uri.base.path>/aai</schema.uri.base.path> + <schema.configuration.location>N/A</schema.configuration.location> + <schema.nodes.location>aai-schema/src/main/resources/${aai.release}/oxm</schema.nodes.location> + <schema.edges.location>aai-schema/src/main/resources/${aai.release}/dbedgerules</schema.edges.location> + <schema.version.depth.start>v9</schema.version.depth.start> + <schema.version.related.link.start>v10</schema.version.related.link.start> + <schema.version.app.root.start>v11</schema.version.app.root.start> + <schema.version.namespace.change.start>v12</schema.version.namespace.change.start> + <schema.version.edge.label.start>v12</schema.version.edge.label.start> + <schema.version.api.default>v14</schema.version.api.default> + <schema.version.list>v8,v9,v10,v11,v12,v13,v14</schema.version.list> + <!-- End of Default ONAP Schema Properties --> + </properties> + <profiles> + <!-- Start of ONAP profile --> + <profile> + <id>onap</id> + <properties> + <aai.release>onap</aai.release> + <schema.configuration.location>N/A</schema.configuration.location> + <schema.nodes.location>aai-schema/src/main/resources/${aai.release}/oxm</schema.nodes.location> + <schema.edges.location>aai-schema/src/main/resources/${aai.release}/dbedgerules</schema.edges.location> + <schema.version.depth.start>v9</schema.version.depth.start> + <schema.version.related.link.start>v10</schema.version.related.link.start> + <schema.version.app.root.start>v11</schema.version.app.root.start> + <schema.version.edge.label.start>v12</schema.version.edge.label.start> + <schema.version.namespace.change.start>v12</schema.version.namespace.change.start> + <schema.version.api.default>v14</schema.version.api.default> + <schema.version.list>v8,v9,v10,v11,v12,v13,v14</schema.version.list> + <gendoc.version>v14</gendoc.version> + </properties> + </profile> + <!-- End of ONAP profile --> + <profile> + <id>generateXsd</id> + <build> + <plugins> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>exec-maven-plugin</artifactId> + <version>1.1.1</version> + <executions> + <execution> + <phase>process-classes</phase> + <goals> + <goal>java</goal> + </goals> + <configuration> + <mainClass>org.onap.aai.util.GenerateXsd</mainClass> + <systemProperties> + <systemProperty> + <key>gen_version</key> + <value>${gendoc.version}</value> + </systemProperty> + <systemProperty> + <key>gen_type</key> + <value>XSD</value> + </systemProperty> + <systemProperty> + <key>yamlresponses_url</key> + <value></value> + </systemProperty> + <systemProperty> + <key>yamlresponses_label</key> + <value></value> + </systemProperty> + <systemProperty> + <key>schema.configuration.location</key> + <value>${schema.configuration.location}</value> + </systemProperty> + <systemProperty> + <key>schema.nodes.location</key> + <value>${schema.nodes.location}</value> + </systemProperty> + <systemProperty> + <key>schema.edges.location</key> + <value>${schema.edges.location}</value> + </systemProperty> + <systemProperty> + <key>schema.version.list</key> + <value>${schema.version.list}</value> + </systemProperty> + <systemProperty> + <key>schema.version.depth.start</key> + <value>${schema.version.depth.start}</value> + </systemProperty> + <systemProperty> + <key>schema.version.depth.start</key> + <value>${schema.version.depth.start}</value> + </systemProperty> + <systemProperty> + <key>schema.version.related.link.start</key> + <value>${schema.version.related.link.start}</value> + </systemProperty> + <systemProperty> + <key>schema.version.app.root.start</key> + <value>${schema.version.app.root.start}</value> + </systemProperty> + <systemProperty> + <key>schema.version.edge.label.start</key> + <value>${schema.version.app.root.start}</value> + </systemProperty> + <systemProperty> + <key>schema.version.namespace.change.start</key> + <value>${schema.version.namespace.change.start}</value> + </systemProperty> + <systemProperty> + <key>schema.version.api.default</key> + <value>${schema.version.api.default}</value> + </systemProperty> + <systemProperty> + <key>schema.uri.base.path</key> + <value>${schema.uri.base.path}</value> + </systemProperty> + <systemProperty> + <key>aai.release</key> + <value>${aai.release}</value> + </systemProperty> + </systemProperties> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> + </profile> + <profile> + <id>generateYaml</id> + <build> + <plugins> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>exec-maven-plugin</artifactId> + <version>1.1.1</version> + <executions> + <execution> + <phase>process-classes</phase> + <goals> + <goal>java</goal> + </goals> + <configuration> + <mainClass>org.onap.aai.util.GenerateXsd</mainClass> + <systemProperties> + <systemProperty> + <key>gen_version</key> + <value>${gendoc.version}</value> + </systemProperty> + <systemProperty> + <key>gen_type</key> + <value>YAML</value> + </systemProperty> + <systemProperty> + <key>yamlresponses_url</key> + <value>https://wiki.web.att.com/pages/viewpage.action?pageId=607391054 + </value> + </systemProperty> + <systemProperty> + <key>yamlresponses_label</key> + <value>Response codes found in [response codes]</value> + </systemProperty> + <systemProperty> + <key>schema.configuration.location</key> + <value>${schema.configuration.location}</value> + </systemProperty> + <systemProperty> + <key>schema.nodes.location</key> + <value>${schema.nodes.location}</value> + </systemProperty> + <systemProperty> + <key>schema.edges.location</key> + <value>${schema.edges.location}</value> + </systemProperty> + <systemProperty> + <key>schema.version.list</key> + <value>${schema.version.list}</value> + </systemProperty> + <systemProperty> + <key>schema.version.depth.start</key> + <value>${schema.version.depth.start}</value> + </systemProperty> + <systemProperty> + <key>schema.version.depth.start</key> + <value>${schema.version.depth.start}</value> + </systemProperty> + <systemProperty> + <key>schema.version.related.link.start</key> + <value>${schema.version.related.link.start}</value> + </systemProperty> + <systemProperty> + <key>schema.version.app.root.start</key> + <value>${schema.version.app.root.start}</value> + </systemProperty> + <systemProperty> + <key>schema.version.edge.label.start</key> + <value>${schema.version.app.root.start}</value> + </systemProperty> + <systemProperty> + <key>schema.version.namespace.change.start</key> + <value>${schema.version.namespace.change.start}</value> + </systemProperty> + <systemProperty> + <key>schema.version.api.default</key> + <value>${schema.version.api.default}</value> + </systemProperty> + <systemProperty> + <key>schema.uri.base.path</key> + <value>${schema.uri.base.path}</value> + </systemProperty> + <systemProperty> + <key>aai.release</key> + <value>${aai.release}</value> + </systemProperty> + </systemProperties> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> + </profile> + <profile> + <id>generateHtml</id> + <build> + <plugins> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>exec-maven-plugin</artifactId> + <version>1.1.1</version> + <executions> + <execution> + <phase>process-classes</phase> + <goals> + <goal>java</goal> + </goals> + <configuration> + <mainClass>org.onap.aai.util.swagger.GenerateSwagger</mainClass> + <systemProperties> + <property> + <key>aai.generate.version</key> + <value>${gendoc.version}</value> + </property> + <property> + <key>aai.wiki.link</key> + <value>${aai.wiki.link}</value> + </property> + <systemProperty> + <key>schema.configuration.location</key> + <value>${schema.configuration.location}</value> + </systemProperty> + <systemProperty> + <key>schema.nodes.location</key> + <value>${schema.nodes.location}</value> + </systemProperty> + <systemProperty> + <key>schema.edges.location</key> + <value>${schema.edges.location}</value> + </systemProperty> + <systemProperty> + <key>schema.version.list</key> + <value>${schema.version.list}</value> + </systemProperty> + <systemProperty> + <key>schema.version.depth.start</key> + <value>${schema.version.depth.start}</value> + </systemProperty> + <systemProperty> + <key>schema.version.depth.start</key> + <value>${schema.version.depth.start}</value> + </systemProperty> + <systemProperty> + <key>schema.version.related.link.start</key> + <value>${schema.version.related.link.start}</value> + </systemProperty> + <systemProperty> + <key>schema.version.app.root.start</key> + <value>${schema.version.app.root.start}</value> + </systemProperty> + <systemProperty> + <key>schema.version.edge.label.start</key> + <value>${schema.version.app.root.start}</value> + </systemProperty> + <systemProperty> + <key>schema.version.namespace.change.start</key> + <value>${schema.version.namespace.change.start}</value> + </systemProperty> + <systemProperty> + <key>schema.version.api.default</key> + <value>${schema.version.api.default}</value> + </systemProperty> + <systemProperty> + <key>schema.uri.base.path</key> + <value>${schema.uri.base.path}</value> + </systemProperty> + <systemProperty> + <key>aai.release</key> + <value>${aai.release}</value> + </systemProperty> + </systemProperties> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> + </profile> + <profile> + <id>autoGenerate</id> + <activation> + <property> + <name>aai.generate.schema</name> + <value>!false</value> + </property> + </activation> + <build> + <plugins> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>exec-maven-plugin</artifactId> + <version>1.1.1</version> + <executions> + <execution> + <id>autoGenerateXsd</id> + <phase>process-classes</phase> + <goals> + <goal>java</goal> + </goals> + <configuration> + <mainClass>org.onap.aai.util.GenerateXsd</mainClass> + <systemProperties> + <systemProperty> + <key>gen_version</key> + <value>ALL</value> + </systemProperty> + <systemProperty> + <key>gen_type</key> + <value>XSD</value> + </systemProperty> + <systemProperty> + <key>yamlresponses_url</key> + <value></value> + </systemProperty> + <systemProperty> + <key>yamlresponses_label</key> + <value></value> + </systemProperty> + <systemProperty> + <key>schema.configuration.location</key> + <value>${schema.configuration.location}</value> + </systemProperty> + <systemProperty> + <key>schema.nodes.location</key> + <value>${schema.nodes.location}</value> + </systemProperty> + <systemProperty> + <key>schema.edges.location</key> + <value>${schema.edges.location}</value> + </systemProperty> + <systemProperty> + <key>schema.version.list</key> + <value>${schema.version.list}</value> + </systemProperty> + <systemProperty> + <key>schema.version.depth.start</key> + <value>${schema.version.depth.start}</value> + </systemProperty> + <systemProperty> + <key>schema.version.depth.start</key> + <value>${schema.version.depth.start}</value> + </systemProperty> + <systemProperty> + <key>schema.version.related.link.start</key> + <value>${schema.version.related.link.start}</value> + </systemProperty> + <systemProperty> + <key>schema.version.app.root.start</key> + <value>${schema.version.app.root.start}</value> + </systemProperty> + <systemProperty> + <key>schema.version.edge.label.start</key> + <value>${schema.version.app.root.start}</value> + </systemProperty> + <systemProperty> + <key>schema.version.namespace.change.start</key> + <value>${schema.version.namespace.change.start}</value> + </systemProperty> + <systemProperty> + <key>schema.version.api.default</key> + <value>${schema.version.api.default}</value> + </systemProperty> + <systemProperty> + <key>schema.uri.base.path</key> + <value>${schema.uri.base.path}</value> + </systemProperty> + <systemProperty> + <key>aai.release</key> + <value>${aai.release}</value> + </systemProperty> + </systemProperties> + </configuration> + </execution> + <execution> + <id>autoGenerateYaml</id> + <phase>process-classes</phase> + <goals> + <goal>java</goal> + </goals> + <configuration> + <mainClass>org.onap.aai.util.GenerateXsd</mainClass> + <systemProperties> + <systemProperty> + <key>gen_version</key> + <value>ALL</value> + </systemProperty> + <systemProperty> + <key>gen_type</key> + <value>YAML</value> + </systemProperty> + <systemProperty> + <key>yamlresponses_url</key> + <value>https://wiki.web.att.com/pages/viewpage.action?pageId=607391054 + </value> + </systemProperty> + <systemProperty> + <key>yamlresponses_label</key> + <value>Response codes found in [response codes]</value> + </systemProperty> + <systemProperty> + <key>schema.configuration.location</key> + <value>${schema.configuration.location}</value> + </systemProperty> + <systemProperty> + <key>schema.nodes.location</key> + <value>${schema.nodes.location}</value> + </systemProperty> + <systemProperty> + <key>schema.edges.location</key> + <value>${schema.edges.location}</value> + </systemProperty> + <systemProperty> + <key>schema.version.list</key> + <value>${schema.version.list}</value> + </systemProperty> + <systemProperty> + <key>schema.version.depth.start</key> + <value>${schema.version.depth.start}</value> + </systemProperty> + <systemProperty> + <key>schema.version.depth.start</key> + <value>${schema.version.depth.start}</value> + </systemProperty> + <systemProperty> + <key>schema.version.related.link.start</key> + <value>${schema.version.related.link.start}</value> + </systemProperty> + <systemProperty> + <key>schema.version.app.root.start</key> + <value>${schema.version.app.root.start}</value> + </systemProperty> + <systemProperty> + <key>schema.version.edge.label.start</key> + <value>${schema.version.app.root.start}</value> + </systemProperty> + <systemProperty> + <key>schema.version.namespace.change.start</key> + <value>${schema.version.namespace.change.start}</value> + </systemProperty> + <systemProperty> + <key>schema.version.api.default</key> + <value>${schema.version.api.default}</value> + </systemProperty> + <systemProperty> + <key>aai.release</key> + <value>${aai.release}</value> + </systemProperty> + </systemProperties> + </configuration> + </execution> + <execution> + <id>autoGenerateHtml</id> + <phase>process-classes</phase> + <goals> + <goal>java</goal> + </goals> + <configuration> + <mainClass>org.onap.aai.util.AutoGenerateHtml</mainClass> + <systemProperties> + <property> + <key>aai.generate.version</key> + <value>${gendoc.version}</value> + </property> + <property> + <key>aai.wiki.link</key> + <value>${aai.wiki.link}</value> + </property> + <systemProperty> + <key>schema.configuration.location</key> + <value>${schema.configuration.location}</value> + </systemProperty> + <systemProperty> + <key>schema.nodes.location</key> + <value>${schema.nodes.location}</value> + </systemProperty> + <systemProperty> + <key>schema.edges.location</key> + <value>${schema.edges.location}</value> + </systemProperty> + <systemProperty> + <key>schema.version.list</key> + <value>${schema.version.list}</value> + </systemProperty> + <systemProperty> + <key>schema.version.depth.start</key> + <value>${schema.version.depth.start}</value> + </systemProperty> + <systemProperty> + <key>schema.version.depth.start</key> + <value>${schema.version.depth.start}</value> + </systemProperty> + <systemProperty> + <key>schema.version.related.link.start</key> + <value>${schema.version.related.link.start}</value> + </systemProperty> + <systemProperty> + <key>schema.version.app.root.start</key> + <value>${schema.version.app.root.start}</value> + </systemProperty> + <systemProperty> + <key>schema.version.edge.label.start</key> + <value>${schema.version.app.root.start}</value> + </systemProperty> + <systemProperty> + <key>schema.version.namespace.change.start</key> + <value>${schema.version.namespace.change.start}</value> + </systemProperty> + <systemProperty> + <key>schema.version.api.default</key> + <value>${schema.version.api.default}</value> + </systemProperty> + <systemProperty> + <key>aai.release</key> + <value>${aai.release}</value> + </systemProperty> + </systemProperties> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> + </profile> + </profiles> + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + <version>2.12.4</version> + <configuration> + <argLine>-noverify ${argLine}</argLine> + <systemPropertyVariables> + <AJSC_HOME>.</AJSC_HOME> + <BUNDLECONFIG_DIR>bundleconfig-local</BUNDLECONFIG_DIR> + </systemPropertyVariables> + </configuration> + </plugin> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>sonar-maven-plugin</artifactId> + <version>3.2</version> + </plugin> + <plugin> + <groupId>org.jacoco</groupId> + <artifactId>jacoco-maven-plugin</artifactId> + <version>0.7.7.201606060606</version> + <configuration> + <dumpOnExit>true</dumpOnExit> + </configuration> + <executions> + <execution> + <id>jacoco-initialize-unit-tests</id> + <goals> + <goal>prepare-agent</goal> + </goals> + <configuration> + <destFile>${project.build.directory}/coverage-reports/jacoco.exec</destFile> + <!-- <append>true</append> --> + </configuration> + </execution> + <execution> + <id>post-unit-test</id> + <phase>test</phase> + <goals> + <goal>report</goal> + </goals> + <configuration> + <!-- Sets the path to the file which contains the execution data. --> + <dataFile>${project.build.directory}/coverage-reports/jacoco.exec</dataFile> + <!-- Sets the output directory for the code coverage report. --> + <outputDirectory>${project.reporting.outputDirectory}/jacoco</outputDirectory> + </configuration> + </execution> + <execution> + <id>default-check</id> + <goals> + <goal>check</goal> + </goals> + <configuration> + <dataFile>${project.build.directory}/coverage-reports/jacoco.exec</dataFile> + <rules> + <rule implementation="org.jacoco.maven.RuleConfiguration"> + <element>BUNDLE</element> + <limits> + <limit implementation="org.jacoco.report.check.Limit"> + <counter>LINE</counter> + <value>COVEREDRATIO</value> + <minimum>${jacoco.line.coverage.limit}</minimum> + </limit> + </limits> + </rule> + </rules> + </configuration> + </execution> + </executions> + </plugin> + <plugin> + <!-- explicitly define maven-deploy-plugin after other to force exec order --> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-deploy-plugin</artifactId> + </plugin> + <plugin> + <groupId>org.sonatype.plugins</groupId> + <artifactId>nexus-staging-maven-plugin</artifactId> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-site-plugin</artifactId> + </plugin> + </plugins> + </build> + + <dependencies> + <dependency> + <groupId>org.onap.aai.aai-common</groupId> + <artifactId>aai-schema-ingest</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.onap.aai.aai-common</groupId> + <artifactId>aai-annotations</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>commons-lang</groupId> + <artifactId>commons-lang</artifactId> + <version>2.6</version> + </dependency> + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-text</artifactId> + <version>1.1</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>com.att.eelf</groupId> + <artifactId>eelf-core</artifactId> + <version>${eelf.core.version}</version> + </dependency> + <dependency> + <groupId>org.codehaus.jackson</groupId> + <artifactId>jackson-core-asl</artifactId> + <version>1.9.13</version> + </dependency> + <dependency> + <groupId>org.codehaus.jackson</groupId> + <artifactId>jackson-mapper-asl</artifactId> + <version>1.9.13</version> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.12</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.hamcrest</groupId> + <artifactId>hamcrest-junit</artifactId> + <version>2.0.0.0</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.hamcrest</groupId> + <artifactId>hamcrest-core</artifactId> + <version>1.3</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-all</artifactId> + <version>1.10.19</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.powermock</groupId> + <artifactId>powermock-module-junit4</artifactId> + <version>1.6.2</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.powermock</groupId> + <artifactId>powermock-api-mockito</artifactId> + <version>1.6.2</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>com.google.guava</groupId> + <artifactId>guava</artifactId> + <version>19.0</version> + </dependency> + <dependency> + <groupId>org.janusgraph</groupId> + <artifactId>janusgraph-core</artifactId> + <version>0.2.0</version> + <exclusions> + <exclusion> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-log4j12</artifactId> + </exclusion> + <exclusion> + <groupId>dom4j</groupId> + <artifactId>dom4j</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>com.fasterxml.jackson.jaxrs</groupId> + <artifactId>jackson-jaxrs-json-provider</artifactId> + <version>${jackson.version}</version> + </dependency> + <dependency> + <groupId>com.googlecode.json-simple</groupId> + <artifactId>json-simple</artifactId> + <version>1.1.1</version> + </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-web</artifactId> + <version>4.3.18.RELEASE</version> + </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-context</artifactId> + <version>4.3.18.RELEASE</version> + </dependency> + <dependency> + <groupId>javax.xml.bind</groupId> + <artifactId>jaxb-api</artifactId> + <version>2.2.11</version> + </dependency> + <dependency> + <groupId>org.eclipse.persistence</groupId> + <artifactId>eclipselink</artifactId> + <version>2.6.2</version> + </dependency> + <dependency> + <groupId>com.google.code.gson</groupId> + <artifactId>gson</artifactId> + <version>2.7</version> + </dependency> + <dependency> + <groupId>com.jayway.jsonpath</groupId> + <artifactId>json-path</artifactId> + <version>2.2.0</version> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-util</artifactId> + <version>${jetty.version}</version> + </dependency> + <dependency> + <groupId>com.fasterxml.jackson.module</groupId> + <artifactId>jackson-module-jaxb-annotations</artifactId> + <version>${jackson.version}</version> + </dependency> + <dependency> + <groupId>com.sun.jersey</groupId> + <artifactId>jersey-core</artifactId> + <version>1.18</version> + </dependency> + <dependency> + <groupId>com.sun.jersey</groupId> + <artifactId>jersey-client</artifactId> + <version>1.18</version> + </dependency> + <dependency> + <groupId>com.sun.jersey</groupId> + <artifactId>jersey-json</artifactId> + <version>1.18</version> + </dependency> + <dependency> + <groupId>javax.ws.rs</groupId> + <artifactId>javax.ws.rs-api</artifactId> + <version>2.0.1</version> + </dependency> + <dependency> + <groupId>org.apache.tinkerpop</groupId> + <artifactId>gremlin-core</artifactId> + <version>${gremlin.version}</version> + </dependency> + <dependency> + <groupId>org.apache.tinkerpop</groupId> + <artifactId>tinkergraph-gremlin</artifactId> + <version>${gremlin.version}</version> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + <version>1.7.5</version> + </dependency> + <dependency> + <groupId>com.fasterxml.jackson.core</groupId> + <artifactId>jackson-annotations</artifactId> + <version>${jackson.version}</version> + </dependency> + <dependency> + <groupId>com.fasterxml.jackson.dataformat</groupId> + <artifactId>jackson-dataformat-yaml</artifactId> + <version>${jackson.version}</version> + </dependency> + <dependency> + <groupId>xml-apis</groupId> + <artifactId>xml-apis</artifactId> + <version>1.0.b2</version> + </dependency> + <dependency> + <groupId>commons-cli</groupId> + <artifactId>commons-cli</artifactId> + <version>1.3</version> + </dependency> + <dependency> + <groupId>com.beust</groupId> + <artifactId>jcommander</artifactId> + <version>1.48</version> + </dependency> + <dependency> + <groupId>org.json</groupId> + <artifactId>json</artifactId> + <version>20160810</version> + </dependency> + <dependency> + <groupId>javax.servlet</groupId> + <artifactId>javax.servlet-api</artifactId> + <version>3.1.0</version> + </dependency> + <dependency> + <groupId>com.bazaarvoice.jolt</groupId> + <artifactId>jolt-complete</artifactId> + <version>0.0.24</version> + </dependency> + <dependency> + <groupId>ch.qos.logback</groupId> + <artifactId>logback-core</artifactId> + <version>${logback.version}</version> + </dependency> + <dependency> + <groupId>ch.qos.logback</groupId> + <artifactId>logback-classic</artifactId> + <version>${logback.version}</version> + </dependency> + <dependency> + <groupId>ch.qos.logback</groupId> + <artifactId>logback-access</artifactId> + <version>${logback.version}</version> + </dependency> + <dependency> + <groupId>org.apache.activemq</groupId> + <artifactId>activemq-broker</artifactId> + <version>${activemq.version}</version> + </dependency> + <dependency> + <groupId>com.opencsv</groupId> + <artifactId>opencsv</artifactId> + <version>3.1</version> + </dependency> + <dependency> + <groupId>org.freemarker</groupId> + <artifactId>freemarker</artifactId> + <version>${freemarker.version}</version> + </dependency> + <dependency> + <groupId>com.github.fge</groupId> + <artifactId>json-patch</artifactId> + <version>1.9</version> + </dependency> + <dependency> + <groupId>org.codehaus.groovy</groupId> + <artifactId>groovy</artifactId> + <version>${groovy.version}</version> + <classifier>indy</classifier> + </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-test</artifactId> + <version>4.3.18.RELEASE</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-test</artifactId> + <version>1.5.1.RELEASE</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.powermock</groupId> + <artifactId>powermock-module-javaagent</artifactId> + <version>1.6.2</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.skyscreamer</groupId> + <artifactId>jsonassert</artifactId> + <version>1.4.0</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.apache.httpcomponents</groupId> + <artifactId>httpclient</artifactId> + <version>${httpclient.version}</version> + </dependency> + <dependency> + <groupId>org.apache.tinkerpop</groupId> + <artifactId>gremlin-groovy</artifactId> + <version>${gremlin.version}</version> + <exclusions> + <exclusion> + <groupId>org.codehaus.groovy</groupId> + <artifactId>groovy</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-jms</artifactId> + <version>4.3.18.RELEASE</version> + </dependency> + <dependency> + <groupId>com.fasterxml.jackson.core</groupId> + <artifactId>jackson-core</artifactId> + <version>2.8.11</version> + </dependency> + <dependency> + <groupId>com.fasterxml.jackson.core</groupId> + <artifactId>jackson-databind</artifactId> + <version>2.8.11</version> + </dependency> + <dependency> + <groupId>com.fasterxml.jackson.core</groupId> + <artifactId>jackson-annotations</artifactId> + <version>2.8.11</version> + </dependency> + <dependency> + <groupId>log4j</groupId> + <artifactId>log4j</artifactId> + <version>1.2.17</version> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot</artifactId> + <version>1.5.15.RELEASE</version> + <scope>compile</scope> + </dependency> + </dependencies> + + <!-- Plugins and repositories --> + <pluginRepositories> + <pluginRepository> + <id>central</id> + <url>http://repo1.maven.org/maven2</url> + </pluginRepository> + <pluginRepository> + <id>EvoSuite</id> + <name>EvoSuite Repository</name> + <url>http://www.evosuite.org/m2</url> + </pluginRepository> + </pluginRepositories> + + <reporting> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-javadoc-plugin</artifactId> + <version>2.10.4</version> + <configuration> + <failOnError>false</failOnError> + <doclet>org.umlgraph.doclet.UmlGraphDoc</doclet> + <docletArtifact> + <groupId>org.umlgraph</groupId> + <artifactId>umlgraph</artifactId> + <version>5.6</version> + </docletArtifact> + <additionalparam>-views</additionalparam> + <useStandardDocletOptions>true</useStandardDocletOptions> + </configuration> + </plugin> + </plugins> + </reporting> +</project> diff --git a/aai-core/src/main/java/org/onap/aai/config/IntrospectionConfig.java b/aai-core/src/main/java/org/onap/aai/config/IntrospectionConfig.java index aa4ec1a1..e737f08d 100644 --- a/aai-core/src/main/java/org/onap/aai/config/IntrospectionConfig.java +++ b/aai-core/src/main/java/org/onap/aai/config/IntrospectionConfig.java @@ -21,14 +21,16 @@ */ package org.onap.aai.config; +import org.onap.aai.schema.enums.ObjectMetadata; import org.onap.aai.setup.SchemaVersion; import org.onap.aai.setup.SchemaVersions; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import java.util.Map; +import java.util.*; import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; import org.onap.aai.introspection.LoaderFactory; import org.onap.aai.introspection.MoxyLoader; 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 c7520dd4..269d6330 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 @@ -36,6 +36,7 @@ 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 { @@ -57,25 +58,25 @@ public abstract class Introspector implements Cloneable { protected String convertPropertyName (String name) { return CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL, name); } - + protected abstract Object get(String name); protected abstract void set(String name, Object value); /** - * + * * @param name the property name you'd like to retrieve the value for * @return the value of the property */ public <T> T getValue(String name) { String convertedName = convertPropertyName(name); Object result = null; - + if (this.hasProperty(name)) { result = this.get(convertedName); } else { /* property not found - slightly ambiguous */ return null; } - + Class<?> clazz = this.getClass(name); if (this.isListType(name) && result == null) { try { @@ -88,18 +89,18 @@ public abstract class Introspector implements Cloneable { return (T)result; } - + public Introspector getWrappedValue(String name) { String convertedName = convertPropertyName(name); Object value = null; - + if (this.hasProperty(name)) { value = this.get(convertedName); } else { /* property not found - slightly ambiguous */ return null; } - + Class<?> clazz = this.getClass(name); if (this.isListType(name) && value == null) { try { @@ -115,9 +116,9 @@ public abstract class Introspector implements Cloneable { //no value return null; } - + } - + public List<Introspector> getWrappedListValue(String name) { String convertedName = convertPropertyName(name); Object value = null; @@ -141,17 +142,17 @@ public abstract class Introspector implements Cloneable { LOGGER.warn(e.getMessage(),e); } } - + List<Object> valueList = (List<Object>)value; - + for (Object item : valueList) { resultList.add(IntrospectorFactory.newInstance(this.getModelType(), item)); } - + return resultList; - + } - + public Object castValueAccordingToSchema(String name, Object obj) { Object result = obj; Class<?> nameClass = this.getClass(name); @@ -159,11 +160,11 @@ public abstract class Introspector implements Cloneable { throw new IllegalArgumentException("property: " + name + " does not exist on " + this.getDbName()); } if (obj != null) { - + try { if (!obj.getClass().getName().equals(nameClass.getName())) { if (nameClass.isPrimitive()) { - nameClass = ClassUtils.primitiveToWrapper(nameClass); + nameClass = ClassUtils.primitiveToWrapper(nameClass); result = nameClass.getConstructor(String.class).newInstance(obj.toString()); } if (obj instanceof String) { @@ -180,35 +181,35 @@ public abstract class Introspector implements Cloneable { } return result; } - + public List<Object> castValueAccordingToSchema(String name, List<?> objs) { List<Object> result = new ArrayList<>(); - + for (Object item : objs) { result.add(this.castValueAccordingToSchema(name, item)); } - + return result; - + } /** - * + * * @param name the property name you'd like to set the value of * @param obj the value to be set * @return */ public void setValue(String name, Object obj) throws IllegalArgumentException { Object box = this.castValueAccordingToSchema(name, obj); - + name = convertPropertyName(name); this.set(name, box); } /** - * + * * @return a list of all the properties available on the object */ public abstract Set<String> getProperties(); - + public Set<String> getProperties(PropertyPredicate<Introspector, String> p) { final Set<String> temp = new LinkedHashSet<>(); this.getProperties().stream().filter(item -> { @@ -217,22 +218,30 @@ public abstract class Introspector implements Cloneable { temp.add(item); }); final Set<String> result = Collections.unmodifiableSet(temp); - + return result; - + } + + public Set<String> getSimpleProperties(PropertyPredicate<Introspector, String> p){ + return this.getProperties() + .stream() + .filter(item -> p.test(this, item)) + .filter(this::isSimpleType) + .collect(Collectors.toSet()); + } /** - * + * * @return a list of the required properties on the object */ public abstract Set<String> getRequiredProperties(); /** - * + * * @return a list of the properties that can be used to query the object in the db */ public abstract Set<String> getKeys(); /** - * + * * @return a list of the all key properties for this object */ public Set<String> getAllKeys() { @@ -274,7 +283,7 @@ public abstract class Introspector implements Cloneable { result = this.indexedProperties; return result; } - + public Set<String> getUniqueProperties() { Set<String> result = null; if (this.uniqueProperties == null) { @@ -292,7 +301,7 @@ public abstract class Introspector implements Cloneable { result = this.uniqueProperties; return result; } - + public Set<String> getDependentOn() { String dependentOn = this.getMetadata(ObjectMetadata.DEPENDENT_ON); if (dependentOn == null) { @@ -301,21 +310,21 @@ public abstract class Introspector implements Cloneable { return new LinkedHashSet<>(Arrays.asList(dependentOn.split(","))); } /** - * + * * @param name * @return the string name of the java class of the named property */ public String getType(String name) { Class<?> resultClass = this.getClass(name); String result = ""; - + if (resultClass != null) { result = resultClass.getName(); if (result.equals("java.util.ArrayList")) { result = "java.util.List"; } } - + return result; } /** @@ -327,33 +336,33 @@ public abstract class Introspector implements Cloneable { public String getGenericType(String name) { Class<?> resultClass = this.getGenericTypeClass(name); String result = ""; - + if (resultClass != null) { result = resultClass.getName(); } - + return result; } /** - * + * * @return the string name of the java class of the underlying object */ public abstract String getJavaClassName(); - + /** - * + * * @param name the property name * @return the Class object */ public abstract Class<?> getClass(String name); - + public abstract Class<?> getGenericTypeClass(String name); /** - * + * * @param name the property name * @return a new instance of the underlying type of this property - * @throws AAIUnknownObjectException + * @throws AAIUnknownObjectException */ public Object newInstanceOfProperty(String name) throws AAIUnknownObjectException { String type = this.getType(name); @@ -364,22 +373,22 @@ public abstract class Introspector implements Cloneable { String type = this.getGenericType(name); return loader.objectFromName(type); } - - + + public Introspector newIntrospectorInstanceOfProperty(String name) throws AAIUnknownObjectException { - + Introspector result = IntrospectorFactory.newInstance(this.getModelType(), this.newInstanceOfProperty(name)); - + return result; - + } - + public Introspector newIntrospectorInstanceOfNestedProperty(String name) throws AAIUnknownObjectException { - + Introspector result = IntrospectorFactory.newInstance(this.getModelType(), this.newInstanceOfNestedProperty(name)); - + return result; - + } /** * Is this type not a Java String or primitive @@ -388,56 +397,56 @@ public abstract class Introspector implements Cloneable { */ public boolean isComplexType(String name) { String result = this.getType(name); - + if (result.contains("aai") || result.equals("java.lang.Object")) { return true; } else { return false; } } - + public boolean isComplexGenericType(String name) { String result = this.getGenericType(name); - + if (result.contains("aai")) { return true; } else { return false; } } - + public boolean isSimpleType(String name) { return !(this.isComplexType(name) || this.isListType(name)); } - + public boolean isSimpleGenericType(String name) { return !this.isComplexGenericType(name); } public boolean isListType(String name) { String result = this.getType(name); - + if (result.contains("java.util.List")) { return true; } else { return false; } } - + public boolean isContainer() { Set<String> props = this.getProperties(); boolean result = false; if (props.size() == 1 && this.isListType(props.iterator().next())) { result = true; } - + return result; } - + public abstract String getChildName(); public String getChildDBName() { String result = this.getChildName(); - + result = namingException.getDBName(result); return result; } @@ -447,10 +456,10 @@ public abstract class Introspector implements Cloneable { String lowerHyphen = this.getName(); lowerHyphen = namingException.getDBName(lowerHyphen); - + return lowerHyphen; } - + public abstract ModelType getModelType(); public boolean hasChild(Introspector child) { @@ -474,7 +483,7 @@ public abstract class Introspector implements Cloneable { } return result; } - + public void setURIChain(String uri) { this.uriChain = uri; } @@ -488,21 +497,21 @@ public abstract class Introspector implements Cloneable { if (this.isContainer()) { result += "/" + this.getName(); } else { - + if (container != null) { result += "/" + container; } result += "/" + this.getDbName() + "/" + this.findKey(); - + if (namespace != null && !namespace.equals("")) { result = "/" + namespace + result; } } - + return result; } - + public String getGenericURI() { String result = ""; if (this.isContainer()) { @@ -513,10 +522,10 @@ public abstract class Introspector implements Cloneable { result += "/{" + this.getDbName() + "-" + key + "}"; } } - + return result; } - + public String getFullGenericURI() { String result = ""; String namespace = this.getMetadata(ObjectMetadata.NAMESPACE); @@ -537,33 +546,33 @@ public abstract class Introspector implements Cloneable { if (namespace != null && !namespace.equals("")) { result = "/" + namespace + result; } - + } - + return result; } public abstract String preProcessKey(String key); - + protected abstract String findKey() throws UnsupportedEncodingException; - + public abstract String marshal(MarshallerProperties properties); - + public abstract Object clone(); public abstract Object getUnderlyingObject(); - + public String marshal(boolean formatted) { MarshallerProperties properties = new MarshallerProperties.Builder(MediaType.APPLICATION_JSON_TYPE).formatted(formatted).build(); - + return marshal(properties); } public String makeSingular(String word) { - + String result = word; result = result.replaceAll("(?:([ho])es|s)$", ""); - + if (result.equals("ClassesOfService")) { result = "ClassOfService"; } else if (result.equals("CvlanTag")) { @@ -573,10 +582,10 @@ public abstract class Introspector implements Cloneable { } return result; } - + protected String makePlural(String word) { String result = word; - + if (result.equals("cvlan-tag-entry")) { return "cvlan-tags"; } else if (result.equals("class-of-service")) { @@ -590,7 +599,7 @@ public abstract class Introspector implements Cloneable { if (result.equals("classes-of-services")) { result = "classes-of-service"; }*/ - + return result; } @@ -599,21 +608,22 @@ public abstract class Introspector implements Cloneable { public Optional<String> getPropertyMetadata(String propName, PropertyMetadata metadataName) { final String resultValue = this.getPropertyMetadata(propName).getOrDefault(metadataName, ""); Optional<String> result = Optional.empty(); - + if (!resultValue.isEmpty()) { result = Optional.of(resultValue); } return result; - + } public abstract SchemaVersion getVersion(); public Loader getLoader() { return this.loader; } - + public boolean isTopLevel() { - + return this.getMetadata(ObjectMetadata.NAMESPACE) != 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 b1447d8f..d54a9833 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 @@ -46,47 +46,47 @@ public class JSONStrategy extends Introspector { throw new IllegalArgumentException("This object has no named type."); } } - + protected JSONStrategy(Object o, String namedType) { super(o); json = (JSONObject)o; this.namedType = namedType; - + } - + @Override public boolean hasProperty(String name) { - //TODO + //TODO return true; } @Override public Object getValue(String name) { Object result = ""; result = json.get(name); - + return result; } @Override public void setValue(String name, Object obj) { json.put(name, obj); - + } @Override public Object getUnderlyingObject() { return this.json; } - + @Override public Set<String> getProperties() { Set<String> result = json.keySet(); return result; } - + @Override public Set<String> getRequiredProperties() { //unknowable - + return this.getProperties(); } @@ -109,11 +109,11 @@ public class JSONStrategy extends Introspector { if (resultClass != null) { result = resultClass.getName(); } - + if (result.equals("org.json.simple.JSONArray")) { result = "java.util.List"; } - + return result; } @@ -136,7 +136,7 @@ public class JSONStrategy extends Introspector { public Class<?> getClass(String name) { Class<?> result = null; result = json.get(name).getClass(); - + return result; } @@ -148,7 +148,7 @@ public class JSONStrategy extends Introspector { if (resultObject.getClass().getName().equals("org.json.simple.JSONArray")) { resultClass = ((List)resultObject).get(0).getClass(); } - + return resultClass; } @@ -169,43 +169,43 @@ public class JSONStrategy extends Introspector { return null; } } - + @Override public boolean isComplexType(String name) { String result = this.getType(name); - + if (result.contains("JSONObject")) { return true; } else { return false; } - + } - + @Override public boolean isComplexGenericType(String name) { String result = this.getGenericType(name); - + if (result.contains("JSONObject")) { return true; } else { return false; } - + } - + @Override public boolean isListType(String name) { String result = this.getType(name); - + if (result.contains("java.util.List")) { return true; } else { return false; } - + } - + @Override public boolean isContainer() { Set<String> props = this.getProperties(); @@ -213,66 +213,66 @@ public class JSONStrategy extends Introspector { if (props.size() == 1 && this.isListType(props.iterator().next())) { result = true; } - + return result; } @Override protected String findKey() { return ""; } - + @Override public String getName() { return this.namedType; } - + @Override public String getDbName() { return this.getName(); } - + @Override public String getURI() { - - // use a UUID for now + + // use a UUID for now return UUID.randomUUID().toString(); } - + @Override public String getGenericURI() { - + //there is none defined for this return ""; } - + @Override public String preProcessKey (String key) { - + // don't do anything with it return key; - + } - + @Override public String marshal(MarshallerProperties properties) { //TODO return null; } - + @Override public Object clone() { //TODO return null; } - + /*@Override public String findEdgeName(String parent, String child) { - + // Always has for now return "has"; - + }*/ - + @Override public ModelType getModelType() { return ModelType.JSON; @@ -341,7 +341,7 @@ public class JSONStrategy extends Introspector { @Override protected void set(String name, Object value) { // TODO Auto-generated method stub - + } @Override diff --git a/aai-core/src/main/java/org/onap/aai/introspection/Loader.java b/aai-core/src/main/java/org/onap/aai/introspection/Loader.java index 3a69e56e..cae4cbb7 100644 --- a/aai-core/src/main/java/org/onap/aai/introspection/Loader.java +++ b/aai-core/src/main/java/org/onap/aai/introspection/Loader.java @@ -25,12 +25,13 @@ import org.onap.aai.restcore.MediaType; import org.onap.aai.setup.SchemaVersion; import java.util.Map; +import java.util.Set; public abstract class Loader { private final SchemaVersion version; private final ModelType modelType; - + /** * Instantiates a new loader. * @@ -41,32 +42,32 @@ public abstract class Loader { this.version = version; this.modelType = modelType; } - + /** * Process. * * @param version the version */ protected abstract void process(SchemaVersion version); - + /** * Object from name. * * @param name the name * @return the object - * @throws AAIUnknownObjectException + * @throws AAIUnknownObjectException */ public abstract Object objectFromName(String name) throws AAIUnknownObjectException; - + /** * Introspector from name. * * @param name the name * @return the introspector - * @throws AAIUnknownObjectException + * @throws AAIUnknownObjectException */ public abstract Introspector introspectorFromName(String name) throws AAIUnknownObjectException; - + /** * Unmarshal. * @@ -76,7 +77,7 @@ public abstract class Loader { * @return the introspector */ public abstract Introspector unmarshal(String type, String json, MediaType mediaType) throws AAIUnmarshallingException; - + /** * Unmarshal. * @@ -88,7 +89,7 @@ public abstract class Loader { return unmarshal(type, json, MediaType.APPLICATION_JSON_TYPE); } - + /** * Gets the model type. * @@ -97,7 +98,7 @@ public abstract class Loader { public ModelType getModelType() { return this.modelType; } - + /** * Gets the version. * @@ -106,6 +107,8 @@ public abstract class Loader { public SchemaVersion getVersion() { return this.version; } - + public abstract Map<String, Introspector> getAllObjects(); + + public abstract Set<String> getNamedPropNodes(); } 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 82504550..fa52d62f 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 @@ -34,6 +34,7 @@ import org.onap.aai.logging.ErrorLogHelper; import org.onap.aai.logging.LogFormatTools; import org.onap.aai.nodes.NodeIngestor; import org.onap.aai.restcore.MediaType; +import org.onap.aai.schema.enums.ObjectMetadata; import org.onap.aai.setup.SchemaVersion; import org.onap.aai.workarounds.NamingExceptions; import org.springframework.stereotype.Component; @@ -44,6 +45,7 @@ import java.io.*; import java.util.HashSet; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; public class MoxyLoader extends Loader { @@ -52,9 +54,11 @@ public class MoxyLoader extends Loader { private Map<String, Introspector> allObjs = null; private Map<SchemaVersion, MoxyLoader> moxyLoaderFactory; - + private NodeIngestor nodeIngestor; + private Set<String> namedProps; + public MoxyLoader(SchemaVersion version, NodeIngestor nodeIngestor) { super(version, ModelType.MOXY); this.nodeIngestor = nodeIngestor; @@ -67,14 +71,14 @@ public class MoxyLoader extends Loader { } /** * {@inheritDoc} - * @throws AAIUnknownObjectException + * @throws AAIUnknownObjectException */ @Override public Introspector introspectorFromName(String name) throws AAIUnknownObjectException { return IntrospectorFactory.newInstance(ModelType.MOXY, objectFromName(name)); } - + /** * {@inheritDoc} */ @@ -93,7 +97,7 @@ public class MoxyLoader extends Loader { } else { upperCamel = CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_CAMEL, sanitizedName); } - + try { final DynamicEntity result = jaxbContext.newDynamicEntity(upperCamel); @@ -115,14 +119,14 @@ public class MoxyLoader extends Loader { * We need to have just same JaxbContext for each version */ jaxbContext = nodeIngestor.getContextForVersion(version); - + } /** * {@inheritDoc} */ @Override - public Introspector unmarshal(String type, String json, MediaType mediaType) throws AAIUnmarshallingException { + public Introspector unmarshal(String type, String json, MediaType mediaType) throws AAIUnmarshallingException { try { final Object clazz = objectFromName(type); final Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); @@ -143,7 +147,7 @@ public class MoxyLoader extends Loader { throw new AAIUnmarshallingException("Could not unmarshall: " + e.getMessage(), e); } } - + @Override public Map<String, Introspector> getAllObjects() { if (this.allObjs != null) { @@ -163,7 +167,7 @@ public class MoxyLoader extends Loader { return allObjs; } } - + private Set<String> objectsInVersion() { Set<String> result = new HashSet<>(); @@ -177,7 +181,21 @@ public class MoxyLoader extends Loader { //result.remove("EdgePropNames"); return result; } - + + @Override + public Set<String> getNamedPropNodes(){ + + if(namedProps == null){ + namedProps = getAllObjects() + .entrySet() + .stream() + .filter( + (entry) -> entry.getValue().getMetadata(ObjectMetadata.NAME_PROPS) != null + ).map(entry -> entry.getKey()).collect(Collectors.toSet()); + } + + return namedProps; + } public DynamicJAXBContext getJAXBContext() { return this.jaxbContext; } 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 ecf31253..f0d487e8 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 @@ -51,9 +51,10 @@ import java.io.StringWriter; import java.io.UnsupportedEncodingException; import java.util.*; import java.util.Map.Entry; +import java.util.stream.Collectors; public class MoxyStrategy extends Introspector { - + private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(MoxyStrategy.class); private DynamicEntity internalObject = null; private DynamicType internalType = null; @@ -67,9 +68,9 @@ public class MoxyStrategy extends Introspector { private Set<String> requiredProperties = null; private boolean isInitialized = false; - + private NodeIngestor nodeIngestor; - + protected MoxyStrategy(Object obj) { super(obj); /* must look up the correct jaxbcontext for this object */ @@ -81,19 +82,19 @@ public class MoxyStrategy extends Introspector { jaxbContext = nodeIngestor.getContextForVersion(version); String simpleName = internalObject.getClass().getName(); internalType = jaxbContext.getDynamicType(simpleName); - + cd = internalType.getDescriptor(); try { marshaller = jaxbContext.createMarshaller(); - + unmarshaller = jaxbContext.createUnmarshaller(); - + } catch (JAXBException e) { } } - + private void init() { isInitialized = true; @@ -104,13 +105,13 @@ public class MoxyStrategy extends Introspector { } props = Collections.unmodifiableSet(props); this.properties = props; - + Set<String> requiredProps = new LinkedHashSet<>(); requiredProps = new LinkedHashSet<>(); for (DatabaseMapping dm : cd.getMappings()) { - if (dm.getField() instanceof XMLField) { + if (dm.getField() instanceof XMLField) { XMLField x = (XMLField)dm.getField(); - if (x != null) { + if (x != null) { if (x.isRequired()) { requiredProps.add(this.removeXPathDescriptor(x.getName())); } @@ -119,25 +120,25 @@ public class MoxyStrategy extends Introspector { } requiredProps = Collections.unmodifiableSet(requiredProps); this.requiredProperties = requiredProps; - + Set<String> keys = new LinkedHashSet<>(); - + for (String name : internalType.getDescriptor().getPrimaryKeyFieldNames()) { keys.add(this.removeXPathDescriptor(name)); } keys = Collections.unmodifiableSet(keys); this.keys = keys; - - + + } - + @Override public boolean hasProperty(String name) { String convertedName = convertPropertyName(name); - return internalType.containsProperty(convertedName); + return internalType.containsProperty(convertedName); } - + @Override public Object get(String name) { return internalObject.get(name); @@ -145,7 +146,7 @@ public class MoxyStrategy extends Introspector { @Override public void set(String name, Object obj) throws IllegalArgumentException { - + internalObject.set(name, obj); } @@ -157,7 +158,7 @@ public class MoxyStrategy extends Introspector { } return this.properties; - + } @Override @@ -179,7 +180,7 @@ public class MoxyStrategy extends Introspector { return this.keys; } - + @Override public Map<PropertyMetadata, String> getPropertyMetadata(String prop) { String propName = this.convertPropertyName(prop); @@ -192,7 +193,7 @@ public class MoxyStrategy extends Introspector { PropertyMetadata.valueOf(CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, (String)entry.getKey())), (String)entry.getValue()); } } - + return result; } @@ -200,8 +201,8 @@ public class MoxyStrategy extends Introspector { public String getJavaClassName() { return internalObject.getClass().getName(); } - - + + @Override public Class<?> getClass(String name) { @@ -211,7 +212,7 @@ public class MoxyStrategy extends Introspector { if (internalType.getPropertyType(name) == null) { if (cd.getMappingForAttributeName(name) instanceof XMLCompositeDirectCollectionMapping) { resultClass = cd.getMappingForAttributeName(name).getContainerPolicy().getContainerClass(); - + } else if (cd.getMappingForAttributeName(name) instanceof XMLCompositeCollectionMapping) { resultClass = cd.getMappingForAttributeName(name).getContainerPolicy().getContainerClass(); } else { @@ -243,7 +244,7 @@ public class MoxyStrategy extends Introspector { resultClass = cd.getMappingForAttributeName(name).getReferenceDescriptor().getJavaClass(); } } - + return resultClass; } @@ -251,20 +252,20 @@ public class MoxyStrategy extends Introspector { public Object getUnderlyingObject() { return this.internalObject; } - + @Override public String getChildName() { - + String className = internalObject.getClass().getSimpleName(); String lowerHyphen = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, className); - + if (this.isContainer()) { lowerHyphen = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN,this.getGenericTypeClass(this.getProperties().iterator().next()).getSimpleName()); } - + return lowerHyphen; } - + @Override public String getName() { String className = internalObject.getClass().getSimpleName(); @@ -273,11 +274,11 @@ public class MoxyStrategy extends Introspector { if (this.isContainer()) { lowerHyphen = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN,this.getGenericTypeClass(this.getProperties().get(0)).getSimpleName()); }*/ - + return lowerHyphen; } - + @Override public String getObjectId() throws UnsupportedEncodingException { String result = ""; @@ -285,17 +286,17 @@ public class MoxyStrategy extends Introspector { if (this.isContainer()) { result += "/" + this.getName(); } else { - + if (container != null) { result += "/" + container; } result += "/" + this.getDbName() + "/" + this.findKey(); - + } - + return result; } - + @Override protected String findKey() throws UnsupportedEncodingException { Set<String> keys = null; @@ -305,10 +306,10 @@ public class MoxyStrategy extends Introspector { String value = UriUtils.encode(this.getValue(key).toString(), "UTF-8"); results.add(value); } - + return Joiner.on("/").join(results); } - + @Override public String preProcessKey (String key) { String result = ""; @@ -316,19 +317,19 @@ public class MoxyStrategy extends Introspector { String[] split = key.split("/"); int i = 0; for (i = split.length-1; i >= 0; i--) { - + if (jaxbContext.getDynamicType(split[i]) != null) { break; - + } - + } result = Joiner.on("/").join(Arrays.copyOfRange(split, 0, i)); - + return result; - + } - + @Override public String marshal(MarshallerProperties properties) { StringWriter result = new StringWriter(); @@ -339,7 +340,7 @@ public class MoxyStrategy extends Introspector { marshaller.setProperty(org.eclipse.persistence.jaxb.MarshallerProperties.JSON_WRAPPER_AS_ARRAY_NAME, properties.getWrapperAsArrayName()); marshaller.setProperty(org.eclipse.persistence.jaxb.MarshallerProperties.JSON_MARSHAL_EMPTY_COLLECTIONS, false); } - + marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, properties.getFormatted()); marshaller.marshal(this.internalObject, result); } catch (JAXBException e) { @@ -348,7 +349,7 @@ public class MoxyStrategy extends Introspector { return result.toString(); } - + @Override public Object clone() { Object result = null; @@ -358,7 +359,7 @@ public class MoxyStrategy extends Introspector { unmarshaller.setProperty(UnmarshallerProperties.MEDIA_TYPE, "application/json"); unmarshaller.setProperty(UnmarshallerProperties.JSON_INCLUDE_ROOT, false); unmarshaller.setProperty(UnmarshallerProperties.JSON_WRAPPER_AS_ARRAY_NAME, true); - + result = unmarshaller.unmarshal(new StreamSource(new StringReader(this.marshal(true))), this.internalObject.getClass()).getValue(); } catch (JAXBException e) { // TODO Auto-generated catch block @@ -371,21 +372,21 @@ public class MoxyStrategy extends Introspector { public ModelType getModelType() { return ModelType.MOXY; } - + private String removeXPathDescriptor(String name) { - + return name.replaceAll("/text\\(\\)", ""); } @Override public String getMetadata(ObjectMetadata name) { - + return (String)cd.getProperty(name.toString()); } @Override public SchemaVersion getVersion() { - + return this.version; } } 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 dd5d42c6..bd7f1b91 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 @@ -8,7 +8,7 @@ * 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 + * 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, @@ -50,6 +50,7 @@ import com.github.fge.jsonpatch.mergepatch.JsonMergePatch; 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.onap.aai.db.props.AAIProperties; @@ -67,6 +68,7 @@ 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.rest.ueb.UEBNotification; import org.onap.aai.restcore.HttpMethod; import org.onap.aai.schema.enums.ObjectMetadata; @@ -93,15 +95,15 @@ public class HttpEntry { private static final String TARGET_ENTITY = "DB"; private ModelType introspectorFactoryType; - + private QueryStyle queryStyle; - + private SchemaVersion version; - + private Loader loader; - + private TransactionalGraphEngine dbEngine; - + private boolean processSingle = true; private int paginationBucket = -1; @@ -148,7 +150,7 @@ public class HttpEntry { } - public HttpEntry setHttpEntryProperties(SchemaVersion version, DBConnectionType connectionType, UEBNotification notification){ + public HttpEntry setHttpEntryProperties(SchemaVersion version, DBConnectionType connectionType, UEBNotification notification){ this.version = version; this.loader = loaderFactory.createLoaderForVersion(introspectorFactoryType, version); this.dbEngine = new JanusGraphDBEngine( @@ -161,7 +163,7 @@ public class HttpEntry { getDbEngine().startTransaction(); return this; } - + /** * Gets the introspector factory type. @@ -316,7 +318,7 @@ public class HttpEntry { QueryEngine queryEngine = dbEngine.getQueryEngine(); int maxRetries = 10; int retry = 0; - + LoggingContext.save(); for (DBRequest request : requests) { response = null; @@ -358,7 +360,7 @@ public class HttpEntry { if (requestContextList != null) { requestContext = requestContextList.get(0); } - + if (cleanUp == null) { cleanUp = "false"; } @@ -426,7 +428,7 @@ public class HttpEntry { result = formatter.output(vertices.stream().map(vertex -> (Object) vertex).collect(Collectors.toList())).toString(); status = Status.OK; } - + break; case PUT: response = this.invokeExtension(dbEngine, this.dbEngine.tx(), method, request, sourceOfTruth, version, loader, obj, uri, true); @@ -441,9 +443,9 @@ public class HttpEntry { } obj = serializer.getLatestVersionView(v); if (query.isDependent()) { - relatedObjects = this.getRelatedObjects(serializer, queryEngine, v); + relatedObjects = this.getRelatedObjects(serializer, queryEngine, v, obj, this.loader); } - LoggingContext.elapsedTime((long)serializer.getDBTimeMsecs() + + LoggingContext.elapsedTime((long)serializer.getDBTimeMsecs() + (long)queryEngine.getDBTimeMsecs(), TimeUnit.MILLISECONDS); LOGGER.info ("Completed "); LoggingContext.restoreIfPossible(); @@ -454,7 +456,7 @@ public class HttpEntry { 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(); @@ -466,7 +468,7 @@ public class HttpEntry { existingObj = this.getObjectFromDb(vertices, serializer, query, existingObj, request.getUri(), 0, false, cleanUp); String existingJson = existingObj.marshal(false); String newJson; - + if (request.getRawRequestContent().isPresent()) { newJson = request.getRawRequestContent().get(); } else { @@ -489,15 +491,15 @@ public class HttpEntry { status = Status.OK; patchedObj = serializer.getLatestVersionView(v); if (query.isDependent()) { - relatedObjects = this.getRelatedObjects(serializer, queryEngine, v); + relatedObjects = this.getRelatedObjects(serializer, queryEngine, v, patchedObj, this.loader); } - LoggingContext.elapsedTime((long)serializer.getDBTimeMsecs() + + LoggingContext.elapsedTime((long)serializer.getDBTimeMsecs() + (long)queryEngine.getDBTimeMsecs(), TimeUnit.MILLISECONDS); LOGGER.info ("Completed"); LoggingContext.restoreIfPossible(); notification.createNotificationEvent(transactionId, sourceOfTruth, status, uri, patchedObj, relatedObjects, basePath); } catch (IOException | JsonPatchException e) { - + LOGGER.info ("Caught exception: " + e.getMessage()); LoggingContext.restoreIfPossible(); throw new AAIException("AAI_3000", "could not perform patch operation"); @@ -507,18 +509,18 @@ public class HttpEntry { String resourceVersion = params.getFirst("resource-version"); obj = serializer.getLatestVersionView(v); if (query.isDependent()) { - relatedObjects = this.getRelatedObjects(serializer, queryEngine, v); + relatedObjects = this.getRelatedObjects(serializer, queryEngine, v, obj, this.loader); } /* * Find all Delete-other-vertex vertices and create structure for notify - * findDeleatble also returns the startVertex v and we dont want to create + * findDeleatble also returns the startVertex v and we dont want to create * duplicate notification events for the same * So remove the startvertex first */ - + List<Vertex> deletableVertices = dbEngine.getQueryEngine().findDeletable(v); Long vId = (Long) v.id(); - + /* * I am assuming vertexId cant be null */ @@ -527,39 +529,39 @@ public class HttpEntry { Map<Vertex, Introspector> deleteObjects = new HashMap<>(); Map<String, URI> uriMap = new HashMap<>(); Map<String, HashMap<String, Introspector>> deleteRelatedObjects = new HashMap<>(); - + if(isDelVerticesPresent){ deleteObjects = this.buildIntrospectorObjects(serializer, deletableVertices); - + uriMap = this.buildURIMap(serializer, deleteObjects); deleteRelatedObjects = 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() + + + 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); - + /* * Notify delete-other-v candidates */ - + if(isDelVerticesPresent){ this.buildNotificationEvent(sourceOfTruth, status, transactionId, notification, deleteObjects, uriMap, deleteRelatedObjects, basePath); } - + break; case DELETE_EDGE: serializer.touchStandardVertexProperties(v, false); serializer.deleteEdge(obj, v); - + LoggingContext.elapsedTime((long)serializer.getDBTimeMsecs(),TimeUnit.MILLISECONDS); LOGGER.info ("Completed"); LoggingContext.restoreIfPossible(); @@ -569,8 +571,8 @@ public class HttpEntry { default: break; } - - + + /* temporarily adding vertex id to the headers * to be able to use for testing the vertex id endpoint functionality * since we presently have no other way of generating those id urls @@ -606,7 +608,7 @@ public class HttpEntry { break; } catch (JanusGraphException e) { this.dbEngine.rollback(); - + LOGGER.info ("Caught exception: " + e.getMessage()); LoggingContext.restoreIfPossible(); AAIException ex = new AAIException("AAI_6142", e); @@ -655,7 +657,7 @@ public class HttpEntry { return Pair.with(success, responses); } - + /** * Gets the media type. * @@ -663,15 +665,15 @@ public class HttpEntry { * @return the media type */ private String getMediaType(List <MediaType> mediaTypeList) { - String mediaType = MediaType.APPLICATION_JSON; // json is the default + String mediaType = MediaType.APPLICATION_JSON; // json is the default for (MediaType mt : mediaTypeList) { if (MediaType.APPLICATION_XML_TYPE.isCompatible(mt)) { mediaType = MediaType.APPLICATION_XML; - } + } } return mediaType; } - + /** * Gets the object from db. * @@ -691,19 +693,19 @@ public class HttpEntry { * @throws NoSuchMethodException the no such method exception * @throws UnsupportedEncodingException the unsupported encoding exception * @throws MalformedURLException the malformed URL exception - * @throws AAIUnknownObjectException - * @throws URISyntaxException + * @throws AAIUnknownObjectException + * @throws URISyntaxException */ private Introspector getObjectFromDb(List<Vertex> results, DBSerializer serializer, QueryParser query, Introspector obj, URI uri, int depth, boolean nodeOnly, String cleanUp) throws AAIException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, SecurityException, InstantiationException, NoSuchMethodException, UnsupportedEncodingException, AAIUnknownObjectException, URISyntaxException { - - //nothing found - if (results.isEmpty()) { - String msg = createNotFoundMessage(query.getResultType(), uri); + + //nothing found + if (results.isEmpty()) { + String msg = createNotFoundMessage(query.getResultType(), uri); throw new AAIException("AAI_6114", msg); - } + } + + return serializer.dbToObject(results, obj, depth, nodeOnly, cleanUp); - return serializer.dbToObject(results, obj, depth, nodeOnly, cleanUp); - } /** @@ -800,7 +802,7 @@ public class HttpEntry { return response; } - + /** * Creates the not found message. * @@ -809,12 +811,12 @@ 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; + String msg = "No Node of type " + resultType + " found at: " + uri.getPath(); + + return msg; } - + /** * Sets the depth. * @@ -831,11 +833,11 @@ public class HttpEntry { return depth; } - if(depthParam == null){ + if(depthParam == null){ if(this.version.compareTo(schemaVersions.getDepthVersion()) >= 0){ depth = 0; } else { - depth = AAIProperties.MAXIMUM_DEPTH; + depth = AAIProperties.MAXIMUM_DEPTH; } } else { if (!depthParam.isEmpty() && !"all".equals(depthParam)){ @@ -847,16 +849,16 @@ public class HttpEntry { } } - String maxDepth = obj.getMetadata(ObjectMetadata.MAXIMUM_DEPTH); - + String maxDepth = obj.getMetadata(ObjectMetadata.MAXIMUM_DEPTH); + int maximumDepth = AAIProperties.MAXIMUM_DEPTH; if(maxDepth != null){ - try { - maximumDepth = Integer.parseInt(maxDepth); - } catch(Exception ex){ - throw new AAIException("AAI_4018"); - } + try { + maximumDepth = Integer.parseInt(maxDepth); + } catch(Exception ex){ + throw new AAIException("AAI_4018"); + } } if(depth > maximumDepth){ @@ -865,7 +867,7 @@ public class HttpEntry { return depth; } - + /** * Checks if is modification method. * @@ -874,31 +876,155 @@ public class HttpEntry { */ 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; - + } - - private HashMap<String, Introspector> getRelatedObjects(DBSerializer serializer, QueryEngine queryEngine, Vertex v) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, SecurityException, InstantiationException, NoSuchMethodException, UnsupportedEncodingException, AAIException, URISyntaxException { + + /** + * 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<>(); - List<Vertex> vertexChain = queryEngine.findParents(v); - for (Vertex vertex : vertexChain) { + 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(vertex); + 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) { @@ -944,7 +1070,7 @@ public class HttpEntry { for (Map.Entry<Vertex, Introspector> entry : introSpector.entrySet()) { try { HashMap<String, Introspector> relatedObjects = this.getRelatedObjects(serializer, queryEngine, - entry.getKey()); + entry.getKey(), entry.getValue(), this.loader); if (null != entry.getValue()) relatedObjectsMap.put(entry.getValue().getObjectId(), relatedObjects); } catch (IllegalAccessException | IllegalArgumentException @@ -959,7 +1085,7 @@ public class HttpEntry { return relatedObjectsMap; } - + private void buildNotificationEvent(String sourceOfTruth, Status status, String transactionId, UEBNotification notification, Map<Vertex, Introspector> deleteObjects, Map<String, URI> uriMap, Map<String, HashMap<String, Introspector>> deleteRelatedObjects, String basePath) { @@ -980,4 +1106,27 @@ public class HttpEntry { } } } + + public void setPaginationParameters(String resultIndex, String resultSize) { + if (resultIndex != null && resultIndex != "-1" && resultSize != null && resultSize != "-1") { + this.setPaginationIndex(Integer.parseInt(resultIndex)); + this.setPaginationBucket(Integer.parseInt(resultSize)); + } + } + + public List<Object> getPaginatedVertexList(List<Object> vertexList) throws AAIException{ + List<Object> vertices; + if(this.isPaginated()) { + 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); + } + vertices = vertexList.subList(startIndex, endIndex); + }else{ + vertices = vertexList; + } + return vertices; + } } 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 7a2c447e..9d107b1f 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 @@ -23,18 +23,21 @@ package org.onap.aai.serialization.db; import com.att.eelf.configuration.EELFLogger; import com.att.eelf.configuration.EELFManager; import com.google.common.base.CaseFormat; -import org.janusgraph.core.SchemaViolationException; +import com.google.common.collect.Multimap; import org.apache.commons.collections.IteratorUtils; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__; import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree; import org.apache.tinkerpop.gremlin.structure.*; -import org.javatuples.Pair; +import org.janusgraph.core.SchemaViolationException; import org.javatuples.Triplet; +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; @@ -57,6 +60,7 @@ import org.onap.aai.schema.enums.PropertyMetadata; import org.onap.aai.serialization.db.exceptions.MultipleEdgeRuleFoundException; import org.onap.aai.serialization.db.exceptions.NoEdgeRuleFoundException; import org.onap.aai.serialization.engines.TransactionalGraphEngine; +import org.onap.aai.serialization.engines.query.QueryEngine; import org.onap.aai.serialization.tinkerpop.TreeBackedVertex; import org.onap.aai.setup.SchemaVersion; import org.onap.aai.setup.SchemaVersions; @@ -64,8 +68,6 @@ import org.onap.aai.util.AAIConfig; import org.onap.aai.util.AAIConstants; import org.onap.aai.workarounds.NamingExceptions; import org.springframework.context.ApplicationContext; -import org.onap.aai.concurrent.AaiCallable; -import org.onap.aai.config.SpringContextAware; import javax.ws.rs.core.UriBuilder; import java.io.UnsupportedEncodingException; @@ -78,1790 +80,1956 @@ import java.util.*; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; +import java.util.function.Function; import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.onap.aai.serialization.engines.query.QueryEngine; +import java.util.stream.Collectors; public class DBSerializer { - - private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(DBSerializer.class); - - private final TransactionalGraphEngine engine; - private final String sourceOfTruth; - private final ModelType introspectionType; - private final SchemaVersion version; - private final Loader latestLoader; - private EdgeSerializer edgeSer; - private EdgeIngestor edgeRules; - private final Loader loader; - private final String baseURL; - private double dbTimeMsecs = 0; - private long currentTimeMillis; - - private SchemaVersions schemaVersions; - /** - * Instantiates a new DB serializer. - * - * @param version the version - * @param engine the engine - * @param introspectionType the introspection type - * @param sourceOfTruth the source of truth - * @throws AAIException - */ - public DBSerializer(SchemaVersion version, TransactionalGraphEngine engine, ModelType introspectionType, String sourceOfTruth) throws AAIException { - this.engine = engine; - this.sourceOfTruth = sourceOfTruth; - this.introspectionType = introspectionType; - this.schemaVersions = SpringContextAware.getBean(SchemaVersions.class); - SchemaVersion LATEST = schemaVersions.getDefaultVersion(); - this.latestLoader = SpringContextAware.getBean(LoaderFactory.class).createLoaderForVersion(introspectionType, LATEST); - this.version = version; - this.loader = SpringContextAware.getBean(LoaderFactory.class).createLoaderForVersion(introspectionType, version); - this.baseURL = AAIConfig.get(AAIConstants.AAI_SERVER_URL_BASE); - this.currentTimeMillis = System.currentTimeMillis(); - initBeans(); - } - - private void initBeans() { - //TODO proper spring wiring, but that requires a lot of refactoring so for now we have this - ApplicationContext ctx = SpringContextAware.getApplicationContext(); - EdgeIngestor ei = ctx.getBean(EdgeIngestor.class); - setEdgeIngestor(ei); - EdgeSerializer es = ctx.getBean(EdgeSerializer.class); - setEdgeSerializer(es); - } - - private void backupESInit() { - setEdgeSerializer(new EdgeSerializer(this.edgeRules)); - } - - public void setEdgeSerializer(EdgeSerializer edgeSer) { - this.edgeSer = edgeSer; - } - - public EdgeSerializer getEdgeSeriailizer() { - return this.edgeSer; - } - - public void setEdgeIngestor(EdgeIngestor ei) { - this.edgeRules = ei; - } - - public EdgeIngestor getEdgeIngestor(){ - return this.edgeRules; - } - - /** - * Touch standard vertex properties. - * - * @param v the v - * @param isNewVertex the is new vertex - */ - public void touchStandardVertexProperties(Vertex v, boolean isNewVertex) { - String timeNowInSec = Long.toString(currentTimeMillis); - - if (isNewVertex) { - 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.RESOURCE_VERSION, timeNowInSec); - v.property(AAIProperties.LAST_MOD_TS, timeNowInSec); - v.property(AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, this.sourceOfTruth); - - } - - private void touchStandardVertexProperties(String nodeType, Vertex v, boolean isNewVertex) { - - v.property(AAIProperties.NODE_TYPE, nodeType); - touchStandardVertexProperties(v, isNewVertex); - - } - - - - /** - * Creates the new vertex. - * - * @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(); - touchStandardVertexProperties(wrappedObject.getDbName(), v, true); - } - finally { - dbTimeMsecs += StopWatch.stopIfStarted(); - } - return v; - } - - /** - * Trim class name. - * - * @param className the class name - * @return the string - */ - /* - * Removes the classpath from a class name - */ - public String trimClassName (String className) { - String returnValue = ""; - - if (className.lastIndexOf('.') == -1) { - return className; - } - returnValue = className.substring(className.lastIndexOf('.') + 1, className.length()); - - return returnValue; - } - - /** - * Serialize to db. - * - * @param obj the obj - * @param v the v - * @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 { - StopWatch.conditionalStart(); - try { - if (uriQuery.isDependent()) { - //try to find the parent - List<Vertex> vertices = uriQuery.getQueryBuilder().getParentQuery().toList(); - if (!vertices.isEmpty()) { - Vertex parent = vertices.get(0); - this.reflectDependentVertex(parent, v, obj, requestContext); - } else { - dbTimeMsecs += StopWatch.stopIfStarted(); - throw new AAIException("AAI_6114", "No parent Node of type " + uriQuery.getParentResultType() + " for " + identifier); - } - } else { - serializeSingleVertex(v, obj, requestContext); - } - - } catch (SchemaViolationException e) { - dbTimeMsecs += StopWatch.stopIfStarted(); - throw new AAIException("AAI_6117", e); - } - dbTimeMsecs += StopWatch.stopIfStarted(); - } - - public void serializeSingleVertex(Vertex v, Introspector obj, String requestContext) throws UnsupportedEncodingException, AAIException { - StopWatch.conditionalStart(); - try { - boolean isTopLevel = obj.isTopLevel(); - if (isTopLevel) { - addUriIfNeeded(v, obj.getURI()); - } - - processObject(obj, v, requestContext); - if (!isTopLevel) { - URI uri = this.getURIForVertex(v); - URIParser parser = new URIParser(this.loader, uri); - if (parser.validate()) { - addUriIfNeeded(v, uri.toString()); - } - } - } catch (SchemaViolationException e) { - throw new AAIException("AAI_6117", e); - } - finally { - dbTimeMsecs += StopWatch.stopIfStarted(); - } - } - - private void addUriIfNeeded(Vertex v, String uri) { - VertexProperty<String> uriProp = v.property(AAIProperties.AAI_URI); - if (!uriProp.isPresent() || (uriProp.isPresent() && !uriProp.value().equals(uri))) { - v.property(AAIProperties.AAI_URI, uri); - } - } - - /** - * 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) 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(obj.getDbName(), 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); - - if (!(isComplexType || isListType)) { - boolean canModify = this.canModify(obj, property, requestContext); - - if (canModify) { - final Map<PropertyMetadata, String> metadata = obj.getPropertyMetadata(property); - String dbProperty = property; - if (metadata.containsKey(PropertyMetadata.DB_ALIAS)) { - dbProperty = metadata.get(PropertyMetadata.DB_ALIAS); - } - if (metadata.containsKey(PropertyMetadata.DATA_LINK)) { - //data linked properties are ephemeral - //they are populated dynamically on GETs - continue; - } - if (value != null) { - if (!value.equals(v.property(dbProperty).orElse(null))) { - if (propertyType.toLowerCase().contains(".long")) { - v.property(dbProperty, new Integer(((Long)value).toString())); - } else { - v.property(dbProperty, value); - } - } - } else { - v.property(dbProperty).remove(); - } - } - } else if (isListType) { - List<Object> list = (List<Object>)value; - if (obj.isComplexGenericType(property)) { - if (list != null) { - for (Object o : list) { - Introspector child = IntrospectorFactory.newInstance(this.introspectionType, o); - child.setURIChain(obj.getURI()); - processedVertexes.add(reflectDependentVertex(v, child, requestContext)); - } - } - } else { - //simple list case - engine.setListProperty(v, property, list); - } - } else { - //method.getReturnType() is not 'simple' then create a vertex and edge recursively returning an edge back to this method - if (value != null) { //effectively ignore complex properties not included in the object we're processing - if (value.getClass().isArray()) { - - int length = Array.getLength(value); - for (int i = 0; i < length; i ++) { - Object arrayElement = Array.get(value, i); - Introspector child = IntrospectorFactory.newInstance(this.introspectionType, arrayElement); - child.setURIChain(obj.getURI()); - processedVertexes.add(reflectDependentVertex(v, child, requestContext)); - - } - } else if (!property.equals("relationship-list")) { - // container case - Introspector introspector = IntrospectorFactory.newInstance(this.introspectionType, value); - if (introspector.isContainer()) { - dependentVertexes.addAll(this.engine.getQueryEngine().findChildrenOfType(v, introspector.getChildDBName())); - introspector.setURIChain(obj.getURI()); - - processedVertexes.addAll(processObject(introspector, v, requestContext)); - - } else { - dependentVertexes.addAll(this.engine.getQueryEngine().findChildrenOfType(v, introspector.getDbName())); - processedVertexes.add(reflectDependentVertex(v, introspector, requestContext)); - - } - } else if (property.equals("relationship-list")) { - handleRelationships(obj, v); - } - } - } - } - this.writeThroughDefaults(v, obj); - /* handle those vertexes not touched */ - for (Vertex toBeRemoved : processedVertexes) { - dependentVertexes.remove(toBeRemoved); - } - this.deleteItemsWithTraversal(dependentVertexes); - - this.executePostSideEffects(obj, v); - return processedVertexes; - } - - /** - * Handle relationships. - * - * @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 - */ - /* - * Handles the explicit relationships defined for an obj - */ - private void handleRelationships(Introspector obj, Vertex vertex) throws UnsupportedEncodingException, AAIException { - - - - Introspector wrappedRl = obj.getWrappedValue("relationship-list"); - processRelationshipList(wrappedRl, vertex); - - - } - - - /** - * Process relationship list. - * - * @param wrapped the wrapped - * @param v the v - * @throws UnsupportedEncodingException the unsupported encoding exception - * @throws AAIException the AAI exception - */ - private void processRelationshipList(Introspector wrapped, Vertex v) throws UnsupportedEncodingException, AAIException { - - 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()); - - for (Object relationship : relationships) { - Edge e = null; - Vertex cousinVertex = null; - String label = null; - Introspector wrappedRel = IntrospectorFactory.newInstance(this.introspectionType, relationship); - QueryParser parser = engine.getQueryBuilder().createQueryFromRelationship(wrappedRel); - - if (wrappedRel.hasProperty("relationship-label")) { - label = wrappedRel.getValue("relationship-label"); - } - - 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()); - ex.getTemplateVars().add(parser.getResultType()); - ex.getTemplateVars().add(parser.getUri().toString()); - throw ex; - } else { - //still an issue if there's more than one - cousinVertex = results.get(0); - } - - if (cousinVertex != null) { - String vType = (String)v.property(AAIProperties.NODE_TYPE).value(); - String cousinType = (String)cousinVertex.property(AAIProperties.NODE_TYPE).value(); - 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):"") +"."); - } else if (edgeRules.hasRule(baseQ.edgeType(EdgeType.TREE).build()) && !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); - } - } - } - - for (Edge edge : existingEdges) { - edge.remove(); - } - for (Triplet<Vertex, Vertex, String> triplet : addEdges) { - try { - edgeSer.addEdge(this.engine.asAdmin().getTraversalSource(), triplet.getValue0(), triplet.getValue1(), triplet.getValue2()); - } catch (NoEdgeRuleFoundException e) { - throw new AAIException("AAI_6129", e); - } - } - - } - - /** - * Write through defaults. - * - * @param v the v - * @param obj the obj - * @throws AAIUnknownObjectException - */ - private void writeThroughDefaults(Vertex v, Introspector obj) throws AAIUnknownObjectException { - Introspector latest = this.latestLoader.introspectorFromName(obj.getName()); - if (latest != null) { - Set<String> required = latest.getRequiredProperties(); - - for (String field : required) { - String defaultValue = null; - Object vertexProp = null; - defaultValue = latest.getPropertyMetadata(field).get(PropertyMetadata.DEFAULT_VALUE); - if (defaultValue != null) { - vertexProp = v.<Object>property(field).orElse(null); - if (vertexProp == null) { - v.property(field, defaultValue); - } - } - } - } - - } - - - /** - * Reflect dependent vertex. - * - * @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 - * @throws AAIUnknownObjectException - */ - 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; - 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()); - } else { - this.verifyResourceVersion("create", dependentObj.getDbName(), "", (String)dependentObj.getValue(AAIProperties.RESOURCE_VERSION), (String)dependentObj.getURI()); - dependentVertex = createNewVertex(dependentObj); - } - - return reflectDependentVertex(v, dependentVertex, dependentObj, requestContext); - - } - - /** - * Reflect dependent vertex. - * - * @param parent the parent - * @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 - * @throws AAIUnknownObjectException - */ - private Vertex reflectDependentVertex(Vertex parent, Vertex child, Introspector obj, String requestContext) throws AAIException, UnsupportedEncodingException { - - String parentUri = parent.<String>property(AAIProperties.AAI_URI).orElse(null); - if (parentUri != null) { - String uri; - uri = obj.getURI(); - addUriIfNeeded(child, parentUri + uri); - } - processObject(obj, child, requestContext); - - Edge e; - e = this.getEdgeBetween(EdgeType.TREE, parent, child, null); - if (e == null) { - String canBeLinked = obj.getMetadata(ObjectMetadata.CAN_BE_LINKED); - if (canBeLinked != null && canBeLinked.equals("true")) { - Loader ldrForCntxt = SpringContextAware.getBean(LoaderFactory.class).createLoaderForVersion(introspectionType, getVerForContext(requestContext)); - boolean isFirst = !this.engine.getQueryBuilder(ldrForCntxt, parent).createEdgeTraversal(EdgeType.TREE, parent, obj).hasNext(); - if (isFirst) { - child.property(AAIProperties.LINKED, true); - } - } - edgeSer.addTreeEdge(this.engine.asAdmin().getTraversalSource(), parent, child); - } - return child; - - } - - private SchemaVersion getVerForContext(String requestContext) { - Pattern pattern = Pattern.compile("v[0-9]+"); - Matcher m = pattern.matcher(requestContext); - if (!m.find()) { - return this.version; - } else { - return new SchemaVersion(requestContext); - } - } - - /** - * 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 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 { - final int internalDepth; - if (depth == Integer.MAX_VALUE) { - internalDepth = depth--; - } else { - internalDepth = depth; - } - StopWatch.conditionalStart(); - 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()); - } else if (obj.isContainer()) { - final List getList; - String listProperty = null; - for (String property : obj.getProperties()) { - if (obj.isListType(property) && obj.isComplexGenericType(property)) { - listProperty = property; - break; - } - } - final String propertyName = listProperty; - getList = (List)obj.getValue(listProperty); - - /* This is an experimental multithreading experiment - * on get alls. - */ - ExecutorService pool = GetAllPool.getInstance().getPool(); - - 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; - } - Tree<Element> tree = tgEngine.findSubGraph(v, internalDepth, nodeOnly); - TreeBackedVertex treeVertex = new TreeBackedVertex(v, tree); - try { - dbToObject(childObject, treeVertex, seen, internalDepth, nodeOnly, cleanUp); - } catch (UnsupportedEncodingException e) { - throw e; - } catch (AAIException e) { - throw e; - } - return childObject.getUnderlyingObject(); - //getList.add(childObject.getUnderlyingObject()); - } - }; - futures.add(pool.submit(task)); - } - - 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) { - dbTimeMsecs += StopWatch.stopIfStarted(); - throw new AAIException("AAI_4000", e); - } - } - } else if (vertices.size() == 1) { - Set<Vertex> seen = new HashSet<>(); - Tree<Element> tree = this.engine.getQueryEngine().findSubGraph(vertices.get(0), depth, nodeOnly); - TreeBackedVertex treeVertex = new TreeBackedVertex(vertices.get(0), tree); - dbToObject(obj, treeVertex, seen, depth, nodeOnly, cleanUp); - } else { - //obj = null; - } - - dbTimeMsecs += StopWatch.stopIfStarted(); - return obj; - } - - /** - * 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 { - - if (depth < 0) { - return null; - } - depth--; - seen.add(v); - - 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); - modified = true; - } else { - if (obj.isComplexType(property)) { - /* container case */ - - if (!property.equals("relationship-list") && depth >= 0) { - Introspector argumentObject = obj.newIntrospectorInstanceOfProperty(property); - Object result = dbToObject(argumentObject, v, seen, depth+1, nodeOnly, cleanUp); - if (result != null) { - obj.setValue(property, argumentObject.getUnderlyingObject()); - modified = true; - } - } else if (property.equals("relationship-list") && !nodeOnly){ - /* relationships need to be handled correctly */ - Introspector relationshipList = obj.newIntrospectorInstanceOfProperty(property); - relationshipList = createRelationshipList(v, relationshipList, cleanUp); - if (relationshipList != null) { - modified = true; - obj.setValue(property, relationshipList.getUnderlyingObject()); - modified = true; - } - - } - } else if (obj.isListType(property)) { - - if (property.equals("any")) { - continue; - } - String genericType = obj.getGenericTypeClass(property).getSimpleName(); - if (obj.isComplexGenericType(property) && depth >= 0) { - final String childDbName = convertFromCamelCase(genericType); - String vType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null); - EdgeRule rule; - - try { - rule = edgeRules.getRule(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); - } - int processed = 0; - int removed = 0; - while (itr.hasNext()) { - Vertex childVertex = itr.next(); - if (!seen.contains(childVertex)) { - Introspector argumentObject = obj.newIntrospectorInstanceOfNestedProperty(property); - - Object result = dbToObject(argumentObject, childVertex, seen, depth, nodeOnly, cleanUp); - if (result != null) { - getList.add(argumentObject.getUnderlyingObject()); - } - - processed++; - } else { - removed++; - LOGGER.warn("Cycle found while serializing vertex id={}", childVertex.id().toString()); - } - } - if (processed == 0) { - //vertices were all seen, reset the list - getList = null; - } - if (processed > 0) { - modified = true; - } - } - } else if (obj.isSimpleGenericType(property)) { - List<Object> temp = this.engine.getListProperty(v, property); - if (temp != null) { - getList = (List<Object>)obj.getValue(property); - getList.addAll(temp); - modified = true; - } - - } - - } - - } - } - - //no changes were made to this obj, discard the instance - if (!modified) { - return null; - } - this.enrichData(obj, v); - return obj; - - } - - - public Introspector getVertexProperties(Vertex v) 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 = 0; - String cleanUp = "false"; - boolean nodeOnly = true; - StopWatch.conditionalStart(); - this.dbToObject(obj, v, seen, depth, nodeOnly, cleanUp); - dbTimeMsecs += StopWatch.stopIfStarted(); - return obj; - - } - public Introspector getLatestVersionView(Vertex v) 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(); - Tree<Element> tree = this.engine.getQueryEngine().findSubGraph(v, depth, nodeOnly); - TreeBackedVertex treeVertex = new TreeBackedVertex(v, tree); - this.dbToObject(obj, treeVertex, seen, depth, nodeOnly, cleanUp); - dbTimeMsecs += StopWatch.stopIfStarted(); - return obj; - } - /** - * Copy simple property. - * - * @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) { - - 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 = v.<Object>property(dbPropertyName).orElse(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 property : obj.getProperties()) { - - - if (!(obj.isComplexType(property) || obj.isListType(property))) { - this.copySimpleProperty(property, obj, v); - } - } - } - - /** - * Creates the relationship list. - * - * @param v the v - * @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 { - - List<Vertex> cousins = this.engine.getQueryEngine().findCousinVertices(v); - - List<Object> relationshipObjList = obj.getValue("relationship"); - - for (Vertex cousin : cousins) { - if (obj.getVersion().compareTo(schemaVersions.getEdgeLabelVersion()) >= 0) { - List<Edge> edges = this.getEdgesBetween(EdgeType.COUSIN, v, cousin); - for (Edge e : edges) { - Introspector relationshipObj = obj.newIntrospectorInstanceOfNestedProperty("relationship"); - Object result = processEdgeRelationship(relationshipObj, cousin, cleanUp, e); - 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); - } - } - - } - - if (relationshipObjList.isEmpty()) { - return null; - } else { - return obj; - } - } - - /** - * Process edge relationship. - * - * @param relationshipObj the relationship obj - * @param edge the edge - * @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, Edge edge) throws UnsupportedEncodingException, AAIUnknownObjectException { - - - //we must look up all parents in this case because we need to compute name-properties - //we cannot used the cached aaiUri to perform this action currently - Optional<Pair<Vertex, List<Introspector>>> tuple = this.getParents(relationshipObj.getLoader(), cousin, "true".equals(cleanUp)); - //damaged vertex found, ignore - if (!tuple.isPresent()) { - return null; - } - List<Introspector> list = tuple.get().getValue1(); - URI uri = this.getURIFromList(list); - - URIToRelationshipObject uriParser = null; - Introspector result = null; - try { - uriParser = new URIToRelationshipObject(relationshipObj.getLoader(), uri, this.baseURL); - result = uriParser.getResult(); - } catch (AAIException | URISyntaxException e) { - LOGGER.error("Error while processing edge relationship in version " + relationshipObj.getVersion() + " (bad vertex ID=" + tuple.get().getValue0().id().toString() + ": " - + e.getMessage() + " " + LogFormatTools.getStackTop(e)); - if ("true".equals(cleanUp)) { - this.deleteWithTraversal(tuple.get().getValue0()); - } - return null; - } - if (!list.isEmpty()) { - this.addRelatedToProperty(result, list.get(0)); - } - - if (edge != null && result.hasProperty("relationship-label")) { - result.setValue("relationship-label", edge.label()); - } - - return result.getUnderlyingObject(); - } - - /** - * Gets the URI for vertex. - * - * @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 - */ - public URI getURIForVertex(Vertex v) throws UnsupportedEncodingException { - - return getURIForVertex(v, false); - } - - public URI getURIForVertex(Vertex v, boolean overwrite) throws UnsupportedEncodingException { - URI uri = UriBuilder.fromPath("/unknown-uri").build(); - - String aaiUri = v.<String>property(AAIProperties.AAI_URI).orElse(null); - - if (aaiUri != null && !overwrite) { - uri = UriBuilder.fromPath(aaiUri).build(); - } else { - StopWatch.conditionalStart(); - Optional<Pair<Vertex, List<Introspector>>> tuple = this.getParents(this.loader, v, false); - dbTimeMsecs += StopWatch.stopIfStarted(); - if (tuple.isPresent()) { - List<Introspector> list = tuple.get().getValue1(); - uri = this.getURIFromList(list); - } - - - } - 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(); - } - - /** - * Gets the parents. - * - * @param start the start - * @param removeDamaged the remove damaged - * @return the parents - * @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 AAIUnknownObjectException - */ - private Optional<Pair<Vertex, List<Introspector>>> getParents(Loader loader, Vertex start, boolean removeDamaged) { - - List<Vertex> results = this.engine.getQueryEngine().findParents(start); - List<Introspector> objs = new ArrayList<>(); - boolean shortCircuit = false; - for (Vertex v : results) { - String nodeType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null); - Introspector obj = null; - //vertex on the other end of this edge is bad - if (nodeType == null) { - //log something here about what was found and that it was removed - ErrorLogHelper.logError("AAI-6143", "Found a damaged parent vertex " + v.id().toString()); - if (removeDamaged) { - this.deleteWithTraversal(v); - } - shortCircuit = true; - } else { - try { - obj = loader.introspectorFromName(nodeType); - } catch (AAIUnknownObjectException e) { - LOGGER.info("attempted to create node type " + nodeType + " but we do not understand it for version: " + loader.getVersion()); - obj = null; - } - } - - if (obj == null) { - //can't make a valid path because we don't understand this object - // don't include it - } else { - this.simpleDbToObject(obj, v); - objs.add(obj); - } - } - - //stop processing and don't return anything for this bad vertex - if (shortCircuit) { - return Optional.empty(); - } - - return Optional.of(new Pair<>(results.get(results.size()-1), objs)); - } - - /** - * Adds the r - * @throws AAIUnknownObjectException - * @throws IllegalArgumentException elated to property. - * - * @param relationship the relationship - * @param child the throws IllegalArgumentException, AAIUnknownObjectException child - */ - public void addRelatedToProperty(Introspector relationship, Introspector child) throws AAIUnknownObjectException { - String nameProps = child.getMetadata(ObjectMetadata.NAME_PROPS); - List<Introspector> relatedToProperties = new ArrayList<>(); - - if (nameProps != null) { - String[] props = nameProps.split(","); - for (String prop : props) { - Introspector relatedTo = relationship.newIntrospectorInstanceOfNestedProperty("related-to-property"); - relatedTo.setValue("property-key", child.getDbName() + "." + prop); - relatedTo.setValue("property-value", child.getValue(prop)); - relatedToProperties.add(relatedTo); - } - } - - if (!relatedToProperties.isEmpty()) { - List relatedToList = (List)relationship.getValue("related-to-property"); - for (Introspector obj : relatedToProperties) { - relatedToList.add(obj.getUnderlyingObject()); - } - } - - } - - /** - * Creates the edge. - * - * @param relationship the relationship - * @param inputVertex the input vertex - * @return true, if successful - * @throws UnsupportedEncodingException the unsupported encoding exception - * @throws AAIException the AAI exception - */ - public boolean createEdge(Introspector relationship, Vertex inputVertex) throws UnsupportedEncodingException, AAIException { - - Vertex relatedVertex = null; - StopWatch.conditionalStart(); - QueryParser parser = engine.getQueryBuilder().createQueryFromRelationship(relationship); - - String label = null; - 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", "Node of type " + parser.getResultType() + ". Could not find object at: " + parser.getUri()); - e.getTemplateVars().add(parser.getResultType()); - e.getTemplateVars().add(parser.getUri().toString()); - throw e; - } else { - //still an issue if there's more than one - relatedVertex = results.get(0); - } - - if (relatedVertex != null) { - - Edge e; - try { - e = this.getEdgeBetween(EdgeType.COUSIN, inputVertex, relatedVertex, label); - if (e == null) { - edgeSer.addEdge(this.engine.asAdmin().getTraversalSource(), inputVertex, relatedVertex, label); - } else { - //attempted to link two vertexes already linked - } - } finally { - dbTimeMsecs += StopWatch.stopIfStarted(); - } - } - - dbTimeMsecs += StopWatch.stopIfStarted(); - return true; - } - - /** - * 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 between the vertexes with the label and type. - * - * @param aVertex the out vertex - * @param bVertex the in vertex - * @param label - * @return the edges between - * @throws AAIException the AAI exception - */ - private List<Edge> getEdgesBetween(EdgeType type, Vertex aVertex, Vertex bVertex, String label) throws AAIException { - - List<Edge> result = new ArrayList<>(); - - if (bVertex != null) { - String aType = aVertex.<String>property(AAIProperties.NODE_TYPE).value(); - String bType = bVertex.<String>property(AAIProperties.NODE_TYPE).value(); - EdgeRuleQuery q = new EdgeRuleQuery.Builder(aType, bType).edgeType(type).label(label).build(); - EdgeRule rule; - try { - rule = edgeRules.getRule(q); - } catch (EdgeRuleNotFoundException e) { - throw new NoEdgeRuleFoundException(e); - } catch (AmbiguousRuleChoiceException e) { - throw new MultipleEdgeRuleFoundException(e); - } - List<Edge> edges = this.getEdgesBetween(type, aVertex, bVertex); - for (Edge edge : edges) { - if (edge.label().equals(rule.getLabel())) { - result.add(edge); - } - } - } - - return result; - } - - /** - * Gets the edge between with the label and edge type. - * - * @param aVertex the out vertex - * @param bVertex the in vertex - * @param label - * @return the edge between - * @throws AAIException the AAI exception - * @throws NoEdgeRuleFoundException - */ - public Edge getEdgeBetween(EdgeType type, Vertex aVertex, Vertex bVertex, String label) throws AAIException { - - StopWatch.conditionalStart(); - if (bVertex != null) { - - List<Edge> edges = this.getEdgesBetween(type, aVertex, bVertex, label); - - if (!edges.isEmpty()) { - dbTimeMsecs += StopWatch.stopIfStarted(); - return edges.get(0); - } - - } - dbTimeMsecs += StopWatch.stopIfStarted(); - return null; - } - public Edge getEdgeBetween(EdgeType type, Vertex aVertex, Vertex bVertex) throws AAIException { - return this.getEdgeBetween(type, aVertex, bVertex, null); - } - - - /** - * Delete edge. - * - * @param relationship the relationship - * @param inputVertex the input vertex - * @return true, if successful - * @throws UnsupportedEncodingException the unsupported encoding exception - * @throws AAIException the AAI exception - */ - public boolean deleteEdge(Introspector relationship, Vertex inputVertex) throws UnsupportedEncodingException, AAIException { - - Vertex relatedVertex = null; - 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 (results.isEmpty()) { - dbTimeMsecs += StopWatch.stopIfStarted(); - return false; - } - - relatedVertex = results.get(0); - Edge edge; - try { - edge = this.getEdgeBetween(EdgeType.COUSIN, inputVertex, relatedVertex, label); - } catch (NoEdgeRuleFoundException e) { - dbTimeMsecs += StopWatch.stopIfStarted(); - throw new AAIException("AAI_6129", e); - } - if (edge != null) { - edge.remove(); - dbTimeMsecs += StopWatch.stopIfStarted(); - return true; - } 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) { + + private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(DBSerializer.class); + + private final TransactionalGraphEngine engine; + private final String sourceOfTruth; + private final ModelType introspectionType; + private final SchemaVersion version; + private final Loader latestLoader; + private EdgeSerializer edgeSer; + private EdgeIngestor edgeRules; + private final Loader loader; + private final String baseURL; + private double dbTimeMsecs = 0; + private long currentTimeMillis; + + private SchemaVersions schemaVersions; + private Set<String> namedPropNodes; + /** + * Instantiates a new DB serializer. + * + * @param version the version + * @param engine the engine + * @param introspectionType the introspection type + * @param sourceOfTruth the source of truth + * @throws AAIException + */ + public DBSerializer(SchemaVersion version, TransactionalGraphEngine engine, ModelType introspectionType, String sourceOfTruth) throws AAIException { + this.engine = engine; + this.sourceOfTruth = sourceOfTruth; + this.introspectionType = introspectionType; + this.schemaVersions = SpringContextAware.getBean(SchemaVersions.class); + SchemaVersion LATEST = schemaVersions.getDefaultVersion(); + this.latestLoader = SpringContextAware.getBean(LoaderFactory.class).createLoaderForVersion(introspectionType, LATEST); + 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(); + initBeans(); + } + + private void initBeans() { + //TODO proper spring wiring, but that requires a lot of refactoring so for now we have this + ApplicationContext ctx = SpringContextAware.getApplicationContext(); + EdgeIngestor ei = ctx.getBean(EdgeIngestor.class); + setEdgeIngestor(ei); + EdgeSerializer es = ctx.getBean(EdgeSerializer.class); + setEdgeSerializer(es); + } + + private void backupESInit() { + setEdgeSerializer(new EdgeSerializer(this.edgeRules)); + } + + public void setEdgeSerializer(EdgeSerializer edgeSer) { + this.edgeSer = edgeSer; + } + + public EdgeSerializer getEdgeSeriailizer() { + return this.edgeSer; + } + + public void setEdgeIngestor(EdgeIngestor ei) { + this.edgeRules = ei; + } + + public EdgeIngestor getEdgeIngestor() { + return this.edgeRules; + } + + /** + * Touch standard vertex properties. + * + * @param v the v + * @param isNewVertex the is new vertex + */ + public void touchStandardVertexProperties(Vertex v, boolean isNewVertex) { + String timeNowInSec = Long.toString(currentTimeMillis); + + if (isNewVertex) { + 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.RESOURCE_VERSION, timeNowInSec); + v.property(AAIProperties.LAST_MOD_TS, timeNowInSec); + v.property(AAIProperties.LAST_MOD_SOURCE_OF_TRUTH, this.sourceOfTruth); + + } + + private void touchStandardVertexProperties(String nodeType, Vertex v, boolean isNewVertex) { + + v.property(AAIProperties.NODE_TYPE, nodeType); + touchStandardVertexProperties(v, isNewVertex); + + } + + + /** + * Creates the new vertex. + * + * @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(); + touchStandardVertexProperties(wrappedObject.getDbName(), v, true); + } finally { + dbTimeMsecs += StopWatch.stopIfStarted(); + } + return v; + } + + /** + * Trim class name. + * + * @param className the class name + * @return the string + */ + /* + * Removes the classpath from a class name + */ + public String trimClassName(String className) { + String returnValue = ""; + + if (className.lastIndexOf('.') == -1) { + return className; + } + returnValue = className.substring(className.lastIndexOf('.') + 1, className.length()); + + return returnValue; + } + + /** + * Serialize to db. + * + * @param obj the obj + * @param v the v + * @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 { + StopWatch.conditionalStart(); + try { + if (uriQuery.isDependent()) { + //try to find the parent + List<Vertex> vertices = uriQuery.getQueryBuilder().getParentQuery().toList(); + if (!vertices.isEmpty()) { + Vertex parent = vertices.get(0); + this.reflectDependentVertex(parent, v, obj, requestContext); + } else { + dbTimeMsecs += StopWatch.stopIfStarted(); + throw new AAIException("AAI_6114", "No parent Node of type " + uriQuery.getParentResultType() + " for " + identifier); + } + } else { + serializeSingleVertex(v, obj, requestContext); + } + + } catch (SchemaViolationException e) { + dbTimeMsecs += StopWatch.stopIfStarted(); + throw new AAIException("AAI_6117", e); + } + dbTimeMsecs += StopWatch.stopIfStarted(); + } + + public void serializeSingleVertex(Vertex v, Introspector obj, String requestContext) throws UnsupportedEncodingException, AAIException { + StopWatch.conditionalStart(); + try { + boolean isTopLevel = obj.isTopLevel(); + if (isTopLevel) { + addUriIfNeeded(v, obj.getURI()); + } + + processObject(obj, v, requestContext); + if (!isTopLevel) { + URI uri = this.getURIForVertex(v); + URIParser parser = new URIParser(this.loader, uri); + if (parser.validate()) { + addUriIfNeeded(v, uri.toString()); + } + } + } catch (SchemaViolationException e) { + throw new AAIException("AAI_6117", e); + } finally { + dbTimeMsecs += StopWatch.stopIfStarted(); + } + } + + private void addUriIfNeeded(Vertex v, String uri) { + VertexProperty<String> uriProp = v.property(AAIProperties.AAI_URI); + if (!uriProp.isPresent() || (uriProp.isPresent() && !uriProp.value().equals(uri))) { + v.property(AAIProperties.AAI_URI, uri); + } + } + + /** + * 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) 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(obj.getDbName(), 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); + + if (!(isComplexType || isListType)) { + boolean canModify = this.canModify(obj, property, requestContext); + + if (canModify) { + final Map<PropertyMetadata, String> metadata = obj.getPropertyMetadata(property); + String dbProperty = property; + if (metadata.containsKey(PropertyMetadata.DB_ALIAS)) { + dbProperty = metadata.get(PropertyMetadata.DB_ALIAS); + } + if (metadata.containsKey(PropertyMetadata.DATA_LINK)) { + //data linked properties are ephemeral + //they are populated dynamically on GETs + continue; + } + if (value != null) { + if (!value.equals(v.property(dbProperty).orElse(null))) { + if (propertyType.toLowerCase().contains(".long")) { + v.property(dbProperty, new Integer(((Long) value).toString())); + } else { + v.property(dbProperty, value); + } + } + } else { + v.property(dbProperty).remove(); + } + } + } else if (isListType) { + List<Object> list = (List<Object>) value; + if (obj.isComplexGenericType(property)) { + if (list != null) { + for (Object o : list) { + Introspector child = IntrospectorFactory.newInstance(this.introspectionType, o); + child.setURIChain(obj.getURI()); + processedVertexes.add(reflectDependentVertex(v, child, requestContext)); + } + } + } else { + //simple list case + engine.setListProperty(v, property, list); + } + } else { + //method.getReturnType() is not 'simple' then create a vertex and edge recursively returning an edge back to this method + if (value != null) { //effectively ignore complex properties not included in the object we're processing + if (value.getClass().isArray()) { + + int length = Array.getLength(value); + for (int i = 0; i < length; i++) { + Object arrayElement = Array.get(value, i); + Introspector child = IntrospectorFactory.newInstance(this.introspectionType, arrayElement); + child.setURIChain(obj.getURI()); + processedVertexes.add(reflectDependentVertex(v, child, requestContext)); + + } + } else if (!property.equals("relationship-list")) { + // container case + Introspector introspector = IntrospectorFactory.newInstance(this.introspectionType, value); + if (introspector.isContainer()) { + dependentVertexes.addAll(this.engine.getQueryEngine().findChildrenOfType(v, introspector.getChildDBName())); + introspector.setURIChain(obj.getURI()); + + processedVertexes.addAll(processObject(introspector, v, requestContext)); + + } else { + dependentVertexes.addAll(this.engine.getQueryEngine().findChildrenOfType(v, introspector.getDbName())); + processedVertexes.add(reflectDependentVertex(v, introspector, requestContext)); + + } + } else if (property.equals("relationship-list")) { + handleRelationships(obj, v); + } + } + } + } + this.writeThroughDefaults(v, obj); + /* handle those vertexes not touched */ + for (Vertex toBeRemoved : processedVertexes) { + dependentVertexes.remove(toBeRemoved); + } + this.deleteItemsWithTraversal(dependentVertexes); + + this.executePostSideEffects(obj, v); + return processedVertexes; + } + + /** + * Handle relationships. + * + * @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 + */ + /* + * Handles the explicit relationships defined for an obj + */ + private void handleRelationships(Introspector obj, Vertex vertex) throws UnsupportedEncodingException, AAIException { + + + Introspector wrappedRl = obj.getWrappedValue("relationship-list"); + processRelationshipList(wrappedRl, vertex); + + + } + + + /** + * Process relationship list. + * + * @param wrapped the wrapped + * @param v the v + * @throws UnsupportedEncodingException the unsupported encoding exception + * @throws AAIException the AAI exception + */ + private void processRelationshipList(Introspector wrapped, Vertex v) throws UnsupportedEncodingException, AAIException { + + 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()); + + for (Object relationship : relationships) { + Edge e = null; + Vertex cousinVertex = null; + String label = null; + Introspector wrappedRel = IntrospectorFactory.newInstance(this.introspectionType, relationship); + QueryParser parser = engine.getQueryBuilder().createQueryFromRelationship(wrappedRel); + + if (wrappedRel.hasProperty("relationship-label")) { + label = wrappedRel.getValue("relationship-label"); + } + + 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()); + ex.getTemplateVars().add(parser.getResultType()); + ex.getTemplateVars().add(parser.getUri().toString()); + throw ex; + } else { + //still an issue if there's more than one + cousinVertex = results.get(0); + } + + if (cousinVertex != null) { + String vType = (String) v.property(AAIProperties.NODE_TYPE).value(); + String cousinType = (String) cousinVertex.property(AAIProperties.NODE_TYPE).value(); + 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) : "") + "."); + } else if (edgeRules.hasRule(baseQ.edgeType(EdgeType.TREE).build()) && !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); + } + } + } + + for (Edge edge : existingEdges) { + edge.remove(); + } + for (Triplet<Vertex, Vertex, String> triplet : addEdges) { + try { + edgeSer.addEdge(this.engine.asAdmin().getTraversalSource(), triplet.getValue0(), triplet.getValue1(), triplet.getValue2()); + } catch (NoEdgeRuleFoundException e) { + throw new AAIException("AAI_6129", e); + } + } + + } + + /** + * Write through defaults. + * + * @param v the v + * @param obj the obj + * @throws AAIUnknownObjectException + */ + private void writeThroughDefaults(Vertex v, Introspector obj) throws AAIUnknownObjectException { + Introspector latest = this.latestLoader.introspectorFromName(obj.getName()); + if (latest != null) { + Set<String> required = latest.getRequiredProperties(); + + for (String field : required) { + String defaultValue = null; + Object vertexProp = null; + defaultValue = latest.getPropertyMetadata(field).get(PropertyMetadata.DEFAULT_VALUE); + if (defaultValue != null) { + vertexProp = v.<Object>property(field).orElse(null); + if (vertexProp == null) { + v.property(field, defaultValue); + } + } + } + } + + } + + + /** + * Reflect dependent vertex. + * + * @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 + * @throws AAIUnknownObjectException + */ + 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; + 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()); + } else { + this.verifyResourceVersion("create", dependentObj.getDbName(), "", (String) dependentObj.getValue(AAIProperties.RESOURCE_VERSION), (String) dependentObj.getURI()); + dependentVertex = createNewVertex(dependentObj); + } + + return reflectDependentVertex(v, dependentVertex, dependentObj, requestContext); + + } + + /** + * Reflect dependent vertex. + * + * @param parent the parent + * @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 + * @throws AAIUnknownObjectException + */ + private Vertex reflectDependentVertex(Vertex parent, Vertex child, Introspector obj, String requestContext) throws AAIException, UnsupportedEncodingException { + + String parentUri = parent.<String>property(AAIProperties.AAI_URI).orElse(null); + if (parentUri != null) { + String uri; + uri = obj.getURI(); + addUriIfNeeded(child, parentUri + uri); + } + processObject(obj, child, requestContext); + + Edge e; + e = this.getEdgeBetween(EdgeType.TREE, parent, child, null); + + if (e == null) { + String canBeLinked = obj.getMetadata(ObjectMetadata.CAN_BE_LINKED); + if (canBeLinked != null && canBeLinked.equals("true")) { + Loader ldrForCntxt = SpringContextAware.getBean(LoaderFactory.class).createLoaderForVersion(introspectionType, getVerForContext(requestContext)); + boolean isFirst = !this.engine.getQueryBuilder(ldrForCntxt, parent).createEdgeTraversal(EdgeType.TREE, parent, obj).hasNext(); + if (isFirst) { + child.property(AAIProperties.LINKED, true); + } + } + edgeSer.addTreeEdge(this.engine.asAdmin().getTraversalSource(), parent, child); + } + return child; + + } + + private SchemaVersion getVerForContext(String requestContext) { + Pattern pattern = Pattern.compile("v[0-9]+"); + Matcher m = pattern.matcher(requestContext); + if (!m.find()) { + return this.version; + } else { + return new SchemaVersion(requestContext); + } + } + + /** + * 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 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 { + final int internalDepth; + if (depth == Integer.MAX_VALUE) { + internalDepth = depth--; + } else { + internalDepth = depth; + } + StopWatch.conditionalStart(); + 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()); + } else if (obj.isContainer()) { + final List getList; + String listProperty = null; + for (String property : obj.getProperties()) { + if (obj.isListType(property) && obj.isComplexGenericType(property)) { + listProperty = property; + break; + } + } + final String propertyName = listProperty; + getList = (List) obj.getValue(listProperty); + + /* This is an experimental multithreading experiment + * on get alls. + */ + ExecutorService pool = GetAllPool.getInstance().getPool(); + + 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; + } + return childObject.getUnderlyingObject(); + //getList.add(childObject.getUnderlyingObject()); + } + }; + futures.add(pool.submit(task)); + } + + 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) { + 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); + } else { + //obj = null; + } + + dbTimeMsecs += StopWatch.stopIfStarted(); + return obj; + } + + /** + * 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 { + + if (depth < 0) { + return null; + } + depth--; + seen.add(v); + + 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); + modified = true; + } else { + if (obj.isComplexType(property)) { + /* container case */ + + if (!property.equals("relationship-list") && depth >= 0) { + Introspector argumentObject = obj.newIntrospectorInstanceOfProperty(property); + Object result = dbToObject(argumentObject, v, seen, depth + 1, nodeOnly, cleanUp); + if (result != null) { + obj.setValue(property, argumentObject.getUnderlyingObject()); + modified = true; + } + } else if (property.equals("relationship-list") && !nodeOnly) { + /* relationships need to be handled correctly */ + Introspector relationshipList = obj.newIntrospectorInstanceOfProperty(property); + relationshipList = createRelationshipList(v, relationshipList, cleanUp); + if (relationshipList != null) { + modified = true; + obj.setValue(property, relationshipList.getUnderlyingObject()); + modified = true; + } + + } + } else if (obj.isListType(property)) { + + if (property.equals("any")) { + continue; + } + String genericType = obj.getGenericTypeClass(property).getSimpleName(); + if (obj.isComplexGenericType(property) && depth >= 0) { + final String childDbName = convertFromCamelCase(genericType); + String vType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null); + EdgeRule rule; + + try { + rule = edgeRules.getRule(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); + } + int processed = 0; + int removed = 0; + while (itr.hasNext()) { + Vertex childVertex = itr.next(); + if (!seen.contains(childVertex)) { + Introspector argumentObject = obj.newIntrospectorInstanceOfNestedProperty(property); + + Object result = dbToObject(argumentObject, childVertex, seen, depth, nodeOnly, cleanUp); + if (result != null) { + getList.add(argumentObject.getUnderlyingObject()); + } + + processed++; + } else { + removed++; + LOGGER.warn("Cycle found while serializing vertex id={}", childVertex.id().toString()); + } + } + if (processed == 0) { + //vertices were all seen, reset the list + getList = null; + } + if (processed > 0) { + modified = true; + } + } + } else if (obj.isSimpleGenericType(property)) { + List<Object> temp = this.engine.getListProperty(v, property); + if (temp != null) { + getList = (List<Object>) obj.getValue(property); + getList.addAll(temp); + modified = true; + } + + } + + } + + } + } + + //no changes were made to this obj, discard the instance + if (!modified) { + return null; + } + this.enrichData(obj, v); + return obj; + + } + + + public Introspector getVertexProperties(Vertex v) 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 = 0; + String cleanUp = "false"; + boolean nodeOnly = true; + StopWatch.conditionalStart(); + this.dbToObject(obj, v, seen, depth, nodeOnly, cleanUp); + dbTimeMsecs += StopWatch.stopIfStarted(); + return obj; + + } + + public Introspector getLatestVersionView(Vertex v) 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(); + Tree<Element> tree = this.engine.getQueryEngine().findSubGraph(v, depth, nodeOnly); + TreeBackedVertex treeVertex = new TreeBackedVertex(v, tree); + this.dbToObject(obj, treeVertex, seen, depth, nodeOnly, cleanUp); + dbTimeMsecs += StopWatch.stopIfStarted(); + return obj; + } + + /** + * Copy simple property. + * + * @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) { + + 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 = v.<Object>property(dbPropertyName).orElse(null); + if (temp != null) { + obj.setValue(property, temp); + } + } + + + /** + * 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())); + + return simplePropsHashMap; + } + + /** + * Creates the relationship list. + * + * @param v the v + * @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 { + + 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); + } + + List<Object> relationshipObjList = obj.getValue("relationship"); + String aNodeType = v.property("aai-node-type").value().toString(); + + TypeAlphabetizer alphabetizer = new TypeAlphabetizer(); + + 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("aai-node-type"); + String bNodeType = null; + if(vertexProperty.isPresent()){ + bNodeType = cousin.property("aai-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 + 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"); + } + 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; + + // 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 + + EdgeRuleQuery ruleQuery = queryBuilder + .to(bNodeType) + .edgeType(EdgeType.COUSIN) + .version(obj.getVersion()) + .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; + } + + 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); + } + } + + } + + if (relationshipObjList.isEmpty()) { + return null; + } else { + return obj; + } + } + + /** + * Process edge relationship. + * + * @param relationshipObj the relationship obj + * @param edge the edge + * @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 { + + VertexProperty aaiUriProperty = cousin.property("aai-uri"); + + if(!aaiUriProperty.isPresent()){ + return null; + } + + URI uri = UriBuilder.fromUri(aaiUriProperty.value().toString()).build(); + + URIToRelationshipObject uriParser = null; + Introspector result = null; + try { + uriParser = new URIToRelationshipObject(relationshipObj.getLoader(), uri, this.baseURL); + result = uriParser.getResult(); + } catch (AAIException | URISyntaxException e) { + LOGGER.error("Error while processing edge relationship in version " + relationshipObj.getVersion() + " (bad vertex ID=" + ": " + + e.getMessage() + " " + LogFormatTools.getStackTop(e)); + return null; + } + + VertexProperty cousinVertexNodeType = cousin.property(AAIProperties.NODE_TYPE); + + if(cousinVertexNodeType.isPresent()){ + if(namedPropNodes.contains(cousinVertexNodeType.value().toString())){ + Introspector cousinObj = loader.introspectorFromName(cousinVertexNodeType.value().toString()); + this.simpleDbToObject(cousinObj, cousin); + this.addRelatedToProperty(result, cousinObj); + } + } + + if (edgeLabel != null && result.hasProperty("relationship-label")) { + result.setValue("relationship-label", edgeLabel); + } + + return result.getUnderlyingObject(); + } + + /** + * Gets the URI for vertex. + * + * @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 + */ + public URI getURIForVertex(Vertex v) throws UnsupportedEncodingException { + + return getURIForVertex(v, false); + } + + public URI getURIForVertex(Vertex v, boolean overwrite) throws UnsupportedEncodingException { + URI uri = UriBuilder.fromPath("/unknown-uri").build(); + + String aaiUri = v.<String>property(AAIProperties.AAI_URI).orElse(null); + + if (aaiUri != null && !overwrite) { + uri = UriBuilder.fromPath(aaiUri).build(); + } + + 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(); + } + + /** + * Adds the r + * + * @param relationship the relationship + * @param child the throws IllegalArgumentException, AAIUnknownObjectException child + * @throws AAIUnknownObjectException + * @throws IllegalArgumentException elated to property. + */ + public void addRelatedToProperty(Introspector relationship, Introspector child) throws AAIUnknownObjectException { + String nameProps = child.getMetadata(ObjectMetadata.NAME_PROPS); + List<Introspector> relatedToProperties = new ArrayList<>(); + + if (nameProps != null) { + String[] props = nameProps.split(","); + for (String prop : props) { + Introspector relatedTo = relationship.newIntrospectorInstanceOfNestedProperty("related-to-property"); + relatedTo.setValue("property-key", child.getDbName() + "." + prop); + relatedTo.setValue("property-value", child.getValue(prop)); + relatedToProperties.add(relatedTo); + } + } + + if (!relatedToProperties.isEmpty()) { + List relatedToList = (List) relationship.getValue("related-to-property"); + for (Introspector obj : relatedToProperties) { + relatedToList.add(obj.getUnderlyingObject()); + } + } + + } + + /** + * Creates the edge. + * + * @param relationship the relationship + * @param inputVertex the input vertex + * @return true, if successful + * @throws UnsupportedEncodingException the unsupported encoding exception + * @throws AAIException the AAI exception + */ + public boolean createEdge(Introspector relationship, Vertex inputVertex) throws UnsupportedEncodingException, AAIException { + + Vertex relatedVertex = null; + StopWatch.conditionalStart(); + QueryParser parser = engine.getQueryBuilder().createQueryFromRelationship(relationship); + + String label = null; + 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", "Node of type " + parser.getResultType() + ". Could not find object at: " + parser.getUri()); + e.getTemplateVars().add(parser.getResultType()); + e.getTemplateVars().add(parser.getUri().toString()); + throw e; + } else { + //still an issue if there's more than one + relatedVertex = results.get(0); + } + + if (relatedVertex != null) { + + Edge e; + try { + e = this.getEdgeBetween(EdgeType.COUSIN, inputVertex, relatedVertex, label); + if (e == null) { + edgeSer.addEdge(this.engine.asAdmin().getTraversalSource(), inputVertex, relatedVertex, label); + } else { + //attempted to link two vertexes already linked + } + } finally { + dbTimeMsecs += StopWatch.stopIfStarted(); + } + } + + dbTimeMsecs += StopWatch.stopIfStarted(); + return true; + } + + /** + * Gets all the edges between of the type with the specified label. + * + * @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) { + + Edge result = null; + + if (bVertex != null) { + GraphTraversal<Vertex, Edge> findEdgesBetween = null; + if (EdgeType.TREE.equals(type)) { + GraphTraversal<Vertex,Vertex> findVertex = this.engine.asAdmin().getTraversalSource().V(bVertex); + if(edgeRule.getDirection().equals(Direction.IN)){ + findEdgesBetween = findVertex.outE(edgeRule.getLabel()) + .has(EdgeProperty.CONTAINS.toString(), edgeRule.getContains()) + .not( + __.has(EdgeField.PRIVATE.toString(), true) + ); + } else { + findEdgesBetween = findVertex.inE(edgeRule.getLabel()) + .has(EdgeProperty.CONTAINS.toString(), edgeRule.getContains()) + .not( + __.has(EdgeField.PRIVATE.toString(), true) + ); + } + findEdgesBetween = findEdgesBetween.filter(__.otherV().hasId(aVertex.id())).limit(1); + } else { + findEdgesBetween = this.engine.asAdmin().getTraversalSource().V(aVertex).bothE(edgeRule.getLabel()); + findEdgesBetween = findEdgesBetween + .has(EdgeProperty.CONTAINS.toString(), "NONE") + .not( + __.has(EdgeField.PRIVATE.toString(), true) + ); + findEdgesBetween = findEdgesBetween.filter(__.otherV().hasId(bVertex.id())).limit(1); + } + List<Edge> list = findEdgesBetween.toList(); + if(!list.isEmpty()){ + result = list.get(0); + } + } + + return result; + } + + /** + * 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) { + + List<String> 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.label().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 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 + * @param bVertex the in vertex + * @param label + * @return the edges between + * @throws AAIException the AAI exception + */ + private Edge getEdgesBetween(EdgeType type, Vertex aVertex, Vertex bVertex, String label) throws AAIException { + + Edge edge = null; + + if (bVertex != null) { + String aType = aVertex.<String>property(AAIProperties.NODE_TYPE).value(); + String bType = bVertex.<String>property(AAIProperties.NODE_TYPE).value(); + EdgeRuleQuery q = new EdgeRuleQuery.Builder(aType, bType).edgeType(type).label(label).build(); + EdgeRule rule; + try { + rule = edgeRules.getRule(q); + } catch (EdgeRuleNotFoundException e) { + throw new NoEdgeRuleFoundException(e); + } catch (AmbiguousRuleChoiceException e) { + throw new MultipleEdgeRuleFoundException(e); + } + edge = this.getEdgeBetweenWithLabel(type, aVertex, bVertex, rule); + } + + return edge; + } + + /** + * Gets the edge between with the label and edge type. + * + * @param aVertex the out vertex + * @param bVertex the in vertex + * @param label + * @return the edge between + * @throws AAIException the AAI exception + * @throws NoEdgeRuleFoundException + */ + public Edge getEdgeBetween(EdgeType type, Vertex aVertex, Vertex bVertex, String label) throws AAIException { + + StopWatch.conditionalStart(); + if (bVertex != null) { + + Edge edge = this.getEdgesBetween(type, aVertex, bVertex, label); + if (edge != null) { + dbTimeMsecs += StopWatch.stopIfStarted(); + return edge; + } + + } + dbTimeMsecs += StopWatch.stopIfStarted(); + return null; + } + + public Edge getEdgeBetween(EdgeType type, Vertex aVertex, Vertex bVertex) throws AAIException { + return this.getEdgeBetween(type, aVertex, bVertex, null); + } + + + /** + * Delete edge. + * + * @param relationship the relationship + * @param inputVertex the input vertex + * @return true, if successful + * @throws UnsupportedEncodingException the unsupported encoding exception + * @throws AAIException the AAI exception + */ + public boolean deleteEdge(Introspector relationship, Vertex inputVertex) throws UnsupportedEncodingException, AAIException { + + Vertex relatedVertex = null; + 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 (results.isEmpty()) { + dbTimeMsecs += StopWatch.stopIfStarted(); + return false; + } + + relatedVertex = results.get(0); + Edge edge; + try { + edge = this.getEdgeBetween(EdgeType.COUSIN, inputVertex, relatedVertex, label); + } catch (NoEdgeRuleFoundException e) { + dbTimeMsecs += StopWatch.stopIfStarted(); + throw new AAIException("AAI_6129", e); + } + if (edge != null) { + edge.remove(); + dbTimeMsecs += StopWatch.stopIfStarted(); + return true; + } 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) { LOGGER.debug("About to delete the vertex with id: " + v.id()); - deleteWithTraversal(v); - } - - } - - /** - * Delete with traversal. - * - * @param startVertex the start vertex - */ - public void deleteWithTraversal(Vertex startVertex) { - StopWatch.conditionalStart(); - List<Vertex> results = this.engine.getQueryEngine().findDeletable(startVertex); - - for (Vertex v : results) { - LOGGER.warn("Removing vertex " + v.id().toString()); - - v.remove(); - } - dbTimeMsecs += StopWatch.stopIfStarted(); - } - - /** - * Delete. - * - * @param v the v - * @param resourceVersion the resource version - * @throws IllegalArgumentException the illegal argument exception - * @throws AAIException the AAI exception - * @throws InterruptedException the interrupted exception - */ - public void delete(Vertex v, List<Vertex> deletableVertices, String resourceVersion, boolean enableResourceVersion) throws IllegalArgumentException, AAIException { - - 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 - * So its better to make these in 2 steps - */ - if(result && !deletableVertices.isEmpty()){ - result = verifyPreventDeleteSemantics(deletableVertices); - } - if (result) { - - try { - deleteWithTraversal(v); - } catch (IllegalStateException e) { - throw new AAIException("AAI_6110", e); - } - - } - - } - - - /** - * Delete. - * - * @param v the v - * @param resourceVersion the resource version - * @throws IllegalArgumentException the illegal argument exception - * @throws AAIException the AAI exception - * @throws InterruptedException the interrupted exception - */ - public void delete(Vertex v, String resourceVersion, boolean enableResourceVersion) throws IllegalArgumentException, AAIException { - - boolean result = verifyDeleteSemantics(v, resourceVersion, enableResourceVersion); - - if (result) { - - try { - deleteWithTraversal(v); - } catch (IllegalStateException e) { - throw new AAIException("AAI_6110", e); - } - - } - - } - /** - * Verify delete semantics. - * - * @param vertex the vertex - * @param resourceVersion the resource version - * @return true, if successful - * @throws AAIException the AAI exception - */ - private boolean verifyDeleteSemantics(Vertex vertex, String resourceVersion, boolean enableResourceVersion) throws AAIException { - boolean result = true; - String nodeType = ""; - String errorDetail = " unknown delete semantic found"; - String aaiExceptionCode = ""; - 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)) { - } - List<Vertex> vertices = new ArrayList<Vertex>(); - vertices.add(vertex); - result = verifyPreventDeleteSemantics(vertices); - - return result; - } - - /** - * Verify Prevent delete semantics. - * @param vertices the list of vertices - * @return true, if successful - * @throws AAIException the AAI exception - */ - private boolean verifyPreventDeleteSemantics(List<Vertex> vertices) throws AAIException { - boolean result = true; - String nodeType = ""; - String errorDetail = " unknown delete semantic found"; - String aaiExceptionCode = ""; - - StopWatch.conditionalStart(); - /* - * This takes in all the vertices in a cascade-delete-chain and checks if there is any edge with a "prevent-delete" condition - * If yes - that should prevent the deletion of the vertex - * Dedup makes sure we dont capture the prevent-delete vertices twice - * The prevent-delete vertices are stored so that the error message displays what prevents the delete - */ - - List<Object> preventDeleteVertices = this.engine.asAdmin().getReadOnlyTraversalSource().V(vertices). - union(__.inE().has(EdgeProperty.PREVENT_DELETE.toString(), AAIDirection.IN.toString()).outV().values(AAIProperties.NODE_TYPE), - __.outE().has(EdgeProperty.PREVENT_DELETE.toString(), AAIDirection.OUT.toString()).inV().values(AAIProperties.NODE_TYPE)) - .dedup().toList(); - - dbTimeMsecs += StopWatch.stopIfStarted(); - if (!preventDeleteVertices.isEmpty()) { - aaiExceptionCode = "AAI_6110"; - errorDetail = String.format("Object is being reference by additional objects preventing it from being deleted. Please clean up references from the following types %s", preventDeleteVertices); - result = false; - } - if (!result) { - throw new AAIException(aaiExceptionCode, errorDetail); - } - return result; - } - - /** - * Verify resource version. - * - * @param action the action - * @param nodeType the node type - * @param currentResourceVersion the current resource version - * @param resourceVersion the resource version - * @param uri the uri - * @return true, if successful - * @throws AAIException the AAI exception - */ - public boolean verifyResourceVersion(String action, String nodeType, String currentResourceVersion, String resourceVersion, String uri) throws AAIException { - String enabled = ""; - String errorDetail = ""; - String aaiExceptionCode = ""; - if (currentResourceVersion == null) { - currentResourceVersion = ""; - } - - if (resourceVersion == null) { - resourceVersion = ""; - } - try { - enabled = AAIConfig.get(AAIConstants.AAI_RESVERSION_ENABLEFLAG); - } catch (AAIException e) { - ErrorLogHelper.logException(e); - } - if (enabled.equals("true")) { - if (!currentResourceVersion.equals(resourceVersion)) { - if (action.equals("create") && !resourceVersion.equals("")) { - errorDetail = "resource-version passed for " + action + " of " + uri; - aaiExceptionCode = "AAI_6135"; - } else if (resourceVersion.equals("")) { - errorDetail = "resource-version not passed for " + action + " of " + uri; - aaiExceptionCode = "AAI_6130"; - } else { - errorDetail = "resource-version MISMATCH for " + action + " of " + uri; - aaiExceptionCode = "AAI_6131"; - } - - throw new AAIException(aaiExceptionCode, errorDetail); - - } - } - return true; - } - - /** - * Convert from camel case. - * - * @param name the name - * @return the string - */ - private String convertFromCamelCase (String name) { - String result = ""; - result = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, name); - - NamingExceptions exceptions = NamingExceptions.getInstance(); - result = exceptions.getDBName(result); - - return result; - } - - private boolean canModify(Introspector obj, String propName, String requestContext) { - final String readOnly = obj.getPropertyMetadata(propName).get(PropertyMetadata.READ_ONLY); - if (readOnly != null) { - final String[] items = readOnly.split(","); - for (String item : items) { - if (requestContext.equals(item)) { - return false; - } - } - } - return true; - } - - private void executePreSideEffects(Introspector obj, Vertex self) throws AAIException { - - SideEffectRunner runner = new SideEffectRunner - .Builder(this.engine, this).addSideEffect(DataCopy.class).addSideEffect(PrivateEdge.class).build(); - - runner.execute(obj, self); - } - - private void executePostSideEffects(Introspector obj, Vertex self) throws AAIException { - - SideEffectRunner runner = new SideEffectRunner - .Builder(this.engine, this).addSideEffect(DataLinkWriter.class).build(); - - runner.execute(obj, self); - } - - private void enrichData(Introspector obj, Vertex self) throws AAIException { - - SideEffectRunner runner = new SideEffectRunner - .Builder(this.engine, this).addSideEffect(DataLinkReader.class).build(); - - runner.execute(obj, self); - } - - public double getDBTimeMsecs() { - return (dbTimeMsecs); - } - - /** - * 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 - * @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 - */ - //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) throws AAIException, UnsupportedEncodingException { - String cleanUp = "false"; - if (depth < 0) { - return null; - } - depth--; - seen.add(v); - 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); - modified = true; - } else { - if (obj.isComplexType(property)) { - /* container case */ - - if (!property.equals("relationship-list") && depth >= 0) { - Introspector argumentObject = obj.newIntrospectorInstanceOfProperty(property); - Object result = dbToObjectWithFilters(argumentObject, v, seen, depth+1, nodeOnly, filterCousinNodes, filterParentNodes); - if (result != null) { - obj.setValue(property, argumentObject.getUnderlyingObject()); - modified = true; - } - } else if (property.equals("relationship-list") && !nodeOnly){ - /* relationships need to be handled correctly */ - Introspector relationshipList = obj.newIntrospectorInstanceOfProperty(property); - relationshipList = createFilteredRelationshipList(v, relationshipList, cleanUp, filterCousinNodes); - if (relationshipList != null) { - modified = true; - obj.setValue(property, relationshipList.getUnderlyingObject()); - modified = true; - } - - } - } else if (obj.isListType(property)) { - - if (property.equals("any")) { - continue; - } - String genericType = obj.getGenericTypeClass(property).getSimpleName(); - if (obj.isComplexGenericType(property) && depth >= 0) { - final String childDbName = convertFromCamelCase(genericType); - String vType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null); - EdgeRule rule; - - boolean isthisParentRequired = filterParentNodes.parallelStream().anyMatch(childDbName::contains); - - EdgeRuleQuery q = new EdgeRuleQuery.Builder(vType, childDbName).edgeType(EdgeType.TREE).build(); - - try { - rule = edgeRules.getRule(q); - } catch (EdgeRuleNotFoundException e) { - throw new NoEdgeRuleFoundException(e); - } 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); - 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); - } - int processed = 0; - int removed = 0; - while (itr.hasNext()) { - Vertex childVertex = itr.next(); - if (!seen.contains(childVertex)) { - Introspector argumentObject = obj.newIntrospectorInstanceOfNestedProperty(property); - - Object result = dbToObjectWithFilters(argumentObject, childVertex, seen, depth, nodeOnly, filterCousinNodes, filterParentNodes); - if (result != null) { - getList.add(argumentObject.getUnderlyingObject()); - } - - processed++; - } else { - removed++; - LOGGER.warn("Cycle found while serializing vertex id={}", childVertex.id().toString()); - } - } - if (processed == 0) { - //vertices were all seen, reset the list - getList = null; - } - if (processed > 0) { - modified = true; - } - } - } else if (obj.isSimpleGenericType(property)) { - List<Object> temp = this.engine.getListProperty(v, property); - if (temp != null) { - getList = (List<Object>)obj.getValue(property); - getList.addAll(temp); - modified = true; - } - - } - - } - - } - } - - //no changes were made to this obj, discard the instance - if (!modified) { - return null; - } - this.enrichData(obj, v); - return obj; - - } - - /** - * Creates the relationship list with the filtered node types. - * - * @param v the v - * @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<Vertex> allCousins = this.engine.getQueryEngine().findCousinVertices(v); - - Iterator<Vertex> cousinVertices = allCousins.stream().filter(item -> { - String node = (String)item.property(AAIProperties.NODE_TYPE).orElse(""); - return filterNodes.parallelStream().anyMatch(node::contains); - }).iterator(); - - - List<Vertex> cousins = (List<Vertex>)IteratorUtils.toList(cousinVertices); - - //items.parallelStream().anyMatch(inputStr::contains) - List<Object> relationshipObjList = obj.getValue("relationship"); - for (Vertex cousin : cousins) { - - Introspector relationshipObj = obj.newIntrospectorInstanceOfNestedProperty("relationship"); - Object result = processEdgeRelationship(relationshipObj, cousin, cleanUp, null); - if (result != null) { - relationshipObjList.add(result); - } - - - } - - if (relationshipObjList.isEmpty()) { - return null; - } else { - return obj; - } - } + deleteWithTraversal(v); + } + + } + + /** + * Delete with traversal. + * + * @param startVertex the start vertex + */ + public void deleteWithTraversal(Vertex startVertex) { + StopWatch.conditionalStart(); + List<Vertex> results = this.engine.getQueryEngine().findDeletable(startVertex); + + for (Vertex v : results) { + LOGGER.warn("Removing vertex " + v.id().toString()); + + v.remove(); + } + dbTimeMsecs += StopWatch.stopIfStarted(); + } + + /** + * Delete. + * + * @param v the v + * @param resourceVersion the resource version + * @throws IllegalArgumentException the illegal argument exception + * @throws AAIException the AAI exception + * @throws InterruptedException the interrupted exception + */ + public void delete(Vertex v, List<Vertex> deletableVertices, String resourceVersion, boolean enableResourceVersion) throws IllegalArgumentException, AAIException { + + 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 + * So its better to make these in 2 steps + */ + if (result && !deletableVertices.isEmpty()) { + result = verifyPreventDeleteSemantics(deletableVertices); + } + if (result) { + + try { + deleteWithTraversal(v); + } catch (IllegalStateException e) { + throw new AAIException("AAI_6110", e); + } + + } + + } + + + /** + * Delete. + * + * @param v the v + * @param resourceVersion the resource version + * @throws IllegalArgumentException the illegal argument exception + * @throws AAIException the AAI exception + * @throws InterruptedException the interrupted exception + */ + public void delete(Vertex v, String resourceVersion, boolean enableResourceVersion) throws IllegalArgumentException, AAIException { + + boolean result = verifyDeleteSemantics(v, resourceVersion, enableResourceVersion); + + if (result) { + + try { + deleteWithTraversal(v); + } catch (IllegalStateException e) { + throw new AAIException("AAI_6110", e); + } + + } + + } + + /** + * Verify delete semantics. + * + * @param vertex the vertex + * @param resourceVersion the resource version + * @return true, if successful + * @throws AAIException the AAI exception + */ + private boolean verifyDeleteSemantics(Vertex vertex, String resourceVersion, boolean enableResourceVersion) throws AAIException { + boolean result = true; + String nodeType = ""; + String errorDetail = " unknown delete semantic found"; + String aaiExceptionCode = ""; + 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)) { + } + List<Vertex> vertices = new ArrayList<Vertex>(); + vertices.add(vertex); + result = verifyPreventDeleteSemantics(vertices); + + return result; + } + + /** + * Verify Prevent delete semantics. + * + * @param vertices the list of vertices + * @return true, if successful + * @throws AAIException the AAI exception + */ + private boolean verifyPreventDeleteSemantics(List<Vertex> vertices) throws AAIException { + boolean result = true; + String nodeType = ""; + String errorDetail = " unknown delete semantic found"; + String aaiExceptionCode = ""; + + StopWatch.conditionalStart(); + /* + * This takes in all the vertices in a cascade-delete-chain and checks if there is any edge with a "prevent-delete" condition + * If yes - that should prevent the deletion of the vertex + * Dedup makes sure we dont capture the prevent-delete vertices twice + * The prevent-delete vertices are stored so that the error message displays what prevents the delete + */ + + List<Object> preventDeleteVertices = this.engine.asAdmin().getReadOnlyTraversalSource().V(vertices). + union(__.inE().has(EdgeProperty.PREVENT_DELETE.toString(), AAIDirection.IN.toString()).outV().values(AAIProperties.NODE_TYPE), + __.outE().has(EdgeProperty.PREVENT_DELETE.toString(), AAIDirection.OUT.toString()).inV().values(AAIProperties.NODE_TYPE)) + .dedup().toList(); + + dbTimeMsecs += StopWatch.stopIfStarted(); + if (!preventDeleteVertices.isEmpty()) { + aaiExceptionCode = "AAI_6110"; + errorDetail = String.format("Object is being reference by additional objects preventing it from being deleted. Please clean up references from the following types %s", preventDeleteVertices); + result = false; + } + if (!result) { + throw new AAIException(aaiExceptionCode, errorDetail); + } + return result; + } + + /** + * Verify resource version. + * + * @param action the action + * @param nodeType the node type + * @param currentResourceVersion the current resource version + * @param resourceVersion the resource version + * @param uri the uri + * @return true, if successful + * @throws AAIException the AAI exception + */ + public boolean verifyResourceVersion(String action, String nodeType, String currentResourceVersion, String resourceVersion, String uri) throws AAIException { + String enabled = ""; + String errorDetail = ""; + String aaiExceptionCode = ""; + if (currentResourceVersion == null) { + currentResourceVersion = ""; + } + + if (resourceVersion == null) { + resourceVersion = ""; + } + try { + enabled = AAIConfig.get(AAIConstants.AAI_RESVERSION_ENABLEFLAG); + } catch (AAIException e) { + ErrorLogHelper.logException(e); + } + if (enabled.equals("true")) { + if (!currentResourceVersion.equals(resourceVersion)) { + if (action.equals("create") && !resourceVersion.equals("")) { + errorDetail = "resource-version passed for " + action + " of " + uri; + aaiExceptionCode = "AAI_6135"; + } else if (resourceVersion.equals("")) { + errorDetail = "resource-version not passed for " + action + " of " + uri; + aaiExceptionCode = "AAI_6130"; + } else { + errorDetail = "resource-version MISMATCH for " + action + " of " + uri; + aaiExceptionCode = "AAI_6131"; + } + + throw new AAIException(aaiExceptionCode, errorDetail); + + } + } + return true; + } + + /** + * Convert from camel case. + * + * @param name the name + * @return the string + */ + private String convertFromCamelCase (String name) { + String result = ""; + result = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, name); + + NamingExceptions exceptions = NamingExceptions.getInstance(); + result = exceptions.getDBName(result); + + return result; + } + + private boolean canModify(Introspector obj, String propName, String requestContext) { + final String readOnly = obj.getPropertyMetadata(propName).get(PropertyMetadata.READ_ONLY); + if (readOnly != null) { + final String[] items = readOnly.split(","); + for (String item : items) { + if (requestContext.equals(item)) { + return false; + } + } + } + return true; + } + + private void executePreSideEffects(Introspector obj, Vertex self) throws AAIException { + + SideEffectRunner runner = new SideEffectRunner + .Builder(this.engine, this).addSideEffect(DataCopy.class).addSideEffect(PrivateEdge.class).build(); + + runner.execute(obj, self); + } + + private void executePostSideEffects(Introspector obj, Vertex self) throws AAIException { + + SideEffectRunner runner = new SideEffectRunner + .Builder(this.engine, this).addSideEffect(DataLinkWriter.class).build(); + + runner.execute(obj, self); + } + + private void enrichData(Introspector obj, Vertex self) throws AAIException { + + SideEffectRunner runner = new SideEffectRunner + .Builder(this.engine, this).addSideEffect(DataLinkReader.class).build(); + + runner.execute(obj, self); + } + + public double getDBTimeMsecs() { + return (dbTimeMsecs); + } + + /** + * 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 + * @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 + */ + //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) throws AAIException, UnsupportedEncodingException { + String cleanUp = "false"; + if (depth < 0) { + return null; + } + depth--; + seen.add(v); + 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); + modified = true; + } else { + if (obj.isComplexType(property)) { + /* container case */ + + if (!property.equals("relationship-list") && depth >= 0) { + Introspector argumentObject = obj.newIntrospectorInstanceOfProperty(property); + Object result = dbToObjectWithFilters(argumentObject, v, seen, depth + 1, nodeOnly, filterCousinNodes, filterParentNodes); + if (result != null) { + obj.setValue(property, argumentObject.getUnderlyingObject()); + modified = true; + } + } else if (property.equals("relationship-list") && !nodeOnly) { + /* relationships need to be handled correctly */ + Introspector relationshipList = obj.newIntrospectorInstanceOfProperty(property); + relationshipList = createFilteredRelationshipList(v, relationshipList, cleanUp, filterCousinNodes); + if (relationshipList != null) { + modified = true; + obj.setValue(property, relationshipList.getUnderlyingObject()); + modified = true; + } + + } + } else if (obj.isListType(property)) { + + if (property.equals("any")) { + continue; + } + String genericType = obj.getGenericTypeClass(property).getSimpleName(); + if (obj.isComplexGenericType(property) && depth >= 0) { + final String childDbName = convertFromCamelCase(genericType); + String vType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null); + EdgeRule rule; + + boolean isthisParentRequired = filterParentNodes.parallelStream().anyMatch(childDbName::contains); + + EdgeRuleQuery q = new EdgeRuleQuery.Builder(vType, childDbName).edgeType(EdgeType.TREE).build(); + + try { + rule = edgeRules.getRule(q); + } catch (EdgeRuleNotFoundException e) { + throw new NoEdgeRuleFoundException(e); + } 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); + 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); + } + int processed = 0; + int removed = 0; + while (itr.hasNext()) { + Vertex childVertex = itr.next(); + if (!seen.contains(childVertex)) { + Introspector argumentObject = obj.newIntrospectorInstanceOfNestedProperty(property); + + Object result = dbToObjectWithFilters(argumentObject, childVertex, seen, depth, nodeOnly, filterCousinNodes, filterParentNodes); + if (result != null) { + getList.add(argumentObject.getUnderlyingObject()); + } + + processed++; + } else { + removed++; + LOGGER.warn("Cycle found while serializing vertex id={}", childVertex.id().toString()); + } + } + if (processed == 0) { + //vertices were all seen, reset the list + getList = null; + } + if (processed > 0) { + modified = true; + } + } + } else if (obj.isSimpleGenericType(property)) { + List<Object> temp = this.engine.getListProperty(v, property); + if (temp != null) { + getList = (List<Object>) obj.getValue(property); + getList.addAll(temp); + modified = true; + } + + } + + } + + } + } + + //no changes were made to this obj, discard the instance + if (!modified) { + return null; + } + this.enrichData(obj, v); + return obj; + + } + + /** + * Creates the relationship list with the filtered node types. + * + * @param v the v + * @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<Vertex> allCousins = this.engine.getQueryEngine().findCousinVertices(v); + + Iterator<Vertex> cousinVertices = allCousins.stream().filter(item -> { + String node = (String) item.property(AAIProperties.NODE_TYPE).orElse(""); + return filterNodes.parallelStream().anyMatch(node::contains); + }).iterator(); + + + List<Vertex> cousins = (List<Vertex>) IteratorUtils.toList(cousinVertices); + + //items.parallelStream().anyMatch(inputStr::contains) + List<Object> relationshipObjList = obj.getValue("relationship"); + for (Vertex cousin : cousins) { + + Introspector relationshipObj = obj.newIntrospectorInstanceOfNestedProperty("relationship"); + Object result = processEdgeRelationship(relationshipObj, cousin, cleanUp, null); + if (result != null) { + relationshipObjList.add(result); + } + + + } + + if (relationshipObjList.isEmpty()) { + return null; + } else { + return obj; + } + } } 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 2158c894..d072db55 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 @@ -30,6 +30,7 @@ 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.dsl.graph.GraphTraversal; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; @@ -45,12 +46,12 @@ import org.onap.aai.logging.StopWatch; /* * This class needs some big explanation despite its compact size. - * This controls all the queries performed by the CRUD API in A&AI. + * This controls all the queries performed by the CRUD API in A&AI. * findParents, findChildren, and findDeletable require special attention * These methods use 'repeat'. You cannot use 'emit' with repeat currently * as it is extremely buggy as of tinkerpop-3.0.1-incubating. The way around * it (for now) is to sideEffect all the vertices we traverse into an ArrayList. - * + * */ public class GraphTraversalQueryEngine extends QueryEngine { @@ -70,6 +71,7 @@ public class GraphTraversalQueryEngine extends QueryEngine { public List<Vertex> findParents(Vertex start) { try { StopWatch.conditionalStart(); + @SuppressWarnings("unchecked") final GraphTraversal<Vertex, Vertex> pipe = this.g.V(start).emit(v -> true).repeat(__.union(__.inE().has(CONTAINS.toString(), OUT.toString()).outV(), __.outE().has(CONTAINS.toString(), IN.toString()).inV())); return pipe.toList(); @@ -79,19 +81,36 @@ public class GraphTraversalQueryEngine extends QueryEngine { } } + /** + * {@inheritDoc} + */ + @Override + public List<Vertex> findParents(String[] uris) { + try { + StopWatch.conditionalStart(); + final GraphTraversal<Vertex, Vertex> pipe = this.g.V() + .has(AAIProperties.AAI_URI, P.within(uris)) + .order().by(AAIProperties.AAI_URI, Order.decr); + return pipe.toList(); + } + finally { + dbTimeMsecs += StopWatch.stopIfStarted(); + } + } + /** * {@inheritDoc} */ @Override public List<Vertex> findAllChildren(Vertex start) { - + @SuppressWarnings("unchecked") GraphTraversal<Vertex, Vertex> pipe = this.g .V(start).emit(v -> true).repeat(__.union(__.outE().has(CONTAINS.toString(), OUT.toString()).inV(), __.inE().has(CONTAINS.toString(), IN.toString()).outV())); - + return pipe.toList(); - + } /** @@ -104,10 +123,10 @@ public class GraphTraversalQueryEngine extends QueryEngine { __.outE().has(CONTAINS.toString(), OUT.toString()).inV(), __.inE().has(CONTAINS.toString(), IN.toString()).outV() ).has(AAIProperties.NODE_TYPE, type).dedup(); - + return pipe.toList(); } - + /** * {@inheritDoc} */ @@ -118,7 +137,7 @@ public class GraphTraversalQueryEngine extends QueryEngine { __.outE().has(CONTAINS.toString(), OUT.toString()), __.inE().has(CONTAINS.toString(), IN.toString()) ).otherV().dedup(); - + return pipe.toList(); } @@ -135,7 +154,7 @@ public class GraphTraversalQueryEngine extends QueryEngine { __.inE().has(DELETE_OTHER_V.toString(), IN.toString()).outV() ) ).dedup(); - + return pipe.toList(); } @@ -158,11 +177,11 @@ public class GraphTraversalQueryEngine extends QueryEngine { default: break; } - + pipe.has(AAIProperties.NODE_TYPE, nodeType).dedup(); return pipe.toList(); } - + @Override public Tree<Element> findSubGraph(Vertex start, int iterations, boolean nodeOnly) { final GraphTraversal<Vertex, ?> t = this.g.V(start).emit(v -> true).times(iterations).repeat( @@ -204,13 +223,13 @@ public class GraphTraversalQueryEngine extends QueryEngine { __.has("private", true) ) .dedup(); - + return pipeline.toList(); } @Override - public List<Vertex> findCousinVertices(Vertex start) { + public List<Vertex> findCousinVertices(Vertex start, String... labels) { // Start at the given vertex // Do a union to copy the start vertex to be run against all // so for the start vertex it gets all of in edges that contains other v set to none @@ -223,8 +242,8 @@ public class GraphTraversalQueryEngine extends QueryEngine { GraphTraversal<Vertex, Vertex> pipeline = this.g .V(start) .union( - __.inE().has(CONTAINS.toString(), NONE.toString()), - __.outE().has(CONTAINS.toString(), NONE.toString()) + __.inE(labels).has(CONTAINS.toString(), NONE.toString()), + __.outE(labels).has(CONTAINS.toString(), NONE.toString()) ) .not( __.has(PRIVATE.toString(), true) @@ -234,7 +253,7 @@ public class GraphTraversalQueryEngine extends QueryEngine { return pipeline.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 c2929468..110f8628 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 @@ -42,16 +42,33 @@ public abstract class QueryEngine { public QueryEngine (GraphTraversalSource g) { this.g = g; } - + /** * Finds all the parents/grandparents/etc of the given start node. * * @param start - the start vertex whose parent chain you want * @return the list of start and start's parent, grandparent, etc, in - * order (ie {start, parent, grandparent, etc} + * order (ie {start, parent, grandparent, etc} */ public abstract List<Vertex> findParents(Vertex start); - + + /** + * Finds all the parents/grandparents/etc of the given start node. + * + * This method should be used in place of the #findParents(Vertex) + * as since the aai-uri is added the lookup for finding the parents + * using the given list of aai-uri will be much faster than using + * a traversal to follow a start vertex and keep repeating since + * as the number of different type of edges keeps growing that call + * will be more expensive than using the aai-uri's as they are fast lookup + * + * @param uris - list of the uris representing the aai-uris of + * parent, grandparent, etc + * @return the list of start and start's parent, grandparent, etc, in + * order (ie {start, parent, grandparent, etc} + */ + public abstract List<Vertex> findParents(String [] uris); + /** * Finds all children, grandchildren, etc of start * @@ -59,7 +76,7 @@ public abstract class QueryEngine { * @return the list of child/grandchild/etc vertices */ public abstract List<Vertex> findAllChildren(Vertex start); - + /** * Finds all immediate children of start (no grandchildren or so forth) of the given type * @param start - the start vertex @@ -67,14 +84,14 @@ public abstract class QueryEngine { * @return the list of immediate child vertices of given type */ public abstract List<Vertex> findChildrenOfType(Vertex start, String type); - + /** * Finds all immediate children of start (no grandchildren or so forth) * @param start - the start vertex * @return the list of immediate child vertices */ public abstract List<Vertex> findChildren(Vertex start); - + /** * Find all vertices that should be deleted in a cascade from a delete of start * @@ -82,34 +99,34 @@ public abstract class QueryEngine { * @return the list of vertices to be deleted when start is deleted */ public abstract List<Vertex> findDeletable(Vertex start); - + /** * Finds the subgraph under start, including cousins as well as start's children/grandchildren/etc. * More specifically, this includes start, all its descendants, start's cousins, and start's * descendants' cousins (but not any of the cousins' cousins or descendants), and the edges * connecting them. - * + * * @param start - the start vertex - * @return - Tree containing nodes and edges of the subgraph + * @return - Tree containing nodes and edges of the subgraph */ public Tree<Element> findSubGraph(Vertex start) { return findSubGraph(start, AAIProperties.MAXIMUM_DEPTH, false); } - + /** * Finds the subgraph under start, including cousins as well as start's children/grandchildren/etc. * More specifically, this includes start, all its descendants, start's cousins, and start's * descendants' cousins (but not any of the cousins' cousins or descendants), and the edges * connecting them. - * + * * @param start - the start vertex - * @param iterations - depth of the subgraph, this limits how many generations of + * @param iterations - depth of the subgraph, this limits how many generations of * descendants are included * @param nodeOnly - if true the subgraph will NOT include the cousins - * @return Tree containing nodes and edges of the subgraph + * @return Tree containing nodes and edges of the subgraph */ public abstract Tree<Element> findSubGraph(Vertex start, int iterations, boolean nodeOnly); - + /** * Find vertices of type nodeType related to start by edges of the given * direction and label. @@ -125,23 +142,23 @@ public abstract class QueryEngine { /** * Finds cousin edges connecting start to other vertices only of types defined in an old version. * The idea is that if a user is using an old version, they won't understand any new node types in - * subsequent versions. Thus, revealing edges to new types will cause problems. This methods + * subsequent versions. Thus, revealing edges to new types will cause problems. This methods * filters any such edges out. - * + * * @param start - the start vertex * @param loader - loader for retrieving the list of allowed node types for the desired version * (version is set when the loader was instantiated) * @return list of cousin edges between start and any node types understood by the version specified in loader */ public abstract List<Edge> findEdgesForVersion(Vertex start, Loader loader); - + /** - * Finds all cousins of start. - * + * Finds all cousins of start. + * * @param start - the start vertex * @return list of start's cousin vertices */ - public abstract List<Vertex> findCousinVertices(Vertex start); + public abstract List<Vertex> findCousinVertices(Vertex start, String... labels); public abstract double getDBTimeMsecs(); 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 82a3efdf..92cb59c5 100644 --- a/aai-core/src/test/java/org/onap/aai/HttpTestUtil.java +++ b/aai-core/src/test/java/org/onap/aai/HttpTestUtil.java @@ -52,11 +52,11 @@ import static org.mockito.Mockito.when; public class HttpTestUtil extends RESTAPI { - - protected HttpEntry traversalHttpEntry; - - protected HttpEntry traversalUriHttpEntry; - + + protected HttpEntry traversalHttpEntry; + + protected HttpEntry traversalUriHttpEntry; + private static final EELFLogger logger = EELFManager.getInstance().getLogger(HttpTestUtil.class); protected static final MediaType APPLICATION_JSON = MediaType.valueOf("application/json"); @@ -77,7 +77,7 @@ public class HttpTestUtil extends RESTAPI { this.queryStyle = qs; traversalHttpEntry = SpringContextAware.getBean("traversalUriHttpEntry", HttpEntry.class); traversalUriHttpEntry = SpringContextAware.getBean("traversalUriHttpEntry", HttpEntry.class); - + } public void init(){ @@ -121,7 +121,10 @@ public class HttpTestUtil extends RESTAPI { try { - uri = uri.replaceAll("/aai/", ""); + 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("/"); @@ -142,7 +145,7 @@ public class HttpTestUtil extends RESTAPI { Mockito.when(uriInfo.getPath()).thenReturn(uri); DBConnectionType type = DBConnectionType.REALTIME; - + traversalHttpEntry.setHttpEntryProperties(version, type); Loader loader = traversalHttpEntry.getLoader(); dbEngine = traversalHttpEntry.getDbEngine(); @@ -206,7 +209,7 @@ public class HttpTestUtil extends RESTAPI { return response; } - public Response doGet(String uri) throws UnsupportedEncodingException, AAIException { + public Response doGet(String uri, String depth){ this.init(); Response response = null; @@ -215,8 +218,11 @@ public class HttpTestUtil extends RESTAPI { try { - uri = uri.replaceAll("/aai/", ""); - logger.info("Starting the GET request for the uri {} with depth {}", uri, "all"); + if(uri.startsWith("/aai/")){ + uri = uri.substring(5); + } + + logger.info("Starting the GET request for the uri {} with depth {}", uri, depth); String [] arr = uri.split("/"); @@ -240,21 +246,29 @@ public class HttpTestUtil extends RESTAPI { dbEngine = traversalHttpEntry.getDbEngine(); URI uriObject = UriBuilder.fromPath(uri).build(); - URIToObject uriToObject = new URIToObject(loader, uriObject); - String objType = uriToObject.getEntityName(); - queryParameters.add("depth", "all"); + if(depth != null){ + queryParameters.add("depth", depth); + } + QueryParser uriQuery = dbEngine.getQueryBuilder().createQueryFromURI(uriObject, queryParameters); Mockito.when(uriInfo.getPath()).thenReturn(uri); + URIToObject uriToObject = new URIToObject(loader, uriObject); + String objType = ""; + if (!uriQuery.getContainerType().equals("")) { + objType = uriQuery.getContainerType(); + } else { + objType = uriQuery.getResultType(); + } logger.info("Unmarshalling the payload to this {}", objType); Introspector obj = loader.introspectorFromName(objType); DBRequest dbRequest = - new DBRequest.Builder(HttpMethod.GET, uriObject, uriQuery, obj, httpHeaders, uriInfo, "JUNIT-TRANSACTION") - .build(); + new DBRequest.Builder(HttpMethod.GET, uriObject, uriQuery, obj, httpHeaders, uriInfo, "JUNIT-TRANSACTION") + .build(); List<DBRequest> dbRequestList = new ArrayList<>(); dbRequestList.add(dbRequest); @@ -288,6 +302,10 @@ public class HttpTestUtil extends RESTAPI { return response; } + public Response doGet(String uri) throws UnsupportedEncodingException, AAIException { + return this.doGet(uri, "all"); + } + public Response doDelete(String uri, String resourceVersion) throws UnsupportedEncodingException, AAIException { this.init(); @@ -321,7 +339,7 @@ public class HttpTestUtil extends RESTAPI { Mockito.when(uriInfo.getPath()).thenReturn(uri); DBConnectionType type = DBConnectionType.REALTIME; traversalHttpEntry.setHttpEntryProperties(version, type); - + traversalHttpEntry.setHttpEntryProperties(version, type); Loader loader = traversalHttpEntry.getLoader(); dbEngine = traversalHttpEntry.getDbEngine(); diff --git a/aai-core/src/test/java/org/onap/aai/parsers/uri/URIToObjectTest.java b/aai-core/src/test/java/org/onap/aai/parsers/uri/URIToObjectTest.java index c7c1f4ca..fc2c64a1 100644 --- a/aai-core/src/test/java/org/onap/aai/parsers/uri/URIToObjectTest.java +++ b/aai-core/src/test/java/org/onap/aai/parsers/uri/URIToObjectTest.java @@ -19,6 +19,7 @@ */ package org.onap.aai.parsers.uri; +import org.onap.aai.schema.enums.ObjectMetadata; import org.onap.aai.setup.SchemaVersion; import org.junit.Ignore; @@ -65,7 +66,7 @@ public class URIToObjectTest extends AAISetup { currentVersion = schemaVersions.getDefaultVersion(); loader = loaderFactory.createLoaderForVersion(ModelType.MOXY, schemaVersions.getRelatedLinkVersion()); } - + @Test public void uri() throws JAXBException, AAIException, IllegalArgumentException, UnsupportedEncodingException { URI uri = UriBuilder.fromPath("/aai/" + loader.getVersion() + "/cloud-infrastructure/cloud-regions/cloud-region/mycloudowner/mycloudregionid/tenants/tenant/key1/vservers/vserver/key2/l-interfaces/l-interface/key3").build(); @@ -74,11 +75,11 @@ public class URIToObjectTest extends AAISetup { String expected = "{\"cloud-owner\":\"mycloudowner\",\"cloud-region-id\":\"mycloudregionid\",\"tenants\":{\"tenant\":[{\"tenant-id\":\"key1\",\"vservers\":{\"vserver\":[{\"vserver-id\":\"key2\",\"l-interfaces\":{\"l-interface\":[{\"interface-name\":\"key3\"}]}}]}}]}}"; String topEntity = "cloud-region"; String entity = "l-interface"; - + testSet(result.marshal(false), parse, expected, topEntity, entity, version); } - + /** * Uri no version. * @@ -86,7 +87,7 @@ public class URIToObjectTest extends AAISetup { * @throws AAIException the AAI exception * @throws IllegalArgumentException the illegal argument exception * @throws UnsupportedEncodingException the unsupported encoding exception - * @throws AAIUnknownObjectException + * @throws AAIUnknownObjectException */ @Test public void uriNoVersion() throws JAXBException, AAIException, IllegalArgumentException, UnsupportedEncodingException, AAIUnknownObjectException { @@ -106,12 +107,12 @@ public class URIToObjectTest extends AAISetup { String expected = "{\"cloud-owner\":\"mycloudowner\",\"cloud-region-id\":\"mycloudregionid\",\"tenants\":{\"tenant\":[{\"tenant-id\":\"key1\",\"tenant-name\":\"name1\",\"vservers\":{\"vserver\":[{\"vserver-id\":\"key2\",\"vserver-name\":\"name2\",\"l-interfaces\":{\"l-interface\":[{\"interface-name\":\"key3\"}]}}]}}]}}"; String topEntity = "cloud-region"; String entity = "l-interface"; - + testSet(result.marshal(false), parse, expected, topEntity, entity, version); - + } - + /** * Bad URI. @@ -124,13 +125,13 @@ public class URIToObjectTest extends AAISetup { @Test public void badURI() throws JAXBException, AAIException, IllegalArgumentException, UnsupportedEncodingException { URI uri = UriBuilder.fromPath("/aai/" + loader.getVersion() + "/cloud-infrastructure/cloud-regions/cloud-region/mycloudowner/mycloudregionid/tenants/tenant/key1/vservers/vserver/key2/l-interadsfaces/l-interface/key3").build(); - + thrown.expect(AAIException.class); thrown.expect(hasProperty("code", is("AAI_3000"))); - + new URIToObject(loader, uri); } - + /** * Starts with valid namespace. * @@ -147,10 +148,10 @@ public class URIToObjectTest extends AAISetup { String expected = "{\"cloud-owner\":\"mycloudowner\",\"cloud-region-id\":\"mycloudregionid\",\"tenants\":{\"tenant\":[{\"tenant-id\":\"key1\",\"vservers\":{\"vserver\":[{\"vserver-id\":\"key2\",\"l-interfaces\":{\"l-interface\":[{\"interface-name\":\"key3\"}]}}]}}]}}"; String topEntity = "cloud-region"; String entity = "l-interface"; - + testSet(result.marshal(false), parse, expected, topEntity, entity, version); } - + /** * Single top level. * @@ -165,14 +166,14 @@ public class URIToObjectTest extends AAISetup { URIToObject parse = new URIToObject(loader, uri); Introspector result = parse.getTopEntity(); String expected = "{\"vnf-id\":\"key1\"}"; - + String topEntity = "generic-vnf"; String entity = "generic-vnf"; - + testSet(result.marshal(false), parse, expected, topEntity, entity, version); } - + /** * Naming exceptions. * @@ -190,11 +191,11 @@ public class URIToObjectTest extends AAISetup { String expected = "{\"vnf-id\":\"key1\",\"port-groups\":{\"port-group\":[{\"interface-id\":\"key2\",\"cvlan-tags\":{\"cvlan-tag-entry\":[{\"cvlan-tag\":655}]}}]}}"; String topEntity = "vce"; String entity = "cvlan-tag"; - + testSet(result.marshal(false), parse, expected, topEntity, entity, version); } - + /** * No list object. * @@ -212,23 +213,23 @@ public class URIToObjectTest extends AAISetup { String entity = "l3-interface-ipv4-address-list"; String expected = "{\"equipment-name\":\"0e6189fd-9257-49b9-a3be-d7ba980ccfc9\",\"lag-interfaces\":{\"lag-interface\":[{\"interface-name\":\"8ae5aa76-d597-4382-b219-04f266fe5e37\",\"l-interfaces\":{\"l-interface\":[{\"interface-name\":\"9e141d03-467b-437f-b4eb-b3133ec1e205\",\"l3-interface-ipv4-address-list\":[{\"l3-interface-ipv4-address\":\"8f19f0ea-a81f-488e-8d5c-9b7b53696c11\"}]}]}}]}}"; testSet(result.marshal(false), parse, expected, topEntity, entity, version); - + } - + @Test public void relativePath() throws JAXBException, AAIException, IllegalArgumentException, UnsupportedEncodingException { URI uri = UriBuilder.fromPath("./l-interfaces/l-interface/key1").build(); URIToObject parse = new URIToObject(loader, uri); Introspector result = parse.getEntity(); String expected = "{\"interface-name\":\"key1\"}"; - + String topEntity = "l-interface"; String entity = "l-interface"; - + testSet(result.marshal(false), parse, expected, topEntity, entity, version); } - + /** * Test set. * @@ -241,15 +242,15 @@ public class URIToObjectTest extends AAISetup { */ public void testSet(String json, URIToObject parse, String expected, String topEntity, String entity, SchemaVersion version) { assertEquals("blah", expected, json); - + assertEquals("top entity", topEntity, parse.getTopEntityName()); assertEquals("entity", entity, parse.getEntityName()); assertEquals("entity object", entity, parse.getEntity().getDbName()); - + assertEquals("parent list object", 1, parse.getParentList().size()); - + assertEquals("object version", version, parse.getObjectVersion()); } } diff --git a/aai-core/src/test/java/org/onap/aai/rest/EdgeNotValidAnymoreTest.java b/aai-core/src/test/java/org/onap/aai/rest/EdgeNotValidAnymoreTest.java new file mode 100644 index 00000000..1a69fc58 --- /dev/null +++ b/aai-core/src/test/java/org/onap/aai/rest/EdgeNotValidAnymoreTest.java @@ -0,0 +1,120 @@ +/** + * ============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.apache.tinkerpop.gremlin.structure.Edge; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.janusgraph.core.JanusGraph; +import org.janusgraph.core.JanusGraphTransaction; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +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.edges.enums.EdgeField; +import org.onap.aai.edges.enums.EdgeProperty; +import org.onap.aai.exceptions.AAIException; +import org.onap.aai.serialization.engines.QueryStyle; + +import javax.ws.rs.core.Response; +import java.io.IOException; +import java.util.UUID; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.Matchers.not; +import static org.junit.Assert.assertThat; + +public class EdgeNotValidAnymoreTest extends AAISetup { + + private HttpTestUtil testUtil; + + @Before + public void setupData() throws IOException, AAIException { + + String cloudRegionEndpoint = "/aai/v13/cloud-infrastructure/cloud-regions/cloud-region/junit-cloud-owner-with-vlan/junit-cloud-region-with-vlan"; + + String cloudRegionBody = PayloadUtil.getResourcePayload("cloud-region-with-vlan.json"); + testUtil = new HttpTestUtil(QueryStyle.TRAVERSAL_URI); + testUtil.doPut(cloudRegionEndpoint, cloudRegionBody); + + JanusGraphTransaction transaction = AAIGraph.getInstance().getGraph().newTransaction(); + GraphTraversalSource g = transaction.traversal(); + + Vertex configurationVertex = g.addV() + .property( AAIProperties.NODE_TYPE, "configuration") + .property( "configuration-id", "ci1") + .property( "configuration-type", "ci1") + .property( AAIProperties.AAI_URI, "/network/configurations/configuration/ci1") + .property(AAIProperties.SOURCE_OF_TRUTH, "JUNIT") + .next(); + + Vertex vlanVertex = g.V() + .has("vlan-interface", "test-vlan-interface-1") + .has(AAIProperties.NODE_TYPE, "vlan") + .next(); + + Edge edge = configurationVertex.addEdge("org.onap.relationships.inventory.PartOf", vlanVertex); + addEdge(edge); + + transaction.commit(); + } + + public void addEdge(Edge edge) { + edge.property(EdgeProperty.CONTAINS.toString(), "NONE"); + edge.property(EdgeProperty.DELETE_OTHER_V.toString(), "NONE"); + edge.property(EdgeProperty.PREVENT_DELETE.toString(), "NONE"); + edge.property(EdgeField.PRIVATE.toString(), false); + edge.property(AAIProperties.AAI_UUID, UUID.randomUUID().toString()); + } + + @Test + public void testWhenEdgeRuleIsNoLongerValidEnsureItRetrievesVertexesWithoutOldEdges() { + + String endpoint = "/aai/v14/network/configurations"; + + Response response = testUtil.doGet(endpoint, null); + assertThat(response.getStatus(), is(200)); + + String body = response.getEntity().toString(); + + assertThat(body, containsString("configuration-id")); + assertThat(body, not(containsString("vlan"))); + } + + @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") + .toList() + .forEach((edge) -> edge.remove()); + + transaction.commit(); + } +} diff --git a/aai-core/src/test/java/org/onap/aai/rest/EntitlementTest.java b/aai-core/src/test/java/org/onap/aai/rest/EntitlementTest.java new file mode 100644 index 00000000..3559b9d6 --- /dev/null +++ b/aai-core/src/test/java/org/onap/aai/rest/EntitlementTest.java @@ -0,0 +1,96 @@ +/** + * ============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.jayway.jsonpath.JsonPath; +import org.junit.After; +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.HttpTestUtil; +import org.onap.aai.PayloadUtil; +import org.onap.aai.exceptions.AAIException; +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.Arrays; +import java.util.Collection; + +import static org.junit.Assert.assertEquals; + +@RunWith(value = Parameterized.class) +@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS) +public class EntitlementTest extends AAISetup { + + private HttpTestUtil httpTestUtil; + + @Parameterized.Parameter(value = 0) + public QueryStyle queryStyle; + + private String vnfPayload; + + private String vnfUri; + + @Parameterized.Parameters(name = "QueryStyle.{0}") + public static Collection<Object[]> data() { + return Arrays.asList(new Object[][]{ + {QueryStyle.TRAVERSAL_URI} + }); + } + + @Before + public void setUp() throws IOException { + httpTestUtil = new HttpTestUtil(queryStyle); + vnfPayload = PayloadUtil.getResourcePayload("vnf.json"); + vnfUri = "/aai/v14/network/generic-vnfs/generic-vnf/vnf1"; + } + + @Test + public void testPutGenericVnfAndThenInsertEntitlement() throws IOException, AAIException { + String entitlementPayload = PayloadUtil.getResourcePayload("entitlement.json"); + String entitlementUri = "/aai/v14/network/generic-vnfs/generic-vnf/vnf1/entitlements/entitlement/g1/r1"; + Response response = httpTestUtil.doPut(vnfUri, vnfPayload); + assertEquals("Expected the Generic Vnf to be created", 201, response.getStatus()); + + response = httpTestUtil.doGet(vnfUri); + assertEquals("Expected the Generic Vnf to be found", 200, response.getStatus()); + String jsonResponse = response.getEntity().toString(); + JSONAssert.assertEquals(vnfPayload, jsonResponse, false); + + response = httpTestUtil.doPut(entitlementUri, entitlementPayload); + assertEquals("Expected the Entitlement to be created", 201, response.getStatus()); + } + + @After + public void tearDown() throws UnsupportedEncodingException, AAIException { + Response response = httpTestUtil.doGet(vnfUri); + assertEquals("Expected the Generic Vnf to be found", 200, response.getStatus()); + String jsonResponse = response.getEntity().toString(); + String resourceVersion = JsonPath.read(jsonResponse, "$.resource-version"); + response = httpTestUtil.doDelete(vnfUri, resourceVersion); + assertEquals("Expected the cloud region to be deleted", 204, response.getStatus()); + } +} diff --git a/aai-core/src/test/java/org/onap/aai/rest/ModelElementTest.java b/aai-core/src/test/java/org/onap/aai/rest/ModelElementTest.java new file mode 100644 index 00000000..d808c993 --- /dev/null +++ b/aai-core/src/test/java/org/onap/aai/rest/ModelElementTest.java @@ -0,0 +1,98 @@ +/** + * ============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.jayway.jsonpath.JsonPath; +import org.junit.After; +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.HttpTestUtil; +import org.onap.aai.PayloadUtil; +import org.onap.aai.exceptions.AAIException; +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.Arrays; +import java.util.Collection; + +import static org.junit.Assert.assertEquals; + +@RunWith(value = Parameterized.class) +@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS) +public class ModelElementTest extends AAISetup { + + private HttpTestUtil httpTestUtil; + + @Parameterized.Parameter(value = 0) + public QueryStyle queryStyle; + + private String modelPayload; + private String modelElementPayload; + + private String modelUri; + private String modelElementUri; + + @Parameterized.Parameters(name = "QueryStyle.{0}") + public static Collection<Object[]> data() { + return Arrays.asList(new Object[][]{ + {QueryStyle.TRAVERSAL_URI} + }); + } + + @Before + public void setUp() throws IOException { + httpTestUtil = new HttpTestUtil(queryStyle); + modelPayload = PayloadUtil.getResourcePayload("model.json"); + modelElementPayload = PayloadUtil.getResourcePayload("model-element.json"); + modelUri = "/aai/v14/service-design-and-creation/models/model/24c04fc5-f3f8-43ec-8792-c6f940638676-test1"; + modelElementUri = "/aai/v14/service-design-and-creation/models/model/24c04fc5-f3f8-43ec-8792-c6f940638676-test1/model-vers/model-ver/0c4c59f0-9864-43ca-b0c2-ca38746b72a5-test1/model-elements/model-element/0dc2b8b6-af8d-4213-970b-7861a603fc86-test1/model-constraints/model-constraint/782ba24a-28ab-4fd0-8e69-da10cc5373f3-test1/constrained-element-sets/constrained-element-set/a33e65c3-1198-4d4c-9799-2b521e4c4212-test1/element-choice-sets/element-choice-set/7df27a94-06c8-46ef-9fc2-5900d8cffbb0-test1/model-elements/model-element/acf8b6cf-e051-4c1b-bcad-b24792f826cf-test1"; + } + + @Test + public void testPutModelAndThenModelElementAndItShouldSucceed() throws IOException, AAIException { + Response response = httpTestUtil.doPut(modelUri, modelPayload); + assertEquals("Expected the cloud region to be created", 201, response.getStatus()); + + response = httpTestUtil.doGet(modelUri); + assertEquals("Expected the cloud region to be found", 200, response.getStatus()); + String jsonResponse = response.getEntity().toString(); + JSONAssert.assertEquals(modelPayload, jsonResponse, false); + + response = httpTestUtil.doPut(modelElementUri, modelElementPayload); + assertEquals("Expected the cloud region to be created", 201, response.getStatus()); + } + + @After + public void tearDown() throws UnsupportedEncodingException, AAIException { + Response response = httpTestUtil.doGet(modelUri); + assertEquals("Expected the cloud region to be found", 200, response.getStatus()); + String jsonResponse = response.getEntity().toString(); + String resourceVersion = JsonPath.read(jsonResponse, "$.resource-version"); + response = httpTestUtil.doDelete(modelUri, resourceVersion); + assertEquals("Expected the cloud region to be deleted", 204, response.getStatus()); + } +} 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 new file mode 100644 index 00000000..71e53be8 --- /dev/null +++ b/aai-core/src/test/java/org/onap/aai/rest/PserverDuplicateTest.java @@ -0,0 +1,135 @@ +/** + * ============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.att.eelf.configuration.EELFLogger; +import com.att.eelf.configuration.EELFManager; +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.junit.Test; +import org.onap.aai.AAISetup; +import org.onap.aai.HttpTestUtil; +import org.onap.aai.db.props.AAIProperties; +import org.onap.aai.dbmap.AAIGraph; +import org.onap.aai.serialization.engines.QueryStyle; + +import javax.ws.rs.core.Response; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; + +public class PserverDuplicateTest extends AAISetup { + + private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(PserverDuplicateTest.class); + + private HttpTestUtil testUtil; + + private String hostname; + + public boolean createDuplicate() throws InterruptedException { + + hostname = getHostname(); + final String aaiUri = "/cloud-infrastructure/pservers/pserver/" + hostname; + final int threads = getNumberOfThreads(); + + ExecutorService service = Executors.newFixedThreadPool(threads); + + JanusGraph janusGraph = AAIGraph.getInstance().getGraph(); + // Due to the lazy instantiation of the graph, it needs to create a new transaction to create schema + janusGraph.newTransaction().rollback(); + + service.invokeAll( + IntStream.range(0, threads) + .mapToObj((i) -> (Callable<Void>) () -> { + JanusGraphTransaction transaction = janusGraph.newTransaction(); + GraphTraversalSource g = transaction.traversal(); + g.addV() + .property(AAIProperties.AAI_URI, aaiUri) + .property(AAIProperties.NODE_TYPE, "pserver") + .property("hostname", hostname) + .next(); + transaction.commit(); + return null; + }).collect(Collectors.toList()) + , 7, TimeUnit.SECONDS + ); + + JanusGraphTransaction readOnlyTransaction = AAIGraph.getInstance().getGraph().buildTransaction().readOnly().start(); + GraphTraversalSource g = readOnlyTransaction.traversal(); + + List<Vertex> pserverList = g.V().has(AAIProperties.AAI_URI, aaiUri).toList(); + LOGGER.debug("Number of pservers with uri {} is {}", aaiUri, pserverList.size()); + + testUtil = new HttpTestUtil(QueryStyle.TRAVERSAL_URI); + + if(pserverList.size() == 1){ + return false; + } + return true; + } + + + @Test + public void testWhenDuplicatesExistInGraphThatGetAllSuceeds() throws InterruptedException { + + int totalRetries = getNumOfRetries(); + for(int retry = 0; retry < totalRetries; retry++){ + if(!this.createDuplicate()){ + if(retry == (totalRetries-1)){ + fail("Unable to produce duplicates in the graph, " + + "please increase retry or ignore test if it becomes impossible to create duplicate this test"); + } + } else { + // Successfully created a duplicate in the janus graph + break; + } + } + + String endpoint = "/aai/v14/cloud-infrastructure/pservers"; + + Response response = testUtil.doGet(endpoint, null); + LOGGER.info("GET ALL Pservers with duplicates status code {} and body {}", response.getStatus(), response.getEntity()); + assertThat(response.getStatus(), is(200)); + } + + public String getHostname(){ + return UUID.randomUUID().toString(); + } + + public int getNumOfRetries(){ + return 10; + } + + public int getNumberOfThreads(){ + return 10; + } +} + diff --git a/aai-core/src/test/java/org/onap/aai/rest/VipAddressListTest.java b/aai-core/src/test/java/org/onap/aai/rest/VipAddressListTest.java new file mode 100644 index 00000000..0351c2c3 --- /dev/null +++ b/aai-core/src/test/java/org/onap/aai/rest/VipAddressListTest.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.rest; + +import com.jayway.jsonpath.JsonPath; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; +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.exceptions.AAIException; +import org.onap.aai.serialization.engines.QueryStyle; +import org.skyscreamer.jsonassert.JSONAssert; + +import javax.ws.rs.core.Response; +import java.io.IOException; +import java.util.Arrays; +import java.util.Collection; + +import static org.junit.Assert.assertEquals; + +@RunWith(value = Parameterized.class) +public class VipAddressListTest extends AAISetup { + + private HttpTestUtil httpTestUtil; + + @Parameterized.Parameter(value = 0) + public QueryStyle queryStyle; + + @Parameterized.Parameters(name = "QueryStyle.{0}") + public static Collection<Object[]> data() { + return Arrays.asList(new Object[][]{ + {QueryStyle.TRAVERSAL_URI} + }); + } + + @Before + public void setUp(){ + httpTestUtil = new HttpTestUtil(queryStyle); + } + + @Test + public void testPutWithAllCloudRegionChildrenNodesAndCheckIfDeleteIsSuccessful() throws IOException, AAIException { + + String cloudRegionPayload = PayloadUtil.getResourcePayload("cloud-region.json"); + String cloudRegionUri = "/aai/v14/cloud-infrastructure/cloud-regions/cloud-region/cloud-region-owner-with-vip-ipv4/cloud-region-id-with-vip-ipv4"; + + Response response = httpTestUtil.doPut(cloudRegionUri, cloudRegionPayload); + assertEquals("Expected the cloud region to be created", 201, response.getStatus()); + + response = httpTestUtil.doGet(cloudRegionUri); + assertEquals("Expected the cloud region to be found", 200, response.getStatus()); + String jsonResponse = response.getEntity().toString(); + + JSONAssert.assertEquals(cloudRegionPayload, jsonResponse, false); + + String vipIpv4Uri = cloudRegionUri + "/vip-ipv4-address-list/vip-ipv4-address-list-1"; + String vipIpv4Payload = PayloadUtil.getResourcePayload("vip-ipv4-address-list.json"); + + response = httpTestUtil.doPut(vipIpv4Uri, vipIpv4Payload); + assertEquals("Expected the ipv4 address list to be created", 201, response.getStatus()); + + response = httpTestUtil.doGet(vipIpv4Uri); + assertEquals("Expected the ipv4 address list to be found", 200, response.getStatus()); + + jsonResponse = response.getEntity().toString(); + String resourceVersion = JsonPath.read(jsonResponse, "$.resource-version"); + + response = httpTestUtil.doDelete(vipIpv4Uri, resourceVersion); + assertEquals("Expected the ipv4 address list to be deleted", 204, response.getStatus()); + + response = httpTestUtil.doGet(cloudRegionUri); + jsonResponse = response.getEntity().toString(); + resourceVersion = JsonPath.read(jsonResponse, "$.resource-version"); + + response = httpTestUtil.doDelete(cloudRegionUri, resourceVersion); + assertEquals("Expected the cloud region to be deleted", 204, response.getStatus()); + } +} 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 a5b968b3..5041c7d1 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 @@ -465,16 +465,18 @@ public class DbSerializerTest extends AAISetup { public void getURIForVertexTest() throws AAIException, URISyntaxException, UnsupportedEncodingException { engine.startTransaction(); - Vertex cr = engine.tx().addVertex("aai-node-type", "cloud-region", "cloud-owner", "me", "cloud-region-id", "123"); + Vertex cr = engine.tx().addVertex("aai-node-type", "cloud-region", "cloud-owner", "me", "cloud-region-id", "123", "aai-uri", "/cloud-infrastructure/cloud-regions/cloud-region/me/123"); Vertex ten = engine.tx().addVertex("aai-node-type", "tenant", "tenant-id", "453"); edgeSer.addTreeEdge(engine.tx().traversal(), cr, ten); + ten.property("aai-uri", "/cloud-infrastructure/cloud-regions/cloud-region/me/123/tenants/tenant/453"); + URI compare = new URI("/cloud-infrastructure/cloud-regions/cloud-region/me/123/tenants/tenant/453"); assertEquals(compare, dbser.getURIForVertex(ten)); - cr.property("aai-node-type").remove(); URI compareFailure = new URI("/unknown-uri"); + ten.property("aai-uri").remove(); assertEquals(compareFailure, dbser.getURIForVertex(ten)); } @@ -619,9 +621,10 @@ public class DbSerializerTest extends AAISetup { public void serializeSingleVertexChildTest() throws AAIException, UnsupportedEncodingException { engine.startTransaction(); - Vertex cr = engine.tx().addVertex("aai-node-type", "cloud-region", "cloud-owner", "me", "cloud-region-id", "123"); + Vertex cr = engine.tx().addVertex("aai-node-type", "cloud-region", "cloud-owner", "me", "cloud-region-id", "123", "aai-uri", "/cloud-infrastructure/cloud-regions/cloud-region/me/123"); Introspector tenIn = loader.introspectorFromName("tenant"); Vertex ten = dbser.createNewVertex(tenIn); + ten.property("aai-uri", cr.property("aai-uri").value().toString() + "/tenants/tenant/453"); edgeSer.addTreeEdge(engine.tx().traversal(), cr, ten); @@ -639,8 +642,8 @@ public class DbSerializerTest extends AAISetup { public void getVertexPropertiesRelationshipHasLabelTest() throws AAIException, UnsupportedEncodingException { engine.startTransaction(); - Vertex gvnf = engine.tx().addVertex("aai-node-type","generic-vnf","vnf-id","vnf-123"); - Vertex vnfc = engine.tx().addVertex("aai-node-type","vnfc","vnfc-name","vnfc-123"); + Vertex gvnf = engine.tx().addVertex("aai-node-type","generic-vnf","vnf-id","vnf-123","aai-uri", "/network/generic-vnfs/generic-vnf/vnf-123"); + Vertex vnfc = engine.tx().addVertex("aai-node-type","vnfc","vnfc-name","vnfc-123","aai-uri", "/network/vnfcs/vnfc/vnfc-123"); edgeSer.addEdge(engine.tx().traversal(), gvnf, vnfc); @@ -672,8 +675,8 @@ public class DbSerializerTest extends AAISetup { engine.startTransaction(); - Vertex gvnf = engine.tx().addVertex("aai-node-type","generic-vnf","vnf-id","vnf-123"); - Vertex vnfc = engine.tx().addVertex("aai-node-type","vnfc","vnfc-name","vnfc-123"); + Vertex gvnf = engine.tx().addVertex("aai-node-type","generic-vnf","vnf-id","vnf-123", "aai-uri", "/network/generic-vnfs/generic-vnf/vnf-123"); + Vertex vnfc = engine.tx().addVertex("aai-node-type","vnfc","vnfc-name","vnfc-123", "aai-uri", "/network/vnfcs/vnfc/vnfc-123"); edgeSer.addEdge(engine.tx().traversal(), gvnf, vnfc); diff --git a/aai-core/src/test/java/org/onap/aai/serialization/engines/query/GraphTraversalQueryEngineTest.java b/aai-core/src/test/java/org/onap/aai/serialization/engines/query/GraphTraversalQueryEngineTest.java index a24855b8..b9431217 100644 --- a/aai-core/src/test/java/org/onap/aai/serialization/engines/query/GraphTraversalQueryEngineTest.java +++ b/aai-core/src/test/java/org/onap/aai/serialization/engines/query/GraphTraversalQueryEngineTest.java @@ -38,6 +38,7 @@ import org.springframework.test.annotation.DirtiesContext; import java.io.InputStream; import java.util.*; +import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.collection.IsIterableContainingInAnyOrder.containsInAnyOrder; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; @@ -53,30 +54,30 @@ public class GraphTraversalQueryEngineTest extends AAISetup { public void testFindParents() throws AAIException { //setup Graph graph = TinkerGraph.open(); - + Vertex cloudreg = graph.addVertex(T.id, "00", "aai-node-type", "cloud-region"); Vertex tenant = graph.addVertex(T.id, "10", "aai-node-type", "tenant"); Vertex vserver = graph.addVertex(T.id, "20", "aai-node-type", "vserver"); - + GraphTraversalSource g = graph.traversal(); - + edgeSer.addTreeEdge(g, cloudreg, tenant); edgeSer.addTreeEdge(g, tenant, vserver); - + //expect start vertex back plus any parents List<Vertex> crExpected = new ArrayList<>(Arrays.asList(cloudreg)); //no parents List<Vertex> tenExpected = new ArrayList<>(Arrays.asList(tenant, cloudreg)); //only has the immediate parent List<Vertex> vsExpected = new ArrayList<>(Arrays.asList(vserver, tenant, cloudreg)); //parent & grandparent - + GraphTraversalQueryEngine engine = new GraphTraversalQueryEngine(g); - + //test List<Vertex> crRes = engine.findParents(cloudreg); assertTrue(crRes.containsAll(crExpected) && crExpected.containsAll(crRes)); - + List<Vertex> tenRes = engine.findParents(tenant); assertTrue(tenRes.containsAll(tenExpected) && tenExpected.containsAll(tenRes)); - + List<Vertex> vsRes = engine.findParents(vserver); assertTrue(vsRes.containsAll(vsExpected) && vsExpected.containsAll(vsRes)); //verify expected ordering - start, parent, grandparent @@ -84,131 +85,157 @@ public class GraphTraversalQueryEngineTest extends AAISetup { assertTrue(vsRes.get(1).equals(tenant)); assertTrue(vsRes.get(2).equals(cloudreg)); } - + + @Test + public void testFindAllParentsGivenAaiUris(){ + + //setup + Graph graph = TinkerGraph.open(); + + Vertex cloudreg = graph.addVertex(T.id, "00", "aai-node-type", "cloud-region", "aai-uri", "/cloud-infrastructure/cloud-regions/cloud-region/testowner/testid"); + Vertex tenant = graph.addVertex(T.id, "10", "aai-node-type", "tenant", "aai-uri", "/cloud-infrastructure/cloud-regions/cloud-region/testowner/testid/tenants/tenant/testTenant1"); + Vertex vserver = graph.addVertex(T.id, "20", "aai-node-type", "vserver", "aai-uri", "/cloud-infrastructure/cloud-regions/cloud-region/testowner/testid/tenants/tenant/testTenant1/vservers/vserver/testVserver1"); + + String [] uris = new String[]{ + "/cloud-infrastructure/cloud-regions/cloud-region/testowner/testid/tenants/tenant/testTenant1", + "/cloud-infrastructure/cloud-regions/cloud-region/testowner/testid/tenants/tenant/testTenant1/vservers/vserver/testVserver1", + "/cloud-infrastructure/cloud-regions/cloud-region/testowner/testid" + }; + + GraphTraversalSource g = graph.traversal(); + GraphTraversalQueryEngine queryEngine = new GraphTraversalQueryEngine(g); + List<Vertex> vertices = queryEngine.findParents(uris); + + assertThat("Returned vertices should be 3 cloud region, tenant and vserver", vertices.size(), is(3)); + assertThat("Expected the first element back to be vserver", vertices.get(0), is(vserver)); + assertThat("Expected the second element back to be tenant", vertices.get(1), is(tenant)); + assertThat("Expected the element back to be cloud region", vertices.get(2), is(cloudreg)); + } + @Test public void testFindAllChildren() throws AAIException { //setup Graph graph = TinkerGraph.open(); - + Vertex cloudreg = graph.addVertex(T.id, "00", "aai-node-type", "cloud-region"); Vertex tenant = graph.addVertex(T.id, "10", "aai-node-type", "tenant"); Vertex vserver = graph.addVertex(T.id, "20", "aai-node-type", "vserver"); Vertex vserver2 = graph.addVertex(T.id, "21", "aai-node-type", "vserver"); Vertex oam = graph.addVertex(T.id, "30", "aai-node-type", "oam-network"); - + GraphTraversalSource g = graph.traversal(); - + edgeSer.addTreeEdge(g, cloudreg, tenant); edgeSer.addTreeEdge(g, tenant, vserver); edgeSer.addTreeEdge(g, tenant, vserver2); edgeSer.addTreeEdge(g, cloudreg, oam); - + List<Vertex> crExpected = new ArrayList<>(Arrays.asList(cloudreg, tenant, vserver, vserver2, oam)); List<Vertex> vsExpected = new ArrayList<>(Arrays.asList(vserver)); - + GraphTraversalQueryEngine engine = new GraphTraversalQueryEngine(g); - + //test List<Vertex> crRes = engine.findAllChildren(cloudreg); assertTrue(crRes.containsAll(crExpected) && crExpected.containsAll(crRes)); - + List<Vertex> vsRes = engine.findAllChildren(vserver); assertTrue(vsRes.containsAll(vsExpected) && vsExpected.containsAll(vsRes)); } - + @Test public void testFindChildrenOfType() throws AAIException { //setup Graph graph = TinkerGraph.open(); - + Vertex gv = graph.addVertex(T.id, "00", "aai-node-type", "generic-vnf"); Vertex lint1 = graph.addVertex(T.id, "10", "aai-node-type", "l-interface"); Vertex lint2 = graph.addVertex(T.id, "11", "aai-node-type", "l-interface"); Vertex lag = graph.addVertex(T.id, "20", "aai-node-type", "lag-interface"); Vertex lint3 = graph.addVertex(T.id, "12", "aai-node-type", "l-interface"); - + GraphTraversalSource g = graph.traversal(); - + edgeSer.addTreeEdge(g, gv, lint1); edgeSer.addTreeEdge(g, gv, lint2); edgeSer.addTreeEdge(g, gv, lag); edgeSer.addTreeEdge(g, lag, lint3); - + List<Vertex> expected = new ArrayList<>(Arrays.asList(lint1, lint2)); - + GraphTraversalQueryEngine engine = new GraphTraversalQueryEngine(g); - + //test List<Vertex> results = engine.findChildrenOfType(gv, "l-interface"); assertTrue(results.containsAll(expected) && expected.containsAll(results)); } - + @Test public void testFindChildren() throws AAIException { //setup Graph graph = TinkerGraph.open(); - + Vertex gv = graph.addVertex(T.id, "00", "aai-node-type", "generic-vnf"); Vertex lint1 = graph.addVertex(T.id, "10", "aai-node-type", "l-interface"); Vertex lint2 = graph.addVertex(T.id, "11", "aai-node-type", "l-interface"); Vertex lag = graph.addVertex(T.id, "20", "aai-node-type", "lag-interface"); Vertex lint3 = graph.addVertex(T.id, "12", "aai-node-type", "l-interface"); - + GraphTraversalSource g = graph.traversal(); - + edgeSer.addTreeEdge(g, gv, lint1); edgeSer.addTreeEdge(g, gv, lint2); edgeSer.addTreeEdge(g, gv, lag); edgeSer.addTreeEdge(g, lag, lint3); - + List<Vertex> expected = new ArrayList<>(Arrays.asList(lint1, lint2, lag)); - + GraphTraversalQueryEngine engine = new GraphTraversalQueryEngine(g); - + //test List<Vertex> results = engine.findChildren(gv); assertTrue(results.containsAll(expected) && expected.containsAll(results)); } - + @Test public void testFindRelatedVertices() throws AAIException { //setup - + Graph graph = TinkerGraph.open(); - + Vertex gv = graph.addVertex(T.id, "00", "aai-node-type", "generic-vnf"); Vertex lint = graph.addVertex(T.id, "10", "aai-node-type", "l-interface"); Vertex lint2 = graph.addVertex(T.id, "11", "aai-node-type", "l-interface"); Vertex log = graph.addVertex(T.id, "20", "aai-node-type", "logical-link"); - + GraphTraversalSource g = graph.traversal(); - + edgeSer.addTreeEdge(g, gv, lint); edgeSer.addEdge(g, lint, log); edgeSer.addEdge(g, log, lint2); - + List<Vertex> outExpected = new ArrayList<>(Arrays.asList(lint)); List<Vertex> inExpected = new ArrayList<>(Arrays.asList(lint, lint2)); List<Vertex> bothExpected = new ArrayList<>(Arrays.asList(log)); - + GraphTraversalQueryEngine engine = new GraphTraversalQueryEngine(g); - + //test List<Vertex> outRes = engine.findRelatedVertices(gv, Direction.IN, "org.onap.relationships.inventory.BelongsTo", "l-interface"); assertTrue(outRes.containsAll(outExpected) && outExpected.containsAll(outRes)); List<Vertex> inRes = engine.findRelatedVertices(log, Direction.IN, "tosca.relationships.network.LinksTo", "l-interface"); assertTrue(inRes.containsAll(inExpected) && inExpected.containsAll(inRes)); - + List<Vertex> bothRes = engine.findRelatedVertices(lint, Direction.BOTH, "tosca.relationships.network.LinksTo", "logical-link"); assertTrue(bothRes.containsAll(bothExpected) && bothExpected.containsAll(bothRes)); } - + @Test public void testFindSubGraph() throws AAIException, EdgeRuleNotFoundException, AmbiguousRuleChoiceException { //setup Graph graph = TinkerGraph.open(); - + Vertex cr = graph.addVertex(T.id, "00", "aai-node-type", "cloud-region"); Vertex ten = graph.addVertex(T.id, "10", "aai-node-type", "tenant"); Vertex ten2 = graph.addVertex(T.id, "11", "aai-node-type", "tenant"); @@ -225,7 +252,7 @@ public class GraphTraversalQueryEngineTest extends AAISetup { Vertex modelVer = graph.addVertex(T.id, "100", "aai-node-type", "model-ver"); GraphTraversalSource g = graph.traversal(); - + Edge crTen = edgeSer.addTreeEdge(g, cr, ten); Edge crTen2 = edgeSer.addTreeEdge(g, cr, ten2); Edge tenVs = edgeSer.addTreeEdge(g, ten, vs); @@ -234,14 +261,14 @@ public class GraphTraversalQueryEngineTest extends AAISetup { Edge lintLog = edgeSer.addEdge(g, lint, log); Edge vsGv = edgeSer.addEdge(g, vs, gv); edgeSer.addEdge(g, gv, vnfc); - + edgeSer.addTreeEdge(g, gv, lag); edgeSer.addTreeEdge(g, lag, lint2); Edge modelVerEdge = edgeSer.addPrivateEdge(g, gv, modelVer, null); edgeSer.addTreeEdge(g, comp, ctag); Edge crComp = edgeSer.addEdge(g, cr, comp); - + //findSubGraph(cr, 0, true) List<Element> expected1 = new ArrayList<>(Arrays.asList(cr)); //findSubGraph(cr, 2, true) @@ -249,48 +276,48 @@ public class GraphTraversalQueryEngineTest extends AAISetup { crTen, crTen2, tenVs, tenVs2)); //findSubGraph(cr) List<Element> expected3 = new ArrayList<>(Arrays.asList(cr, ten, ten2, comp, vs, vs2, lint, gv, log, - crTen, crTen2, crComp, tenVs, tenVs2, vsLInt, + crTen, crTen2, crComp, tenVs, tenVs2, vsLInt, vsGv, lintLog)); - + GraphTraversalQueryEngine engine = new GraphTraversalQueryEngine(g); - + //test Tree<Element> res1 = engine.findSubGraph(cr, 0, true); Set<Element> resList1 = treeToList(res1); assertTrue(resList1.containsAll(expected1) && expected1.containsAll(resList1)); - + Tree<Element> res2 = engine.findSubGraph(cr, 2, true); Set<Element> resList2 = treeToList(res2); assertTrue(resList2.containsAll(expected2) && expected2.containsAll(resList2)); - + Tree<Element> res3 = engine.findSubGraph(cr); Set<Element> resList3 = treeToList(res3); assertThat(resList3, containsInAnyOrder(expected3.toArray())); // assertTrue(resList3.containsAll(expected3) && expected3.containsAll(resList3)); } - + /** - * convenience helper method to make it easier to check the contents of the tree against + * convenience helper method to make it easier to check the contents of the tree against * a list of expected results * @param tree - the tree whose contents you want in collection form * @return set of the contents of the tree */ private Set<Element> treeToList(Tree<Element> tree) { Set<Element> ret = new HashSet<>(); - + for (Element key : tree.keySet()) { ret.add(key); ret.addAll(treeToList(tree.get(key))); } - + return ret; } - + @Test public void testFindEdgesForVersion() throws AAIException, EdgeRuleNotFoundException, AmbiguousRuleChoiceException { //setup Graph graph = TinkerGraph.open(); - + Vertex gv = graph.addVertex(T.id, "00", "aai-node-type", "generic-vnf"); Vertex vnfc = graph.addVertex(T.id, "10", "aai-node-type", "vnfc"); Vertex lob = graph.addVertex(T.id, "20", "aai-node-type", "line-of-business"); @@ -303,16 +330,16 @@ public class GraphTraversalQueryEngineTest extends AAISetup { .addEdge("some-edge", cr, CONTAINS.toString(), "NONE"); GraphTraversalSource g = graph.traversal(); - + edgeSer.addTreeEdge(g, gv, lint); //tree edge so shouldn't appear in results Edge gvVnfc = edgeSer.addEdge(g, gv, vnfc); edgeSer.addEdge(g, gv, lob); //v11/12 not v10 Edge gvMvEdge = edgeSer.addPrivateEdge(g, gv, mv, null); List<Edge> expected = new ArrayList<>(Arrays.asList(gvVnfc)); - + GraphTraversalQueryEngine engine = new GraphTraversalQueryEngine(g); - + //test Loader loader = loaderFactory.createLoaderForVersion(ModelType.MOXY, schemaVersions.getRelatedLinkVersion()); List<Edge> results = engine.findEdgesForVersion(gv, loader); @@ -322,27 +349,27 @@ public class GraphTraversalQueryEngineTest extends AAISetup { results = engine.findEdgesForVersion(cr, loader); assertThat(results, containsInAnyOrder(expected.toArray())); } - + @Test public void testFindCousinVertices() throws AAIException { //setup Graph graph = TinkerGraph.open(); - + Vertex gv = graph.addVertex(T.id, "00", "aai-node-type", "generic-vnf"); Vertex vnfc = graph.addVertex(T.id, "10", "aai-node-type", "vnfc"); Vertex lob = graph.addVertex(T.id, "20", "aai-node-type", "line-of-business"); Vertex lint = graph.addVertex(T.id, "30", "aai-node-type", "l-interface"); - + GraphTraversalSource g = graph.traversal(); - + edgeSer.addTreeEdge(g, gv, lint); //tree edge so shouldn't appear in results edgeSer.addEdge(g, gv, vnfc); edgeSer.addEdge(g, gv, lob); - + List<Vertex> expected = new ArrayList<>(Arrays.asList(vnfc, lob)); - + GraphTraversalQueryEngine engine = new GraphTraversalQueryEngine(g); - + //test List<Vertex> results = engine.findCousinVertices(gv); assertTrue(results.containsAll(expected) && expected.containsAll(results)); diff --git a/aai-core/src/test/resources/payloads/resource/cloud-region-with-vlan.json b/aai-core/src/test/resources/payloads/resource/cloud-region-with-vlan.json new file mode 100644 index 00000000..bad4fadf --- /dev/null +++ b/aai-core/src/test/resources/payloads/resource/cloud-region-with-vlan.json @@ -0,0 +1,50 @@ +{ + "cloud-owner" : "junit-cloud-owner-with-vlan", + "cloud-region-id" : "junit-cloud-region-with-vlan", + "cloud-type" : "P9P1X6U9eDXR", + "owner-defined-type" : "OUrR8kI6Br", + "tenants" : { + "tenant" : [ { + "tenant-id" : "tenant1-with-vlan", + "tenant-name" : "yhgVBcv3Pr", + "vservers" : { + "vserver" : [ { + "vserver-id" : "vserver1-with-vlan", + "vserver-name" : "P3SJ347Uyv", + "vserver-name2" : "1dHd", + "vserver-selflink" : "v7dU8H", + "in-maint" : false, + "is-closed-loop-disabled" : true, + "l-interfaces" : { + "l-interface" : [ { + "interface-name" : "top-linterface-with-vlan", + "interface-role" : "3W1FAJGSQ", + "v6-wan-link-ip" : "WugWw3N", + "selflink" : "Of4j0pU", + "interface-id" : "eoW", + "macaddr" : "XNbbIy33", + "network-name" : "ZETDv5sGhiS", + "management-option" : "qR3RyCxgEU", + "vlans" : { + "vlan" : [ { + "vlan-interface" : "test-vlan-interface-1", + "vlan-id-inner" : 884, + "vlan-id-outer" : 992, + "speed-value" : "RyFPm", + "speed-units" : "ZrckmLff7b", + "vlan-description" : "zjAeUFgeagpf", + "backdoor-connection" : "gANMvUquB", + "vpn-key" : "l0rV7bb2Sc", + "orchestration-status" : "WVnLpbzIx", + "in-maint" : false, + "prov-status" : "tYMRi6df", + "is-ip-unnumbered" : false + } ] + } + } ] + } + } ] + } + } ] + } +} diff --git a/aai-core/src/test/resources/payloads/resource/cloud-region.json b/aai-core/src/test/resources/payloads/resource/cloud-region.json new file mode 100644 index 00000000..0bbf6398 --- /dev/null +++ b/aai-core/src/test/resources/payloads/resource/cloud-region.json @@ -0,0 +1,4 @@ +{ + "cloud-owner": "cloud-region-owner-with-vip-ipv4", + "cloud-region-id": "cloud-region-id-with-vip-ipv4" +} diff --git a/aai-core/src/test/resources/payloads/resource/entitlement.json b/aai-core/src/test/resources/payloads/resource/entitlement.json new file mode 100644 index 00000000..09afb617 --- /dev/null +++ b/aai-core/src/test/resources/payloads/resource/entitlement.json @@ -0,0 +1,4 @@ +{ + "group-uuid":"g1", + "resource-uuid":"r1" +} diff --git a/aai-core/src/test/resources/payloads/resource/model-element.json b/aai-core/src/test/resources/payloads/resource/model-element.json new file mode 100644 index 00000000..935f1b05 --- /dev/null +++ b/aai-core/src/test/resources/payloads/resource/model-element.json @@ -0,0 +1,230 @@ +{ + "model-element-uuid": "acf8b6cf-e051-4c1b-bcad-b24792f826cf-test1", + "new-data-del-flag": "7hWigbwQCh", + "cardinality": "loWHX7E8X", + "linkage-points": [ + "Ve4JU" + ], + "model-elements": { + "model-element": [ + { + "model-element-uuid": "01b757d5-6468-48d0-a1cd-2aa8310dadab-test1", + "new-data-del-flag": "IXoM0QnE0W", + "cardinality": "THLHKl" + }, + { + "model-element-uuid": "2e5d5696-2221-4bcf-a493-e0ca92e323de-test1", + "new-data-del-flag": "icATJZ7Vbhz", + "cardinality": "tOIz" + } + ] + }, + "model-constraints": { + "model-constraint": [ + { + "model-constraint-uuid": "9f2e872b-000e-4bb9-9398-f308a997dd4f-test1", + "constrained-element-set-uuid-to-replace": "XfAVftTYu", + "constrained-element-sets": { + "constrained-element-set": [ + { + "constrained-element-set-uuid": "103cc6f7-b648-4a3f-b5aa-0ffdac4d4bc5-test1", + "constraint-type": "FLKyNFdqbSSje", + "check-type": "IDLSYTM", + "element-choice-sets": { + "element-choice-set": [ + { + "element-choice-set-uuid": "5c063d38-d83e-4fe5-a721-86296fe39267-test1", + "element-choice-set-name": "EFc5b4k7LN8hF", + "cardinality": "xx8", + "model-elements": { + "model-element": [ + { + "model-element-uuid": "0b7a5aa2-5061-4916-a2c6-5280e67e0a71-test1", + "new-data-del-flag": "x1Lo15W", + "cardinality": "COu" + }, + { + "model-element-uuid": "f0af348b-1701-409f-bb11-e3acc77ad718-test1", + "new-data-del-flag": "eiWkNQEj", + "cardinality": "3aju5XtI" + } + ] + } + }, + { + "element-choice-set-uuid": "2c0888a6-fb6d-4a72-b0a1-3349c90d9e33-test1", + "element-choice-set-name": "Ko4", + "cardinality": "aXjnyYfCRFTDK", + "model-elements": { + "model-element": [ + { + "model-element-uuid": "ea8853be-8473-4f80-8229-9041864e143e-test1", + "new-data-del-flag": "4tirsCs0fjDdS", + "cardinality": "v2hbEn8u" + }, + { + "model-element-uuid": "f1267f37-5aa0-4f4a-ae66-3cf782ff4a9d-test1", + "new-data-del-flag": "mzuWZTlc9f", + "cardinality": "ysBXVL" + } + ] + } + } + ] + } + }, + { + "constrained-element-set-uuid": "a82256df-5bc8-4433-851f-9b09f63432b4-test1", + "constraint-type": "qgnLpj", + "check-type": "zFug3wfyCe5cF", + "element-choice-sets": { + "element-choice-set": [ + { + "element-choice-set-uuid": "3ce79981-c0cc-4210-9dab-89b8866797be-test1", + "element-choice-set-name": "rZ2f7Es", + "cardinality": "H1b", + "model-elements": { + "model-element": [ + { + "model-element-uuid": "52362a88-eb7a-4fe5-a6d5-1ca414cfed64-test1", + "new-data-del-flag": "8cQmvQgeKJz", + "cardinality": "6T7GiwYlJR5" + }, + { + "model-element-uuid": "e9d00d89-a340-4ef1-ab19-63367a5e8642-test1", + "new-data-del-flag": "ec8DWfYeMJdr", + "cardinality": "Bumc8fT7" + } + ] + } + }, + { + "element-choice-set-uuid": "335bac38-9739-4ff7-8743-e186310d86a9-test1", + "element-choice-set-name": "K0MH", + "cardinality": "rL3fH1Oz", + "model-elements": { + "model-element": [ + { + "model-element-uuid": "29244639-38ab-45b2-82b7-b91001ad56da-test1", + "new-data-del-flag": "YZGbB6", + "cardinality": "ushcYd" + }, + { + "model-element-uuid": "e36d3159-bfa7-465a-849f-de9ca6d4f304-test1", + "new-data-del-flag": "ZtzRhZbxv2i", + "cardinality": "NE4m8n5hj" + } + ] + } + } + ] + } + } + ] + } + }, + { + "model-constraint-uuid": "9e74a97c-52a9-43b4-bb9d-144cb5a2216e-test1", + "constrained-element-set-uuid-to-replace": "bZqdarfk6", + "constrained-element-sets": { + "constrained-element-set": [ + { + "constrained-element-set-uuid": "6c4db1da-8860-4445-a0ad-3ae00709e2bb-test1", + "constraint-type": "Xzat2eVcU36g", + "check-type": "3Y5Bi32VkRHFl", + "element-choice-sets": { + "element-choice-set": [ + { + "element-choice-set-uuid": "33dc52b0-3461-4ca6-a195-c3cacc2ab426-test1", + "element-choice-set-name": "2ziwMvQGmanJ", + "cardinality": "7XXcdT5sqsOf", + "model-elements": { + "model-element": [ + { + "model-element-uuid": "c0fb7805-dfc4-4972-9a1c-d9409560f6e3-test1", + "new-data-del-flag": "262Lx", + "cardinality": "0ZaryC" + }, + { + "model-element-uuid": "e868506d-ef7d-4843-9c1b-47712c7c1b77-test1", + "new-data-del-flag": "f7cKUCEbVuj6", + "cardinality": "6LlYciE99" + } + ] + } + }, + { + "element-choice-set-uuid": "aca6b107-ba99-4e10-aef5-ff35a5b25a60-test1", + "element-choice-set-name": "lqfZDs", + "cardinality": "9AwB7", + "model-elements": { + "model-element": [ + { + "model-element-uuid": "527faaf0-f989-47a4-9ffd-4ea16d034be1-test1", + "new-data-del-flag": "mPra14ZfLilOw", + "cardinality": "y6mYr6" + }, + { + "model-element-uuid": "dfd7c245-0a28-494d-b388-faf27481674c-test1", + "new-data-del-flag": "muGR", + "cardinality": "TUj4Z" + } + ] + } + } + ] + } + }, + { + "constrained-element-set-uuid": "17999338-a062-4447-b8c3-b27228255ede-test1", + "constraint-type": "WhTbdWCLyA", + "check-type": "tN02MBeB", + "element-choice-sets": { + "element-choice-set": [ + { + "element-choice-set-uuid": "633c6757-2270-48fb-bff7-61145e6c943f-test1", + "element-choice-set-name": "Ith1PEe6", + "cardinality": "8sta", + "model-elements": { + "model-element": [ + { + "model-element-uuid": "827c40a9-cabe-460a-b537-2f117ca62db5-test1", + "new-data-del-flag": "fS65rXWQY", + "cardinality": "Kq42Z8GzCh" + }, + { + "model-element-uuid": "c107a4bd-59e4-4249-bbc3-a006645dcb01-test1", + "new-data-del-flag": "EtgTeJdo19", + "cardinality": "tvzpgg" + } + ] + } + }, + { + "element-choice-set-uuid": "930260d8-4cfd-4494-ba2c-d619c143a390-test1", + "element-choice-set-name": "ugDc0", + "cardinality": "K8MXjV", + "model-elements": { + "model-element": [ + { + "model-element-uuid": "f17f9eea-d421-4e8a-8628-32a4b56507ef-test1", + "new-data-del-flag": "rjAbq7gyZWe", + "cardinality": "VbDCFB9" + }, + { + "model-element-uuid": "ee1d800e-46c1-4bb0-8664-f257850ffff9-test1", + "new-data-del-flag": "YontPXK4sj4s", + "cardinality": "UQnNPld4sE" + } + ] + } + } + ] + } + } + ] + } + } + ] + } +} diff --git a/aai-core/src/test/resources/payloads/resource/model.json b/aai-core/src/test/resources/payloads/resource/model.json new file mode 100644 index 00000000..a86a1de8 --- /dev/null +++ b/aai-core/src/test/resources/payloads/resource/model.json @@ -0,0 +1,975 @@ +{ + "model-invariant-id": "24c04fc5-f3f8-43ec-8792-c6f940638676-test1", + "model-type": "woZ4dpF3TM", + "model-vers": { + "model-ver": [ + { + "model-version-id": "0c4c59f0-9864-43ca-b0c2-ca38746b72a5-test1", + "model-name": "vzZn3Q3h", + "model-version": "RcN2FIwUF", + "distribution-status": "qcCHkye", + "model-description": "qcPB4hOig9", + "model-elements": { + "model-element": [ + { + "model-element-uuid": "0dc2b8b6-af8d-4213-970b-7861a603fc86-test1", + "new-data-del-flag": "OzhypC", + "cardinality": "vNpFfHn", + "linkage-points": [ + "BTDVw7pA" + ], + "model-elements": { + "model-element": [ + { + "model-element-uuid": "0ff7bfc5-e42b-474d-b728-cfdc08310971-test1", + "new-data-del-flag": "v54vhcTX", + "cardinality": "uHLsCw" + }, + { + "model-element-uuid": "4fb1b036-9963-467e-93fe-c6e499859b2e-test1", + "new-data-del-flag": "UAJAjOCe9dIiW", + "cardinality": "8PhfKI" + } + ] + }, + "model-constraints": { + "model-constraint": [ + { + "model-constraint-uuid": "782ba24a-28ab-4fd0-8e69-da10cc5373f3-test1", + "constrained-element-set-uuid-to-replace": "8vcq", + "constrained-element-sets": { + "constrained-element-set": [ + { + "constrained-element-set-uuid": "a33e65c3-1198-4d4c-9799-2b521e4c4212-test1", + "constraint-type": "4jqozTvJSD", + "check-type": "J9aM", + "element-choice-sets": { + "element-choice-set": [ + { + "element-choice-set-uuid": "7df27a94-06c8-46ef-9fc2-5900d8cffbb0-test1", + "element-choice-set-name": "wjNT", + "cardinality": "XSPmZH", + "model-elements": { + "model-element": [ + { + "model-element-uuid": "fcf1450b-cf5c-414a-99c0-2bd7ca247997-test1", + "new-data-del-flag": "uhwWkaDw", + "cardinality": "jeBU9v" + }, + { + "model-element-uuid": "85bfca5f-03ac-4653-a3b4-bdfad8dd1c13-test1", + "new-data-del-flag": "L2BQe2kyA", + "cardinality": "asciE2y7RWGVa" + } + ] + } + }, + { + "element-choice-set-uuid": "d20040e2-0417-4a2d-978e-e6c9f353a0c5-test1", + "element-choice-set-name": "x7vEDj5", + "cardinality": "A6f2Us", + "model-elements": { + "model-element": [ + { + "model-element-uuid": "5cdcbb91-22eb-4c12-9a54-b8c3ff5aa591-test1", + "new-data-del-flag": "BCo", + "cardinality": "FejO1GRl" + }, + { + "model-element-uuid": "7a401382-7d45-40f9-8fe7-236629273226-test1", + "new-data-del-flag": "zFj", + "cardinality": "9DzyB7u" + } + ] + } + } + ] + } + }, + { + "constrained-element-set-uuid": "2f7a375a-135d-461b-b806-e7cd636506f4-test1", + "constraint-type": "Toy", + "check-type": "uYEWZon81Wa", + "element-choice-sets": { + "element-choice-set": [ + { + "element-choice-set-uuid": "8aab42ee-561f-4506-ab66-6432442193f8-test1", + "element-choice-set-name": "RpJJn1eRQL", + "cardinality": "q0XXZ52", + "model-elements": { + "model-element": [ + { + "model-element-uuid": "2a35ad40-02ef-4947-b20c-94a90440ffc7-test1", + "new-data-del-flag": "gXHt5O5XyRKb", + "cardinality": "idg0cH" + }, + { + "model-element-uuid": "7aae6c34-086e-477b-845a-01cedc2a4e25-test1", + "new-data-del-flag": "Zwj", + "cardinality": "3vkT" + } + ] + } + }, + { + "element-choice-set-uuid": "f42dcd25-aa82-401f-b987-5d0f46d6b5d6-test1", + "element-choice-set-name": "Cuon", + "cardinality": "cfxfo3MAF", + "model-elements": { + "model-element": [ + { + "model-element-uuid": "2f9f4c5c-216c-45c0-913b-5513faa6f887-test1", + "new-data-del-flag": "2ZTs", + "cardinality": "zki" + }, + { + "model-element-uuid": "6abd9eb0-59b2-45d1-bc31-51913bc9f54b-test1", + "new-data-del-flag": "9cQkkA", + "cardinality": "NGY7CgvUQDN" + } + ] + } + } + ] + } + } + ] + } + }, + { + "model-constraint-uuid": "8544de93-b647-4d79-aa55-a3ebe01664e7-test1", + "constrained-element-set-uuid-to-replace": "phbhKDPCcUjK", + "constrained-element-sets": { + "constrained-element-set": [ + { + "constrained-element-set-uuid": "61624b66-e059-49c6-a97c-06ca4643e259-test1", + "constraint-type": "gp0nB63dH", + "check-type": "NFnVJKceCMc", + "element-choice-sets": { + "element-choice-set": [ + { + "element-choice-set-uuid": "f85f1ee8-d28f-4128-83d8-02c2e07f9e27-test1", + "element-choice-set-name": "8noi", + "cardinality": "mTFoGk", + "model-elements": { + "model-element": [ + { + "model-element-uuid": "1e15718d-17e8-4a34-852e-2edede549b63-test1", + "new-data-del-flag": "f3p1f", + "cardinality": "c0Z6zG0iKX" + }, + { + "model-element-uuid": "4ad51c91-1e90-4683-b9ea-017cf0bc528e-test1", + "new-data-del-flag": "05r47Aldegi", + "cardinality": "aoF" + } + ] + } + }, + { + "element-choice-set-uuid": "fb2c7824-fc87-4fe9-93c6-10586a59384e-test1", + "element-choice-set-name": "EIjKr0w3tJ", + "cardinality": "qlw6EFFF", + "model-elements": { + "model-element": [ + { + "model-element-uuid": "2395bed7-399d-41cd-81af-e5002854bc69-test1", + "new-data-del-flag": "Uj2", + "cardinality": "eLHBGqv7wz5z" + }, + { + "model-element-uuid": "77840aeb-0868-49c1-a97d-6ded16115174-test1", + "new-data-del-flag": "rOR", + "cardinality": "ddXm59kMQ01y" + } + ] + } + } + ] + } + }, + { + "constrained-element-set-uuid": "4f1f30ee-5bd5-4f19-b11d-23ebf0fcd569-test1", + "constraint-type": "Ul7rn0Gyh", + "check-type": "5KpT6x", + "element-choice-sets": { + "element-choice-set": [ + { + "element-choice-set-uuid": "d2b9a3f5-29de-45ba-ad5a-184e0635607a-test1", + "element-choice-set-name": "OWFEeT", + "cardinality": "g2wvznpf", + "model-elements": { + "model-element": [ + { + "model-element-uuid": "93d0b10b-529a-4ad4-88fa-afc7273ec538-test1", + "new-data-del-flag": "BHqDTu", + "cardinality": "bUZd3Zj4b" + }, + { + "model-element-uuid": "fd6548f8-211a-4194-a78e-857efc443180-test1", + "new-data-del-flag": "ygDuebv", + "cardinality": "UZx1v0HH7I" + } + ] + } + }, + { + "element-choice-set-uuid": "f393b086-40b6-47d9-b28a-b830d5d7f896-test1", + "element-choice-set-name": "dxt8afBT", + "cardinality": "L3mtZIH342JVw", + "model-elements": { + "model-element": [ + { + "model-element-uuid": "d802155e-8e16-4b9d-986a-d0f490d83e56-test1", + "new-data-del-flag": "cPapfw", + "cardinality": "4O3aiKf" + }, + { + "model-element-uuid": "64cf1800-77b7-4c1d-80b2-38fc156769a6-test1", + "new-data-del-flag": "T2dc7t3", + "cardinality": "LTrGUfoB7imS" + } + ] + } + } + ] + } + } + ] + } + } + ] + } + }, + { + "model-element-uuid": "1db3d04c-92c6-4100-b851-16a0a2318909-test1", + "new-data-del-flag": "9Gc", + "cardinality": "vtJk", + "linkage-points": [ + "NKC5OiZl" + ], + "model-elements": { + "model-element": [ + { + "model-element-uuid": "16b90f9d-d2ed-46e8-8a0d-f2907ecf723d-test1", + "new-data-del-flag": "jcjL", + "cardinality": "qxX" + }, + { + "model-element-uuid": "46afb085-7025-4a35-99e3-6170dc98b74b-test1", + "new-data-del-flag": "tXgrF6T4HrirE", + "cardinality": "55waV3oUI" + } + ] + }, + "model-constraints": { + "model-constraint": [ + { + "model-constraint-uuid": "6f6fbf96-c9a7-4393-9e81-284d194ba6a3-test1", + "constrained-element-set-uuid-to-replace": "HF81PuSuM", + "constrained-element-sets": { + "constrained-element-set": [ + { + "constrained-element-set-uuid": "cf2d2ff1-1ffc-4ad6-b3ce-8729c3352637-test1", + "constraint-type": "XfD", + "check-type": "mVERn7luqFc", + "element-choice-sets": { + "element-choice-set": [ + { + "element-choice-set-uuid": "85fb8953-f86d-4d58-8ca2-3169cba074c6-test1", + "element-choice-set-name": "4s6Jf", + "cardinality": "KL8eVh9xZ", + "model-elements": { + "model-element": [ + { + "model-element-uuid": "7b1fd5b5-b633-4ed6-a9e8-9c3430eaaae0-test1", + "new-data-del-flag": "uNbESfr", + "cardinality": "aEj2c5UXN2qW" + }, + { + "model-element-uuid": "c67a3856-3812-4c16-abb3-484fe68ba65e-test1", + "new-data-del-flag": "cg1GbGyps", + "cardinality": "cCPBuauJ" + } + ] + } + }, + { + "element-choice-set-uuid": "4748a324-a8aa-420a-9f48-0fd0b7418a1a-test1", + "element-choice-set-name": "U3JuW0tx", + "cardinality": "4jpXRS43G", + "model-elements": { + "model-element": [ + { + "model-element-uuid": "daad8caa-dbfc-487a-91d4-a93021a86e0c-test1", + "new-data-del-flag": "ZoRQyflmIqEaA", + "cardinality": "Mu7PzxNg8cta" + }, + { + "model-element-uuid": "e5a640f1-1203-410c-8665-0ee325179368-test1", + "new-data-del-flag": "thsF0L", + "cardinality": "fViD" + } + ] + } + } + ] + } + }, + { + "constrained-element-set-uuid": "5d1b2701-d719-4eb5-b5bc-355f99042648-test1", + "constraint-type": "4wPy2Xd", + "check-type": "sDuGfZji", + "element-choice-sets": { + "element-choice-set": [ + { + "element-choice-set-uuid": "d01f1c5b-5ba1-4c21-b80d-901867a1d810-test1", + "element-choice-set-name": "FdrVe6o", + "cardinality": "F1MXs1fET0jr3", + "model-elements": { + "model-element": [ + { + "model-element-uuid": "6e059bfe-5386-4491-8e84-b1b6dd8b5333-test1", + "new-data-del-flag": "DfodMIT72h7", + "cardinality": "KvRbLIJFL" + }, + { + "model-element-uuid": "ea73886a-ff64-4d3c-9b17-5ae5b2196dea-test1", + "new-data-del-flag": "n9PnoK5", + "cardinality": "0E3fM6" + } + ] + } + }, + { + "element-choice-set-uuid": "abb55d08-28b6-48d8-b19e-91b12c096649-test1", + "element-choice-set-name": "MRFYeF7", + "cardinality": "b64jIhgbYH7", + "model-elements": { + "model-element": [ + { + "model-element-uuid": "c449a692-bd7d-4d86-b46e-1c417b17099f-test1", + "new-data-del-flag": "ApwuLwUkkw", + "cardinality": "m23c6lsF" + }, + { + "model-element-uuid": "7cb770d9-55d8-45d2-8b9b-abdff7a2c88b-test1", + "new-data-del-flag": "MeSjvno", + "cardinality": "lGFfcOOl19" + } + ] + } + } + ] + } + } + ] + } + }, + { + "model-constraint-uuid": "ce9e9365-1fec-4c29-8201-c4417ee2ea1d-test1", + "constrained-element-set-uuid-to-replace": "Buq56Km4W9BD", + "constrained-element-sets": { + "constrained-element-set": [ + { + "constrained-element-set-uuid": "3dcea521-a227-46f3-bd4f-ef1fcff0755e-test1", + "constraint-type": "WZr", + "check-type": "pxJXuyaXvsaQy", + "element-choice-sets": { + "element-choice-set": [ + { + "element-choice-set-uuid": "19dc8b4a-c58b-4ff8-b507-877c6521d91a-test1", + "element-choice-set-name": "af5CO7sD5TWwz", + "cardinality": "uGwotewgnmls", + "model-elements": { + "model-element": [ + { + "model-element-uuid": "5d476750-ddc3-4822-b629-5fba93445ed9-test1", + "new-data-del-flag": "mMjS6OflV3c", + "cardinality": "Gidw5" + }, + { + "model-element-uuid": "d4d4f1f6-ad60-4a94-b076-eb36db6fb362-test1", + "new-data-del-flag": "kWLrcR", + "cardinality": "AU6llmk" + } + ] + } + }, + { + "element-choice-set-uuid": "d6616e1a-3de5-4981-a216-805bdd97d65e-test1", + "element-choice-set-name": "9w67AaiJNt0", + "cardinality": "kKax01oqb", + "model-elements": { + "model-element": [ + { + "model-element-uuid": "bb11c9c1-5013-4b51-9a06-9729addfd4af-test1", + "new-data-del-flag": "ANM8TN0a", + "cardinality": "UPtA8wc4m" + }, + { + "model-element-uuid": "71b323c0-1829-414e-85f6-99f4b5835e44-test1", + "new-data-del-flag": "okC9", + "cardinality": "1KP3eU5j8" + } + ] + } + } + ] + } + }, + { + "constrained-element-set-uuid": "77d1cc2d-6e94-4a4f-a7ec-f725605f18d3-test1", + "constraint-type": "inJa", + "check-type": "JkoIos3V", + "element-choice-sets": { + "element-choice-set": [ + { + "element-choice-set-uuid": "9893bb02-e422-4810-bccc-a594b0489ded-test1", + "element-choice-set-name": "ZIync", + "cardinality": "WZfSZe", + "model-elements": { + "model-element": [ + { + "model-element-uuid": "b0aaa08d-a7fe-44ae-a6d8-d21645831a23-test1", + "new-data-del-flag": "RdwsDmBBz", + "cardinality": "Ry6V3zZtLOS" + }, + { + "model-element-uuid": "a2670e8e-f57e-4c0e-9522-6d16b4e2cf18-test1", + "new-data-del-flag": "aCECwDjNyauTZ", + "cardinality": "a28MCzMm24JBI" + } + ] + } + }, + { + "element-choice-set-uuid": "321ccc75-61ae-4358-af89-53809a28f956-test1", + "element-choice-set-name": "HjNWjs", + "cardinality": "bxRIxMP", + "model-elements": { + "model-element": [ + { + "model-element-uuid": "41965df8-b42d-47ba-8bf6-cade35804311-test1", + "new-data-del-flag": "CPLVd", + "cardinality": "4Ij4hep2" + }, + { + "model-element-uuid": "db7ee384-420e-44fb-a1ca-809f94add6b8-test1", + "new-data-del-flag": "Cj5GVv", + "cardinality": "1LSdRvvzBBfa" + } + ] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + }, + "metadata": { + "metadatum": [ + { + "metaname": "8b3496f1-822e-4acf-b1fc-d07a494d3a86-test1", + "metaval": "gZwqNxIDsw" + }, + { + "metaname": "d9a50737-f3df-4156-881d-e3875031b413-test1", + "metaval": "qMugMK" + } + ] + } + }, + { + "model-version-id": "1e6ec4df-ad66-40bc-8f1d-ba40c835e77e-test1", + "model-name": "wStuf", + "model-version": "HAm", + "distribution-status": "zsKxpTc5YTW1", + "model-description": "zxHpALNUvX8V", + "model-elements": { + "model-element": [ + { + "model-element-uuid": "b1ac6004-59bd-4372-ab16-f327d04d647e-test1", + "new-data-del-flag": "j58MXR", + "cardinality": "9Xr0gNa", + "linkage-points": [ + "LmE7mpec2" + ], + "model-elements": { + "model-element": [ + { + "model-element-uuid": "38295729-dc3b-4b7b-87e3-446513a802df-test1", + "new-data-del-flag": "R5KeFH8", + "cardinality": "9wkk9Z" + }, + { + "model-element-uuid": "b1ac08c3-3047-4637-8796-6b5e43bbad19-test1", + "new-data-del-flag": "KOS9kMuahku", + "cardinality": "F6A" + } + ] + }, + "model-constraints": { + "model-constraint": [ + { + "model-constraint-uuid": "0c7f45c8-2552-400a-b029-e20cddda592b-test1", + "constrained-element-set-uuid-to-replace": "105ZUJ", + "constrained-element-sets": { + "constrained-element-set": [ + { + "constrained-element-set-uuid": "162ea223-ae49-4e6d-ba30-8215c433a7e2-test1", + "constraint-type": "GAq", + "check-type": "ippNik", + "element-choice-sets": { + "element-choice-set": [ + { + "element-choice-set-uuid": "5caa493c-e804-4c28-aad6-3389a1801e29-test1", + "element-choice-set-name": "oLPlXWcCL", + "cardinality": "ns6", + "model-elements": { + "model-element": [ + { + "model-element-uuid": "ff8f0de4-220f-4f7f-8447-07c67ed8a109-test1", + "new-data-del-flag": "TlLVzdU5Mz", + "cardinality": "wQI" + }, + { + "model-element-uuid": "fd6018bc-b3ce-4073-b494-848c06aaef83-test1", + "new-data-del-flag": "ZIkOtmdu8ij", + "cardinality": "XfOsai" + } + ] + } + }, + { + "element-choice-set-uuid": "45d079e2-94f8-4c75-9e58-fca00da8e032-test1", + "element-choice-set-name": "nfOh9SvgG", + "cardinality": "j5u1OHFt", + "model-elements": { + "model-element": [ + { + "model-element-uuid": "3edbf250-7039-47cd-b31d-019e5639006b-test1", + "new-data-del-flag": "Qo5M8AB", + "cardinality": "crDs4E" + }, + { + "model-element-uuid": "566c492a-4b8d-4393-9634-5deb36114390-test1", + "new-data-del-flag": "tSl", + "cardinality": "xZK7oAuI1" + } + ] + } + } + ] + } + }, + { + "constrained-element-set-uuid": "6efd9e99-bca6-4f3b-a7dc-38ad373c38e9-test1", + "constraint-type": "v3RYRkCdTm", + "check-type": "adGnhMq6P4", + "element-choice-sets": { + "element-choice-set": [ + { + "element-choice-set-uuid": "09d59684-e8e5-4e08-93af-b2a65d0328e6-test1", + "element-choice-set-name": "Q1rPa", + "cardinality": "ENpTrUR", + "model-elements": { + "model-element": [ + { + "model-element-uuid": "904654a2-4d7d-4d07-af26-ddb881dd05d7-test1", + "new-data-del-flag": "76D6azxVm1XR9", + "cardinality": "R0Zb34f" + }, + { + "model-element-uuid": "898cfb56-6e36-4b03-8967-9384d06b3a3e-test1", + "new-data-del-flag": "SJtXdr4", + "cardinality": "vG4JrjQ8" + } + ] + } + }, + { + "element-choice-set-uuid": "9ac87d60-51c5-4dd6-bb1e-1b8dd234b5a9-test1", + "element-choice-set-name": "azv", + "cardinality": "oJfnKsDO5k", + "model-elements": { + "model-element": [ + { + "model-element-uuid": "6ec8304f-8159-4344-b06d-faf1001fd275-test1", + "new-data-del-flag": "3s5zQjf8Vwl4", + "cardinality": "6SogRPhZX38Ol" + }, + { + "model-element-uuid": "cfd9b055-3d8a-4429-9ea6-078a2270e469-test1", + "new-data-del-flag": "VaW81J59tqiY", + "cardinality": "t1mNuU7JnNc7L" + } + ] + } + } + ] + } + } + ] + } + }, + { + "model-constraint-uuid": "fe9d4b0d-dc65-4440-a10f-5237f135255c-test1", + "constrained-element-set-uuid-to-replace": "pWv26", + "constrained-element-sets": { + "constrained-element-set": [ + { + "constrained-element-set-uuid": "ea1473a3-e72d-4838-b8d8-7c8e86e0b3c8-test1", + "constraint-type": "Mdbb0G5nLxcx3", + "check-type": "a8rlES", + "element-choice-sets": { + "element-choice-set": [ + { + "element-choice-set-uuid": "86726d80-74d6-4b7e-9532-65ebb76133ef-test1", + "element-choice-set-name": "fBm0", + "cardinality": "csPsKpgV", + "model-elements": { + "model-element": [ + { + "model-element-uuid": "c0df13d1-a8be-4bc0-a572-44ca28d35d62-test1", + "new-data-del-flag": "k9x8eFMP", + "cardinality": "5xHWzWretpyAN" + }, + { + "model-element-uuid": "ef4f9a86-a1b8-48ef-a7aa-ff56a1879ef7-test1", + "new-data-del-flag": "JdujO3QQr4", + "cardinality": "N6pvsIK" + } + ] + } + }, + { + "element-choice-set-uuid": "07f1ae12-8e40-4c42-bb8c-e5931f82be84-test1", + "element-choice-set-name": "by4K", + "cardinality": "HfJt7", + "model-elements": { + "model-element": [ + { + "model-element-uuid": "aed78a3d-de9e-4825-88b3-8251a822e87c-test1", + "new-data-del-flag": "NbAWo0r1su", + "cardinality": "GIHSc" + }, + { + "model-element-uuid": "451ef346-a43e-4d9c-ae94-4d14f12b7776-test1", + "new-data-del-flag": "o6GI", + "cardinality": "Hbbm3HRFeXw8U" + } + ] + } + } + ] + } + }, + { + "constrained-element-set-uuid": "1b3d0f60-b438-4789-b711-5d48c211e9b3-test1", + "constraint-type": "G7HBqSqa8", + "check-type": "Rky", + "element-choice-sets": { + "element-choice-set": [ + { + "element-choice-set-uuid": "c47b3c18-912b-4781-82a9-961702e58712-test1", + "element-choice-set-name": "ntxJ1ETx96", + "cardinality": "6B1XDdERKUk0f", + "model-elements": { + "model-element": [ + { + "model-element-uuid": "d451967f-5cb9-4aba-8595-938d44bed081-test1", + "new-data-del-flag": "pwHvYjtFEvmn", + "cardinality": "X6jiiniZ24e3" + }, + { + "model-element-uuid": "0f6196d6-b3b7-451a-a3d8-2a0a9bf401b7-test1", + "new-data-del-flag": "YFY4Dmyr", + "cardinality": "CMF05rTle1" + } + ] + } + }, + { + "element-choice-set-uuid": "927a4c5d-c06f-474c-bc39-b1bf8edbd5a9-test1", + "element-choice-set-name": "C19", + "cardinality": "7xCo", + "model-elements": { + "model-element": [ + { + "model-element-uuid": "b839b84d-4508-4aa6-8c32-0566a25d62d1-test1", + "new-data-del-flag": "QdvVPKk", + "cardinality": "QWO7FG" + }, + { + "model-element-uuid": "20df13a4-aad9-46ed-8c40-d2c9ee25c0c0-test1", + "new-data-del-flag": "aFu39uCq", + "cardinality": "wFwAw3L3wT2x5" + } + ] + } + } + ] + } + } + ] + } + } + ] + } + }, + { + "model-element-uuid": "c198c7e7-162f-4b36-ab18-1ea652940569-test1", + "new-data-del-flag": "c9VM1nU9", + "cardinality": "na6ev", + "linkage-points": [ + "Qn71", + "VqVquEM" + ], + "model-elements": { + "model-element": [ + { + "model-element-uuid": "5a3d5001-ed82-4586-9f8e-f4754c5a7a18-test1", + "new-data-del-flag": "x5unCqf", + "cardinality": "SelKZSH" + }, + { + "model-element-uuid": "b150a826-8d8e-4e76-8661-6cbc67fd0d9a-test1", + "new-data-del-flag": "9LfZWv", + "cardinality": "uMtY5vRkmCnw" + } + ] + }, + "model-constraints": { + "model-constraint": [ + { + "model-constraint-uuid": "43871728-3816-470f-9b36-4097731910a4-test1", + "constrained-element-set-uuid-to-replace": "R8Uhk", + "constrained-element-sets": { + "constrained-element-set": [ + { + "constrained-element-set-uuid": "0fd99298-8079-4a3c-bbed-dce0ceadf790-test1", + "constraint-type": "JFVkmI9ilV", + "check-type": "9eqnm", + "element-choice-sets": { + "element-choice-set": [ + { + "element-choice-set-uuid": "22a978b9-4dcc-4c7d-b88a-6bdbab97dd7c-test1", + "element-choice-set-name": "4fHNNV", + "cardinality": "VBAiH", + "model-elements": { + "model-element": [ + { + "model-element-uuid": "d9bef0c1-07c9-4251-b621-196be3b7870e-test1", + "new-data-del-flag": "FQen9U2BTGx", + "cardinality": "ohd" + }, + { + "model-element-uuid": "60d8b814-8035-4010-8d46-9db2e5962f17-test1", + "new-data-del-flag": "2aJgwjV3UZv", + "cardinality": "WMb" + } + ] + } + }, + { + "element-choice-set-uuid": "a5b753eb-162e-4bea-8185-43b7e96c0770-test1", + "element-choice-set-name": "k9Ud", + "cardinality": "VAL51", + "model-elements": { + "model-element": [ + { + "model-element-uuid": "1ecfe4f4-6696-4df4-8b93-b2b3fa39c377-test1", + "new-data-del-flag": "SRFYVMGe", + "cardinality": "muxuy0DZBBW" + }, + { + "model-element-uuid": "96acb4b2-f178-4119-8c32-6c5901896417-test1", + "new-data-del-flag": "wbzd", + "cardinality": "M0Y7Meota" + } + ] + } + } + ] + } + }, + { + "constrained-element-set-uuid": "b22dc84b-5568-4b7d-9b58-0bc90c969619-test1", + "constraint-type": "waPRf1NGHeFy", + "check-type": "YziABbwA4", + "element-choice-sets": { + "element-choice-set": [ + { + "element-choice-set-uuid": "fb4d5b28-2083-4bb6-a87d-e53eadd14d54-test1", + "element-choice-set-name": "VnX7QOx", + "cardinality": "qk4aMYBkw", + "model-elements": { + "model-element": [ + { + "model-element-uuid": "1b5481f2-66c9-4cd4-89ee-492e333570fe-test1", + "new-data-del-flag": "ba6QIyym", + "cardinality": "zUJ9gpkRq" + }, + { + "model-element-uuid": "c9918ba3-dcb3-46e8-870f-316251f459a3-test1", + "new-data-del-flag": "X2MIS2y", + "cardinality": "u3xIyaL" + } + ] + } + }, + { + "element-choice-set-uuid": "f5a14c3b-6536-4803-9660-4a2f2263dfdd-test1", + "element-choice-set-name": "KiVnNej1flt", + "cardinality": "AwImrctM5", + "model-elements": { + "model-element": [ + { + "model-element-uuid": "e5e3b7db-7336-498b-8eca-f43f979dda68-test1", + "new-data-del-flag": "v3JnIH7JEK", + "cardinality": "pzypSipEOA" + }, + { + "model-element-uuid": "24426103-516b-4634-83f6-0b02db4d10ed-test1", + "new-data-del-flag": "lNx", + "cardinality": "OFMiiE1w4K" + } + ] + } + } + ] + } + } + ] + } + }, + { + "model-constraint-uuid": "310f083b-2d76-4e2d-ab82-b4c6b2a49637-test1", + "constrained-element-set-uuid-to-replace": "70UQQ", + "constrained-element-sets": { + "constrained-element-set": [ + { + "constrained-element-set-uuid": "f6b24791-facd-41d8-8b4e-b76d750ef3e8-test1", + "constraint-type": "eBTDI1Xx", + "check-type": "uyscxXaNEt", + "element-choice-sets": { + "element-choice-set": [ + { + "element-choice-set-uuid": "efc328ed-3302-4808-b25a-adbbe88af7d9-test1", + "element-choice-set-name": "HwpVVTGb6e", + "cardinality": "dZ78oR", + "model-elements": { + "model-element": [ + { + "model-element-uuid": "1f20c582-952d-4489-a45b-b7b898062bc4-test1", + "new-data-del-flag": "Vq8f3STu8ez", + "cardinality": "5lN" + }, + { + "model-element-uuid": "77f61b0a-ecf4-43ed-84b8-478372922557-test1", + "new-data-del-flag": "OrbNIIvUvTQ", + "cardinality": "CwT1hp9uUn" + } + ] + } + }, + { + "element-choice-set-uuid": "7561f91e-5d71-4871-b745-5974a29fa4f0-test1", + "element-choice-set-name": "JyMxtTdSzEYI", + "cardinality": "CU5", + "model-elements": { + "model-element": [ + { + "model-element-uuid": "7857bb38-b373-4f32-bfed-fb698b38f288-test1", + "new-data-del-flag": "qGYsqE", + "cardinality": "m1wtW502" + }, + { + "model-element-uuid": "27097500-1e6a-4692-bcfc-8c5751094416-test1", + "new-data-del-flag": "e3LD9ESy1h2we", + "cardinality": "a0jEiwQq" + } + ] + } + } + ] + } + }, + { + "constrained-element-set-uuid": "a63f212b-0608-4676-a801-eae9704ca6f8-test1", + "constraint-type": "1s642QAY3emE", + "check-type": "3sR23Vt", + "element-choice-sets": { + "element-choice-set": [ + { + "element-choice-set-uuid": "e6f1f3eb-61c5-4e00-877b-253d41dc8bc1-test1", + "element-choice-set-name": "EBhZUZSbs", + "cardinality": "1LrK8RM4o33LD", + "model-elements": { + "model-element": [ + { + "model-element-uuid": "323c6b90-7aba-41ad-8313-5a4a2b2c56ae-test1", + "new-data-del-flag": "R3oKjC8hz87", + "cardinality": "LT8Phj" + }, + { + "model-element-uuid": "6a4f5cbe-6251-402e-aa0c-d42284acf4f3-test1", + "new-data-del-flag": "XeIPIYLqyIL", + "cardinality": "pGK" + } + ] + } + }, + { + "element-choice-set-uuid": "4937bd81-08f1-4cb7-b3bd-9c9db142a791-test1", + "element-choice-set-name": "VXcx", + "cardinality": "hIKH", + "model-elements": { + "model-element": [ + { + "model-element-uuid": "db4ddcd0-6a57-47af-b72d-f10e806bd779-test1", + "new-data-del-flag": "2lsYwLYukGh43", + "cardinality": "zhcfiBQ" + }, + { + "model-element-uuid": "7f0823ec-87f7-4f0a-b6ed-d19571917f3d-test1", + "new-data-del-flag": "8xUASuYyIym", + "cardinality": "ktmQThTtgu" + } + ] + } + } + ] + } + } + ] + } + } + ] + } + } + ] + }, + "metadata": { + "metadatum": [ + { + "metaname": "a4f78e88-e09f-4ca1-b26a-093141044aea-test1", + "metaval": "kfsTQsxZk" + }, + { + "metaname": "1d153c8b-ba38-4566-876b-53795a71b8f9-test1", + "metaval": "xr0Z" + } + ] + } + } + ] + } +} diff --git a/aai-core/src/test/resources/payloads/resource/vip-ipv4-address-list.json b/aai-core/src/test/resources/payloads/resource/vip-ipv4-address-list.json new file mode 100644 index 00000000..4978d2af --- /dev/null +++ b/aai-core/src/test/resources/payloads/resource/vip-ipv4-address-list.json @@ -0,0 +1,6 @@ +{ + "vip-ipv4-address": "vip-ipv4-address-list-1", + "vip-ipv4-prefix-length": 3333, + "vlan-id-inner": 3333, + "vlan-id-outer": 3333 +} diff --git a/aai-core/src/test/resources/payloads/resource/vnf.json b/aai-core/src/test/resources/payloads/resource/vnf.json new file mode 100644 index 00000000..e3e7a35f --- /dev/null +++ b/aai-core/src/test/resources/payloads/resource/vnf.json @@ -0,0 +1,4 @@ +{ + "vnf-id":"vnf1", + "vnf-type":"someval" +} 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 dfcd0db3..c2c58d5f 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 @@ -1,4 +1,4 @@ -/** +/** * ============LICENSE_START======================================================= * org.onap.aai * ================================================================================ @@ -20,11 +20,16 @@ package org.onap.aai.edges; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.Map.Entry; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; import org.apache.tinkerpop.gremlin.structure.Direction; import org.onap.aai.edges.enums.DirectionNotation; import org.onap.aai.edges.enums.EdgeField; @@ -34,6 +39,8 @@ import org.onap.aai.edges.exceptions.EdgeRuleNotFoundException; import org.onap.aai.setup.ConfigTranslator; import org.onap.aai.setup.SchemaVersion; import org.onap.aai.setup.SchemaVersions; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -51,15 +58,25 @@ import static com.jayway.jsonpath.Criteria.where; */ @Component public class EdgeIngestor { - private Map<SchemaVersion, List<DocumentContext>> versionJsonFilesMap; + + private static final Logger LOG = LoggerFactory.getLogger(EdgeIngestor.class); + + private Map<SchemaVersion, List<DocumentContext>> versionJsonFilesMap; private static final String READ_START = "$.rules.[?]"; private static final String READ_ALL_START = "$.rules.*"; private SchemaVersions schemaVersions; + + private Set<String> multipleLabelKeys; + + private final LoadingCache<SchemaFilter,Multimap<String,EdgeRule>> cacheFilterStore; + + private final LoadingCache<String, String[]> cousinLabelStore; + //-----ingest-----// /** * Instantiates the EdgeIngestor bean. - * + * * @param translator - ConfigTranslator autowired in by Spring framework which * contains the configuration information needed to ingest the desired files. */ @@ -69,20 +86,41 @@ public class EdgeIngestor { JsonIngestor ji = new JsonIngestor(); this.schemaVersions = schemaVersions; versionJsonFilesMap = ji.ingest(filesToIngest); + this.cacheFilterStore = CacheBuilder.newBuilder() + .maximumSize(2000) + .build( + new CacheLoader<SchemaFilter, Multimap<String, EdgeRule>>() { + @Override + public Multimap<String, EdgeRule> load(SchemaFilter key) { + return extractRules(key); + } + } + ); + + this.cousinLabelStore = CacheBuilder.newBuilder() + .maximumSize(50) + .build( + new CacheLoader<String, String[]>() { + @Override + public String[] load(String key) throws Exception { + return retrieveCousinLabels(key); + } + } + ); } - + //-----methods for getting rule info-----// - + /** * Gets list of all edge rules defined in the latest version's schema - * + * * @return Multimap<String, EdgeRule> of node names keys to the EdgeRules associated with those types - * where the key takes the form of + * where the key takes the form of * {alphabetically first nodetype}|{alphabetically second nodetype}. Map will be empty if * no rules are found. * ex: buildAlphabetizedKey("l-interface", "logical-link") -> "l-interface|logical-link" * buildAlphabetizedKey("logical-link", "l-interface") -> "l-interface|logical-link" - * + * * This is alphabetical order to normalize the keys, as sometimes there will be multiple * rules for a pair of node types but the from/to value in the json is flipped for some of them. * @throws EdgeRuleNotFoundException if none found @@ -90,17 +128,47 @@ public class EdgeIngestor { public Multimap<String, EdgeRule> getAllCurrentRules() throws EdgeRuleNotFoundException { return getAllRules(schemaVersions.getDefaultVersion()); } - + + /** + * Retrieves all the nodes that contain multiple edge labels + * + * A lazy instantiation to retrieve all this info on first call + * + * @return a set containing a list of strings where each string is + * concatenated by a pipe (|) character such as aNodeType|bNodeType + */ + public Set<String> getMultipleLabelKeys(){ + + if(multipleLabelKeys == null){ + multipleLabelKeys = new HashSet<>(); + try { + final Multimap<String, EdgeRule> edges = this.getAllCurrentRules(); + if(edges == null || edges.isEmpty()){ + LOG.warn("Unable to find any edge rules for the latest version"); + } + edges.keySet().forEach((key) -> { + Collection<EdgeRule> rules = edges.get(key); + if(rules.size() > 1){ + multipleLabelKeys.add(key); + } + }); + } catch (EdgeRuleNotFoundException e) { + LOG.info("For the latest schema version, unable to find any edges with multiple keys"); + } + } + + return multipleLabelKeys; + } /** * Gets list of all edge rules defined in the given version's schema - * + * * @return Multimap<String, EdgeRule> of node names keys to the EdgeRules associated with those types - * where the key takes the form of + * where the key takes the form of * {alphabetically first nodetype}|{alphabetically second nodetype}. Map will be empty if * no rules are found. * ex: buildAlphabetizedKey("l-interface", "logical-link") -> "l-interface|logical-link" * buildAlphabetizedKey("logical-link", "l-interface") -> "l-interface|logical-link" - * + * * This is alphabetical order to normalize the keys, as sometimes there will be multiple * rules for a pair of node types but the from/to value in the json is flipped for some of them. * @throws EdgeRuleNotFoundException if none found @@ -113,19 +181,19 @@ public class EdgeIngestor { return found; } } - + /** * Finds the rules (if any) matching the given query criteria. If none, the returned Multimap * will be empty. - * + * * @param q - EdgeRuleQuery with filter criteria set - * - * @return Multimap<String, EdgeRule> of node names keys to the EdgeRules where the key takes the form of + * + * @return Multimap<String, EdgeRule> of node names keys to the EdgeRules where the key takes the form of * {alphabetically first nodetype}|{alphabetically second nodetype}. Map will be empty if * no rules are found. * ex: buildAlphabetizedKey("l-interface", "logical-link") -> "l-interface|logical-link" * buildAlphabetizedKey("logical-link", "l-interface") -> "l-interface|logical-link" - * + * * This is alphabetical order to normalize the keys, as sometimes there will be multiple * rules for a pair of node types but the from/to value in the json is flipped for some of them. * @throws EdgeRuleNotFoundException if none found @@ -140,36 +208,40 @@ public class EdgeIngestor { if (found.isEmpty()) { throw new EdgeRuleNotFoundException("No rules found for " + q.toString()); } else { - for (EdgeRule rule : found.values()) { - if (!q.getFromType().equals(rule.getFrom())) { - /* To maintain backwards compatibility with old EdgeRules API, - * where the direction of the returned EdgeRule would be - * flipped (if necessary) to match the directionality of - * the input params. - * ie, If the rule is from=A,to=B,direction=OUT, - * if the user asked (A,B) the direction would be OUT, - * if they asked (B,A), it would be IN to match. - */ - rule.flipDirection(); - } - } - return found; + Multimap<String, EdgeRule> copy = ArrayListMultimap.create(); + found.entries().stream().forEach((entry) -> { + EdgeRule rule = new EdgeRule(entry.getValue()); + if(!q.getFromType().equals(rule.getFrom())){ + /* To maintain backwards compatibility with old EdgeRules API, + * where the direction of the returned EdgeRule would be + * flipped (if necessary) to match the directionality of + * the input params. + * ie, If the rule is from=A,to=B,direction=OUT, + * if the user asked (A,B) the direction would be OUT, + * if they asked (B,A), it would be IN to match. + */ + rule.flipDirection(); + } + copy.put(entry.getKey(), rule); + }); + + return copy; } } - + /** * Gets the rule satisfying the given filter criteria. If there are more than one - * that match, return the default rule. If there is no clear default to return, or + * that match, return the default rule. If there is no clear default to return, or * no rules match at all, error. - * + * * @param q - EdgeRuleQuery with filter criteria set * @return EdgeRule satisfying given criteria * @throws EdgeRuleNotFoundException if none found that match * @throws AmbiguousRuleChoiceException if multiple match but no way to choice one from them - * Specifically, if multiple node type pairs come back (ie bar|foo and asdf|foo, + * Specifically, if multiple node type pairs come back (ie bar|foo and asdf|foo, * no way to know which is appropriate over the others), * or if there is a mix of Tree and Cousin edges because again there is no way to - * know which is "defaulter" than the other. + * know which is "defaulter" than the other. * The default property only clarifies among multiple cousin edges of the same node pair, * ex: which l-interface|logical-link rule to default to. */ @@ -184,7 +256,7 @@ public class EdgeIngestor { if (found.isEmpty()) { throw new EdgeRuleNotFoundException("No rule found for " + q.toString() + "."); } - + EdgeRule rule = null; if (found.keys().size() == 1) { //only one found, cool we're done for (Entry<String, EdgeRule> e : found.entries()) { @@ -193,10 +265,12 @@ public class EdgeIngestor { } else { rule = getDefaultRule(found); } - + + if (rule == null) { //should never get here though throw new EdgeRuleNotFoundException("No rule found for " + q.toString() + "."); } else { + rule = new EdgeRule(rule); if (!q.getFromType().equals(rule.getFrom())) { /* To maintain backwards compatibility with old EdgeRules API, * where the direction of the returned EdgeRule would be @@ -211,7 +285,9 @@ public class EdgeIngestor { return rule; } } - + + + private EdgeRule getDefaultRule(Multimap<String, EdgeRule> found) throws AmbiguousRuleChoiceException { if (found.keySet().size() > 1) { //ie multiple node pairs (a|c and b|c not just all a|c) case StringBuilder sb = new StringBuilder(); @@ -220,7 +296,7 @@ public class EdgeIngestor { } throw new AmbiguousRuleChoiceException("No way to select single rule from these pairs: " + sb.toString() + "."); } - + int defaultCount = 0; EdgeRule defRule = null; for (Entry<String, EdgeRule> e : found.entries()) { @@ -235,13 +311,13 @@ public class EdgeIngestor { } else if (defaultCount == 0) { throw new AmbiguousRuleChoiceException("No default found."); } - + return defRule; } - + /** * Checks if there exists any rule that satisfies the given filter criteria. - * + * * @param q - EdgeRuleQuery with filter criteria set * @return boolean */ @@ -252,42 +328,59 @@ public class EdgeIngestor { return !extractRules(q.getFilter(), schemaVersions.getDefaultVersion()).isEmpty(); } } - + /** * Gets all cousin rules for the given node type in the latest schema version. - * + * * @param nodeType - * @return Multimap<String, EdgeRule> of node names keys to the EdgeRules where the key takes the form of + * @return Multimap<String, EdgeRule> of node names keys to the EdgeRules where the key takes the form of * {alphabetically first nodetype}|{alphabetically second nodetype}. Map will be empty if * no rules are found. * ex: buildAlphabetizedKey("l-interface", "logical-link") -> "l-interface|logical-link" * buildAlphabetizedKey("logical-link", "l-interface") -> "l-interface|logical-link" - * + * * This is alphabetical order to normalize the keys, as sometimes there will be multiple * rules for a pair of node types but the from/to value in the json is flipped for some of them. */ public Multimap<String, EdgeRule> getCousinRules(String nodeType) { return getCousinRules(nodeType, schemaVersions.getDefaultVersion()); //default to latest } - + + + public String[] retrieveCousinLabels(String nodeType){ + + Multimap<String, EdgeRule> cousinRules = getCousinRules(nodeType); + String[] cousinLabels = new String[cousinRules.size()]; + + return cousinRules.entries() + .stream() + .map((entry) -> entry.getValue().getLabel()) + .collect(Collectors.toList()) + .toArray(cousinLabels); + } + + public String[] retrieveCachedCousinLabels(String nodeType) throws ExecutionException { + return cousinLabelStore.get(nodeType); + } + /** * Gets all cousin rules for the given node type in the given schema version. - * + * * @param nodeType * @param v - the version of the edge rules to query - * @return Multimap<String, EdgeRule> of node names keys to the EdgeRules where the key takes the form of + * @return Multimap<String, EdgeRule> of node names keys to the EdgeRules where the key takes the form of * {alphabetically first nodetype}|{alphabetically second nodetype}. Map will be empty if * no rules are found. * ex: buildAlphabetizedKey("l-interface", "logical-link") -> "l-interface|logical-link" * buildAlphabetizedKey("logical-link", "l-interface") -> "l-interface|logical-link" - * + * * This is alphabetical order to normalize the keys, as sometimes there will be multiple - * rules for a pair of node types but the from/to value in the json is flipped for some of them. + * rules for a pair of node types but the from/to value in the json is flipped for some of them. */ public Multimap<String, EdgeRule> getCousinRules(String nodeType, SchemaVersion v) { return extractRules(new EdgeRuleQuery.Builder(nodeType).edgeType(EdgeType.COUSIN).build().getFilter(), v); } - + /** * Returns if the given node type has any cousin relationships in the current version. * @param nodeType @@ -296,7 +389,7 @@ public class EdgeIngestor { public boolean hasCousinRule(String nodeType) { return hasCousinRule(nodeType, schemaVersions.getDefaultVersion()); } - + /** * Returns if the given node type has any cousin relationships in the given version. * @param nodeType @@ -305,45 +398,45 @@ public class EdgeIngestor { public boolean hasCousinRule(String nodeType, SchemaVersion v) { return !getCousinRules(nodeType, v).isEmpty(); } - + /** * Gets all rules where "{given nodeType} contains {otherType}" in the latest schema version. - * + * * @param nodeType - node type that is the container in the returned relationships - * @return Multimap<String, EdgeRule> of node names keys to the EdgeRules where the key takes the form of + * @return Multimap<String, EdgeRule> of node names keys to the EdgeRules where the key takes the form of * {alphabetically first nodetype}|{alphabetically second nodetype}. Map will be empty if * no rules are found. * ex: buildAlphabetizedKey("l-interface", "logical-link") -> "l-interface|logical-link" * buildAlphabetizedKey("logical-link", "l-interface") -> "l-interface|logical-link" - * + * * This is alphabetical order to normalize the keys, as sometimes there will be multiple - * rules for a pair of node types but the from/to value in the json is flipped for some of them. + * rules for a pair of node types but the from/to value in the json is flipped for some of them. */ public Multimap<String, EdgeRule> getChildRules(String nodeType) { return getChildRules(nodeType, schemaVersions.getDefaultVersion()); } - + /** * Gets all rules where "{given nodeType} contains {otherType}" in the given schema version. - * + * * @param nodeType - node type that is the container in the returned relationships - * @return Multimap<String, EdgeRule> of node names keys to the EdgeRules where the key takes the form of + * @return Multimap<String, EdgeRule> of node names keys to the EdgeRules where the key takes the form of * {alphabetically first nodetype}|{alphabetically second nodetype}. Map will be empty if * no rules are found. * ex: buildAlphabetizedKey("l-interface", "logical-link") -> "l-interface|logical-link" * buildAlphabetizedKey("logical-link", "l-interface") -> "l-interface|logical-link" - * + * * This is alphabetical order to normalize the keys, as sometimes there will be multiple - * rules for a pair of node types but the from/to value in the json is flipped for some of them. + * rules for a pair of node types but the from/to value in the json is flipped for some of them. */ public Multimap<String, EdgeRule> getChildRules(String nodeType, SchemaVersion v) { Filter from = assembleFilterSegments(where(EdgeField.FROM.toString()).is(nodeType), getSameDirectionContainmentCriteria()); Filter to = assembleFilterSegments(where(EdgeField.TO.toString()).is(nodeType), getOppositeDirectionContainmentCriteria()); Filter total = from.or(to); - + return extractRules(total, v); } - + /** * Returns if the given node type has any child relationships (ie it contains another node type) in the current version. * @param nodeType @@ -352,7 +445,7 @@ public class EdgeIngestor { public boolean hasChildRule(String nodeType) { return hasChildRule(nodeType, schemaVersions.getDefaultVersion()); } - + /** * Returns if the given node type has any child relationships (ie it contains another node type) in the given version. * @param nodeType @@ -361,45 +454,45 @@ public class EdgeIngestor { public boolean hasChildRule(String nodeType, SchemaVersion v) { return !getChildRules(nodeType, v).isEmpty(); } - + /** * Gets all rules where "{given nodeType} is contained by {otherType}" in the latest schema version. - * + * * @param nodeType - node type that is the containee in the returned relationships - * @return Multimap<String, EdgeRule> of node names keys to the EdgeRules where the key takes the form of + * @return Multimap<String, EdgeRule> of node names keys to the EdgeRules where the key takes the form of * {alphabetically first nodetype}|{alphabetically second nodetype}. Map will be empty if * no rules are found. * ex: buildAlphabetizedKey("l-interface", "logical-link") -> "l-interface|logical-link" * buildAlphabetizedKey("logical-link", "l-interface") -> "l-interface|logical-link" - * + * * This is alphabetical order to normalize the keys, as sometimes there will be multiple * rules for a pair of node types but the from/to value in the json is flipped for some of them. */ public Multimap<String, EdgeRule> getParentRules(String nodeType) { return getParentRules(nodeType, schemaVersions.getDefaultVersion()); } - + /** * Gets all rules where "{given nodeType} is contained by {otherType}" in the given schema version. - * + * * @param nodeType - node type that is the containee in the returned relationships - * @return Multimap<String, EdgeRule> of node names keys to the EdgeRules where the key takes the form of + * @return Multimap<String, EdgeRule> of node names keys to the EdgeRules where the key takes the form of * {alphabetically first nodetype}|{alphabetically second nodetype}. Map will be empty if * no rules are found. * ex: buildAlphabetizedKey("l-interface", "logical-link") -> "l-interface|logical-link" * buildAlphabetizedKey("logical-link", "l-interface") -> "l-interface|logical-link" - * + * * This is alphabetical order to normalize the keys, as sometimes there will be multiple - * rules for a pair of node types but the from/to value in the json is flipped for some of them. + * rules for a pair of node types but the from/to value in the json is flipped for some of them. */ public Multimap<String, EdgeRule> getParentRules(String nodeType, SchemaVersion v) { Filter from = assembleFilterSegments(where(EdgeField.FROM.toString()).is(nodeType), getOppositeDirectionContainmentCriteria()); Filter to = assembleFilterSegments(where(EdgeField.TO.toString()).is(nodeType), getSameDirectionContainmentCriteria()); Filter total = from.or(to); - + return extractRules(total, v); } - + /** * Returns if the given node type has any parent relationships (ie it is contained by another node type) in the current version. * @param nodeType @@ -408,7 +501,7 @@ public class EdgeIngestor { public boolean hasParentRule(String nodeType) { return hasParentRule(nodeType, schemaVersions.getDefaultVersion()); } - + /** * Returns if the given node type has any parent relationships (ie it is contained by another node type) in the given version. * @param nodeType @@ -417,47 +510,57 @@ public class EdgeIngestor { public boolean hasParentRule(String nodeType, SchemaVersion v) { return !getParentRules(nodeType, v).isEmpty(); } - + /** * Applies the given filter to the DocumentContext(s) for the given version to extract * edge rules, and converts this extracted information into the Multimap form - * + * * @param filter - JsonPath filter to read the DocumentContexts with. May be null * to denote no filter, ie get all. * @param v - The schema version to extract from - * @return Multimap<String, EdgeRule> of node names keys to the EdgeRules where the key takes the form of + * @return Multimap<String, EdgeRule> of node names keys to the EdgeRules where the key takes the form of * {alphabetically first nodetype}|{alphabetically second nodetype}. Map will be empty if * no rules are found. * ex: buildAlphabetizedKey("l-interface", "logical-link") -> "l-interface|logical-link" * buildAlphabetizedKey("logical-link", "l-interface") -> "l-interface|logical-link" - * + * * This is alphabetical order to normalize the keys, as sometimes there will be multiple - * rules for a pair of node types but the from/to value in the json is flipped for some of them. + * rules for a pair of node types but the from/to value in the json is flipped for some of them. */ private Multimap<String, EdgeRule> extractRules(Filter filter, SchemaVersion v) { - List<Map<String, String>> foundRules = new ArrayList<>(); - List<DocumentContext> docs = versionJsonFilesMap.get(v); - if (docs != null) { - for (DocumentContext doc : docs) { - if (filter == null) { - foundRules.addAll(doc.read(READ_ALL_START)); - } else { - foundRules.addAll(doc.read(READ_START, filter)); - } - } - } - - return convertToEdgeRules(foundRules); - } - + SchemaFilter schemaFilter = new SchemaFilter(filter, v); + try { + return cacheFilterStore.get(schemaFilter); + } catch (ExecutionException e) { + LOG.info("Encountered exception during the retrieval of the rules"); + return ArrayListMultimap.create(); + } + } + + public Multimap<String, EdgeRule> extractRules(SchemaFilter schemaFilter){ + List<Map<String, String>> foundRules = new ArrayList<>(); + List<DocumentContext> docs = versionJsonFilesMap.get(schemaFilter.getSchemaVersion()); + if (docs != null) { + for (DocumentContext doc : docs) { + if (schemaFilter.getFilter() == null) { + foundRules.addAll(doc.read(READ_ALL_START)); + } else { + foundRules.addAll(doc.read(READ_START, Filter.parse(schemaFilter.getFilter()))); + } + } + } + + return convertToEdgeRules(foundRules); + } + //-----filter building helpers-----// /** * ANDs together the given start criteria with each criteria in the pieces list, and * then ORs together these segments into one filter. - * + * * JsonPath doesn't have an OR method on Criteria, only on Filters, so assembling * a complete filter requires this sort of roundabout construction. - * + * * @param start - Criteria of the form where(from/to).is(nodeType) * (ie the start of any A&AI edge rule query) * @param pieces - Other Criteria to be applied @@ -474,91 +577,91 @@ public class EdgeIngestor { } return assembled; } - + /** * Builds the sub-Criteria for a containment edge rule query where the direction * and containment fields must match. - * + * * Used for getChildRules() where the container node type is in the "from" position and * for getParentRules() where the containee type is in the "to" position. - * + * * @return List<Criteria> covering property permutations defined with either notation or explicit direction */ private List<Criteria> getSameDirectionContainmentCriteria() { List<Criteria> crits = new ArrayList<>(); - + crits.add(where(EdgeField.CONTAINS.toString()).is(DirectionNotation.DIRECTION.toString())); - + crits.add(where(EdgeField.DIRECTION.toString()).is(Direction.OUT.toString()) .and(EdgeField.CONTAINS.toString()).is(Direction.OUT.toString())); - + crits.add(where(EdgeField.DIRECTION.toString()).is(Direction.IN.toString()) .and(EdgeField.CONTAINS.toString()).is(Direction.IN.toString())); - + return crits; } - + /** * Builds the sub-Criteria for a containment edge rule query where the direction * and containment fields must not match. - * + * * Used for getChildRules() where the container node type is in the "to" position and * for getParentRules() where the containee type is in the "from" position. - * + * * @return List<Criteria> covering property permutations defined with either notation or explicit direction */ private List<Criteria> getOppositeDirectionContainmentCriteria() { List<Criteria> crits = new ArrayList<>(); - + crits.add(where(EdgeField.CONTAINS.toString()).is(DirectionNotation.OPPOSITE.toString())); - + crits.add(where(EdgeField.DIRECTION.toString()).is(Direction.OUT.toString()) .and(EdgeField.CONTAINS.toString()).is(Direction.IN.toString())); - + crits.add(where(EdgeField.DIRECTION.toString()).is(Direction.IN.toString()) .and(EdgeField.CONTAINS.toString()).is(Direction.OUT.toString())); - + return crits; } - + //-----rule packaging helpers-----// /** * Converts the raw output from reading the json file to the Multimap<String key, EdgeRule> format - * + * * @param allFound - raw edge rule output read from json file(s) * (could be empty if none found) - * @return Multimap<String, EdgeRule> of node names keys to the EdgeRules where the key takes the form of + * @return Multimap<String, EdgeRule> of node names keys to the EdgeRules where the key takes the form of * {alphabetically first nodetype}|{alphabetically second nodetype}. Will be empty if input * was empty. * ex: buildAlphabetizedKey("l-interface", "logical-link") -> "l-interface|logical-link" * buildAlphabetizedKey("logical-link", "l-interface") -> "l-interface|logical-link" - * + * * This is alphabetical order to normalize the keys, as sometimes there will be multiple - * rules for a pair of node types but the from/to value in the json is flipped for some of them. + * rules for a pair of node types but the from/to value in the json is flipped for some of them. */ private Multimap<String, EdgeRule> convertToEdgeRules(List<Map<String, String>> allFound) { Multimap<String, EdgeRule> rules = ArrayListMultimap.create(); - + TypeAlphabetizer alpher = new TypeAlphabetizer(); - + for (Map<String, String> raw : allFound) { EdgeRule converted = new EdgeRule(raw); if (converted.getFrom().equals(converted.getTo())) { - /* the way the code worked in the past was with outs and - * when we switched it to in the same-node-type to - * same-node-type parent child edges were failing because all - * of the calling code would pass the parent as the left argument, - * so it was either in that method swap the parent/child, - * flip the edge rule or make all callers swap. the last seemed - * like a bad idea. and felt like the edge flip was the better + /* the way the code worked in the past was with outs and + * when we switched it to in the same-node-type to + * same-node-type parent child edges were failing because all + * of the calling code would pass the parent as the left argument, + * so it was either in that method swap the parent/child, + * flip the edge rule or make all callers swap. the last seemed + * like a bad idea. and felt like the edge flip was the better * of the remaining 2 */ converted.flipDirection(); } String alphabetizedKey = alpher.buildAlphabetizedKey(raw.get(EdgeField.FROM.toString()), raw.get(EdgeField.TO.toString())); rules.put(alphabetizedKey, converted); } - + return 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 e1cb240e..f914f6cb 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 @@ -26,7 +26,9 @@ import org.onap.aai.edges.enums.EdgeField; import org.onap.aai.edges.enums.EdgeProperty; import org.onap.aai.edges.enums.MultiplicityRule; +import java.util.Collections; import java.util.EnumMap; +import java.util.HashMap; import java.util.Map; /** @@ -43,16 +45,16 @@ public class EdgeRule { private String description; private boolean isPrivateEdge = false; - /** + /** * Instantiates a new edge rule. - * + * * @param fieldVals - Map<String, String> where first string is - * an EdgeField value and second string is the + * an EdgeField value and second string is the * value of that field */ public EdgeRule(Map<String, String> fieldVals) { edgeFields = new EnumMap<>(EdgeProperty.class); - + from = fieldVals.get(EdgeField.FROM.toString()); to = fieldVals.get(EdgeField.TO.toString()); label = fieldVals.get(EdgeField.LABEL.toString()); @@ -63,19 +65,32 @@ public class EdgeRule { String rawVal = fieldVals.get(prop.toString()); edgeFields.put(prop, convertNotation(direction, rawVal)); } - + isDefaultEdge = Boolean.valueOf(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 = ""; } } + // Copy Constructor + public EdgeRule(EdgeRule edgeRule){ + this.from = edgeRule.from; + this.to = edgeRule.to; + this.label = edgeRule.label; + this.direction = Direction.valueOf(edgeRule.direction.toString()); + this.multiplicityRule = MultiplicityRule.valueOf(edgeRule.multiplicityRule.toString()); + this.edgeFields = new HashMap<>(edgeRule.edgeFields); + this.isDefaultEdge = edgeRule.isDefaultEdge; + this.description = edgeRule.description; + this.isPrivateEdge = edgeRule.isPrivateEdge; + } + /** * 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} @@ -92,7 +107,7 @@ public class EdgeRule { } else if (AAIDirection.IN.toString().equalsIgnoreCase(rawVal)) { return AAIDirection.IN; } - + DirectionNotation rawDN = DirectionNotation.getValue(rawVal); if (DirectionNotation.DIRECTION.equals(rawDN)) { return AAIDirection.getValue(dir); @@ -100,7 +115,7 @@ public class EdgeRule { return AAIDirection.getValue(dir.opposite()); } } - + /** * Gets the name of the node type in the "from" field * @return String nodetype @@ -125,7 +140,7 @@ public class EdgeRule { public String getLabel() { return label; } - + /** * Gets the multiplicity rule. * @@ -134,7 +149,7 @@ public class EdgeRule { public MultiplicityRule getMultiplicityRule() { return multiplicityRule; } - + /** * Gets the edge direction * @@ -143,7 +158,7 @@ public class EdgeRule { public Direction getDirection() { return direction; } - + /** * Gets the value of contains-other-v * @@ -152,7 +167,7 @@ public class EdgeRule { public String getContains() { return edgeFields.get(EdgeProperty.CONTAINS).toString(); } - + /** * Gets the value of delete-other-v * @@ -161,10 +176,10 @@ public class EdgeRule { public String getDeleteOtherV() { return edgeFields.get(EdgeProperty.DELETE_OTHER_V).toString(); } - + /** * Gets the value of the prevent-delete property - * + * * @return String prevent-delete property value */ public String getPreventDelete() { @@ -173,13 +188,13 @@ public class EdgeRule { /** * Returns if this rule is a default or not - * + * * @return boolean */ public boolean isDefault() { return isDefaultEdge; } - + /** * Gets the description on the edge rule (if there is one) * @return String description @@ -187,7 +202,7 @@ public class EdgeRule { public String getDescription() { return this.description; } - + /** * Flips the direction value * IN -> OUT diff --git a/aai-schema-ingest/src/main/java/org/onap/aai/edges/EdgeRuleQuery.java b/aai-schema-ingest/src/main/java/org/onap/aai/edges/EdgeRuleQuery.java index 5801e816..58c8c546 100644 --- a/aai-schema-ingest/src/main/java/org/onap/aai/edges/EdgeRuleQuery.java +++ b/aai-schema-ingest/src/main/java/org/onap/aai/edges/EdgeRuleQuery.java @@ -1,4 +1,4 @@ -/** +/** * ============LICENSE_START======================================================= * org.onap.aai * ================================================================================ @@ -36,6 +36,7 @@ import static com.jayway.jsonpath.Filter.filter; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.Optional; import static com.jayway.jsonpath.Criteria.where; @@ -90,6 +91,12 @@ public class EdgeRuleQuery { private String getSecondNodeType() { return nodeB; } + + public Builder to(String nodeB){ + this.nodeB = nodeB; + return this; + } + public Builder toOnly() { //Allows this to be used with single parameter constructor Builder(String nodeA) if(StringUtils.isEmpty(this.nodeB) && StringUtils.isNotEmpty(this.nodeA) ) { @@ -312,6 +319,30 @@ public class EdgeRuleQuery { } return sb.toString(); } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + EdgeRuleQuery ruleQuery = (EdgeRuleQuery) o; + return isPrivate == ruleQuery.isPrivate && + Objects.equals(v, ruleQuery.v) && + Objects.equals(nodeA, ruleQuery.nodeA) && + Objects.equals(nodeB, ruleQuery.nodeB) && + Objects.equals(label, ruleQuery.label) && + direction == ruleQuery.direction && + type == ruleQuery.type; + } + + @Override + public int hashCode() { + if(v.isPresent()){ + return Objects.hash(v.get(), nodeA, nodeB, label, direction, type, isPrivate); + } else { + return Objects.hash(nodeA, nodeB, label, direction, type, isPrivate); + } + } + } diff --git a/aai-schema-ingest/src/main/java/org/onap/aai/edges/SchemaFilter.java b/aai-schema-ingest/src/main/java/org/onap/aai/edges/SchemaFilter.java new file mode 100644 index 00000000..792e3c51 --- /dev/null +++ b/aai-schema-ingest/src/main/java/org/onap/aai/edges/SchemaFilter.java @@ -0,0 +1,69 @@ +/** + * ============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========================================================= + */ +package org.onap.aai.edges; + +import com.jayway.jsonpath.Filter; +import org.onap.aai.setup.SchemaVersion; + +import java.util.Objects; + +public class SchemaFilter { + + private String filter; + + private SchemaVersion schemaVersion; + + public SchemaFilter(Filter filter, SchemaVersion schemaVersion){ + if(filter != null){ + this.filter = filter.toString(); + } + this.schemaVersion = schemaVersion; + } + + public SchemaVersion getSchemaVersion() { + return schemaVersion; + } + + public String getFilter() { + return filter; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + SchemaFilter that = (SchemaFilter) o; + return Objects.equals(filter, that.filter) && + Objects.equals(schemaVersion, that.schemaVersion); + } + + @Override + public int hashCode() { + return Objects.hash(filter, schemaVersion); + } + + @Override + public String toString() { + return "SchemaFilter{" + + "filter='" + filter + '\'' + + ", schemaVersion=" + schemaVersion + + '}'; + } +} diff --git a/aai-schema-ingest/src/main/java/org/onap/aai/edges/exceptions/AmbiguousRuleChoiceException.java b/aai-schema-ingest/src/main/java/org/onap/aai/edges/exceptions/AmbiguousRuleChoiceException.java index b218cecd..3ddced9a 100644 --- a/aai-schema-ingest/src/main/java/org/onap/aai/edges/exceptions/AmbiguousRuleChoiceException.java +++ b/aai-schema-ingest/src/main/java/org/onap/aai/edges/exceptions/AmbiguousRuleChoiceException.java @@ -1,4 +1,4 @@ -/** +/** * ============LICENSE_START======================================================= * org.onap.aai * ================================================================================ @@ -24,4 +24,8 @@ public class AmbiguousRuleChoiceException extends Exception { public AmbiguousRuleChoiceException(String msg) { super(msg); } + + public AmbiguousRuleChoiceException(Throwable throwable){ + super(throwable); + } } diff --git a/aai-schema-ingest/src/main/java/org/onap/aai/edges/exceptions/EdgeRuleNotFoundException.java b/aai-schema-ingest/src/main/java/org/onap/aai/edges/exceptions/EdgeRuleNotFoundException.java index 4d339de2..de022bc5 100644 --- a/aai-schema-ingest/src/main/java/org/onap/aai/edges/exceptions/EdgeRuleNotFoundException.java +++ b/aai-schema-ingest/src/main/java/org/onap/aai/edges/exceptions/EdgeRuleNotFoundException.java @@ -1,4 +1,4 @@ -/** +/** * ============LICENSE_START======================================================= * org.onap.aai * ================================================================================ @@ -24,4 +24,8 @@ public class EdgeRuleNotFoundException extends Exception { public EdgeRuleNotFoundException(String msg) { super(msg); } + + public EdgeRuleNotFoundException(Throwable throwable){ + super(throwable); + } } diff --git a/aai-schema/src/main/resources/onap/oxm/v15/aai_oxm_v15.xml b/aai-schema/src/main/resources/onap/oxm/v15/aai_oxm_v15.xml index f068b009..ce7f2d52 100644 --- a/aai-schema/src/main/resources/onap/oxm/v15/aai_oxm_v15.xml +++ b/aai-schema/src/main/resources/onap/oxm/v15/aai_oxm_v15.xml @@ -5704,8 +5704,8 @@ <java-type name="ReservedPropNames"> <xml-properties> <xml-property name="description" value="Internal map to define some reserved properties of a vertex"/> - <xml-property name="uniqueProps" value="aai-unique-key"/> - <xml-property name="indexedProps" value="aai-unique-key,source-of-truth,aai-node-type,aai-uri"/> + <xml-property name="uniqueProps" value="aai-unique-key,aai-uri,aai-uuid"/> + <xml-property name="indexedProps" value="aai-unique-key,source-of-truth,aai-node-type,aai-uri,aai-uuid"/> </xml-properties> <xml-root-element name="reserved-prop-names"/> <java-attributes> |