add fluent type builder support to A&AI client 22/106922/2
authorBenjamin, Max <max.benjamin@att.com>
Thu, 30 Apr 2020 14:41:46 +0000 (10:41 -0400)
committerBenjamin, Max (mb388a) <mb388a@att.com>
Thu, 30 Apr 2020 15:08:10 +0000 (11:08 -0400)
add fluent type builder support to A&AI client

Issue-ID: SO-2856
Signed-off-by: Benjamin, Max (mb388a) <mb388a@att.com>
Change-Id: I2957aedb84a1c6b23979ff2e1c4dfb16b3a646c7

30 files changed:
graph-inventory/aai-client/pom.xml
graph-inventory/aai-client/src/main/java/org/onap/aaiclient/client/aai/AAIDSLQueryClient.java
graph-inventory/aai-client/src/main/java/org/onap/aaiclient/client/aai/AAIObjectName.java [new file with mode: 0644]
graph-inventory/aai-client/src/main/java/org/onap/aaiclient/client/aai/AAIObjectPlurals.java
graph-inventory/aai-client/src/main/java/org/onap/aaiclient/client/aai/AAIObjectType.java
graph-inventory/aai-client/src/main/java/org/onap/aaiclient/client/aai/AAIQueryClient.java
graph-inventory/aai-client/src/main/java/org/onap/aaiclient/client/aai/entities/Relationships.java
graph-inventory/aai-client/src/main/java/org/onap/aaiclient/client/aai/entities/uri/AAIFluentPluralType.java [new file with mode: 0644]
graph-inventory/aai-client/src/main/java/org/onap/aaiclient/client/aai/entities/uri/AAIFluentSingleType.java [new file with mode: 0644]
graph-inventory/aai-client/src/main/java/org/onap/aaiclient/client/aai/entities/uri/AAIFluentTopLevelType.java [new file with mode: 0644]
graph-inventory/aai-client/src/main/java/org/onap/aaiclient/client/aai/entities/uri/AAIFluentTypeReverseLookup.java [new file with mode: 0644]
graph-inventory/aai-client/src/main/java/org/onap/aaiclient/client/aai/entities/uri/AAIUriFactory.java
graph-inventory/aai-client/src/main/java/org/onap/aaiclient/client/graphinventory/GraphInventoryFluentTopLevelType.java [new file with mode: 0644]
graph-inventory/aai-client/src/main/java/org/onap/aaiclient/client/graphinventory/GraphInventoryFluentType.java [new file with mode: 0644]
graph-inventory/aai-client/src/main/java/org/onap/aaiclient/client/graphinventory/GraphInventoryFluentTypeBase.java [new file with mode: 0644]
graph-inventory/aai-client/src/main/java/org/onap/aaiclient/client/graphinventory/GraphInventoryObjectPlurals.java
graph-inventory/aai-client/src/main/java/org/onap/aaiclient/client/graphinventory/GraphInventoryQueryClient.java
graph-inventory/aai-client/src/main/java/org/onap/aaiclient/client/graphinventory/entities/GraphInventoryRelationships.java
graph-inventory/aai-client/src/main/java/org/onap/aaiclient/client/graphinventory/entities/uri/parsers/UriParser.java
graph-inventory/aai-client/src/main/java/org/onap/aaiclient/client/graphinventory/entities/uri/parsers/UriParserSpringImpl.java
graph-inventory/aai-client/src/test/java/org/onap/aaiclient/client/aai/AAIResourcesClientTest.java
graph-inventory/aai-client/src/test/java/org/onap/aaiclient/client/aai/entities/uri/AAIFluentTypeReverseLookupTest.java [new file with mode: 0644]
graph-inventory/aai-client/src/test/java/org/onap/aaiclient/client/aai/entities/uri/AAISimpleUriTest.java
graph-inventory/fluent-builder-maven-plugin/pom.xml [new file with mode: 0644]
graph-inventory/fluent-builder-maven-plugin/src/main/java/org/onap/graphinventory/generate/FluentGenerator.java [new file with mode: 0644]
graph-inventory/fluent-builder-maven-plugin/src/main/java/org/onap/graphinventory/generate/FluentGeneratorMojo.java [new file with mode: 0644]
graph-inventory/fluent-builder-maven-plugin/src/main/java/org/onap/graphinventory/generate/ObjectField.java [new file with mode: 0644]
graph-inventory/fluent-builder-maven-plugin/src/main/java/org/onap/graphinventory/generate/ObjectType.java [new file with mode: 0644]
graph-inventory/fluent-builder-maven-plugin/src/main/java/org/onap/graphinventory/generate/SwaggerConverter.java [new file with mode: 0644]
graph-inventory/pom.xml

index c8b10cc..754f1bb 100644 (file)
@@ -7,6 +7,125 @@
     <version>1.6.0-SNAPSHOT</version>
   </parent>
   <artifactId>aai-client</artifactId>
+  <build>
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <groupId>org.eclipse.m2e</groupId>
+          <artifactId>lifecycle-mapping</artifactId>
+          <version>1.0.0</version>
+          <configuration>
+            <lifecycleMappingMetadata>
+              <pluginExecutions>
+                <pluginExecution>
+                  <pluginExecutionFilter>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-dependency-plugin</artifactId>
+                    <versionRange>[1.0.0,)</versionRange>
+                    <goals>
+                      <goal>unpack</goal>
+                    </goals>
+                  </pluginExecutionFilter>
+                  <action>
+                    <execute />
+                  </action>
+                </pluginExecution>
+                <pluginExecution>
+                  <pluginExecutionFilter>
+                    <groupId>org.onap.so</groupId>
+                    <artifactId>fluent-builder-maven-plugin</artifactId>
+                    <goals>
+                      <goal>generate-builders</goal>
+                    </goals>
+                    <versionRange>[0.0,)</versionRange>
+                  </pluginExecutionFilter>
+                  <action>
+                    <execute />
+                  </action>
+                </pluginExecution>
+              </pluginExecutions>
+            </lifecycleMappingMetadata>
+          </configuration>
+        </plugin>
+      </plugins>
+    </pluginManagement>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-dependency-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>unpack</id>
+            <phase>generate-sources</phase>
+            <goals>
+              <goal>unpack</goal>
+            </goals>
+            <configuration>
+              <artifactItems>
+                <artifactItem>
+                  <groupId>org.onap.aai.traversal</groupId>
+                  <artifactId>aai-traversal</artifactId>
+                  <version>1.6.3</version>
+                  <outputDirectory>${project.build.directory}/antlr</outputDirectory>
+                  <includes>**/*.g4</includes>
+                </artifactItem>
+                <artifactItem>
+                  <groupId>org.onap.aai.schema-service</groupId>
+                  <artifactId>aai-schema</artifactId>
+                  <version>1.6.5</version>
+                  <outputDirectory>${project.build.directory}/swagger</outputDirectory>
+                  <includes>**/*.yaml</includes>
+                </artifactItem>
+              </artifactItems>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.onap.so</groupId>
+        <artifactId>fluent-builder-maven-plugin</artifactId>
+        <version>${project.version}</version>
+        <executions>
+          <execution>
+            <goals>
+              <goal>generate-builders</goal>
+            </goals>
+            <configuration>
+              <destination>${project.build.directory}/generated-sources</destination>
+              <destinationClasspath>org.onap.aaiclient.client.generated.fluentbuilders</destinationClasspath>
+              <builderName>AAIFluentTypeBuilder</builderName>
+              <swaggerLocation>${project.build.directory}/swagger/onap/aai_swagger_yaml/aai_swagger_v19.yaml</swaggerLocation>
+              <singularBuilderClass>org.onap.aaiclient.client.aai.entities.uri.AAIFluentSingleType</singularBuilderClass>
+              <pluralBuilderClass>org.onap.aaiclient.client.aai.entities.uri.AAIFluentPluralType</pluralBuilderClass>
+              <topLevelBuilderClass>org.onap.aaiclient.client.aai.entities.uri.AAIFluentTopLevelType</topLevelBuilderClass>
+              <baseBuilderClass>org.onap.aaiclient.client.graphinventory.GraphInventoryFluentTypeBase</baseBuilderClass>
+              <singularClass>org.onap.aaiclient.client.aai.AAIObjectType</singularClass>
+              <pluralClass>org.onap.aaiclient.client.aai.AAIObjectPlurals</pluralClass>
+              <nameClass>org.onap.aaiclient.client.aai.AAIObjectName</nameClass>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>build-helper-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>add-source</id>
+            <phase>generate-sources</phase>
+            <goals>
+              <goal>add-source</goal>
+            </goals>
+            <configuration>
+              <sources>
+                <source>${project.build.directory}/generated-sources/fluent/</source>
+              </sources>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
   <dependencies>
     <dependency>
       <groupId>org.onap.so</groupId>
index 4c45a67..238e873 100644 (file)
@@ -21,6 +21,7 @@
 package org.onap.aaiclient.client.aai;
 
 import org.onap.aaiclient.client.aai.entities.AAIResultWrapper;
+import org.onap.aaiclient.client.aai.entities.uri.AAIFluentTypeReverseLookup;
 import org.onap.aaiclient.client.aai.entities.uri.AAIUriFactory;
 import org.onap.aaiclient.client.graphinventory.GraphInventoryQueryClient;
 import org.onap.aaiclient.client.graphinventory.entities.DSLQuery;
@@ -49,8 +50,8 @@ public class AAIDSLQueryClient
     }
 
     @Override
-    public AAIObjectType createType(String name) {
-        return AAIObjectType.fromTypeName(name);
+    public AAIObjectType createType(String name, String uri) {
+        return new AAIFluentTypeReverseLookup().fromName(name, uri);
     }
 
 }
diff --git a/graph-inventory/aai-client/src/main/java/org/onap/aaiclient/client/aai/AAIObjectName.java b/graph-inventory/aai-client/src/main/java/org/onap/aaiclient/client/aai/AAIObjectName.java
new file mode 100644 (file)
index 0000000..180a99e
--- /dev/null
@@ -0,0 +1,23 @@
+package org.onap.aaiclient.client.aai;
+
+import org.onap.aaiclient.client.graphinventory.GraphInventoryObjectName;
+import com.google.common.base.CaseFormat;
+
+public class AAIObjectName implements GraphInventoryObjectName {
+
+    private final String name;
+
+    public AAIObjectName(String name) {
+        this.name = name;
+    }
+
+    @Override
+    public String typeName() {
+        return name;
+    }
+
+    @Override
+    public String typeName(CaseFormat format) {
+        return CaseFormat.LOWER_HYPHEN.to(format, this.name);
+    }
+}
index fcda3c8..5b68d0c 100644 (file)
@@ -77,12 +77,18 @@ public class AAIObjectPlurals implements AAIObjectBase, GraphInventoryObjectPlur
 
     private final String uriTemplate;
     private final String partialUri;
-    private final AAIObjectType type;
+    private final String name;
 
     protected AAIObjectPlurals(AAIObjectType type, String parentUri, String partialUri) {
         this.uriTemplate = parentUri + partialUri;
         this.partialUri = partialUri;
-        this.type = type;
+        this.name = type.typeName();
+    }
+
+    public AAIObjectPlurals(String name, String parentUri, String partialUri) {
+        this.uriTemplate = parentUri + partialUri;
+        this.partialUri = partialUri;
+        this.name = name;
     }
 
     @Override
@@ -101,17 +107,27 @@ public class AAIObjectPlurals implements AAIObjectBase, GraphInventoryObjectPlur
     }
 
     @Override
-    public AAIObjectType getType() {
-        return this.type;
+    public String typeName() {
+        return this.typeName(CaseFormat.LOWER_HYPHEN);
     }
 
     @Override
-    public String typeName() {
-        return this.getType().typeName();
+    public String typeName(CaseFormat format) {
+        return CaseFormat.LOWER_HYPHEN.to(format, this.name.replace("default-", ""));
     }
 
     @Override
-    public String typeName(CaseFormat format) {
-        return this.getType().typeName(format);
+    public int hashCode() {
+        return this.typeName().hashCode();
+    }
+
+    @Override
+    public boolean equals(Object o) {
+
+        if (o instanceof AAIObjectBase) {
+            return this.typeName().equals(((AAIObjectBase) o).typeName());
+        }
+
+        return false;
     }
 }
index 8045a22..b3402fa 100644 (file)
@@ -74,6 +74,7 @@ import org.onap.aai.domain.yang.VolumeGroup;
 import org.onap.aai.domain.yang.VpnBinding;
 import org.onap.aai.domain.yang.Vserver;
 import org.onap.aai.domain.yang.Zone;
+import org.onap.aaiclient.client.aai.entities.uri.AAIFluentTypeReverseLookup;
 import org.onap.aaiclient.client.graphinventory.GraphInventoryObjectType;
 import org.onap.so.constants.Defaults;
 import org.reflections.Reflections;
@@ -262,12 +263,16 @@ public class AAIObjectType implements AAIObjectBase, GraphInventoryObjectType, S
     }
 
     protected AAIObjectType(String parentUri, String partialUri, String name) {
+        this(parentUri, partialUri, name, true);
+    }
+
+    public AAIObjectType(String parentUri, String partialUri, String name, boolean register) {
         this.parentUri = parentUri;
         this.partialUri = partialUri;
         this.uriTemplate = parentUri + partialUri;
         this.aaiObjectClass = null;
         this.name = name;
-        if (!AAIObjectType.map.containsKey(name)) {
+        if (register && !AAIObjectType.map.containsKey(name)) {
             AAIObjectType.map.put(name, this);
         }
     }
@@ -288,6 +293,11 @@ public class AAIObjectType implements AAIObjectBase, GraphInventoryObjectType, S
         return this.uriTemplate();
     }
 
+    public static AAIObjectType fromTypeName(String name, String uri) {
+
+        return new AAIFluentTypeReverseLookup().fromName(name, uri);
+    }
+
     public static AAIObjectType fromTypeName(String name) {
         if (map.containsKey(name)) {
             return map.get(name);
@@ -316,6 +326,21 @@ public class AAIObjectType implements AAIObjectBase, GraphInventoryObjectType, S
         return this.partialUri;
     }
 
+    @Override
+    public int hashCode() {
+        return this.typeName().hashCode();
+    }
+
+    @Override
+    public boolean equals(Object o) {
+
+        if (o instanceof AAIObjectBase) {
+            return this.typeName().equals(((AAIObjectBase) o).typeName());
+        }
+
+        return false;
+    }
+
     protected String removeParentUri(Class<?> aaiObjectClass, String parentUri) {
         return aaiObjectClass.getAnnotation(Metadata.class).uriTemplate().replaceFirst(Pattern.quote(parentUri), "");
     }
index 5e8b052..75d4a6f 100644 (file)
@@ -22,6 +22,7 @@ package org.onap.aaiclient.client.aai;
 
 import org.onap.aaiclient.client.aai.entities.AAIResultWrapper;
 import org.onap.aaiclient.client.aai.entities.CustomQuery;
+import org.onap.aaiclient.client.aai.entities.uri.AAIFluentTypeReverseLookup;
 import org.onap.aaiclient.client.aai.entities.uri.AAIUriFactory;
 import org.onap.aaiclient.client.graphinventory.GraphInventoryQueryClient;
 import org.onap.aaiclient.client.graphinventory.entities.uri.GraphInventoryUri;
@@ -53,8 +54,8 @@ public class AAIQueryClient
     }
 
     @Override
-    public AAIObjectType createType(String name) {
-        return AAIObjectType.fromTypeName(name);
+    public AAIObjectType createType(String name, String uri) {
+        return new AAIFluentTypeReverseLookup().fromName(name, uri);
     }
 
 }
index fb20531..b8a80f0 100644 (file)
@@ -24,6 +24,7 @@ import java.util.List;
 import javax.ws.rs.core.UriBuilder;
 import org.onap.aaiclient.client.aai.AAIObjectType;
 import org.onap.aaiclient.client.aai.AAIResourcesClient;
+import org.onap.aaiclient.client.aai.entities.uri.AAIFluentTypeReverseLookup;
 import org.onap.aaiclient.client.aai.entities.uri.AAIResourceUri;
 import org.onap.aaiclient.client.aai.entities.uri.AAIUriFactory;
 import org.onap.aaiclient.client.graphinventory.GraphInventoryObjectName;
@@ -68,7 +69,7 @@ public class Relationships extends GraphInventoryRelationships<AAIResultWrapper,
     }
 
     @Override
-    protected AAIObjectType fromTypeName(String name) {
-        return AAIObjectType.fromTypeName(name);
+    protected AAIObjectType fromTypeName(String name, String uri) {
+        return new AAIFluentTypeReverseLookup().fromName(name, uri);
     }
 }
diff --git a/graph-inventory/aai-client/src/main/java/org/onap/aaiclient/client/aai/entities/uri/AAIFluentPluralType.java b/graph-inventory/aai-client/src/main/java/org/onap/aaiclient/client/aai/entities/uri/AAIFluentPluralType.java
new file mode 100644 (file)
index 0000000..ea81e7b
--- /dev/null
@@ -0,0 +1,12 @@
+package org.onap.aaiclient.client.aai.entities.uri;
+
+import org.onap.aaiclient.client.aai.AAIObjectPlurals;
+import org.onap.aaiclient.client.graphinventory.GraphInventoryFluentType;
+
+public interface AAIFluentPluralType extends GraphInventoryFluentType<AAIObjectPlurals> {
+
+    public interface Info extends GraphInventoryFluentType.Info {
+
+
+    }
+}
diff --git a/graph-inventory/aai-client/src/main/java/org/onap/aaiclient/client/aai/entities/uri/AAIFluentSingleType.java b/graph-inventory/aai-client/src/main/java/org/onap/aaiclient/client/aai/entities/uri/AAIFluentSingleType.java
new file mode 100644 (file)
index 0000000..9310933
--- /dev/null
@@ -0,0 +1,12 @@
+package org.onap.aaiclient.client.aai.entities.uri;
+
+import org.onap.aaiclient.client.aai.AAIObjectType;
+import org.onap.aaiclient.client.graphinventory.GraphInventoryFluentType;
+
+public interface AAIFluentSingleType extends GraphInventoryFluentType<AAIObjectType> {
+
+    public interface Info extends GraphInventoryFluentType.Info {
+
+
+    }
+}
diff --git a/graph-inventory/aai-client/src/main/java/org/onap/aaiclient/client/aai/entities/uri/AAIFluentTopLevelType.java b/graph-inventory/aai-client/src/main/java/org/onap/aaiclient/client/aai/entities/uri/AAIFluentTopLevelType.java
new file mode 100644 (file)
index 0000000..46a521d
--- /dev/null
@@ -0,0 +1,11 @@
+package org.onap.aaiclient.client.aai.entities.uri;
+
+import org.onap.aaiclient.client.graphinventory.GraphInventoryFluentTopLevelType;
+
+public interface AAIFluentTopLevelType extends GraphInventoryFluentTopLevelType {
+
+    public interface Info extends GraphInventoryFluentTopLevelType.Info {
+
+
+    }
+}
diff --git a/graph-inventory/aai-client/src/main/java/org/onap/aaiclient/client/aai/entities/uri/AAIFluentTypeReverseLookup.java b/graph-inventory/aai-client/src/main/java/org/onap/aaiclient/client/aai/entities/uri/AAIFluentTypeReverseLookup.java
new file mode 100644 (file)
index 0000000..bd9f4c7
--- /dev/null
@@ -0,0 +1,51 @@
+package org.onap.aaiclient.client.aai.entities.uri;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+import org.onap.aaiclient.client.aai.AAIObjectType;
+import org.onap.aaiclient.client.graphinventory.GraphInventoryFluentType;
+import org.onap.aaiclient.client.graphinventory.entities.uri.parsers.UriParserSpringImpl;
+import com.google.common.base.CaseFormat;
+
+public class AAIFluentTypeReverseLookup {
+
+    public AAIObjectType fromName(String name, String uri) {
+
+        String className = CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_CAMEL, name);
+
+        uri = uri.replaceFirst(".*?/v\\d+", "");
+        try {
+            Class<? extends GraphInventoryFluentType.Info> clazz =
+                    (Class<? extends GraphInventoryFluentType.Info>) Class
+                            .forName("org.onap.aaiclient.client.generated.fluentbuilders." + className + "$Info");
+
+            GraphInventoryFluentType.Info type = clazz.newInstance();
+
+            Optional<String> parentTemplate = findParentPath(type, uri);
+            if (parentTemplate.isPresent()) {
+                return new AAIObjectType(parentTemplate.get(), type.getPartialUri(), type.getName(), false);
+            } else {
+                // fallback to enum lookup
+                return AAIObjectType.fromTypeName(name);
+            }
+        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
+        }
+        return AAIObjectType.UNKNOWN;
+    }
+
+    protected Optional<String> findParentPath(GraphInventoryFluentType.Info type, String uri) {
+
+        List<UriParserSpringImpl> parsers =
+                type.getPaths().stream().map(path -> new UriParserSpringImpl(path)).collect(Collectors.toList());
+
+        for (UriParserSpringImpl parser : parsers) {
+            if (parser.isMatch(uri)) {
+                String partialUriReplacer = type.getPartialUri().replaceAll("\\{[^}]+\\}", "[^/]+");
+                return Optional.of(parser.getTemplate().replaceFirst(partialUriReplacer + "$", ""));
+            }
+        }
+
+        return Optional.empty();
+    }
+}
index 31b5595..6bb2cbd 100644 (file)
@@ -47,6 +47,10 @@ public class AAIUriFactory {
         }
     }
 
+    public static AAIResourceUri createResourceUri(AAIFluentSingleType uri) {
+        return new AAISimpleUri(uri.build(), uri.values());
+    }
+
     public static NodesSingleUri createNodesUri(AAIObjectType type, Object... values) {
         return new NodesSingleUri(type, values);
 
@@ -88,6 +92,12 @@ public class AAIUriFactory {
         return new AAISimplePluralUri(parentUri, childType);
     }
 
+    public static AAISimplePluralUri createResourceUri(AAIFluentPluralType uri) {
+
+        return new AAISimplePluralUri(uri.build());
+
+    }
+
     /**
      * Creates a uri for a plural type e.g. /cloud-infrastructure/pservers
      * 
diff --git a/graph-inventory/aai-client/src/main/java/org/onap/aaiclient/client/graphinventory/GraphInventoryFluentTopLevelType.java b/graph-inventory/aai-client/src/main/java/org/onap/aaiclient/client/graphinventory/GraphInventoryFluentTopLevelType.java
new file mode 100644 (file)
index 0000000..9740016
--- /dev/null
@@ -0,0 +1,5 @@
+package org.onap.aaiclient.client.graphinventory;
+
+public interface GraphInventoryFluentTopLevelType extends GraphInventoryFluentTypeBase {
+
+}
diff --git a/graph-inventory/aai-client/src/main/java/org/onap/aaiclient/client/graphinventory/GraphInventoryFluentType.java b/graph-inventory/aai-client/src/main/java/org/onap/aaiclient/client/graphinventory/GraphInventoryFluentType.java
new file mode 100644 (file)
index 0000000..94fa240
--- /dev/null
@@ -0,0 +1,10 @@
+package org.onap.aaiclient.client.graphinventory;
+
+public interface GraphInventoryFluentType<T> extends GraphInventoryFluentTypeBase {
+
+    public interface Info extends GraphInventoryFluentTypeBase.Info {
+        String getName();
+    }
+
+    T build();
+}
diff --git a/graph-inventory/aai-client/src/main/java/org/onap/aaiclient/client/graphinventory/GraphInventoryFluentTypeBase.java b/graph-inventory/aai-client/src/main/java/org/onap/aaiclient/client/graphinventory/GraphInventoryFluentTypeBase.java
new file mode 100644 (file)
index 0000000..1a258fc
--- /dev/null
@@ -0,0 +1,16 @@
+package org.onap.aaiclient.client.graphinventory;
+
+import java.util.List;
+
+public interface GraphInventoryFluentTypeBase {
+
+    public interface Info {
+        String getPartialUri();
+
+        List<String> getPaths();
+    }
+
+    Object[] values();
+
+    String uriTemplate();
+}
index 8aa03e2..c749561 100644 (file)
@@ -95,8 +95,8 @@ public abstract class GraphInventoryQueryClient<S, I, Wrapper extends GraphInven
                 if (!entrySet.getKey().equals("url")) {
                     String url = (String) m.get("url");
                     String stringJson = mapper.writeValueAsString(entrySet.getValue());
-                    result.add(
-                            new ResourceAndUrl<Wrapper>(url, createType(entrySet.getKey()), createWrapper(stringJson)));
+                    result.add(new ResourceAndUrl<Wrapper>(url, createType(entrySet.getKey(), url),
+                            createWrapper(stringJson)));
                 }
             }
         }
@@ -106,7 +106,7 @@ public abstract class GraphInventoryQueryClient<S, I, Wrapper extends GraphInven
 
     public abstract Wrapper createWrapper(String json);
 
-    public abstract Type createType(String name);
+    public abstract Type createType(String name, String uri);
 
     public S depth(String depth) {
         this.depth = Optional.of(depth);
index 7d96087..48feba2 100644 (file)
@@ -86,8 +86,8 @@ public abstract class GraphInventoryRelationships<Wrapper extends GraphInventory
                 final String relatedTo = (String) relationship.get("related-to");
                 if (p.test(relatedTo)) {
                     Type type;
-                    type = fromTypeName(relatedTo);
                     final String relatedLink = (String) relationship.get("related-link");
+                    type = fromTypeName(relatedTo, relatedLink);
 
                     result.add(createUri(type, relatedLink));
                 }
@@ -116,7 +116,7 @@ public abstract class GraphInventoryRelationships<Wrapper extends GraphInventory
 
     protected abstract Uri createUri(Type type, String relatedLink);
 
-    protected abstract Type fromTypeName(String name);
+    protected abstract Type fromTypeName(String name, String uri);
 
     protected List<String> getRelatedLinks(Optional<GraphInventoryObjectName> type) {
         String matcher = "";
index db13ef7..291e395 100644 (file)
@@ -32,9 +32,16 @@ import org.springframework.web.util.UriUtils;
 public class UriParserSpringImpl implements UriParser {
 
     private final UriTemplate uriTemplate;
+    private final String template;
 
     public UriParserSpringImpl(final String template) {
         this.uriTemplate = new UriTemplate(template);
+        this.template = template;
+    }
+
+    @Override
+    public boolean isMatch(final String uri) {
+        return this.uriTemplate.matches(uri);
     }
 
     @Override
@@ -51,6 +58,11 @@ public class UriParserSpringImpl implements UriParser {
         return Collections.unmodifiableSet(new LinkedHashSet<String>(this.uriTemplate.getVariableNames()));
     }
 
+    @Override
+    public String getTemplate() {
+        return this.template;
+    }
+
     protected Map<String, String> decodeParams(Map<String, String> map) {
         final Map<String, String> result = new LinkedHashMap<>();
 
index 4cb79ef..ca361f4 100644 (file)
@@ -49,7 +49,6 @@ import org.mockito.junit.MockitoJUnitRunner;
 import org.onap.aai.domain.yang.GenericVnf;
 import org.onap.aai.domain.yang.GenericVnfs;
 import org.onap.aai.domain.yang.Relationship;
-import org.onap.so.client.RestClient;
 import org.onap.aaiclient.client.aai.entities.AAIEdgeLabel;
 import org.onap.aaiclient.client.aai.entities.AAIResultWrapper;
 import org.onap.aaiclient.client.aai.entities.uri.AAIPluralResourceUri;
@@ -57,6 +56,7 @@ import org.onap.aaiclient.client.aai.entities.uri.AAIResourceUri;
 import org.onap.aaiclient.client.aai.entities.uri.AAIUriFactory;
 import org.onap.aaiclient.client.defaultproperties.DefaultAAIPropertiesImpl;
 import org.onap.aaiclient.client.graphinventory.exceptions.GraphInventoryMultipleItemsException;
+import org.onap.so.client.RestClient;
 import com.github.tomakehurst.wiremock.admin.NotFoundException;
 import com.github.tomakehurst.wiremock.junit.WireMockRule;
 
diff --git a/graph-inventory/aai-client/src/test/java/org/onap/aaiclient/client/aai/entities/uri/AAIFluentTypeReverseLookupTest.java b/graph-inventory/aai-client/src/test/java/org/onap/aaiclient/client/aai/entities/uri/AAIFluentTypeReverseLookupTest.java
new file mode 100644 (file)
index 0000000..699eac9
--- /dev/null
@@ -0,0 +1,74 @@
+package org.onap.aaiclient.client.aai.entities.uri;
+
+import static org.junit.Assert.assertEquals;
+import org.junit.Test;
+import org.onap.aaiclient.client.aai.AAIObjectType;
+
+public class AAIFluentTypeReverseLookupTest {
+
+
+    @Test
+    public void reverseParseEntryUri() {
+        String cloudRegion =
+                "http://localhost:8888/aai/v38/cloud-infrastructure/cloud-regions/cloud-region/{cloud-owner}/{cloud-region-id}";
+        String newvce = "/aai/v9/network/newvces/newvce/{vnf-id2}";
+
+        AAIFluentTypeReverseLookup lookup = new AAIFluentTypeReverseLookup();
+        AAIObjectType type = lookup.fromName("cloud-region", cloudRegion);
+
+        assertEquals("cloud-region", type.typeName());
+        assertEquals("/cloud-regions/cloud-region/{cloud-owner}/{cloud-region-id}", type.partialUri());
+        assertEquals("/cloud-infrastructure/cloud-regions/cloud-region/{cloud-owner}/{cloud-region-id}",
+                type.uriTemplate());
+
+        type = lookup.fromName("newvce", newvce);
+
+        assertEquals("newvce", type.typeName());
+        assertEquals("/newvces/newvce/{vnf-id2}", type.partialUri());
+        assertEquals("/network/newvces/newvce/{vnf-id2}", type.uriTemplate());
+
+        type = lookup.fromName("unknown-type-of-something", "/some/endpoint");
+
+        assertEquals("unknown", type.typeName());
+
+    }
+
+    @Test
+    public void reverseParseTest() {
+
+        String pserverParent =
+                "/aai/v9/cloud-infrastructure/pservers/pserver/{hostname}/lag-interfaces/lag-interface/{interface-name}/l-interfaces/l-interface/{l-interface.interface-name}";
+        String cloudRegionParent =
+                "http://localhost:8888/aai/v38/cloud-infrastructure/cloud-regions/cloud-region/{cloud-owner}/{cloud-region-id}/tenants/tenant/{tenant-id}/vservers/vserver/{vserver-id}/l-interfaces/l-interface/{interface-name}";
+        String newVceParent = "/network/newvces/newvce/{vnf-id2}/l-interfaces/l-interface/{l-interface.interface-name}";
+
+
+        AAIFluentTypeReverseLookup lookup = new AAIFluentTypeReverseLookup();
+
+        AAIObjectType type = lookup.fromName("l-interface", pserverParent);
+
+        assertEquals("l-interface", type.typeName());
+        assertEquals("/l-interfaces/l-interface/{l-interface.interface-name}", type.partialUri());
+        assertEquals(
+                "/cloud-infrastructure/pservers/pserver/{hostname}/lag-interfaces/lag-interface/{interface-name}/l-interfaces/l-interface/{l-interface.interface-name}",
+                type.uriTemplate());
+
+        type = lookup.fromName("l-interface", cloudRegionParent);
+
+        assertEquals("l-interface", type.typeName());
+        assertEquals("/l-interfaces/l-interface/{l-interface.interface-name}", type.partialUri());
+        assertEquals(
+                "/cloud-infrastructure/cloud-regions/cloud-region/{cloud-owner}/{cloud-region-id}/tenants/tenant/{tenant-id}/vservers/vserver/{vserver-id}/l-interfaces/l-interface/{l-interface.interface-name}",
+                type.uriTemplate());
+
+        type = lookup.fromName("l-interface", newVceParent);
+
+        assertEquals("l-interface", type.typeName());
+        assertEquals("/l-interfaces/l-interface/{l-interface.interface-name}", type.partialUri());
+        assertEquals("/network/newvces/newvce/{vnf-id2}/l-interfaces/l-interface/{l-interface.interface-name}",
+                type.uriTemplate());
+
+
+
+    }
+}
index 3b11c01..f8dd172 100644 (file)
@@ -31,6 +31,7 @@ import java.util.Map;
 import org.junit.Test;
 import org.onap.aaiclient.client.aai.AAIObjectPlurals;
 import org.onap.aaiclient.client.aai.AAIObjectType;
+import org.onap.aaiclient.client.generated.fluentbuilders.AAIFluentTypeBuilder;
 import org.onap.aaiclient.client.graphinventory.entities.uri.Depth;
 
 public class AAISimpleUriTest {
@@ -130,4 +131,14 @@ public class AAISimpleUriTest {
 
         assertEquals(e2.build().toString(), uri.build().toString());
     }
+
+    @Test
+    public void fluentBuilderTest() {
+        AAIResourceUri uri = AAIUriFactory.createResourceUri(AAIFluentTypeBuilder.cloudInfrastructure()
+                .cloudRegion("cloud1", "cloud-id").tenant("tenant-id").vserver("vserver-id"));
+
+        assertEquals(
+                "/cloud-infrastructure/cloud-regions/cloud-region/cloud1/cloud-id/tenants/tenant/tenant-id/vservers/vserver/vserver-id",
+                uri.build().toString());
+    }
 }
diff --git a/graph-inventory/fluent-builder-maven-plugin/pom.xml b/graph-inventory/fluent-builder-maven-plugin/pom.xml
new file mode 100644 (file)
index 0000000..7833bce
--- /dev/null
@@ -0,0 +1,55 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.onap.so</groupId>
+    <artifactId>graph-inventory</artifactId>
+    <version>1.6.0-SNAPSHOT</version>
+  </parent>
+  <artifactId>fluent-builder-maven-plugin</artifactId>
+  <packaging>maven-plugin</packaging>
+  <properties>
+    <maven.compiler.source>1.8</maven.compiler.source>
+    <maven.compiler.target>1.8</maven.compiler.target>
+  </properties>
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-plugin-plugin</artifactId>
+        <version>3.6.0</version>
+        <configuration>
+          <goalPrefix>fluent-builder</goalPrefix>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-plugin-api</artifactId>
+      <version>3.6.3</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven.plugin-tools</groupId>
+      <artifactId>maven-plugin-annotations</artifactId>
+      <version>3.6.0</version>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-project</artifactId>
+      <version>2.2.1</version>
+    </dependency>
+    <dependency>
+      <groupId>io.swagger</groupId>
+      <artifactId>swagger-parser</artifactId>
+      <version>1.0.50</version>
+    </dependency>
+    <dependency>
+      <groupId>com.squareup</groupId>
+      <artifactId>javapoet</artifactId>
+      <version>1.12.1</version>
+    </dependency>
+  </dependencies>
+</project>
diff --git a/graph-inventory/fluent-builder-maven-plugin/src/main/java/org/onap/graphinventory/generate/FluentGenerator.java b/graph-inventory/fluent-builder-maven-plugin/src/main/java/org/onap/graphinventory/generate/FluentGenerator.java
new file mode 100644 (file)
index 0000000..f9c6643
--- /dev/null
@@ -0,0 +1,324 @@
+package org.onap.graphinventory.generate;
+
+import java.io.IOException;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.stream.Collectors;
+import javax.lang.model.element.Modifier;
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.maven.plugin.logging.Log;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.google.common.base.CaseFormat;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.FieldSpec;
+import com.squareup.javapoet.JavaFile;
+import com.squareup.javapoet.MethodSpec;
+import com.squareup.javapoet.ParameterSpec;
+import com.squareup.javapoet.ParameterizedTypeName;
+import com.squareup.javapoet.TypeSpec;
+
+public class FluentGenerator {
+
+    private final Map<String, ObjectType> doc;
+    private final String location;
+    private final String CLASSPATH;
+
+    private final String singularBuilderClass;
+    private final String pluralBuilderClass;
+    private final String topLevelBuilderClass;
+    private final String baseBuilderClass;
+    private final String singularClass;
+    private final String pluralClass;
+    private final String builderName;
+    private final String nameClass;
+
+    public FluentGenerator(Log log, String location, String destinationClasspath, String swaggerLocation,
+            String builderName, String singularBuilderClass, String pluralBuilderClass, String topLevelBuilderClass,
+            String baseBuilderClass, String singularClass, String pluralClass, String nameClass)
+            throws JsonProcessingException {
+
+        this.location = location;
+        this.CLASSPATH = destinationClasspath;
+        this.builderName = builderName;
+        this.singularBuilderClass = singularBuilderClass;
+        this.pluralBuilderClass = pluralBuilderClass;
+        this.topLevelBuilderClass = topLevelBuilderClass;
+        this.baseBuilderClass = baseBuilderClass;
+        this.singularClass = singularClass;
+        this.pluralClass = pluralClass;
+        this.nameClass = nameClass;
+        doc = new SwaggerConverter(log).getDoc(swaggerLocation);
+    }
+
+    public void run() throws IOException {
+        List<JavaFile> files = new ArrayList<>();
+        for (Entry<String, ObjectType> entry : doc.entrySet()) {
+            // String key = "routing-instance";
+            // ObjectType oType = test;
+            String key = entry.getKey();
+            ObjectType oType = entry.getValue();
+            MethodSpec.Builder constructor = MethodSpec.constructorBuilder().addModifiers(Modifier.PROTECTED);
+            List<ParameterSpec> constructorParams = new ArrayList<>();
+            List<FieldSpec> classFields = new ArrayList<>();
+
+            if (!oType.getType().equals("top level")) {
+                Pair<String, String> path = splitClasspath(this.baseBuilderClass);
+                ClassName parameterizedTypeName = ClassName.get(path.getLeft(), path.getRight());
+                constructorParams.add(ParameterSpec.builder(parameterizedTypeName, "parentObj").build());
+                classFields.add(FieldSpec.builder(parameterizedTypeName, "parentObj")
+                        .addModifiers(Modifier.PRIVATE, Modifier.FINAL).build());
+            }
+            List<ParameterSpec> typeParams = new ArrayList<>();
+
+            for (ObjectField oF : oType.getFields()) {
+                if (oF.getType().equals("string")) {
+                    typeParams.add(ParameterSpec.builder(String.class, lowerCamel(makeValidJavaVariable(oF.getName())))
+                            .build());
+                    classFields.add(FieldSpec.builder(String.class, lowerCamel(makeValidJavaVariable(oF.getName())))
+                            .addModifiers(Modifier.PRIVATE, Modifier.FINAL).build());
+                } else if (oF.getType().equals("integer")) {
+                    typeParams.add(
+                            ParameterSpec.builder(int.class, lowerCamel(makeValidJavaVariable(oF.getName()))).build());
+                    classFields.add(FieldSpec.builder(int.class, lowerCamel(makeValidJavaVariable(oF.getName())))
+                            .addModifiers(Modifier.PRIVATE, Modifier.FINAL).build());
+                }
+            }
+            constructorParams.addAll(typeParams);
+            constructor.addParameters(constructorParams);
+            for (ParameterSpec p : constructorParams) {
+                constructor.addStatement("this.$L = $L", p.name, p.name);
+
+            }
+            List<MethodSpec> methods = new ArrayList<>();
+            methods.add(constructor.build());
+
+            methods.addAll(createChildMethods(oType));
+
+            methods.addAll(createInterfaceMethods(oType, typeParams));
+
+            ClassName superType = null;
+            if (oType.getType().equals("top level")) {
+                Pair<String, String> path = splitClasspath(this.topLevelBuilderClass);
+                superType = ClassName.get(path.getLeft(), path.getRight());
+            } else {
+                if (oType.getType().equals("singular")) {
+                    Pair<String, String> path = splitClasspath(this.singularBuilderClass);
+                    superType = ClassName.get(path.getLeft(), path.getRight());
+
+                } else if (oType.getType().equals("plural")) {
+                    Pair<String, String> path = splitClasspath(this.pluralBuilderClass);
+                    superType = ClassName.get(path.getLeft(), path.getRight());
+                }
+            }
+
+            TypeSpec type = TypeSpec.classBuilder(upperCamel(key)).addModifiers(Modifier.PUBLIC, Modifier.FINAL)
+                    .addType(createInnerInfoClass(oType)).addSuperinterface(superType).addFields(classFields)
+                    .addMethods(methods).build();
+
+            files.add(JavaFile.builder(CLASSPATH, type).build());
+
+        }
+
+        files.add(createBuilderClass());
+
+        files.stream().forEach(javaFile -> {
+            try {
+                javaFile.writeTo(Paths.get(location, "fluent"));
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+        });
+
+    }
+
+    protected List<MethodSpec> createInterfaceMethods(ObjectType oType, List<ParameterSpec> typeParams) {
+
+        List<MethodSpec> methods = new ArrayList<>();
+
+        CodeBlock.Builder uriTemplateCodeBlock = CodeBlock.builder();
+        if (!oType.getType().equals("top level")) {
+            uriTemplateCodeBlock.add("return this.parentObj.uriTemplate() + Info.partialUri");
+        } else {
+            uriTemplateCodeBlock.add("return Info.partialUri");
+
+        }
+        methods.add(MethodSpec.methodBuilder("uriTemplate").returns(String.class).addModifiers(Modifier.PUBLIC)
+                .addStatement(uriTemplateCodeBlock.build()).addAnnotation(Override.class).build());
+
+        ClassName arrayUtils = ClassName.get(ArrayUtils.class);
+
+        CodeBlock.Builder valuesReturn = CodeBlock.builder();
+
+        if (oType.getType().equals("top level")) {
+            valuesReturn.add("return new Object[0]");
+        } else {
+            if (!typeParams.isEmpty()) {
+                valuesReturn.add("return $T.addAll(this.parentObj.values(), $L)", arrayUtils, String.join(", ",
+                        typeParams.stream().map(item -> "this." + item.name).collect(Collectors.toList())));
+            } else {
+                valuesReturn.add("return this.parentObj.values()");
+            }
+        }
+        methods.add(MethodSpec.methodBuilder("values").returns(Object[].class).addModifiers(Modifier.PUBLIC)
+                .addAnnotation(Override.class).addStatement(valuesReturn.build()).build());
+
+        if (!oType.getType().equals("top level")) {
+            ClassName returnType = null;
+            CodeBlock.Builder block = CodeBlock.builder();
+            if (oType.getType().equals("singular")) {
+                Pair<String, String> path = splitClasspath(this.singularClass);
+                returnType = ClassName.get(path.getLeft(), path.getRight());
+                block.add("return new $T(this.parentObj.uriTemplate(), Info.partialUri, Info.name, false)", returnType);
+            } else if (oType.getType().equals("plural")) {
+                Pair<String, String> path = splitClasspath(this.pluralClass);
+                returnType = ClassName.get(path.getLeft(), path.getRight());
+                block.add("return new $T(Info.name, this.parentObj.uriTemplate(), Info.partialUri)", returnType);
+            }
+
+            methods.add(MethodSpec.methodBuilder("build").returns(returnType).addModifiers(Modifier.PUBLIC)
+                    .addAnnotation(Override.class).addStatement(block.build()).build());
+
+        }
+
+        return methods;
+    }
+
+    protected List<MethodSpec> createChildMethods(ObjectType oType) {
+        List<MethodSpec> methods = new ArrayList<>();
+        for (String child : oType.getChildren()) {
+            methods.add(createAccessMethod(doc.get(child), true, false));
+        }
+
+        return methods;
+    }
+
+    protected MethodSpec createAccessMethod(ObjectType oType, boolean isChild, boolean isStatic) {
+
+        ClassName childClass = ClassName.get(CLASSPATH, upperCamel(oType.getName()));
+        MethodSpec.Builder b = MethodSpec.methodBuilder(lowerCamel(oType.getName())).returns(childClass);
+        List<Modifier> modifiers = new ArrayList<>();
+        if (isStatic) {
+            modifiers.add(Modifier.STATIC);
+        }
+        modifiers.add(Modifier.PUBLIC);
+        b.addModifiers(modifiers);
+        List<ParameterSpec> params = new ArrayList<>();
+        for (ObjectField oF : doc.get(oType.getName()).getFields()) {
+            if (oF.getType().equals("string")) {
+                params.add(
+                        ParameterSpec.builder(String.class, lowerCamel(makeValidJavaVariable(oF.getName()))).build());
+            } else if (oF.getType().equals("integer")) {
+                params.add(ParameterSpec.builder(int.class, lowerCamel(makeValidJavaVariable(oF.getName()))).build());
+            }
+        }
+        List<String> paramNames = params.stream().map(item -> item.name).collect(Collectors.toList());
+        if (isChild) {
+            paramNames.add(0, "this");
+        }
+        b.addParameters(params).addStatement("return new $T($L)", childClass, String.join(", ", paramNames));
+
+        return b.build();
+    }
+
+    protected JavaFile createBuilderClass() {
+
+        List<MethodSpec> methods = doc.values().stream().filter(item -> item.getType().equals("top level"))
+                .map(item -> createAccessMethod(item, false, true)).collect(Collectors.toList());
+
+        TypeSpec type = TypeSpec.classBuilder(this.builderName).addModifiers(Modifier.PUBLIC, Modifier.FINAL)
+                .addMethods(methods).addType(createTypes()).build();
+
+        return JavaFile.builder(CLASSPATH, type).build();
+
+    }
+
+    protected TypeSpec createTypes() {
+        Pair<String, String> path = splitClasspath(this.nameClass);
+        ClassName nameType = ClassName.get(path.getLeft(), path.getRight());
+
+        List<FieldSpec> params =
+                doc.values().stream().filter(item -> item.getType().equals("singular"))
+                        .sorted(Comparator
+                                .comparing(item -> item.getName()))
+                        .map(item -> FieldSpec
+                                .builder(nameType,
+                                        CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_UNDERSCORE, item.getName()),
+                                        Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL)
+                                .initializer("new $T($S)", nameType, item.getName()).build())
+                        .collect(Collectors.toList());
+
+        TypeSpec type = TypeSpec.classBuilder("Types").addModifiers(Modifier.PUBLIC, Modifier.FINAL, Modifier.STATIC)
+                .addFields(params).build();
+
+        return type;
+
+    }
+
+    protected TypeSpec createInnerInfoClass(ObjectType oType) {
+        List<FieldSpec> classFields = new ArrayList<>();
+        List<MethodSpec> methods = new ArrayList<>();
+
+        classFields.add(FieldSpec.builder(String.class, "partialUri")
+                .addModifiers(Modifier.PRIVATE, Modifier.FINAL, Modifier.STATIC)
+                .initializer("$S", oType.getPartialUri()).build());
+
+        classFields.add(FieldSpec.builder(ParameterizedTypeName.get(List.class, String.class), "paths")
+                .addModifiers(Modifier.PRIVATE, Modifier.FINAL, Modifier.STATIC)
+                .initializer("$T.asList($L)", ClassName.get(Arrays.class),
+                        "\"" + oType.getPaths().stream().collect(Collectors.joining("\", \"")) + "\"")
+                .build());
+
+        ClassName superInterface;
+        if (oType.getType().equals("plural")) {
+            classFields.add(FieldSpec.builder(String.class, "name")
+                    .addModifiers(Modifier.PRIVATE, Modifier.FINAL, Modifier.STATIC)
+                    .initializer("$S", oType.getAdditionalName()).build());
+            superInterface = ClassName.get(this.pluralBuilderClass, "Info");
+        } else if (oType.getType().equals("singular")) {
+            classFields.add(FieldSpec.builder(String.class, "name")
+                    .addModifiers(Modifier.PRIVATE, Modifier.FINAL, Modifier.STATIC).initializer("$S", oType.getName())
+                    .build());
+            superInterface = ClassName.get(this.singularBuilderClass, "Info");
+        } else {
+            superInterface = ClassName.get(this.topLevelBuilderClass, "Info");
+        }
+        methods.add(MethodSpec.methodBuilder("getPaths").returns(ParameterizedTypeName.get(List.class, String.class))
+                .addModifiers(Modifier.PUBLIC).addAnnotation(Override.class).addStatement("return Info.paths").build());
+        methods.add(MethodSpec.methodBuilder("getPartialUri").returns(String.class).addModifiers(Modifier.PUBLIC)
+                .addAnnotation(Override.class).addStatement("return Info.partialUri").build());
+        if (!oType.getType().equals("top level")) {
+            methods.add(MethodSpec.methodBuilder("getName").returns(String.class).addModifiers(Modifier.PUBLIC)
+                    .addAnnotation(Override.class).addStatement("return Info.name").build());
+        }
+        return TypeSpec.classBuilder("Info").addModifiers(Modifier.PUBLIC, Modifier.STATIC)
+                .addSuperinterface(superInterface).addFields(classFields).addMethods(methods).build();
+
+    }
+
+    protected String makeValidJavaVariable(String name) {
+
+        return name.replace(".", "_");
+    }
+
+    protected Pair<String, String> splitClasspath(String path) {
+
+        return Pair.of(path.substring(0, path.lastIndexOf(".")),
+                path.substring(path.lastIndexOf(".") + 1, path.length()));
+    }
+
+    protected String lowerCamel(String s) {
+        return CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL, s);
+    }
+
+    protected String upperCamel(String s) {
+        return CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_CAMEL, s);
+    }
+
+}
diff --git a/graph-inventory/fluent-builder-maven-plugin/src/main/java/org/onap/graphinventory/generate/FluentGeneratorMojo.java b/graph-inventory/fluent-builder-maven-plugin/src/main/java/org/onap/graphinventory/generate/FluentGeneratorMojo.java
new file mode 100644 (file)
index 0000000..9de249f
--- /dev/null
@@ -0,0 +1,53 @@
+package org.onap.graphinventory.generate;
+
+import java.io.IOException;
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.plugins.annotations.LifecyclePhase;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.Parameter;
+import com.fasterxml.jackson.core.JsonProcessingException;
+
+@Mojo(name = "generate-builders", defaultPhase = LifecyclePhase.GENERATE_SOURCES)
+public class FluentGeneratorMojo extends AbstractMojo {
+
+    @Parameter
+    private String destination;
+    @Parameter
+    private String destinationClasspath;
+    @Parameter
+    private String builderName;
+    @Parameter
+    private String swaggerLocation;
+    @Parameter
+    private String singularBuilderClass;
+    @Parameter
+    private String pluralBuilderClass;
+    @Parameter
+    private String topLevelBuilderClass;
+    @Parameter
+    private String baseBuilderClass;
+    @Parameter
+    private String singularClass;
+    @Parameter
+    private String pluralClass;
+    @Parameter
+    private String nameClass;
+
+    public void execute() throws MojoExecutionException, MojoFailureException {
+
+        try {
+            new FluentGenerator(getLog(), destination, destinationClasspath, swaggerLocation, builderName,
+                    singularBuilderClass, pluralBuilderClass, topLevelBuilderClass, baseBuilderClass, singularClass,
+                    pluralClass, nameClass).run();
+        } catch (JsonProcessingException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        } catch (IOException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+
+    }
+}
diff --git a/graph-inventory/fluent-builder-maven-plugin/src/main/java/org/onap/graphinventory/generate/ObjectField.java b/graph-inventory/fluent-builder-maven-plugin/src/main/java/org/onap/graphinventory/generate/ObjectField.java
new file mode 100644 (file)
index 0000000..7c93804
--- /dev/null
@@ -0,0 +1,26 @@
+package org.onap.graphinventory.generate;
+
+public class ObjectField {
+
+
+    private String name;
+    private String type;
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+
+}
diff --git a/graph-inventory/fluent-builder-maven-plugin/src/main/java/org/onap/graphinventory/generate/ObjectType.java b/graph-inventory/fluent-builder-maven-plugin/src/main/java/org/onap/graphinventory/generate/ObjectType.java
new file mode 100644 (file)
index 0000000..3e7f7dc
--- /dev/null
@@ -0,0 +1,91 @@
+package org.onap.graphinventory.generate;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+public class ObjectType {
+
+    private List<String> paths = new ArrayList<>();
+
+    private Set<String> children = new HashSet<>();
+
+    private String name;
+
+    private String additionalName;
+
+    private String topLevel;
+
+    private String type;
+
+    private String partialUri;
+
+    private List<ObjectField> fields = new ArrayList<>();
+
+    public List<String> getPaths() {
+        return paths;
+    }
+
+    public void setPaths(List<String> paths) {
+        this.paths = paths;
+    }
+
+    public String getTopLevel() {
+        return topLevel;
+    }
+
+    public void setTopLevel(String topLevel) {
+        this.topLevel = topLevel;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public List<ObjectField> getFields() {
+        return fields;
+    }
+
+    public void setFields(List<ObjectField> fields) {
+        this.fields = fields;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public Set<String> getChildren() {
+        return children;
+    }
+
+    public void setChildren(Set<String> children) {
+        this.children = children;
+    }
+
+    public String getPartialUri() {
+        return partialUri;
+    }
+
+    public void setPartialUri(String partialUri) {
+        this.partialUri = partialUri;
+    }
+
+    public String getAdditionalName() {
+        return additionalName;
+    }
+
+    public void setAdditionalName(String additionalName) {
+        this.additionalName = additionalName;
+    }
+
+
+}
diff --git a/graph-inventory/fluent-builder-maven-plugin/src/main/java/org/onap/graphinventory/generate/SwaggerConverter.java b/graph-inventory/fluent-builder-maven-plugin/src/main/java/org/onap/graphinventory/generate/SwaggerConverter.java
new file mode 100644 (file)
index 0000000..b3ced65
--- /dev/null
@@ -0,0 +1,176 @@
+package org.onap.graphinventory.generate;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+import org.apache.maven.plugin.logging.Log;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import io.swagger.models.Path;
+import io.swagger.models.Swagger;
+import io.swagger.models.parameters.Parameter;
+import io.swagger.models.parameters.SerializableParameter;
+import io.swagger.parser.SwaggerParser;
+
+public class SwaggerConverter {
+
+    private final Log log;
+
+    public SwaggerConverter(Log log) {
+        this.log = log;
+    }
+
+    public Map<String, ObjectType> getDoc(String swaggerLocation) throws JsonProcessingException {
+        Swagger swagger = new SwaggerParser().read(swaggerLocation);
+
+        Map<String, Path> paths = swagger.getPaths().entrySet().stream()
+                .filter(item -> !item.getKey().endsWith("/relationship-list/relationship"))
+                .collect(Collectors.toMap(item -> item.getKey(), item -> item.getValue()));
+
+        Pattern pluralPattern = Pattern.compile(".*(?<partial>/(?<name>[^{]*$))");
+        Pattern singularPattern = Pattern.compile(".*(?<partial>/(?<name>[^/{}]*)/\\{.*$)");
+        Pattern topLevelPattern = Pattern.compile("^/([^/]+)/.*");
+        Pattern urlTemplatePattern = Pattern.compile("\\{([^}]+)\\}");
+        Matcher pluralMatcher;
+        Matcher singularMatcher;
+        Matcher topLevelMatcher;
+
+        Map<String, ObjectType> output = new HashMap<>();
+        for (Map.Entry<String, Path> entry : paths.entrySet()) {
+
+            pluralMatcher = pluralPattern.matcher(entry.getKey());
+            singularMatcher = singularPattern.matcher(entry.getKey());
+            topLevelMatcher = topLevelPattern.matcher(entry.getKey());
+            ObjectType item;
+            if (pluralMatcher.matches()) {
+                if (!output.containsKey(pluralMatcher.group("name"))) {
+                    output.put(pluralMatcher.group("name"), new ObjectType());
+                }
+                item = output.get(pluralMatcher.group("name"));
+                item.setType("plural");
+                item.setName(pluralMatcher.group("name"));
+                item.setPartialUri(pluralMatcher.group("partial"));
+                item.getPaths().add(entry.getKey());
+
+                if (topLevelMatcher.matches()) {
+                    item.setTopLevel(topLevelMatcher.group(1));
+                    if (!output.containsKey(topLevelMatcher.group(1))) {
+                        output.put(topLevelMatcher.group(1), new ObjectType());
+                        output.get(topLevelMatcher.group(1)).setType("top level");
+                        output.get(topLevelMatcher.group(1)).setName(topLevelMatcher.group(1));
+                        output.get(topLevelMatcher.group(1)).setPartialUri("/" + topLevelMatcher.group(1));
+                        output.get(topLevelMatcher.group(1)).getPaths().add("/" + topLevelMatcher.group(1));
+
+                    }
+                }
+            } else if (singularMatcher.matches()) {
+
+                if (!output.containsKey(singularMatcher.group("name"))) {
+                    output.put(singularMatcher.group("name"), new ObjectType());
+
+                    item = output.get(singularMatcher.group("name"));
+
+                    item.setType("singular");
+                    item.setName(singularMatcher.group("name"));
+                    item.setPartialUri(singularMatcher.group("partial"));
+
+                    item.getPaths().add(entry.getKey());
+
+                    if (topLevelMatcher.matches()) {
+                        item.setTopLevel(topLevelMatcher.group(1));
+                        if (!output.containsKey(topLevelMatcher.group(1))) {
+                            output.put(topLevelMatcher.group(1), new ObjectType());
+                            output.get(topLevelMatcher.group(1)).setType("top level");
+                            output.get(topLevelMatcher.group(1)).setName(topLevelMatcher.group(1));
+                            output.get(topLevelMatcher.group(1)).setPartialUri("/" + topLevelMatcher.group(1));
+                            output.get(topLevelMatcher.group(1)).getPaths().add("/" + topLevelMatcher.group(1));
+                        }
+                    }
+                    List<Parameter> parameters = entry.getValue().getGet().getParameters();
+
+                    if (parameters != null) {
+                        parameters.stream().filter(param -> "path".equals(param.getIn())).collect(Collectors.toList());
+                    }
+                    for (Parameter p : parameters) {
+                        ObjectField field = new ObjectField();
+
+                        field.setName(p.getName());
+                        field.setType(((SerializableParameter) p).getType());
+                        item.getFields().add(field);
+                    }
+
+                } else {
+                    item = output.get(singularMatcher.group("name"));
+                    if (singularMatcher.group("partial").contains(item.getName() + ".")) {
+                        item.setPartialUri(singularMatcher.group("partial"));
+                    }
+                    item.getPaths().add(entry.getKey());
+                }
+            }
+
+        }
+        ObjectMapper mapper = new ObjectMapper();
+
+        for (ObjectType item : output.values()) {
+            for (String path : item.getPaths()) {
+                String partialUriReplacer = item.getPartialUri().replaceAll("\\{[^}]+\\}", "[^/]+");
+                String childParentUri = path.replaceFirst(partialUriReplacer + "$", "");
+                for (ObjectType itemToUpdate : output.values()) {
+                    if (itemToUpdate.getPaths().stream()
+                            .anyMatch(itemToUpdateUri -> itemToUpdateUri.equals(childParentUri))) {
+                        itemToUpdate.getChildren().add(item.getName());
+                    }
+                }
+            }
+        }
+
+        log.debug(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(output));
+
+        for (Map.Entry<String, ObjectType> item : output.entrySet()) {
+
+            if (item.getValue().getType().equals("plural")) {
+                Set<String> children = item.getValue().getChildren();
+                // should only be one
+                if (!children.isEmpty()) {
+                    item.getValue().setAdditionalName(children.iterator().next());
+                }
+            }
+            Set<String> pluralChildren = new HashSet<>();
+            for (String child : item.getValue().getChildren()) {
+                if (output.get(child).getType().equals("plural")) {
+                    Set<String> children = output.get(child).getChildren();
+                    pluralChildren.addAll(children);
+                }
+            }
+            item.getValue().getChildren().addAll(pluralChildren);
+
+            if (item.getValue().getType().equals("plural")) {
+                for (String child : item.getValue().getChildren()) {
+                    output.get(child)
+                            .setPartialUri(item.getValue().getPartialUri() + output.get(child).getPartialUri());
+                }
+            }
+
+            if (!item.getValue().getFields().isEmpty()) {
+                Matcher templates = urlTemplatePattern.matcher(item.getValue().getPartialUri());
+                List<String> localFields = new ArrayList<>();
+                while (templates.find()) {
+                    localFields.add(templates.group(1));
+                }
+                item.getValue().setFields(item.getValue().getFields().stream()
+                        .filter(f -> localFields.contains(f.getName())).collect(Collectors.toList()));
+            }
+        }
+
+        output.values().stream().filter(item -> item.getType().equals("plural"))
+                .forEach(item -> item.getChildren().clear());
+
+        return output;
+    }
+}
index d01b0ec..0f465b0 100644 (file)
@@ -9,7 +9,7 @@
   <artifactId>graph-inventory</artifactId>
   <packaging>pom</packaging>
   <modules>
-    <!--  <module>fluent-builder-maven-plugin</module>-->
+    <module>fluent-builder-maven-plugin</module>
     <module>aai-client</module>
   </modules>
 </project>