b/161148892 create extension value class and extension factory

Change-Id: Ieffdf5dbb5ce547f424750598c410bdeda17bb7e
diff --git a/build.gradle b/build.gradle
index 76a7207..dc3dcd7 100644
--- a/build.gradle
+++ b/build.gradle
@@ -17,7 +17,7 @@
 ext.libVersions = [
     // Core Libraries
     "guava": "29.0-jre", // 22 June 2020
-    "guice": "4.2.3", // 22 June 2020
+    "guice": "4.2.3", // 22 June 2020,
 
     // Logging
     "flogger": "0.5.1", // 22 June 2020
@@ -85,11 +85,6 @@
         implementation "com.google.guava:guava:${libVersions.guava}"
         implementation "com.google.inject:guice:${libVersions.guice}"
         implementation "commons-validator:commons-validator:${libVersions.apacheCommonsValidator}"
-
-        //testCompile project(':oas-test')
-
-        //testImplementation "junit:junit:${libVersions.junit}"
-        //testImplementation "org.mockito:mockito-core:${libVersions.mockito}"
     }
 
     checkstyle {
diff --git a/oas-core/build.gradle b/oas-core/build.gradle
index 4556733..25acf9d 100644
--- a/oas-core/build.gradle
+++ b/oas-core/build.gradle
@@ -1,6 +1,7 @@
 dependencies {
     implementation "org.openapi4j:openapi-parser:${libVersions.openapiParser}"
     implementation "org.openapi4j:openapi-core:${libVersions.openapiCore}"
+    implementation "com.google.inject.extensions:guice-assistedinject:${libVersions.guice}"
 
     testImplementation project(":oas-test")
 }
\ No newline at end of file
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/BaseExtension.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/BaseExtension.java
new file mode 100644
index 0000000..0526ba4
--- /dev/null
+++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/BaseExtension.java
@@ -0,0 +1,46 @@
+package com.apigee.security.oas.extendedvalidator;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.google.common.collect.ImmutableSet;
+import com.google.errorprone.annotations.Var;
+import com.google.inject.assistedinject.Assisted;
+import javax.inject.Inject;
+import org.openapi4j.parser.model.OpenApiSchema;
+
+/** Stores extensions information and validates the extension. */
+final class BaseExtension implements Extension {
+  private final String extensionName;
+  private final JsonNode extensionContent;
+  private final ImmutableSet<Class<? extends OpenApiSchema>> extensionPath;
+
+  @Inject
+  BaseExtension(
+      @Var @Assisted String extensionName,
+      @Var @Assisted JsonNode extensionContent,
+      @Var @Assisted ImmutableSet<Class<? extends OpenApiSchema>> extensionPath) {
+    this.extensionName = extensionName;
+    this.extensionContent = extensionContent;
+    this.extensionPath = extensionPath;
+  }
+
+  @Override
+  public JsonNode getExtensionContent() {
+    return extensionContent;
+  }
+
+  @Override
+  public ImmutableSet<Class<? extends OpenApiSchema>> getExtensionPath() {
+    return extensionPath;
+  }
+
+  @Override
+  public String getExtensionName() {
+    return extensionName;
+  }
+
+  /** Validates the extension with given {@link ExtensionValidator}. */
+  @Override
+  public boolean validate(@Var ExtensionValidator extensionValidator) {
+    return extensionValidator.validate(this);
+  }
+}
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ExtendedValidatorMainModule.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ExtendedValidatorMainModule.java
new file mode 100644
index 0000000..2451529
--- /dev/null
+++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ExtendedValidatorMainModule.java
@@ -0,0 +1,14 @@
+package com.apigee.security.oas.extendedvalidator;
+
+import com.google.inject.AbstractModule;
+
+/**
+ * An {@link AbstractModule} that installs all required bindings for the ExtendedValidator module.
+ */
+public class ExtendedValidatorMainModule extends AbstractModule {
+  @Override
+  protected void configure() {
+    install(new ExtensionModule());
+    binder().requireExplicitBindings();
+  }
+}
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/Extension.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/Extension.java
new file mode 100644
index 0000000..3428e2d
--- /dev/null
+++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/Extension.java
@@ -0,0 +1,24 @@
+package com.apigee.security.oas.extendedvalidator;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.google.common.collect.ImmutableSet;
+import org.openapi4j.parser.model.OpenApiSchema;
+
+/** Stores details of and validates the extension. */
+public interface Extension {
+
+  /** Validates the {@code Extension} with {@link ExtensionValidator}. */
+  boolean validate(ExtensionValidator extensionValidator);
+
+  /** Returns the content of the Extension. */
+  JsonNode getExtensionContent();
+
+  /**
+   * Returns the path of {@link org.openapi4j.parser.model.OpenApiSchema} classes from the root
+   * node.
+   */
+  ImmutableSet<Class<? extends OpenApiSchema>> getExtensionPath();
+
+  /** Returns the name of the Extension. */
+  String getExtensionName();
+}
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ExtensionFactory.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ExtensionFactory.java
new file mode 100644
index 0000000..22d7b9b
--- /dev/null
+++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ExtensionFactory.java
@@ -0,0 +1,18 @@
+package com.apigee.security.oas.extendedvalidator;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.google.common.collect.ImmutableSet;
+import org.openapi4j.parser.model.OpenApiSchema;
+
+/** Factory to create an {@link Extension}. */
+public interface ExtensionFactory {
+
+  /**
+   * Generates an {@link Extension} class object with {@code extensionContent} and {@code
+   * extensionPath} of the extension from {@code extensionName}.
+   */
+  Extension create(
+      String extensionName,
+      JsonNode extensionContent,
+      ImmutableSet<Class<? extends OpenApiSchema>> extensionPath);
+}
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ExtensionModule.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ExtensionModule.java
new file mode 100644
index 0000000..c595190
--- /dev/null
+++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ExtensionModule.java
@@ -0,0 +1,18 @@
+package com.apigee.security.oas.extendedvalidator;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.assistedinject.FactoryModuleBuilder;
+
+/**
+ * Module with instructions for instantiating instances of {@link Extension} and building {@link
+ * ExtensionFactory}.
+ */
+public class ExtensionModule extends AbstractModule {
+  @Override
+  protected void configure() {
+    install(
+        new FactoryModuleBuilder()
+            .implement(Extension.class, BaseExtension.class)
+            .build(ExtensionFactory.class));
+  }
+}
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ExtensionName.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ExtensionName.java
new file mode 100644
index 0000000..cacee5a
--- /dev/null
+++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ExtensionName.java
@@ -0,0 +1,37 @@
+package com.apigee.security.oas.extendedvalidator;
+
+import com.google.common.base.Optional;
+import com.google.errorprone.annotations.Var;
+
+/** Stores all the supported {@code x-security-*} extensions as constants. */
+enum ExtensionName {
+  X_SECURITY_TYPE("x-security-type");
+
+  private final String extensionName;
+
+  ExtensionName(String extensionName) {
+    this.extensionName = extensionName;
+  }
+
+  String getExtensionName() {
+    return extensionName;
+  }
+
+  /**
+   * Returns an {@code Optional<ExtensionName>} from an extension name.
+   *
+   * <p>The method will return an empty {@code Optional} if the extensionName is not found, and an
+   * {@link ExtensionName} if extensionName is found.
+   *
+   * @param extensionName The name of the extension in OpenApi3 Specification.
+   */
+  static Optional<ExtensionName> valueOfExtensionName(String extensionName) {
+    @Var ExtensionName extensionEnum = null;
+    for (ExtensionName extension : values()) {
+      if (extension.extensionName.equals(extensionName)) {
+        extensionEnum = extension;
+      }
+    }
+    return Optional.fromNullable(extensionEnum);
+  }
+}
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ExtensionValidator.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ExtensionValidator.java
new file mode 100644
index 0000000..d944371
--- /dev/null
+++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ExtensionValidator.java
@@ -0,0 +1,8 @@
+package com.apigee.security.oas.extendedvalidator;
+
+/** Validates a {@link Extension} based on the type of {@code Extension}. */
+public interface ExtensionValidator {
+
+  /** Validates a {@link Extension}. */
+  boolean validate(Extension extension);
+}
diff --git a/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/BaseExtensionTest.java b/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/BaseExtensionTest.java
new file mode 100644
index 0000000..02d9b05
--- /dev/null
+++ b/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/BaseExtensionTest.java
@@ -0,0 +1,77 @@
+package com.apigee.security.oas.extendedvalidator;
+
+import static com.apigee.security.oas.extendedvalidator.ExtensionName.X_SECURITY_TYPE;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.collect.ImmutableSet;
+import com.google.inject.Guice;
+import java.util.Arrays;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.openapi4j.parser.model.OpenApiSchema;
+import org.openapi4j.parser.model.v3.Operation;
+import org.openapi4j.parser.model.v3.Path;
+
+@RunWith(JUnit4.class)
+public class BaseExtensionTest {
+
+  @Rule public final MockitoRule rule = MockitoJUnit.rule();
+  private static final ObjectMapper mapper = new ObjectMapper();
+  private static final ExtensionFactory factory =
+      Guice.createInjector(new ExtensionModule()).getInstance(ExtensionFactory.class);
+
+  private JsonNode node;
+  private Extension extension;
+  private ImmutableSet<Class<? extends OpenApiSchema>> extensionPath;
+  @Mock private ExtensionValidator extensionValidator;
+
+  /** Setting up an {@link Extension} using {@link ExtensionFactory}. */
+  @Before
+  public void setup() {
+    node = mapper.valueToTree("[]");
+    extensionPath = ImmutableSet.copyOf(Arrays.asList(Path.class, Operation.class));
+    extension = factory.create(X_SECURITY_TYPE.getExtensionName(), node, extensionPath);
+  }
+
+  @Test
+  public void create_returnsExtension() {
+    assertThat(extension).isInstanceOf(Extension.class);
+  }
+
+  @Test
+  public void validate_callsExtensionValidator() {
+    when(extensionValidator.validate(any(Extension.class))).thenReturn(true);
+
+    boolean isValid = extension.validate(extensionValidator);
+
+    assertThat(isValid).isTrue();
+    verify(extensionValidator, atLeastOnce()).validate(any(Extension.class));
+  }
+
+  @Test
+  public void getExtensionName_returnsString() {
+    assertThat(extension.getExtensionName()).isEqualTo(X_SECURITY_TYPE.getExtensionName());
+  }
+
+  @Test
+  public void getExtensionPath_returnsImmutableSetInstance() {
+    assertThat(extension.getExtensionPath()).isEqualTo(extensionPath);
+  }
+
+  @Test
+  public void getExtensionContent_returnsJsonNodeInstance() {
+    assertThat(extension.getExtensionContent()).isEqualTo(node);
+  }
+}
diff --git a/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/ExtendedValidatorMainModuleTest.java b/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/ExtendedValidatorMainModuleTest.java
new file mode 100644
index 0000000..7c020e9
--- /dev/null
+++ b/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/ExtendedValidatorMainModuleTest.java
@@ -0,0 +1,28 @@
+package com.apigee.security.oas.extendedvalidator;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.catchThrowable;
+
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class ExtendedValidatorMainModuleTest {
+  private Injector injector;
+
+  /** Sets up main module Guice {@link Injector}. */
+  @Before
+  public void setup() {
+    injector = Guice.createInjector(new ExtendedValidatorMainModule());
+  }
+
+  @Test
+  public void createExtensionFactory_shouldNotFail() {
+    assertThat(catchThrowable(() -> injector.getInstance(ExtensionFactory.class)))
+        .doesNotThrowAnyException();
+  }
+}
diff --git a/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/ExtensionFactoryTest.java b/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/ExtensionFactoryTest.java
new file mode 100644
index 0000000..0216741
--- /dev/null
+++ b/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/ExtensionFactoryTest.java
@@ -0,0 +1,49 @@
+package com.apigee.security.oas.extendedvalidator;
+
+import static com.apigee.security.oas.extendedvalidator.ExtensionName.X_SECURITY_TYPE;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.collect.ImmutableSet;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import java.util.Arrays;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.openapi4j.parser.model.OpenApiSchema;
+import org.openapi4j.parser.model.v3.Operation;
+import org.openapi4j.parser.model.v3.Path;
+
+@RunWith(JUnit4.class)
+public class ExtensionFactoryTest {
+
+  private JsonNode node;
+  private ImmutableSet<Class<? extends OpenApiSchema>> extensionPath;
+  private ExtensionFactory factory;
+
+  /** Setting up parameters and {@link ExtensionFactory} instance.. */
+  @Before
+  public void setup() {
+    node = new ObjectMapper().valueToTree("[]");
+    extensionPath = ImmutableSet.copyOf(Arrays.asList(Path.class, Operation.class));
+    Injector injector = Guice.createInjector(new ExtensionModule());
+    factory = injector.getInstance(ExtensionFactory.class);
+  }
+
+  @Test
+  public void generateExtension_xSecurityExtensionName_returnsExtension() {
+    Extension extension = factory.create(X_SECURITY_TYPE.getExtensionName(), node, extensionPath);
+
+    assertThat(extension).isInstanceOf(Extension.class);
+  }
+
+  @Test
+  public void generateExtension_unsupportedExtensionName_returnsExtension() {
+    Extension extension = factory.create("x-unsupported", node, extensionPath);
+
+    assertThat(extension).isInstanceOf(Extension.class);
+  }
+}
diff --git a/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/ExtensionNameTest.java b/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/ExtensionNameTest.java
new file mode 100644
index 0000000..4024b9d
--- /dev/null
+++ b/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/ExtensionNameTest.java
@@ -0,0 +1,32 @@
+package com.apigee.security.oas.extendedvalidator;
+
+import static com.apigee.security.oas.extendedvalidator.ExtensionName.X_SECURITY_TYPE;
+import static com.apigee.security.oas.extendedvalidator.ExtensionName.valueOfExtensionName;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import com.google.common.base.Optional;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class ExtensionNameTest {
+
+  @Test
+  public void valueOfExtensionName_supportedExtension_returnsExtensionNameOptional() {
+    Optional<ExtensionName> extensionNameOptional =
+        valueOfExtensionName(X_SECURITY_TYPE.getExtensionName());
+
+    assertThat(extensionNameOptional.isPresent()).isTrue();
+    assertThat(extensionNameOptional.get())
+        .isInstanceOf(ExtensionName.class)
+        .isEqualTo(X_SECURITY_TYPE);
+  }
+
+  @Test
+  public void valueOfExtensionName_unsupportedExtension_returnsEmptyOptional() {
+    Optional<ExtensionName> extensionNameOptional = valueOfExtensionName("x-unsupported");
+
+    assertThat(extensionNameOptional.isPresent()).isFalse();
+  }
+}