diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index f03a7d4989795cac0acbcbbb43dd28911d1e05bd..1455572f7535e72b310b8bbe478e69954498a26a 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -14,13 +14,15 @@ variables:
   GCP_DOMAIN: cloud.slb-ds.com
   GCP_STORAGE_URL: https://osdu-indexer-dot-opendes.appspot.com/api/storage/v2/
 
-  OSDU_GCP_BUILD_SUBDIR: provider/indexer-gcp
-  OSDU_GCP_INT_TEST_SUBDIR: testing/indexer-test-gcp
   OSDU_GCP_APPLICATION_NAME: os-indexer
-  OSDU_GCP_PROJECT: nice-etching-277309
-  OSDU_GCP_TENANT_NAME: osdu
-  OSDU_GCP_STORAGE_SCHEMA_HOST: https://os-storage-dot-nice-etching-277309.uc.r.appspot.com/api/storage/v2/schemas
+  OSDU_GCP_SERVICE: indexer
+  OSDU_GCP_VENDOR: gcp
+  OSDU_GCP_QUEUE_SA_EMAIL: pub-sub-indexer-queue@nice-etching-277309.iam.gserviceaccount.com
+  OSDU_GCP_SERVICE_ACCOUNT: osdu-gcp-sa@nice-etching-277309.iam.gserviceaccount.com
   OSDU_SECURITY_HTTPS_CERTIFICATE_TRUST: 'true'
+  OSDU_GCP_STORAGE_RECORDS_BATCH_SIZE: 20
+  OSDU_GCP_DATA_GROUP: osdu
+  OSDU_GCP_ENV_VARS: AUTHORIZE_API=$OSDU_GCP_ENTITLEMENTS_URL,GOOGLE_CLOUD_PROJECT=$OSDU_GCP_PROJECT,REDIS_SEARCH_HOST=$REDIS_SEARCH_HOST,REDIS_GROUP_HOST=$REDIS_GROUP_HOST,SECURITY_HTTPS_CERTIFICATE_TRUST=$OSDU_SECURITY_HTTPS_CERTIFICATE_TRUST,INDEXER_HOST=$OSDU_GCP_INDEXER_HOST,STORAGE_QUERY_RECORD_HOST=$OSDU_GCP_STORAGE_QUERY_RECORD_HOST,STORAGE_SCHEMA_HOST=$OSDU_GCP_STORAGE_SCHEMA_HOST,STORAGE_QUERY_RECORD_FOR_CONVERSION_HOST=$OSDU_GCP_STORAGE_QUERY_RECORD_FOR_CONVERSION_HOST,STORAGE_HOSTNAME=$OSDU_GCP_STORAGE_HOSTNAME,STORAGE_RECORDS_BATCH_SIZE=$OSDU_GCP_STORAGE_RECORDS_BATCH_SIZE,INDEXER_QUEUE_HOST=$OSDU_GCP_INDEXER_QUEUE_HOST,LEGALTAG_API=$OSDU_GCP_LEGALTAG_API,CRS_API=$OSDU_GCP_CRS_API,DATA_GROUP=$OSDU_GCP_DATA_GROUP,GOOGLE_AUDIENCES=$GOOGLE_AUDIENCE,INDEXER_QUE_SERVICE_MAIL=$OSDU_GCP_QUEUE_SA_EMAIL --vpc-connector=$OSDU_GCP_VPC_CONNECTOR
 
   IBM_BUILD_SUBDIR: provider/indexer-ibm
   IBM_INT_TEST_SUBDIR: testing/indexer-test-ibm
@@ -37,7 +39,7 @@ include:
     file: "build/maven.yml"
 
   - project: "osdu/platform/ci-cd-pipelines"
-    file: "scanners/fossa.yml"
+    file: "scanners/fossa-maven.yml"
 
   - project: "osdu/platform/ci-cd-pipelines"
     file: "scanners/gitlab-ultimate.yml"
@@ -56,7 +58,7 @@ include:
 
   - project: 'osdu/platform/ci-cd-pipelines'
     ref: "master"
-    file: 'cloud-providers/osdu-gcp.yml'
+    file: 'cloud-providers/osdu-gcp-cloudrun.yml'
 
 
 aws-test-java:
diff --git a/NOTICE b/NOTICE
index 3483ecfed18e16e6594381f48db4aac3fb0f202b..84fce0ab8b27440e2ed9829ca5363c68df979117 100644
--- a/NOTICE
+++ b/NOTICE
@@ -11,6 +11,7 @@ The following software have components provided under the terms of this license:
 - Cobertura code coverage (from http://cobertura.sourceforge.net)
 - Plexus :: Default Container (from )
 - Plexus Common Utilities (from http://plexus.codehaus.org/plexus-utils)
+- StAX (from http://stax.codehaus.org/)
 - oro (from )
 
 ========================================================================
@@ -27,6 +28,20 @@ The following software have components provided under the terms of this license:
 - ASM Tree (from )
 - ASM Util (from )
 - ASM based accessors helper used by json-smart (from )
+- AWS Event Stream (from https://github.com/awslabs/aws-eventstream-java)
+- AWS Java SDK :: AWS Core (from https://aws.amazon.com/sdkforjava)
+- AWS Java SDK :: Annotations (from )
+- AWS Java SDK :: Auth (from https://aws.amazon.com/sdkforjava)
+- AWS Java SDK :: Core :: Protocols :: AWS Json Protocol (from https://aws.amazon.com/sdkforjava)
+- AWS Java SDK :: Core :: Protocols :: Protocol Core (from https://aws.amazon.com/sdkforjava)
+- AWS Java SDK :: HTTP Client Interface (from )
+- AWS Java SDK :: HTTP Clients :: Apache (from )
+- AWS Java SDK :: HTTP Clients :: Netty Non-Blocking I/O (from )
+- AWS Java SDK :: Profiles (from https://aws.amazon.com/sdkforjava)
+- AWS Java SDK :: Regions (from )
+- AWS Java SDK :: SDK Core (from https://aws.amazon.com/sdkforjava)
+- AWS Java SDK :: Services :: AWS Simple Systems Management (SSM) (from https://aws.amazon.com/sdkforjava)
+- AWS Java SDK :: Utilities (from )
 - AWS Java SDK for AWS AppSync (from https://aws.amazon.com/sdkforjava)
 - AWS Java SDK for AWS Application Auto Scaling (from https://aws.amazon.com/sdkforjava)
 - AWS Java SDK for AWS Application Discovery Service (from https://aws.amazon.com/sdkforjava)
@@ -165,11 +180,8 @@ The following software have components provided under the terms of this license:
 - Apache Commons BeanUtils (from http://commons.apache.org/proper/commons-beanutils/)
 - Apache Commons CLI (from http://commons.apache.org/proper/commons-cli/)
 - Apache Commons Codec (from http://commons.apache.org/proper/commons-codec/)
-- Apache Commons Collections (from http://commons.apache.org/proper/commons-collections/)
 - Apache Commons Lang (from http://commons.apache.org/proper/commons-lang/)
 - Apache Commons Logging (from http://commons.apache.org/proper/commons-logging/)
-- Apache Commons Text (from http://commons.apache.org/proper/commons-text/)
-- Apache Commons Validator (from http://commons.apache.org/proper/commons-validator/)
 - Apache Commons Validator (from http://commons.apache.org/proper/commons-validator/)
 - Apache Geronimo JMS Spec 2.0 (from http://geronimo.apache.org/maven/${siteId}/${version})
 - Apache HttpAsyncClient (from http://hc.apache.org/httpcomponents-asyncclient)
@@ -196,6 +208,8 @@ The following software have components provided under the terms of this license:
 - Asynchronous Http Client (from )
 - Asynchronous Http Client Netty Utils (from )
 - AutoValue (from )
+- Azure AD Spring Security Integration Spring Boot Starter (from https://github.com/Microsoft/azure-spring-boot)
+- Azure Metrics Spring Boot Starter (from https://github.com/Microsoft/azure-spring-boot)
 - Bean Validation API (from http://beanvalidation.org)
 - Byte Buddy (without dependencies) (from )
 - Byte Buddy Java agent (from )
@@ -204,8 +218,6 @@ The following software have components provided under the terms of this license:
 - CloudWatch Metrics for AWS Java SDK (from https://aws.amazon.com/sdkforjava)
 - Cobertura code coverage (from http://cobertura.sourceforge.net)
 - Commons Digester (from http://commons.apache.org/digester/)
-- Commons Digester (from http://commons.apache.org/digester/)
-- Commons IO (from http://commons.apache.org/io/)
 - Commons IO (from http://commons.apache.org/io/)
 - Commons Lang (from http://commons.apache.org/lang/)
 - Converter: Jackson (from )
@@ -248,6 +260,7 @@ The following software have components provided under the terms of this license:
 - IBM COS SDK For Java (from https://github.com/ibm/ibm-cos-sdk-java)
 - IBM COS SDK for Java - Core (from https://github.com/ibm/ibm-cos-sdk-java)
 - Identity and Access Management (IAM) API v1-rev247-1.23.0 (from )
+- IntelliJ IDEA Annotations (from http://www.jetbrains.org)
 - J2ObjC Annotations (from https://github.com/google/j2objc/)
 - J2ObjC Annotations (from https://github.com/google/j2objc/)
 - JBoss Logging 3 (from http://www.jboss.org)
@@ -263,29 +276,43 @@ The following software have components provided under the terms of this license:
 - Jackson (from http://jackson.codehaus.org)
 - Jackson 2 extensions to the Google HTTP Client Library for Java. (from https://github.com/google/google-http-java-client.git/google-http-client-jackson2)
 - Jackson dataformat: CBOR (from http://github.com/FasterXML/jackson-dataformats-binary)
+- Jackson dataformat: CBOR (from http://github.com/FasterXML/jackson-dataformats-binary)
+- Jackson datatype: JSR310 (from http://wiki.fasterxml.com/JacksonModuleJSR310)
 - Jackson datatype: JSR310 (from http://wiki.fasterxml.com/JacksonModuleJSR310)
 - Jackson extensions to the Google HTTP Client Library for Java. (from )
 - Jackson-annotations (from http://github.com/FasterXML/jackson)
+- Jackson-annotations (from http://github.com/FasterXML/jackson)
 - Jackson-core (from https://github.com/FasterXML/jackson-core)
 - Jackson-dataformat-Smile (from http://github.com/FasterXML/jackson-dataformat-smile)
+- Jackson-dataformat-Smile (from http://github.com/FasterXML/jackson-dataformat-smile)
 - Jackson-dataformat-XML (from http://wiki.fasterxml.com/JacksonExtensionXmlDataBinding)
 - Jackson-dataformat-YAML (from https://github.com/FasterXML/jackson)
+- Jackson-dataformat-YAML (from https://github.com/FasterXML/jackson)
 - Jackson-datatype-Joda (from http://wiki.fasterxml.com/JacksonModuleJoda)
 - Jackson-datatype-jdk8 (from )
+- Jackson-datatype-jdk8 (from )
+- Jackson-module-Afterburner (from http://wiki.fasterxml.com/JacksonHome)
 - Jackson-module-JAXB-annotations (from http://wiki.fasterxml.com/JacksonJAXBAnnotations)
+- Jackson-module-JAXB-annotations (from http://wiki.fasterxml.com/JacksonJAXBAnnotations)
+- Jackson-module-parameter-names (from )
 - Jackson-module-parameter-names (from )
 - Jakarta Bean Validation API (from https://beanvalidation.org)
 - Java Libraries for Amazon Simple WorkFlow (from https://aws.amazon.com/sdkforjava)
 - Java Native Access (from https://github.com/java-native-access/jna)
 - Java Native Access Platform (from https://github.com/java-native-access/jna)
 - Java Servlet API (from http://servlet-spec.java.net)
-- Java UUID Generator (from http://wiki.fasterxml.com/JugHome)
 - Javassist (from http://www.javassist.org/)
 - Javassist (from http://www.javassist.org/)
 - Jetty Server (from )
 - Jetty Utilities (from )
 - Joda-Time (from http://www.joda.org/joda-time/)
 - Json Path (from https://github.com/jayway/JsonPath)
+- KeePassJava2 :: All (from https://repo1.maven.org/maven2/org/linguafranca/pwdb/KeePassJava2)
+- KeePassJava2 :: DOM (from https://repo1.maven.org/maven2/org/linguafranca/pwdb/KeePassJava2-dom)
+- KeePassJava2 :: JAXB (from https://repo1.maven.org/maven2/org/linguafranca/pwdb/KeePassJava2-jaxb)
+- KeePassJava2 :: KDB (from https://repo1.maven.org/maven2/org/linguafranca/pwdb/KeePassJava2-kdb)
+- KeePassJava2 :: KDBX (from https://repo1.maven.org/maven2/org/linguafranca/pwdb/KeePassJava2-kdbx)
+- KeePassJava2 :: Simple (from https://repo1.maven.org/maven2/org/linguafranca/pwdb/KeePassJava2-simple)
 - Lucene Common Analyzers (from )
 - Lucene Common Analyzers (from )
 - Lucene Core (from )
@@ -338,15 +365,16 @@ The following software have components provided under the terms of this license:
 - Microsoft Application Insights Java SDK Web Module (from https://github.com/Microsoft/ApplicationInsights-Java)
 - Microsoft Application Insights Log4j 2 Appender (from https://github.com/Microsoft/ApplicationInsights-Java)
 - Microsoft Azure Netty HTTP Client Library (from https://github.com/Azure/azure-sdk-for-java)
+- Microsoft Azure SDK for SQL API of Azure Cosmos DB Service (from https://github.com/Azure/azure-sdk-for-java)
 - Mockito (from http://mockito.org)
 - Mockito (from http://www.mockito.org)
 - Mockito (from http://mockito.org)
 - Mockito (from http://mockito.org)
 - Mojo's Maven plugin for Cobertura (from http://mojo.codehaus.org/cobertura-maven-plugin/)
+- Netty Reactive Streams HTTP support (from )
 - Netty Reactive Streams Implementation (from )
 - Netty/Buffer (from http://netty.io/)
 - Netty/Codec (from )
-- Netty/Codec/DNS (from )
 - Netty/Codec/HTTP (from )
 - Netty/Codec/HTTP2 (from )
 - Netty/Codec/Socks (from )
@@ -354,7 +382,6 @@ The following software have components provided under the terms of this license:
 - Netty/Handler (from )
 - Netty/Handler/Proxy (from )
 - Netty/Resolver (from )
-- Netty/Resolver/DNS (from )
 - Netty/TomcatNative [BoringSSL - Static] (from )
 - Netty/Transport (from http://netty.io/)
 - Netty/Transport/Native/Unix/Common (from )
@@ -376,6 +403,7 @@ The following software have components provided under the terms of this license:
 - OpenCensus (from https://github.com/census-instrumentation/opencensus-java)
 - OpenCensus (from https://github.com/census-instrumentation/opencensus-java)
 - OpenCensus (from https://github.com/census-instrumentation/opencensus-java)
+- PWDB :: Database (from https://repo1.maven.org/maven2/org/linguafranca/pwdb/database)
 - Plexus :: Default Container (from )
 - Plexus Common Utilities (from http://plexus.codehaus.org/plexus-utils)
 - Plexus Default Interactivity Handler (from )
@@ -387,6 +415,7 @@ The following software have components provided under the terms of this license:
 - Reactive Streams Netty driver (from https://github.com/reactor/reactor-netty)
 - Retrofit (from )
 - Servlet Specification 2.5 API (from )
+- Simple XML (from http://simple.sourceforge.net)
 - SnakeYAML (from http://www.snakeyaml.org)
 - Spatial4J (from http://www.locationtech.org/projects/locationtech.spatial4j)
 - Spring AOP (from https://github.com/spring-projects/spring-framework)
@@ -426,11 +455,15 @@ The following software have components provided under the terms of this license:
 - Spring Transaction (from https://github.com/spring-projects/spring-framework)
 - Spring Web (from https://github.com/spring-projects/spring-framework)
 - Spring Web MVC (from https://github.com/spring-projects/spring-framework)
+- StAX (from http://stax.codehaus.org/)
+- StAX API (from http://stax.codehaus.org/)
 - T-Digest (from https://github.com/tdunning/t-digest)
 - Woodstox (from https://github.com/FasterXML/woodstox)
 - Xerces2-j (from https://xerces.apache.org/xerces2-j/)
+- aalto-xml (from )
 - aggs-matrix-stats (from https://github.com/elastic/elasticsearch)
 - aggs-matrix-stats (from https://github.com/elastic/elasticsearch)
+- aws-ssm-java-caching-client (from https://github.com/awslabs/aws-ssm-java-caching-client)
 - cli (from https://github.com/elastic/elasticsearch)
 - cli (from https://github.com/elastic/elasticsearch)
 - com.google.api.grpc:grpc-google-cloud-pubsub-v1 (from https://github.com/googleapis/googleapis)
@@ -460,6 +493,7 @@ The following software have components provided under the terms of this license:
 - jackson-databind (from http://github.com/FasterXML/jackson)
 - java-cloudant (from https://cloudant.com)
 - java-cloudant (from https://cloudant.com)
+- javatuples (from http://www.javatuples.org)
 - javax.inject (from http://code.google.com/p/atinject/)
 - javax.ws.rs-api (from http://jax-rs-spec.java.net)
 - jersey-container-servlet (from git://java.net/jersey~code/project/jersey-container-servlet)
@@ -490,7 +524,6 @@ The following software have components provided under the terms of this license:
 - powermock-reflect (from )
 - proto-google-cloud-datastore-v1 (from https://github.com/googleapis/api-client-staging)
 - proton-j (from )
-- proton-j (from )
 - rank-eval (from https://github.com/elastic/elasticsearch)
 - rank-eval (from https://github.com/elastic/elasticsearch)
 - rest (from https://github.com/elastic/elasticsearch)
@@ -498,7 +531,6 @@ The following software have components provided under the terms of this license:
 - rest-high-level (from https://github.com/elastic/elasticsearch)
 - rest-high-level (from https://github.com/elastic/elasticsearch)
 - rxjava (from https://github.com/ReactiveX/RxJava)
-- rxjava (from https://github.com/ReactiveX/RxJava)
 - secure-sm (from https://github.com/elastic/elasticsearch)
 - secure-sm (from https://github.com/elastic/elasticsearch)
 - spring-security-config (from http://spring.io/spring-security)
@@ -541,10 +573,10 @@ The following software have components provided under the terms of this license:
 - Lucene Common Analyzers (from )
 - Plexus :: Default Container (from )
 - Plexus Common Utilities (from http://plexus.codehaus.org/plexus-utils)
+- StAX (from http://stax.codehaus.org/)
 - Stax2 API (from http://github.com/FasterXML/stax2-api)
 - jersey-ext-bean-validation (from )
 - jersey-spring4 (from )
-- oro (from )
 
 ========================================================================
 BSD-3-Clause
@@ -608,12 +640,6 @@ CC-BY-2.5
 The following software have components provided under the terms of this license:
 
 - Checker Qual (from https://checkerframework.org)
-
-========================================================================
-CC-BY-3.0
-========================================================================
-The following software have components provided under the terms of this license:
-
 - FindBugs-jsr305 (from http://findbugs.sourceforge.net/)
 
 ========================================================================
@@ -648,7 +674,6 @@ The following software have components provided under the terms of this license:
 - HK2 core module (from )
 - HK2 module of HK2 itself (from )
 - JavaBeans Activation Framework API jar (from )
-- JavaBeans(TM) Activation Framework (from http://java.sun.com/javase/technologies/desktop/javabeans/jaf/index.jsp)
 - Run Level Service (from )
 - ServiceLocator Default Implementation (from git://java.net/hk2~git/hk2-locator)
 - Servlet Specification 2.5 API (from )
@@ -673,6 +698,7 @@ The following software have components provided under the terms of this license:
 - Java Architecture For XML Binding (from )
 - Java Servlet API (from http://servlet-spec.java.net)
 - JavaBeans Activation Framework (from )
+- JavaBeans(TM) Activation Framework (from http://java.sun.com/javase/technologies/desktop/javabeans/jaf/index.jsp)
 - JavaMail API (from )
 - OSGi resource locator (from )
 - jersey-ext-bean-validation (from )
@@ -684,6 +710,7 @@ CPL-1.0
 ========================================================================
 The following software have components provided under the terms of this license:
 
+- JUnit (from http://junit.org)
 - System Rules (from http://stefanbirkner.github.io/system-rules/)
 
 ========================================================================
@@ -691,7 +718,6 @@ EPL-1.0
 ========================================================================
 The following software have components provided under the terms of this license:
 
-- JUnit (from http://junit.org)
 - Logback Classic Module (from )
 - Logback Core Module (from )
 - Microsoft Application Insights Java SDK Core (from https://github.com/Microsoft/ApplicationInsights-Java)
@@ -817,7 +843,6 @@ LGPL-2.1-or-later
 ========================================================================
 The following software have components provided under the terms of this license:
 
-- Java Native Access (from https://github.com/java-native-access/jna)
 - Java Native Access Platform (from https://github.com/java-native-access/jna)
 - Javassist (from http://www.javassist.org/)
 - SnakeYAML (from http://www.snakeyaml.org)
@@ -842,7 +867,6 @@ The following software have components provided under the terms of this license:
 - Azure Java Client Runtime for AutoRest (from https://github.com/Azure/autorest-clientruntime-for-java)
 - Azure Metrics Spring Boot Starter (from https://github.com/Microsoft/azure-spring-boot)
 - Azure Spring Boot AutoConfigure (from https://github.com/Microsoft/azure-spring-boot)
-- Azure Spring Boot Starter (from https://github.com/Microsoft/azure-spring-boot)
 - Bouncy Castle Provider (from http://www.bouncycastle.org/java.html)
 - Bouncy Castle Provider (from http://www.bouncycastle.org/java.html)
 - Checker Qual (from https://checkerframework.org)
@@ -870,9 +894,10 @@ The following software have components provided under the terms of this license:
 - Microsoft Azure client library for Identity (from https://github.com/Azure/azure-sdk-for-java)
 - Microsoft Azure client library for KeyVault Secrets (from https://github.com/Azure/azure-sdk-for-java)
 - Microsoft Azure common module for Storage (from https://github.com/Azure/azure-sdk-for-java)
-- Mockito (from http://www.mockito.org)
+- Microsoft Azure internal Avro module for Storage (from https://github.com/Azure/azure-sdk-for-java)
 - Mockito (from http://mockito.org)
 - Mockito (from http://mockito.org)
+- Mockito (from http://www.mockito.org)
 - Mockito (from http://mockito.org)
 - Netty/Codec/HTTP (from )
 - Netty/Common (from )
@@ -881,9 +906,12 @@ The following software have components provided under the terms of this license:
 - Project Lombok (from https://projectlombok.org)
 - Project Lombok (from https://projectlombok.org)
 - SLF4J API Module (from http://www.slf4j.org)
+- Spongy Castle (from http://rtyley.github.io/spongycastle/)
+- Spring Data for Azure Cosmos DB SQL API (from https://github.com/Azure/azure-sdk-for-java/tree/master/sdk/cosmos/azure-spring-data-cosmos)
 - adal4j (from https://github.com/AzureAD/azure-activedirectory-library-for-java)
 - micrometer-core (from https://github.com/micrometer-metrics/micrometer)
 - msal4j (from https://github.com/AzureAD/microsoft-authentication-library-for-java)
+- msal4j-persistence-extension (from https://github.com/AzureAD/microsoft-authentication-extensions-for-java)
 - spring-security-core (from http://spring.io/spring-security)
 
 ========================================================================
@@ -920,10 +948,10 @@ The following software have components provided under the terms of this license:
 - JTidy (from http://jtidy.sourceforge.net)
 - LatencyUtils (from http://latencyutils.github.io/LatencyUtils/)
 - Plexus Common Utilities (from http://plexus.codehaus.org/plexus-utils)
+- Spongy Castle (from http://rtyley.github.io/spongycastle/)
 - jersey-core-common (from )
 - jersey-core-server (from git://java.net/jersey~code/jersey-server)
 - jts-core (from )
-- xml-apis (from )
 
 ========================================================================
 SISSL-1.2
@@ -962,6 +990,7 @@ public-domain
 ========================================================================
 The following software have components provided under the terms of this license:
 
+- AWS Java SDK :: SDK Core (from https://aws.amazon.com/sdkforjava)
 - AWS SDK for Java - Models (from https://aws.amazon.com/sdkforjava)
 - Asynchronous Http Client (from )
 - Bouncy Castle PKIX, CMS, EAC, TSP, PKCS, OCSP, CMP, and CRMF APIs (from http://www.bouncycastle.org/java.html)
@@ -981,7 +1010,10 @@ The following software have components provided under the terms of this license:
 - Spring Security JWT Library (from http://github.com/spring-projects/spring-security-oauth)
 - Spring Security JWT Library (from http://github.com/spring-projects/spring-security-oauth)
 - Spring Web (from https://github.com/spring-projects/spring-framework)
+- StAX API (from http://stax.codehaus.org/)
+- msal4j (from https://github.com/AzureAD/microsoft-authentication-library-for-java)
 - reactive-streams (from http://www.reactive-streams.org/)
+- xml-apis (from )
 
 ========================================================================
 unknown
@@ -993,8 +1025,10 @@ The following software have components provided under the terms of this license:
 - Bouncy Castle Provider (from http://www.bouncycastle.org/java.html)
 - Bouncy Castle Provider (from http://www.bouncycastle.org/java.html)
 - Byte Buddy (without dependencies) (from )
+- JUnit (from http://junit.org)
 - JavaBeans Activation Framework API jar (from )
 - Servlet Specification 2.5 API (from )
+- Spongy Castle (from http://rtyley.github.io/spongycastle/)
 - System Rules (from http://stefanbirkner.github.io/system-rules/)
 - jakarta.xml.bind-api (from )
 - jaxen (from http://jaxen.codehaus.org/)
diff --git a/README.md b/README.md
index 5e081a10b1a16179aad7aadafe2b55fa0e5314c9..724f7df4cd11d492bcdffbc8005551e83c4a1218 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,7 @@
 # Introduction 
 
+os-indexer-azure is a [Spring Boot](https://spring.io/projects/spring-boot) service that is responsible for indexing Records that enable the `os-search` service to execute OSDU R2 domain searches against Elasticsearch.
+
 ## Azure Implementation
 
 The [os-indexer-azure README.md](./provider/indexer-azure/README.md) has all the information needed to get started
@@ -9,3 +11,4 @@ running the `os-indexer` Azure implementation
 
 All documentation for the GCP implementation of `os-indexer` lives [here](./provider/indexer-gcp/README.md)
 
+
diff --git a/devops/azure/chart/templates/deployment.yaml b/devops/azure/chart/templates/deployment.yaml
index 788491ed0c315deef32d9d4faa6b860567e155ba..8a7b075e355448152cb8b55795f58460a2a4c899 100644
--- a/devops/azure/chart/templates/deployment.yaml
+++ b/devops/azure/chart/templates/deployment.yaml
@@ -68,21 +68,6 @@ spec:
             configMapKeyRef:
               name: osdu-svc-properties
               key: ENV_KEYVAULT
-        - name: AZURE_CLIENT_ID
-          valueFrom:
-            secretKeyRef:
-              name: active-directory
-              key: principal-clientid
-        - name: AZURE_CLIENT_SECRET
-          valueFrom:
-            secretKeyRef:
-              name: active-directory
-              key: principal-clientpassword
-        - name: AZURE_TENANT_ID
-          valueFrom:
-            secretKeyRef:
-              name: active-directory
-              key: tenantid
         - name: aad_client_id
           valueFrom:
             secretKeyRef:
@@ -106,6 +91,8 @@ spec:
           value: http://entitlements-azure/entitlements/v1
         - name: entitlements_service_api_key
           value: "OBSOLETE"
+        - name: schema_service_url
+          value: http://schema-service/api/schema-service/v1
         - name: storage_service_url
           value: http://storage/api/storage/v2
         - name: STORAGE_SCHEMA_HOST
diff --git a/devops/azure/development-pipeline.yml b/devops/azure/development-pipeline.yml
index 3b09fa1b05e9ecfc936c525e58cbbc76e872c023..adbc5ad1f823ba858c2ff2e8e80fa73bd81c2cd7 100644
--- a/devops/azure/development-pipeline.yml
+++ b/devops/azure/development-pipeline.yml
@@ -50,14 +50,16 @@ variables:
     value: $[ resources.repositories['FluxRepo'].name ]
   - name: SKIP_TESTS
     value: 'false'
+  - name: 'MAVEN_CACHE_FOLDER'
+    value: $(Pipeline.Workspace)/.m2/repository
 
 stages:
   - template: /devops/build-stage.yml@TemplateRepo
     parameters:
       mavenGoal: 'package'
       mavenPublishJUnitResults: true
-      serviceCoreMavenOptions: '-P indexer-core'
-      mavenOptions: '-P indexer-azure'
+      serviceCoreMavenOptions: '-P indexer-core --settings .mvn/community-maven.settings.xml -Dmaven.repo.local=$(MAVEN_CACHE_FOLDER)'
+      mavenOptions: '-P indexer-azure --settings .mvn/community-maven.settings.xml -Dmaven.repo.local=$(MAVEN_CACHE_FOLDER)'
       copyFileContents: |
         pom.xml
         provider/indexer-azure/maven/settings.xml
diff --git a/devops/azure/pipeline.yml b/devops/azure/pipeline.yml
index dbfc9fae6f271fbd28235be8a7696752796f25ad..1ccfb6beea0048b15c65afe5629f84b5ca143bb6 100644
--- a/devops/azure/pipeline.yml
+++ b/devops/azure/pipeline.yml
@@ -50,14 +50,16 @@ variables:
     value: $[ resources.repositories['FluxRepo'].name ]
   - name: SKIP_TESTS
     value: 'false'
+  - name: 'MAVEN_CACHE_FOLDER'
+    value: $(Pipeline.Workspace)/.m2/repository
 
 stages:
   - template: /devops/build-stage.yml@TemplateRepo
     parameters:
       mavenGoal: 'package'
       mavenPublishJUnitResults: true
-      serviceCoreMavenOptions: '-P indexer-core'
-      mavenOptions: '-P indexer-azure'
+      serviceCoreMavenOptions: '-P indexer-core --settings .mvn/community-maven.settings.xml -Dmaven.repo.local=$(MAVEN_CACHE_FOLDER)'
+      mavenOptions: '-P indexer-azure --settings .mvn/community-maven.settings.xml -Dmaven.repo.local=$(MAVEN_CACHE_FOLDER)'
       copyFileContents: |
         pom.xml
         provider/indexer-azure/maven/settings.xml
diff --git a/devops/azure/release.yaml b/devops/azure/release.yaml
index 540d39689a9503daf6db8fa8529570eeca3deb5e..dca21e377c5a3c6d13d9dc59ff9e2f661851d2c2 100644
--- a/devops/azure/release.yaml
+++ b/devops/azure/release.yaml
@@ -152,6 +152,8 @@ spec:
           value: http://entitlements-azure/entitlements/v1
         - name: entitlements_service_api_key
           value: "OBSOLETE"
+        - name: schema_service_url
+          value: http://schema-service/api/schema-service/v1
         - name: storage_service_url
           value: http://storage/api/storage/v2
         - name: STORAGE_SCHEMA_HOST
diff --git a/docs/tutorial/IndexerService.md b/docs/tutorial/IndexerService.md
index ca1a75afd20979700121b86086387f2e1a155c08..d11f167561fe101c5aa81affb1d7a0eae0b2496a 100644
--- a/docs/tutorial/IndexerService.md
+++ b/docs/tutorial/IndexerService.md
@@ -7,6 +7,7 @@
 - [Reindex <a name="reindex"></a>](#reindex)
 - [Copy Index <a name="copy-index"></a>](#copy-index)
 - [Get task status <a name="get-task-status"></a>](#get-task-status)
+- [Schema Service adoption <a name="schema-service-adoption"></a>](#schema-service-adoption)
 
 
 ##Introduction <a name="introduction"></a>
@@ -250,3 +251,12 @@ API will respond with status of task.
 
 [Back to table of contents](#TOC)
 
+##Shema Service adoption <a name="schema-service-adoption"></a>
+
+Indexer service is in adaptation process to use schemas from the Schema service instead of Storage Service.
+The Indexer Service retrieves a schema from the Schema Service if the schema is not found on the Storage Service.
+Change affects only Azure implementation so far.
+Later call to the Storage Service will be deprecated and then removed (after the end of the deprecation period).
+
+[Back to table of contents](#TOC)
+
diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/config/IndexerConfigurationProperties.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/config/IndexerConfigurationProperties.java
index a139637e72da789c60d8f50bb4702098a2e2fa29..13ed75f28a0ba814cd3af9b01e3a166a5b05ae7d 100644
--- a/indexer-core/src/main/java/org/opengroup/osdu/indexer/config/IndexerConfigurationProperties.java
+++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/config/IndexerConfigurationProperties.java
@@ -47,6 +47,7 @@ public class IndexerConfigurationProperties {
 	private String storageQueryRecordHost;
 	private Integer storageRecordsBatchSize;
 	private String storageSchemaHost;
+	private String schemaHost;
 	private String entitlementsHost;
 	private String entitlementTargetAudience;
 	private String indexerQueueHost;
diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/logging/AuditEvents.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/logging/AuditEvents.java
index bfc441ac9850b3cdb5b2e9b8217d5560920fd487..9ac4df7da845cbd6014f19d4e53602011ffb8dbb 100644
--- a/indexer-core/src/main/java/org/opengroup/osdu/indexer/logging/AuditEvents.java
+++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/logging/AuditEvents.java
@@ -27,6 +27,7 @@ public class AuditEvents {
     private static final String INDEX_CREATE_RECORDS_SUCCESS = "Successfully created record in index";
     private static final String INDEX_CREATE_RECORDS_FAILURE = "Failed creating record in index";
 
+
     private static final String INDEX_UPDATE_RECORD_ACTION_ID = "IN002";
     private static final String INDEX_UPDATE_RECORDS_SUCCESS = "Successfully updated record in index";
     private static final String INDEX_UPDATE_RECORDS_FAILURE = "Failed updating record in index";
diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/schema/converter/PropertiesProcessor.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/schema/converter/PropertiesProcessor.java
new file mode 100644
index 0000000000000000000000000000000000000000..6de10d528cea2a4cbffe060409d361a21ef8c99a
--- /dev/null
+++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/schema/converter/PropertiesProcessor.java
@@ -0,0 +1,178 @@
+// Copyright 2017-2020, Schlumberger
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.opengroup.osdu.indexer.schema.converter;
+import org.apache.http.HttpStatus;
+import org.opengroup.osdu.core.common.logging.JaxRsDpsLog;
+import org.opengroup.osdu.core.common.model.http.AppException;
+import org.opengroup.osdu.core.common.search.Preconditions;
+import org.opengroup.osdu.indexer.schema.converter.config.SchemaConverterConfig;
+import org.opengroup.osdu.indexer.schema.converter.config.SchemaConverterPropertiesConfig;
+import org.opengroup.osdu.indexer.schema.converter.tags.AllOfItem;
+import org.opengroup.osdu.indexer.schema.converter.tags.Definition;
+import org.opengroup.osdu.indexer.schema.converter.tags.Definitions;
+import org.opengroup.osdu.indexer.schema.converter.tags.TypeProperty;
+
+import java.util.*;
+import java.util.function.Supplier;
+import java.util.stream.Stream;
+
+public class PropertiesProcessor {
+
+    private JaxRsDpsLog log;
+    private SchemaConverterConfig schemaConverterConfig;
+
+    private static final String DEF_PREFIX = "#/definitions/";
+    private static final String LINK_PREFIX = "^srn";
+    private static final String LINK_TYPE = "link";
+
+    private final Definitions definitions;
+    private final String pathPrefix;
+    private final String pathPrefixWithDot;
+
+    public PropertiesProcessor(Definitions definitions, JaxRsDpsLog log, SchemaConverterConfig schemaConverterConfig) {
+        this(definitions, null, log, schemaConverterConfig);
+    }
+
+    public PropertiesProcessor(Definitions definitions, String pathPrefix, JaxRsDpsLog log, SchemaConverterConfig schemaConverterConfig) {
+        this.log = log;
+        this.definitions = definitions;
+        this.pathPrefix = pathPrefix;
+        this.pathPrefixWithDot = Objects.isNull(pathPrefix) || pathPrefix.isEmpty() ? "" : pathPrefix + ".";
+        this.schemaConverterConfig = schemaConverterConfig;
+    }
+
+    public Stream<Map<String, Object>> processItem(AllOfItem allOfItem) {
+        Preconditions.checkNotNull(allOfItem, "allOfItem cannot be null");
+
+        String ref = allOfItem.getRef();
+
+        return Objects.isNull(ref) ?
+                allOfItem.getProperties().entrySet().stream().flatMap(this::processPropertyEntry) : processRef(ref);
+    }
+
+    public Stream<Map<String, Object>> processRef(String ref) {
+        Preconditions.checkNotNull(ref, "reference cannot be null");
+
+        if (!ref.contains(DEF_PREFIX)) {
+            log.warning("Unknown definition:" + ref);
+            return Stream.empty();
+        }
+
+        String definitionSubRef = ref.substring(DEF_PREFIX.length());
+
+        if (schemaConverterConfig.getSkippedDefinitions().contains(definitionSubRef)) {
+            return Stream.empty();
+        }
+
+        if (Objects.nonNull(schemaConverterConfig.getSpecialDefinitionsMap().get(definitionSubRef))) {
+            return storageSchemaEntry(schemaConverterConfig.getSpecialDefinitionsMap().get(definitionSubRef), pathPrefix);
+        }
+
+        Definition definition = definitions.getDefinition(definitionSubRef);
+        Optional.ofNullable(definition).orElseThrow(() ->
+                new AppException(HttpStatus.SC_NOT_FOUND, "Failed to find definition:" + definitionSubRef,
+                        "Unknown definition:" + definitionSubRef));
+
+        return definition.getProperties().entrySet().stream().flatMap(this::processPropertyEntry);
+    }
+
+    private Stream<Map<String, Object>> processPropertyEntry(Map.Entry<String, TypeProperty> entry) {
+        Preconditions.checkNotNull(entry, "entry cannot be null");
+
+        if ("object".equals(entry.getValue().getType())
+                && Objects.isNull(entry.getValue().getItems())
+                && Objects.isNull(entry.getValue().getRef())
+                && Objects.isNull(entry.getValue().getProperties())) {
+            return Stream.empty();
+        }
+
+        if ("array".equals(entry.getValue().getType())) {
+            if (schemaConverterConfig.getSupportedArrayTypes().contains(entry.getValue().getItems().getType())) {
+                return storageSchemaEntry("[]" + getTypeByDefinitionProperty(entry.getValue()), pathPrefixWithDot + entry.getKey());
+            }
+
+            return Stream.empty();
+        }
+
+        if (Objects.nonNull(entry.getValue().getProperties())) {
+            PropertiesProcessor propertiesProcessor = new PropertiesProcessor(definitions, pathPrefixWithDot + entry.getKey()
+                    , log, new SchemaConverterPropertiesConfig());
+            return entry.getValue().getProperties().entrySet().stream().flatMap(propertiesProcessor::processPropertyEntry);
+        }
+
+        if (Objects.nonNull(entry.getValue().getRef())) {
+            return new PropertiesProcessor(definitions, pathPrefixWithDot + entry.getKey(), log, new SchemaConverterPropertiesConfig())
+                    .processRef(entry.getValue().getRef());
+        }
+
+        return storageSchemaEntry(getTypeByDefinitionProperty(entry.getValue()), pathPrefixWithDot + entry.getKey());
+    }
+
+    private Stream<Map<String, Object>> storageSchemaEntry(String kind, String path) {
+        Preconditions.checkNotNullOrEmpty(kind, "kind cannot be null or empty");
+        Preconditions.checkNotNullOrEmpty(path, "path cannot be null or empty");
+
+        Map<String, Object> map = new HashMap<>();
+        map.put("kind", kind);
+        map.put("path", path);
+        return Stream.of(map);
+    }
+
+    private String getTypeByDefinitionProperty(TypeProperty definitionProperty) {
+        Preconditions.checkNotNull(definitionProperty, "definitionProperty cannot be null");
+
+        return Stream.of(
+                getFromPattern(definitionProperty.getPattern()),
+                getFromItemsPattern(() -> definitionProperty.getItems() != null ? definitionProperty.getItems().getPattern() : null),
+                getFromFormat(definitionProperty::getFormat),
+                getFromItemsType (() -> definitionProperty.getItems() != null ? definitionProperty.getItems().getType() : null))
+                .filter(x -> x.get() != null)
+                .findFirst()
+                .orElse(getFromType(definitionProperty::getType)).get();
+    }
+
+    private Supplier<String> getFromPattern(String pattern) {
+        return () -> Objects.nonNull(pattern) && pattern.startsWith(LINK_PREFIX) ? LINK_TYPE : null;
+    }
+
+    private Supplier<String> getFromItemsPattern(Supplier<String> itemsPatternSupplier) {
+        return () -> {
+                String itemsPattern = itemsPatternSupplier.get();
+                return Objects.nonNull(itemsPattern) && itemsPattern.startsWith(LINK_PREFIX) ? LINK_TYPE : null;
+            };
+    }
+
+    private Supplier<String> getFromType(Supplier<String> typeSupplier) {
+        return  () -> {
+            String type = typeSupplier.get();
+            return schemaConverterConfig.getPrimitiveTypesMap().getOrDefault(type, type);
+        };
+    }
+
+    private Supplier<String> getFromFormat(Supplier<String> formatSupplier){
+        return  () -> {
+            String format = formatSupplier.get();;
+            return Objects.nonNull(format) ? schemaConverterConfig.getPrimitiveTypesMap().getOrDefault(format, format) : null;
+        };
+    }
+
+    private Supplier<String> getFromItemsType(Supplier<String> itemsTypeSupplier) {
+        return () -> {
+            String itemsType = itemsTypeSupplier.get();
+            return Objects.nonNull(itemsType) ? schemaConverterConfig.getPrimitiveTypesMap().getOrDefault(itemsType, itemsType) : null;
+        };
+    }
+
+}
diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/schema/converter/SchemaToStorageFormatImpl.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/schema/converter/SchemaToStorageFormatImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..d35c8d257f4ac4f16ce4c214558ae6f3b0f4653d
--- /dev/null
+++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/schema/converter/SchemaToStorageFormatImpl.java
@@ -0,0 +1,116 @@
+// Copyright 2017-2020, Schlumberger
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.opengroup.osdu.indexer.schema.converter;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.http.HttpStatus;
+import org.opengroup.osdu.core.common.logging.JaxRsDpsLog;
+import org.opengroup.osdu.core.common.model.http.AppException;
+import org.opengroup.osdu.core.common.search.Preconditions;
+import org.opengroup.osdu.indexer.schema.converter.config.SchemaConverterConfig;
+import org.opengroup.osdu.indexer.schema.converter.interfaces.SchemaToStorageFormat;
+import org.opengroup.osdu.indexer.schema.converter.tags.PropertiesData;
+import org.opengroup.osdu.indexer.schema.converter.tags.SchemaRoot;
+import org.springframework.stereotype.Component;
+
+import javax.inject.Inject;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * Converts schema from Schema Service format to Storage Service format
+ */
+@Component
+public class SchemaToStorageFormatImpl implements SchemaToStorageFormat {
+
+    private ObjectMapper objectMapper;
+    private JaxRsDpsLog log;
+    private SchemaConverterConfig schemaConverterConfig;
+
+    @Inject
+    public SchemaToStorageFormatImpl(ObjectMapper objectMapper, JaxRsDpsLog log, SchemaConverterConfig schemaConverterConfig) {
+        Preconditions.checkNotNull(objectMapper, "objectMapper cannot be null");
+
+        this.objectMapper = objectMapper;
+        this.log = log;
+        this.schemaConverterConfig = schemaConverterConfig;
+    }
+
+    @Override
+    public String convertToString(final String schemaServiceFormat, String kind) {
+        Preconditions.checkNotNullOrEmpty(schemaServiceFormat, "schemaServiceFormat cannot be null or empty");
+        Preconditions.checkNotNullOrEmpty(kind, "kind cannot be null or empty");
+
+        return saveJsonToString(convert(parserJsonString(schemaServiceFormat), kind));
+    }
+
+    public Map<String, Object> convertToMap(final String schemaServiceFormat, String kind) {
+        Preconditions.checkNotNullOrEmpty(schemaServiceFormat, "schemaServiceFormat cannot be null or empty");
+        Preconditions.checkNotNullOrEmpty(kind, "kind cannot be null or empty");
+
+        return convert(parserJsonString(schemaServiceFormat), kind);
+    }
+
+    private SchemaRoot parserJsonString(final String schemaServiceFormat) {
+        try {
+            return objectMapper.readValue(schemaServiceFormat, SchemaRoot.class);
+        } catch (JsonProcessingException e) {
+            throw new AppException(HttpStatus.SC_BAD_REQUEST, "Loading shchem error", "Failed to load schema", e);
+        }
+    }
+
+    private String saveJsonToString(final Map<String, Object> schemaServiceFormat) {
+        try {
+            return objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(schemaServiceFormat);
+        } catch (JsonProcessingException e) {
+            throw new AppException(HttpStatus.SC_UNPROCESSABLE_ENTITY, "Saving JSON error", "Failed to save a JSON file", e);
+        }
+    }
+
+    private Map<String, Object> convert(SchemaRoot schemaServiceSchema, String kind) {
+        Preconditions.checkNotNull(objectMapper, "schemaServiceSchema cannot be null");
+        Preconditions.checkNotNullOrEmpty(kind, "kind cannot be null or empty");
+
+        PropertiesProcessor propertiesProcessor = new PropertiesProcessor(schemaServiceSchema.getDefinitions(), log, schemaConverterConfig);
+
+        final List<Map<String, Object>> storageSchemaItems = new ArrayList<>();
+        if (schemaServiceSchema.getProperties() != null) {
+            PropertiesData schemaData = schemaServiceSchema.getProperties().getData();
+            if (!Objects.isNull(schemaData)) {
+
+                if (schemaData.getAllOf() != null) {
+                    storageSchemaItems.addAll(schemaServiceSchema.getProperties().getData().getAllOf().stream()
+                            .flatMap(propertiesProcessor::processItem)
+                            .collect(Collectors.toList()));
+                }
+
+                if (schemaData.getRef() != null) {
+                    storageSchemaItems.addAll(propertiesProcessor.processRef(schemaData.getRef())
+                            .collect(Collectors.toList()));
+                }
+            }
+        } else {
+            log.warning("Schema doesn't have properties, kind:" + kind);
+        }
+
+        final Map<String, Object> result = new LinkedHashMap<>();
+        result.put("kind", kind);
+        result.put("schema", storageSchemaItems);
+
+        return result;
+    }
+
+}
diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/schema/converter/config/SchemaConverterConfig.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/schema/converter/config/SchemaConverterConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..539b2bdfd16b67422e680d7b3b58ac64948937e4
--- /dev/null
+++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/schema/converter/config/SchemaConverterConfig.java
@@ -0,0 +1,14 @@
+package org.opengroup.osdu.indexer.schema.converter.config;
+
+import java.util.Map;
+import java.util.Set;
+
+/*
+Provides configuration for the schema converter
+ */
+public interface SchemaConverterConfig {
+    Set<String> getSkippedDefinitions();
+    Set<String> getSupportedArrayTypes();
+    Map<String, String> getSpecialDefinitionsMap();
+    Map<String, String> getPrimitiveTypesMap();
+}
diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/schema/converter/config/SchemaConverterPropertiesConfig.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/schema/converter/config/SchemaConverterPropertiesConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..f530c842ba0bae004bc3e54e080cca143edb88c9
--- /dev/null
+++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/schema/converter/config/SchemaConverterPropertiesConfig.java
@@ -0,0 +1,54 @@
+package org.opengroup.osdu.indexer.schema.converter.config;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.*;
+
+@Configuration
+@ConfigurationProperties(prefix = "schema.converter")
+@Getter
+@Setter
+public class SchemaConverterPropertiesConfig implements SchemaConverterConfig {
+
+    private Set<String> skippedDefinitions = getDefaultSkippedDefinitions();
+    private Set<String> supportedArrayTypes = getDefaultSupportedArrayTypes();
+    private Map<String, String> specialDefinitionsMap = getDefaultSpecialDefinitionsMap();
+    private Map<String, String> primitiveTypesMap = getDefaultPrimitiveTypesMap();
+
+    private Set<String> getDefaultSkippedDefinitions() {
+        return new HashSet<>(Arrays.asList("AbstractAnyCrsFeatureCollection.1.0.0",
+                "anyCrsGeoJsonFeatureCollection"));
+    }
+
+    private Set<String> getDefaultSupportedArrayTypes() {
+        return new HashSet<>(Arrays.asList("boolean", "integer", "number", "string"));
+    }
+
+    private Map<String, String> getDefaultSpecialDefinitionsMap() {
+        Map<String, String> defaultSpecialDefinitions = new HashMap<>();
+
+        defaultSpecialDefinitions.put("AbstractFeatureCollection.1.0.0", "core:dl:geoshape:1.0.0");
+        defaultSpecialDefinitions.put("core_dl_geopoint", "core:dl:geopoint:1.0.0");
+        defaultSpecialDefinitions.put("geoJsonFeatureCollection", "core:dl:geoshape:1.0.0");
+
+        return defaultSpecialDefinitions;
+    }
+
+    private Map<String, String> getDefaultPrimitiveTypesMap() {
+        Map<String, String> defaultPrimitiveTypesMap = new HashMap<>();
+
+        defaultPrimitiveTypesMap.put("boolean", "bool");
+        defaultPrimitiveTypesMap.put("number", "double");
+        defaultPrimitiveTypesMap.put("date-time", "datetime");
+        defaultPrimitiveTypesMap.put("date", "datetime");
+        defaultPrimitiveTypesMap.put("time", "datetime");
+        defaultPrimitiveTypesMap.put("int32", "int");
+        defaultPrimitiveTypesMap.put("integer", "int");
+        defaultPrimitiveTypesMap.put("int64", "long");
+
+        return defaultPrimitiveTypesMap;
+    }
+}
diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/schema/converter/interfaces/SchemaToStorageFormat.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/schema/converter/interfaces/SchemaToStorageFormat.java
new file mode 100644
index 0000000000000000000000000000000000000000..9d481343264e47ae054b454f7be0d1e6e192212b
--- /dev/null
+++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/schema/converter/interfaces/SchemaToStorageFormat.java
@@ -0,0 +1,19 @@
+// Copyright 2017-2020, Schlumberger
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.opengroup.osdu.indexer.schema.converter.interfaces;
+
+public interface SchemaToStorageFormat {
+    String convertToString(String schemaServiceFormat, String kind);
+}
diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/schema/converter/readme.md b/indexer-core/src/main/java/org/opengroup/osdu/indexer/schema/converter/readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..845325962f475bd6c02e3999d02a32b43b7fafba
--- /dev/null
+++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/schema/converter/readme.md
@@ -0,0 +1,302 @@
+Schema Service schema conversion.
+=================================
+
+Purpose
+-------
+
+The purpose of this document is to describe schema conversion from the
+Schema Service format to the Storage Service format.
+
+Storage Service schema has the following JSON format
+----------------------------------------------------
+```json
+{
+  "kind": "<kind>",
+  "schema": [
+    {
+      "kind": "<type>",
+      "path": "<path>"
+    },
+    {
+      "kind": "<type>",
+      "path": "<path>"
+    },
+	…
+}
+
+```
+
+Where \<kind\> - id of a kind, \<type\> - type of the described entity
+(for instance link, string,datetime, \[\]string, etc.), \<path\> -
+path/name/id of the described entity (for instance FacilityID, WellID,
+ProjectedBottomHoleLocation.CoordinateQualityCheckDateTime, etc.)
+
+Shema Service format follows JSON schema format. 
+------------------------------------------------
+
+Please see <https://tools.ietf.org/html/draft-handrews-json-schema-02>
+for the details
+
+Example
+
+```json
+{
+  "$schema": "http://json-schema.org/draft-07/schema#",
+  "title": "Wellbore",
+  "description": "A hole in the ground extending from a point at the earth's surface to the maximum point of penetration.",
+  "type": "object",
+  "properties": {…},
+  "required": […],
+  "additionalProperties": false,
+  "definitions": {…}
+}
+
+```
+
+We are interested in "properties.data" and "definitions" sections.
+
+"definitions" contains definitions of complex types. "properties.data"
+contains attributes that are used in a certain schema and can refer to
+the definition section (in that case we have to unwrap definition
+section and turn into simple types). Sibling properties to
+properties.data are ignored as the so-called system properties are
+shared with all records.
+
+"properties.data" may have 0..n references to the "definitions" section
+and 0..m properties that describe schema sections. For instance
+
+```json
+"data": {
+  "$ref": "#/definitions/wellboreData",
+  "description": "Wellbore data container",
+  "title": "Wellbore Data"
+}
+
+```
+
+This means "wellboreData" has to be found among definitions and data are
+included
+
+```json
+"data": {
+  "allOf": [
+    {
+      "$ref": "#/definitions/AbstractFacility.1.0.0"
+    },
+    {
+      "type": "object",
+      "properties": {
+        "WellID": {
+          "type": "string",
+          "pattern": "^srn:<namespace>:master-data\\/Well:[^:]+:[0-9]*$"
+        },
+        "SequenceNumber": {
+          "description": "A number that indicates the order in which wellbores were drilled.",
+          "type": "integer"
+        },
+…
+
+```
+
+
+This means \"AbstractFacility.1.0.0\" must be processed, plus
+\"WellID\", \"SequenceNumber\", ...
+
+References can have references to other reference(-s), in that case
+Storage Schema has a composite path.
+
+For instance,
+
+```json
+"elevationReference": {
+  "$ref": "#/definitions/simpleElevationReference",
+  "description": "…",
+  "title": "Elevation Reference",
+  "type": "object"
+},
+…
+"simpleElevationReference": {
+  "description": "...",
+  "properties": {
+    "elevationFromMsl": {
+      "$ref": "#/definitions/valueWithUnit",
+      "description": "…",
+      "example": 123.45,
+      "title": "Elevation from MSL",
+      "x-slb-measurement": "Standard_Depth_Index"
+    },
+…
+"valueWithUnit": {
+  "description": "Number value ...",
+  "properties": {
+    "value": {
+      "description": "Value of the corresponding...",
+      "example": 30.2,
+      "title": "Value",
+      "type": "number"
+    }
+  }
+
+```
+
+Is converted to
+
+```json
+{
+  "kind": "double",
+  "path": "elevationReference.elevationFromMsl.value"
+}
+
+```
+
+\"path\":\"elevationReference.elevationFromMsl.value\" consists of 3
+names separated with dot.
+
+Not all data are converted to the storage service schema format:
+----------------------------------------------------------------
+
+1.  Definitions
+
+Ignored definition(-s) are not included into Storage Service schema:
+
+```json
+AbstractAnyCrsFeatureCollection.1.0.0
+anyCrsGeoJsonFeatureCollection
+```
+
+Following definitions are not unwrapped and kind is determined according
+to the following types conversions:
+
+```json
+AbstractFeatureCollection.1.0.0 -> core:dl:geoshape:1.0.0
+geoJsonFeatureCollection -> core:dl:geoshape:1.0.0
+core_dl_geopoint -> core:dl:geopoint:1.0.0
+```
+
+for instance
+
+```json
+"Wgs84Coordinates": {
+  "title": "WGS 84 Coordinates",
+  "description": "…",
+  "$ref": "#/definitions/AbstractFeatureCollection.1.0.0"
+}
+
+```
+
+Is converted to
+
+```json
+{
+  "kind": "core:dl:geoshape:1.0.0",
+  "path": "Wgs84Coordinates"
+}
+```
+
+2.  Arrays
+
+Arrays of complex types are ignored, only following arrays of primitive
+types are supported
+
+```json
+"number", "string", "integer", "boolean"
+```
+
+Following primitive types are converted to the Storage Service Schema types (all other types like string are used as is):
+----------------------------------------------------------------------------
+
+```json
+"date-time"->"datetime"
+"date"->"datetime"
+"int64"->"long"
+"number"->"double"
+"boolean"->"bool"
+"integer"->"int"
+```
+
+Type selection according to attributes.
+---------------------------------------
+
+One or more attributes of a single entity may have values with types.
+Following attributes are considered to select a type for the Storage
+Schema kind (ordered according to selection priority):
+```json
+"pattern", "format", "items.type", "type"
+```
+If \"pattern\" starts with \"\^srn\" the returned kind is \"link\"
+
+Arrays of primitive types have \[\] before the type (for instance
+\"\[\]string\")
+
+Examples
+--------
+
+#### Simple String
+
+```json
+"FacilityID": {
+  "description": "A system-specified unique identifier of a Facility.",
+  "type": "string"
+},
+
+```
+
+\"kind\":\"string\"
+
+#### Nested Arrays of Structures
+
+```json
+"FacilityTypeID": {
+  "description": "The definition of a kind of capability to perform a business function or a service.",
+  "type": "string",
+  "pattern": "^srn:<namespace>:reference-data\\/FacilityType:[^:]+:[0-9]*$"
+},
+
+```
+
+\"kind\":\"link\"
+
+```json
+"FacilityOperator": {
+  "description": "The history of operator organizations of the facility.",
+  "type": "array",
+  "items": {
+    "$ref": "#/definitions/AbstractFacilityOperator.1.0.0"
+  }
+}
+
+```
+
+Ignored for now (array of references)
+
+#### Object References by ID
+
+```json
+"externalIds": {
+  "description": "An array of identities (e.g. some kind if URL to be resolved in an external data store), which links to external realizations of the same entity.",
+  "format": "link",
+  "items": {
+    "type": "string"
+  },
+  "title": "Array of External IDs",
+  "type": "array"
+},
+
+```
+
+\"kind\": \"\[\]link\"
+
+#### Long Integers
+
+```json
+"version": {
+  "description": "The version number of this wellbore; set by the framework.",
+  "example": "1040815391631285",
+  "format": "int64",
+  "title": "Entity Version Number",
+  "type": "number"
+}
+
+```
+
+\"kind\": \"long\"
\ No newline at end of file
diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/schema/converter/tags/AllOfItem.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/schema/converter/tags/AllOfItem.java
new file mode 100644
index 0000000000000000000000000000000000000000..9499e5636227d0b5c3b8647ce8237856b185aec1
--- /dev/null
+++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/schema/converter/tags/AllOfItem.java
@@ -0,0 +1,28 @@
+// Copyright 2017-2020, Schlumberger
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.opengroup.osdu.indexer.schema.converter.tags;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+import java.util.Map;
+
+@Data
+public class AllOfItem {
+    @JsonProperty("$ref")
+    private String ref;
+    private String type;
+    private Map<String, TypeProperty> properties;
+}
\ No newline at end of file
diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/schema/converter/tags/Definition.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/schema/converter/tags/Definition.java
new file mode 100644
index 0000000000000000000000000000000000000000..f1b820f3870962093d59c7fed97961daa96b82ae
--- /dev/null
+++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/schema/converter/tags/Definition.java
@@ -0,0 +1,24 @@
+// Copyright 2017-2020, Schlumberger
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.opengroup.osdu.indexer.schema.converter.tags;
+
+import lombok.Data;
+
+import java.util.Map;
+
+@Data
+public class Definition {
+    private Map<String, TypeProperty> properties;
+}
diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/schema/converter/tags/Definitions.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/schema/converter/tags/Definitions.java
new file mode 100644
index 0000000000000000000000000000000000000000..69e585852c366b7e54b770a890948a4f22c45390
--- /dev/null
+++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/schema/converter/tags/Definitions.java
@@ -0,0 +1,39 @@
+// Copyright 2017-2020, Schlumberger
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.opengroup.osdu.indexer.schema.converter.tags;
+
+import com.fasterxml.jackson.annotation.JsonAnyGetter;
+import com.fasterxml.jackson.annotation.JsonAnySetter;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class Definitions {
+    private Map<String, Definition> items = new HashMap<>();
+
+    public Definition getDefinition(String name) {
+        return items.get(name);
+    }
+
+    @JsonAnySetter
+    public void add(String key, Definition value) {
+        items.put(key, value);
+    }
+
+    @JsonAnyGetter
+    public Map<String, Definition> getProperties() {
+        return items;
+    }
+}
diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/schema/converter/tags/Items.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/schema/converter/tags/Items.java
new file mode 100644
index 0000000000000000000000000000000000000000..dc3ef69e9ef19c7cdfbfebb48ddedc393067f98f
--- /dev/null
+++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/schema/converter/tags/Items.java
@@ -0,0 +1,23 @@
+// Copyright 2017-2020, Schlumberger
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.opengroup.osdu.indexer.schema.converter.tags;
+
+import lombok.Data;
+
+@Data
+public class Items {
+    private String type;
+    private String pattern;
+}
diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/schema/converter/tags/Properties.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/schema/converter/tags/Properties.java
new file mode 100644
index 0000000000000000000000000000000000000000..e08beb4d71f4163f76ad13fc089e4ce98242a515
--- /dev/null
+++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/schema/converter/tags/Properties.java
@@ -0,0 +1,25 @@
+// Copyright 2017-2020, Schlumberger
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.opengroup.osdu.indexer.schema.converter.tags;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+@Data
+public class Properties {
+    private PropertiesData data;
+    @JsonProperty("$ref")
+    private String ref;
+}
diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/schema/converter/tags/PropertiesData.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/schema/converter/tags/PropertiesData.java
new file mode 100644
index 0000000000000000000000000000000000000000..706ee8b1172d5dd79dd7d8d9d0e6cef3bee1dce0
--- /dev/null
+++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/schema/converter/tags/PropertiesData.java
@@ -0,0 +1,27 @@
+// Copyright 2017-2020, Schlumberger
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.opengroup.osdu.indexer.schema.converter.tags;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class PropertiesData {
+    private List<AllOfItem> allOf;
+    @JsonProperty("$ref")
+    private String ref;
+}
diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/schema/converter/tags/SchemaRoot.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/schema/converter/tags/SchemaRoot.java
new file mode 100644
index 0000000000000000000000000000000000000000..27f78de6702b29e282eb5cc9320a745d53329197
--- /dev/null
+++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/schema/converter/tags/SchemaRoot.java
@@ -0,0 +1,23 @@
+// Copyright 2017-2020, Schlumberger
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.opengroup.osdu.indexer.schema.converter.tags;
+
+import lombok.Data;
+
+@Data
+public class SchemaRoot {
+    private Definitions definitions;
+    private Properties properties;
+}
diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/schema/converter/tags/TypeProperty.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/schema/converter/tags/TypeProperty.java
new file mode 100644
index 0000000000000000000000000000000000000000..0710bedee52af3a9e06011cd58dec3897879b395
--- /dev/null
+++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/schema/converter/tags/TypeProperty.java
@@ -0,0 +1,31 @@
+// Copyright 2017-2020, Schlumberger
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.opengroup.osdu.indexer.schema.converter.tags;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+import java.util.Map;
+
+@Data
+public class TypeProperty {
+    private String type;
+    private String pattern;
+    private String format;
+    @JsonProperty("$ref")
+    private String ref;
+    private Items items;
+    private Map<String, TypeProperty> properties;
+}
diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/service/IndexSchemaServiceImpl.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/service/IndexSchemaServiceImpl.java
index 4d0240b652ebe86c92fe65b7f0d472ad3f52e63f..113dc54bde6c9e4bf11e2fc36ab1725d0be77b72 100644
--- a/indexer-core/src/main/java/org/opengroup/osdu/indexer/service/IndexSchemaServiceImpl.java
+++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/service/IndexSchemaServiceImpl.java
@@ -16,29 +16,30 @@ package org.opengroup.osdu.indexer.service;
 
 import com.google.common.base.Strings;
 import com.google.gson.Gson;
+import org.apache.http.HttpStatus;
 import org.elasticsearch.ElasticsearchException;
 import org.elasticsearch.ElasticsearchStatusException;
 import org.elasticsearch.client.RestHighLevelClient;
-import org.opengroup.osdu.core.common.model.storage.SchemaItem;
-import org.opengroup.osdu.core.common.model.http.AppException;
 import org.opengroup.osdu.core.common.logging.JaxRsDpsLog;
-import org.opengroup.osdu.indexer.util.ElasticClientHandler;
-import org.opengroup.osdu.core.common.search.ElasticIndexNameResolver;
-import org.opengroup.osdu.core.common.search.IndicesService;
+import org.opengroup.osdu.core.common.model.http.AppException;
+import org.opengroup.osdu.core.common.model.http.RequestStatus;
 import org.opengroup.osdu.core.common.model.indexer.IndexSchema;
 import org.opengroup.osdu.core.common.model.indexer.OperationType;
-import org.opengroup.osdu.core.common.model.storage.Schema;
 import org.opengroup.osdu.core.common.model.indexer.StorageType;
+import org.opengroup.osdu.core.common.model.search.RecordMetaAttribute;
+import org.opengroup.osdu.core.common.model.storage.Schema;
+import org.opengroup.osdu.core.common.model.storage.SchemaItem;
+import org.opengroup.osdu.core.common.search.ElasticIndexNameResolver;
+import org.opengroup.osdu.core.common.search.IndicesService;
 import org.opengroup.osdu.indexer.provider.interfaces.ISchemaCache;
+import org.opengroup.osdu.indexer.util.ElasticClientHandler;
 import org.opengroup.osdu.indexer.util.TypeMapper;
-import org.opengroup.osdu.core.common.model.http.RequestStatus;
-import org.opengroup.osdu.core.common.model.search.RecordMetaAttribute;
-import org.apache.http.HttpStatus;
 import org.springframework.stereotype.Service;
 
 import javax.inject.Inject;
-
 import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.URISyntaxException;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -52,7 +53,7 @@ public class IndexSchemaServiceImpl implements IndexSchemaService {
     @Inject
     private JaxRsDpsLog log;
     @Inject
-    private StorageService storageService;
+    private SchemaService schemaProvider;
     @Inject
     private ElasticClientHandler elasticClientHandler;
     @Inject
@@ -129,7 +130,7 @@ public class IndexSchemaServiceImpl implements IndexSchemaService {
             String schema = (String) this.schemaCache.get(kind);
             if (Strings.isNullOrEmpty(schema)) {
                 // get from storage
-                schema = this.storageService.getStorageSchema(kind);
+                schema = getSchema(kind);
                 if (Strings.isNullOrEmpty(schema)) {
                     Schema basicSchema = Schema.builder().kind(kind).build();
                     return normalizeSchema(gson.toJson(basicSchema));
@@ -159,6 +160,10 @@ public class IndexSchemaServiceImpl implements IndexSchemaService {
         }
     }
 
+    private String getSchema(String kind) throws URISyntaxException, UnsupportedEncodingException {
+        return this.schemaProvider.getSchema(kind);
+    }
+
     public void syncIndexMappingWithStorageSchema(String kind) throws ElasticsearchException, IOException, AppException {
         String index = this.elasticIndexNameResolver.getIndexNameFromKind(kind);
         try (RestHighLevelClient restClient = this.elasticClientHandler.createRestClient()) {
diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/service/SchemaService.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/service/SchemaService.java
new file mode 100644
index 0000000000000000000000000000000000000000..174630771365a1aa6761298dc0f0c0d7582c960b
--- /dev/null
+++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/service/SchemaService.java
@@ -0,0 +1,32 @@
+// Copyright 2017-2020, Schlumberger
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.opengroup.osdu.indexer.service;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URISyntaxException;
+
+/**
+ * Interface to retriew schemas from the Schema Service
+ */
+public interface SchemaService {
+    /**
+     *
+     * @param kind key to retrieve schema
+     * @return obtained schema
+     * @throws URISyntaxException
+     * @throws UnsupportedEncodingException
+     */
+    String getSchema(String kind) throws URISyntaxException, UnsupportedEncodingException;
+}
diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/service/StorageServiceImpl.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/service/StorageServiceImpl.java
index 3a9b59cea966ecd5ee5444920f4143bbed7d85b8..b8a3bf8aabbc4340309cbdaeb5cd29db22c60da1 100644
--- a/indexer-core/src/main/java/org/opengroup/osdu/indexer/service/StorageServiceImpl.java
+++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/service/StorageServiceImpl.java
@@ -34,7 +34,6 @@ import org.opengroup.osdu.core.common.model.search.RecordMetaAttribute;
 import org.opengroup.osdu.core.common.provider.interfaces.IRequestInfo;
 import org.apache.http.HttpStatus;
 import org.opengroup.osdu.indexer.config.IndexerConfigurationProperties;
-import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Component;
 
 import javax.inject.Inject;
diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/service/impl/SchemaProviderImpl.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/service/impl/SchemaProviderImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..70ef41dd6cef5e0c6687ad38f2fb1de8b6a08ffe
--- /dev/null
+++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/service/impl/SchemaProviderImpl.java
@@ -0,0 +1,105 @@
+// Copyright 2017-2020, Schlumberger
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.opengroup.osdu.indexer.service.impl;
+
+import com.google.api.client.http.HttpMethods;
+import org.apache.http.HttpStatus;
+import org.opengroup.osdu.core.common.http.FetchServiceHttpRequest;
+import org.opengroup.osdu.core.common.http.IUrlFetchService;
+import org.opengroup.osdu.core.common.logging.JaxRsDpsLog;
+import org.opengroup.osdu.core.common.model.http.HttpResponse;
+import org.opengroup.osdu.core.common.provider.interfaces.IRequestInfo;
+import org.opengroup.osdu.indexer.config.IndexerConfigurationProperties;
+import org.opengroup.osdu.indexer.schema.converter.interfaces.SchemaToStorageFormat;
+import org.opengroup.osdu.indexer.service.SchemaService;
+import org.opengroup.osdu.indexer.service.StorageService;
+import org.springframework.stereotype.Component;
+
+import javax.inject.Inject;
+import java.io.UnsupportedEncodingException;
+import java.net.URISyntaxException;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * Provides implementation of the client service that retrieves schemas from the Schema Service
+ */
+@Component
+public class SchemaProviderImpl implements SchemaService {
+    @Inject
+    private JaxRsDpsLog log;
+
+    @Inject
+    private IUrlFetchService urlFetchService;
+
+    @Inject
+    private IndexerConfigurationProperties configurationProperties;
+
+    @Inject
+    private IRequestInfo requestInfo;
+
+    @Inject
+    private SchemaToStorageFormat schemaToStorageFormat;
+
+    @Inject
+    private StorageService storageService;
+
+    @Override
+    public String getSchema(String kind) throws URISyntaxException, UnsupportedEncodingException {
+        String schemaFromStorageService = getFromStorageService(kind);
+
+        if (schemaFromStorageService != null) {
+            return schemaFromStorageService;
+        }
+
+        return getFromSchemaService(kind);
+    }
+
+    protected String getFromSchemaService(String kind) throws UnsupportedEncodingException, URISyntaxException {
+        HttpResponse response = getSchemaServiceResponse(kind);
+
+        if (response.getResponseCode() == HttpStatus.SC_NOT_FOUND) {
+            log.warning("Schema is not found on the Schema Service:" + kind);
+            return null;
+        }
+
+        return response.getResponseCode() != HttpStatus.SC_OK ? null :
+                schemaToStorageFormat.convertToString(response.getBody(), kind);
+    }
+
+    protected String getFromStorageService(String kind) throws URISyntaxException, UnsupportedEncodingException {
+        String schemaFromStorageService = storageService.getStorageSchema(kind);
+
+        if (schemaFromStorageService != null) {
+            return schemaFromStorageService;
+        }
+
+        log.warning("Schema is not found on the Storage Service:" + kind);
+
+        return null;
+    }
+
+    private HttpResponse getSchemaServiceResponse(String kind) throws UnsupportedEncodingException, URISyntaxException {
+        String url = String.format("%s/%s", configurationProperties.getSchemaHost(), URLEncoder.encode(kind, StandardCharsets.UTF_8.toString()));
+        FetchServiceHttpRequest request = FetchServiceHttpRequest.builder()
+                .httpMethod(HttpMethods.GET)
+                .headers(this.requestInfo.getHeadersMap())
+                .url(url)
+                .build();
+        
+        return this.urlFetchService.sendRequest(request);
+    }
+
+}
diff --git a/indexer-core/src/test/java/org/opengroup/osdu/indexer/api/CleanupIndiciesApiTest.java b/indexer-core/src/test/java/org/opengroup/osdu/indexer/api/CleanupIndiciesApiTest.java
index e9e08994d97426370881c042f0665a569e7f91c1..6a9f2ead5cf965f9e05f0e1d1782d97843ff7deb 100644
--- a/indexer-core/src/test/java/org/opengroup/osdu/indexer/api/CleanupIndiciesApiTest.java
+++ b/indexer-core/src/test/java/org/opengroup/osdu/indexer/api/CleanupIndiciesApiTest.java
@@ -13,6 +13,7 @@ import org.opengroup.osdu.core.common.http.HeadersUtil;
 import org.opengroup.osdu.core.common.model.http.AppException;
 import org.opengroup.osdu.core.common.model.http.DpsHeaders;
 import org.opengroup.osdu.core.common.model.search.RecordChangedMessages;
+import org.opengroup.osdu.core.common.search.Config;
 import org.opengroup.osdu.indexer.service.IndexerService;
 import org.opengroup.osdu.indexer.util.IndexerQueueTaskBuilder;
 import org.powermock.core.classloader.annotations.PrepareForTest;
@@ -21,7 +22,7 @@ import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
 
 @RunWith(PowerMockRunner.class)
-@PrepareForTest({HeadersUtil.class, IndexerQueueTaskBuilder.class, DpsHeaders.class})
+@PrepareForTest({HeadersUtil.class, IndexerQueueTaskBuilder.class, DpsHeaders.class, Config.class})
 public class CleanupIndiciesApiTest {
 
   private final String messageValid = "{\"data\":\"[{\\\"id\\\":\\\"opendes:welldb:wellbore-d9033ae1-fb15-496c-9ba0-880fd1d2b2cf\\\",\\\"kind\\\":\\\"tenant1:welldb:wellbore:1.0.0\\\",\\\"op\\\":\\\"purge_schema\\\"}]\",\"attributes\":{\"account-id\":\"opendes\",\"correlation-id\":\"b5a281bd-f59d-4db2-9939-b2d85036fc7e\"},\"messageId\":\"75328163778221\",\"publishTime\":\"2018-05-08T21:48:56.131Z\"}";
diff --git a/indexer-core/src/test/java/org/opengroup/osdu/indexer/schema/converter/PropertiesProcessorTest.java b/indexer-core/src/test/java/org/opengroup/osdu/indexer/schema/converter/PropertiesProcessorTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..600af3b43e448a1ac1c9603cf4007a546e333e4c
--- /dev/null
+++ b/indexer-core/src/test/java/org/opengroup/osdu/indexer/schema/converter/PropertiesProcessorTest.java
@@ -0,0 +1,104 @@
+// Copyright 2017-2020, Schlumberger
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.opengroup.osdu.indexer.schema.converter;
+
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.opengroup.osdu.core.common.logging.JaxRsDpsLog;
+import org.opengroup.osdu.core.common.model.http.AppException;
+import org.opengroup.osdu.indexer.schema.converter.config.SchemaConverterPropertiesConfig;
+import org.opengroup.osdu.indexer.schema.converter.tags.AllOfItem;
+import org.opengroup.osdu.indexer.schema.converter.tags.Definition;
+import org.opengroup.osdu.indexer.schema.converter.tags.Definitions;
+import org.opengroup.osdu.indexer.schema.converter.tags.TypeProperty;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+public class PropertiesProcessorTest {
+
+    private static final String PATH = "given_path";
+    private static final String DEFINITIONS_PREFIX = "#/definitions/";
+
+    @Test(expected = AppException.class)
+    public void should_fail_on_unknown_reference_definition() {
+        JaxRsDpsLog log = Mockito.mock(JaxRsDpsLog.class);
+
+        new PropertiesProcessor(Mockito.mock(Definitions.class), log, new SchemaConverterPropertiesConfig())
+                .processRef(DEFINITIONS_PREFIX + "unknownDefinition");
+    }
+
+    @Test
+    public void should_not_process_special_reference() {
+        JaxRsDpsLog log = Mockito.mock(JaxRsDpsLog.class);
+
+        assertFalse(new PropertiesProcessor(null, log, new SchemaConverterPropertiesConfig())
+                .processRef(DEFINITIONS_PREFIX + "anyCrsGeoJsonFeatureCollection").findAny().isPresent());
+    }
+
+    @Test
+    public void should_return_special_type() {
+        JaxRsDpsLog log = Mockito.mock(JaxRsDpsLog.class);
+
+        String res = new PropertiesProcessor(null, PATH, log, new SchemaConverterPropertiesConfig())
+                .processRef(DEFINITIONS_PREFIX + "core_dl_geopoint").map(Object::toString).reduce("", String::concat);
+        assertEquals("{path=" + PATH + ", kind=core:dl:geopoint:1.0.0}", res);
+    }
+
+    @Test
+    public void should_process_definition_correctly() {
+        JaxRsDpsLog log = Mockito.mock(JaxRsDpsLog.class);
+
+        Definitions definitions = new Definitions();
+        Definition definition = new Definition();
+
+        TypeProperty property = new TypeProperty();
+        property.setFormat("string");
+        String propertyName = "propName";
+
+        Map<String, TypeProperty> properties = new LinkedHashMap<>();
+        properties.put(propertyName, property);
+
+        definition.setProperties(properties);
+
+        String defName = "defName";
+        definitions.add(defName, definition);
+
+        String res = new PropertiesProcessor(definitions, PATH, log, new SchemaConverterPropertiesConfig())
+                .processRef(DEFINITIONS_PREFIX + defName).map(Object::toString).reduce("", String::concat);
+        assertEquals(res, "{path="+ PATH + "." + propertyName + ", kind=string}");
+    }
+
+    @Test
+    public void should_return_int_item() {
+        JaxRsDpsLog log = Mockito.mock(JaxRsDpsLog.class);
+
+        AllOfItem allOfItem = new AllOfItem();
+
+        TypeProperty property = new TypeProperty();
+        property.setFormat("integer");
+
+        Map<String, TypeProperty> properties = new LinkedHashMap<>();
+        properties.put(PATH, property);
+        allOfItem.setProperties(properties);
+
+        String res = new PropertiesProcessor(Mockito.mock(Definitions.class), log, new SchemaConverterPropertiesConfig())
+                .processItem(allOfItem).map(Object::toString).reduce("", String::concat);
+        assertEquals("{path=" + PATH + ", kind=int}", res);
+    }
+}
\ No newline at end of file
diff --git a/indexer-core/src/test/java/org/opengroup/osdu/indexer/schema/converter/SchemaToStorageFormatImplTest.java b/indexer-core/src/test/java/org/opengroup/osdu/indexer/schema/converter/SchemaToStorageFormatImplTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..f43d626175c5c367da75cc7f107c43766ae66c5a
--- /dev/null
+++ b/indexer-core/src/test/java/org/opengroup/osdu/indexer/schema/converter/SchemaToStorageFormatImplTest.java
@@ -0,0 +1,138 @@
+// Copyright 2017-2019, Schlumberger
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.opengroup.osdu.indexer.schema.converter;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.opengroup.osdu.core.common.logging.JaxRsDpsLog;
+import org.opengroup.osdu.indexer.schema.converter.config.SchemaConverterPropertiesConfig;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+@SpringBootTest
+public class SchemaToStorageFormatImplTest {
+
+    private ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json().build();
+
+    private JaxRsDpsLog jaxRsDpsLog = Mockito.mock(JaxRsDpsLog.class);
+    
+    private SchemaToStorageFormatImpl schemaToStorageFormatImpl
+            = new SchemaToStorageFormatImpl(objectMapper, jaxRsDpsLog
+                    , new SchemaConverterPropertiesConfig());
+
+    @Test
+    public void firstSchemaPassed() {
+        testSingleFile("/converter/basic/schema.json", "osdu:osdu:Wellbore:1.0.0");
+    }
+
+    @Test
+    public void integrationTestSchema1() {
+        testSingleFile("/converter/integration-tests/index_records_1.schema", "KIND_VAL");
+    }
+
+    @Test
+    public void integrationTestSchema2() {
+        testSingleFile("/converter/integration-tests/index_records_2.schema", "KIND_VAL");
+    }
+
+    @Test
+    public void integrationTestSchema3() {
+        testSingleFile("/converter/integration-tests/index_records_3.schema", "KIND_VAL");
+    }
+
+    @Test
+    public void wkeSchemaPassed() {
+        testSingleFile("/converter/wks/slb_wke_wellbore.json", "slb:wks:wellbore:1.0.6");
+    }
+
+    @Test
+    public void folderPassed() throws URISyntaxException, IOException {
+
+        String folder = "/converter/R3-json-schema";
+        Path path = Paths.get(this.getClass().getResource(folder).toURI());
+        Files.walk(path)
+                .filter(Files::isRegularFile)
+                .filter(f -> f.toString().endsWith(".json"))
+                .forEach( f -> testSingleFile(f.toString().replaceAll("\\\\", "/").substring(f.toString().replaceAll("\\\\", "/").indexOf(folder)), "osdu:osdu:Wellbore:1.0.0"));
+    }
+
+    private void testSingleFile(String filename, String kind) {
+        String json = getSchemaFromSchemaService(filename);
+        Map<String, Object> expected = getStorageSchema( filename + ".res");
+        Map<String, Object> converted = schemaToStorageFormatImpl.convertToMap(json, kind);
+
+        compareSchemas(expected, converted, filename);
+    }
+
+    private Map<String, Object> getStorageSchema(String s)  {
+
+        TypeReference<Map<String, Object>> typeRef
+                = new TypeReference<Map<String, Object>>() {
+        };
+        try {
+            return objectMapper.readValue(this.getClass().getResource(s), typeRef);
+        } catch (IOException | IllegalArgumentException e) {
+            fail("Failed to load schema from file:" + s);
+        }
+
+        return null;
+    }
+
+    private String getSchemaFromSchemaService(String s) {
+        try {
+            return new String(Files.readAllBytes(
+                    Paths.get(this.getClass().getResource(s).toURI())), StandardCharsets.UTF_8);
+        } catch (Throwable e) {
+            fail("Failed to read file:" + s);
+        }
+        return null;
+    }
+
+    private void compareSchemas(Map<String, Object> expected, Map<String, Object> converted, String filename) {
+        assertEquals("File:" + filename, expected.size(), converted.size());
+        assertEquals("File:" + filename, expected.get("kind"), converted.get("kind"));
+        ArrayList<Map<String, String>> conv = (ArrayList<Map<String, String>>) converted.get("schema");
+        ArrayList<Map<String, String>> exp = (ArrayList<Map<String, String>>) expected.get("schema");
+
+        checkSchemaIteamsAreEqual(exp, conv, filename);
+    }
+
+    private void checkSchemaIteamsAreEqual(ArrayList<Map<String, String>> exp, List<Map<String, String>> conv, String filename) {
+        assertEquals("File:" + filename, exp.size(), conv.size());
+        conv.forEach((c) -> checkItemIn(c, exp, filename));
+    }
+
+    private void checkItemIn(Map<String, String> item, List<Map<String, String>> exp, String filename) {
+        String itemPath = item.get("path");
+        assertEquals("File:" + filename + ", " + itemPath + " is missed(or too many) see count", exp.stream().filter(e->itemPath.equals(e.get("path"))).count(), 1L);
+        Map<String, String> found =  exp.stream().filter(e->item.get("path").equals(e.get("path"))).findAny().get();
+        assertEquals("File:" + filename + ", in " + itemPath, found.get("kind"), item.get("kind"));
+    }
+}
\ No newline at end of file
diff --git a/indexer-core/src/test/java/org/opengroup/osdu/indexer/service/impl/SchemaProviderImplTest.java b/indexer-core/src/test/java/org/opengroup/osdu/indexer/service/impl/SchemaProviderImplTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..a3c5b46e73f938c8b5824fe484a7aa993919d5a0
--- /dev/null
+++ b/indexer-core/src/test/java/org/opengroup/osdu/indexer/service/impl/SchemaProviderImplTest.java
@@ -0,0 +1,177 @@
+// Copyright 2017-2020, Schlumberger
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.package org.opengroup.osdu.indexer.service.impl;
+
+package org.opengroup.osdu.indexer.service.impl;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.http.HttpStatus;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.*;
+import org.opengroup.osdu.core.common.http.IUrlFetchService;
+import org.opengroup.osdu.core.common.logging.JaxRsDpsLog;
+import org.opengroup.osdu.core.common.model.http.HttpResponse;
+import org.opengroup.osdu.core.common.provider.interfaces.IRequestInfo;
+import org.opengroup.osdu.indexer.config.IndexerConfigurationProperties;
+import org.opengroup.osdu.indexer.schema.converter.SchemaToStorageFormatImpl;
+import org.opengroup.osdu.indexer.service.StorageService;
+import org.powermock.api.mockito.PowerMockito;
+import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URISyntaxException;
+import java.util.Map;
+
+import static org.junit.Assert.*;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.*;
+import static org.powermock.api.mockito.PowerMockito.when;
+
+@RunWith(SpringRunner.class)
+public class SchemaProviderImplTest {
+
+    private ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json().build();
+    private JaxRsDpsLog jaxRsDpsLog = Mockito.mock(JaxRsDpsLog.class);
+
+    @Spy
+    private SchemaToStorageFormatImpl schemaToStorageFormat = new SchemaToStorageFormatImpl(objectMapper, jaxRsDpsLog, null);
+
+    @Mock
+    private IUrlFetchService urlFetchService;
+
+    @Mock
+    private IRequestInfo requestInfo;
+
+    @Mock
+    private StorageService storageService;
+
+    @Mock
+    private IndexerConfigurationProperties configurationProperties;
+
+    @InjectMocks
+    private SchemaProviderImpl sut;
+
+    @Test
+    public void test_empty_schema() throws UnsupportedEncodingException, URISyntaxException {
+        org.opengroup.osdu.core.common.model.http.HttpResponse httpResponse =
+                mock(org.opengroup.osdu.core.common.model.http.HttpResponse.class);
+        when(httpResponse.getResponseCode()).thenReturn(HttpStatus.SC_OK);
+        when(httpResponse.getBody()).thenReturn("{}");
+
+        when(urlFetchService.sendRequest(any())).thenReturn(httpResponse);
+        String schema = sut.getSchema("fake");
+        Assert.assertEquals("{\n" +
+                "  \"kind\" : \"fake\",\n" +
+                "  \"schema\" : [ ]\n" +
+                "}", schema);
+
+    }
+
+    @Test
+    public void should_returnValidResponse_givenValidSchema() throws Exception {
+
+        String validSchemaFromSchemaService = "{\n" +
+                "\"properties\": {" +
+                "   \"data\":{\n" +
+                "      \"allOf\":[\n" +
+                "         {\n" +
+                "            \"type\":\"object\",\n" +
+                "            \"properties\":{\n" +
+                "               \"WellID\":{\n" +
+                "                  \"type\":\"string\",\n" +
+                "                  \"pattern\":\"^srn:<namespace>:master-data\\\\/Well:[^:]+:[0-9]*$\"\n" +
+                "               }\n" +
+                "            }\n" +
+                "         }\n" +
+                "      ]\n" +
+                "   }\n" +
+                "   }\n" +
+                "}";
+        String kind = "tenant:test:test:1.0.0";
+
+        HttpResponse httpResponse = new HttpResponse();
+        httpResponse.setResponseCode(org.springframework.http.HttpStatus.OK.value());
+        httpResponse.setBody(validSchemaFromSchemaService);
+
+        PowerMockito.when(this.urlFetchService.sendRequest(any())).thenReturn(httpResponse);
+
+        String recordSchemaResponse = this.sut.getSchema(kind);
+
+        Map<String, Object> result = objectMapper.readValue(recordSchemaResponse,
+                new TypeReference<Map<String,Object>>(){});
+        assertEquals("Schema must have two root items", 2, result.size());
+        assertEquals("Wrong kind", "tenant:test:test:1.0.0", result.get("kind"));
+        assertEquals("Wrong schema attributes", "[{path=WellID, kind=link}]", result.get("schema").toString());
+
+        assertNotNull(recordSchemaResponse);
+    }
+
+    @Test
+    public void should_returnNullResponse_givenAbsentKind_getSchemaByKind() throws Exception {
+
+        String kind = "tenant:test:test:1.0.0";
+
+        HttpResponse httpResponse = new HttpResponse();
+        httpResponse.setResponseCode(org.springframework.http.HttpStatus.NOT_FOUND.value());
+
+        PowerMockito.when(this.urlFetchService.sendRequest(any())).thenReturn(httpResponse);
+
+        String recordSchemaResponse = this.sut.getSchema(kind);
+
+        assertNull(recordSchemaResponse);
+    }
+
+    @Test
+    public void should_call_Storage_then_Schema() throws Exception {
+        String kind = "tenant:test:test:1.0.0";
+
+        SchemaProviderImpl schemaService = Mockito.mock(SchemaProviderImpl.class);
+        PowerMockito.when(schemaService.getSchema(any())).thenCallRealMethod();
+
+        InOrder inOrder = inOrder(schemaService);
+
+        String recordSchemaResponse = schemaService.getSchema(kind);
+        assertNull(recordSchemaResponse);
+
+        inOrder.verify(schemaService).getSchema(any());
+        inOrder.verify(schemaService).getFromStorageService(any());
+        inOrder.verify(schemaService).getFromSchemaService(any());
+        verify(schemaService, times(1)).getFromStorageService(any());
+        verify(schemaService, times(1)).getFromSchemaService(any());
+    }
+
+    @Test
+    public void should_call_only_Storage_if_it_returns_result() throws Exception {
+        String kind = "tenant:test:test:1.0.0";
+
+        SchemaProviderImpl schemaService = Mockito.mock(SchemaProviderImpl.class);
+        when(schemaService.getSchema(any())).thenCallRealMethod();
+        String someSchema = "some schema";
+        when(schemaService.getFromStorageService(any())).thenReturn(someSchema);
+
+        InOrder inOrder = inOrder(schemaService);
+
+        String recordSchemaResponse = schemaService.getSchema(kind);
+        assertEquals(recordSchemaResponse, someSchema);
+
+        inOrder.verify(schemaService).getSchema(any());
+        inOrder.verify(schemaService).getFromStorageService(any());
+        verify(schemaService, times(0)).getFromSchemaService(any());
+        verify(schemaService, times(1)).getFromStorageService(any());
+    }
+
+}
\ No newline at end of file
diff --git a/indexer-core/src/test/java/org/opengroup/osdu/indexer/util/ElasticClientHandlerTest.java b/indexer-core/src/test/java/org/opengroup/osdu/indexer/util/ElasticClientHandlerTest.java
index e5782165553a1efd1a5a39a3ffa6891696371993..effda48aaef31616b6f583844fdadbd31276747a 100644
--- a/indexer-core/src/test/java/org/opengroup/osdu/indexer/util/ElasticClientHandlerTest.java
+++ b/indexer-core/src/test/java/org/opengroup/osdu/indexer/util/ElasticClientHandlerTest.java
@@ -19,29 +19,30 @@ import org.elasticsearch.client.RestClient;
 import org.elasticsearch.client.RestClientBuilder;
 import org.elasticsearch.client.RestHighLevelClient;
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
-import org.opengroup.osdu.core.common.model.http.AppException;
 import org.opengroup.osdu.core.common.logging.JaxRsDpsLog;
+import org.opengroup.osdu.core.common.model.http.AppException;
 import org.opengroup.osdu.core.common.model.indexer.IElasticSettingService;
 import org.opengroup.osdu.core.common.model.search.ClusterSettings;
 import org.opengroup.osdu.core.common.model.search.DeploymentEnvironment;
 import org.opengroup.osdu.indexer.config.IndexerConfigurationProperties;
 import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.springframework.test.context.junit4.SpringRunner;
+import org.powermock.modules.junit4.PowerMockRunner;
 
 import static org.junit.Assert.assertEquals;
 import static org.mockito.Mockito.when;
 import static org.mockito.MockitoAnnotations.initMocks;
+import static org.powermock.api.mockito.PowerMockito.mockStatic;
 
-@Ignore
-@RunWith(SpringRunner.class)
-@PrepareForTest({RestClientBuilder.class, RestClient.class, RestHighLevelClient.class})
+@RunWith(PowerMockRunner.class)
+@PrepareForTest({RestClient.class, RestHighLevelClient.class})
 public class ElasticClientHandlerTest {
 
+    private static final boolean SECURITY_HTTPS_CERTIFICATE_TRUST = false;
+
     @Mock
     private IndexerConfigurationProperties configurationProperties;
     @Mock
@@ -62,7 +63,9 @@ public class ElasticClientHandlerTest {
     public void setup() {
         initMocks(this);
 
-//        mockStatic(RestClient.class);
+        mockStatic(RestClient.class);
+
+        elasticClientHandler.setSecurityHttpsCertificateTrust(SECURITY_HTTPS_CERTIFICATE_TRUST);
     }
 
     @Test
@@ -70,7 +73,7 @@ public class ElasticClientHandlerTest {
         ClusterSettings clusterSettings = new ClusterSettings("H", 1, "U:P");
         when(configurationProperties.getDeploymentEnvironment()).thenReturn(DeploymentEnvironment.CLOUD);
         when(elasticSettingService.getElasticClusterInformation()).thenReturn(clusterSettings);
-        when(RestClient.builder(new HttpHost("H", 1, "https"))).thenReturn(builder);
+        when(RestClient.builder(new HttpHost("H", 1, "https"))).thenAnswer(invocation -> builder);
         when(builder.setRequestConfigCallback(requestConfigBuilder -> requestConfigBuilder.setConnectTimeout(5000).setSocketTimeout(60000))).thenReturn(builder);
         when(builder.build()).thenReturn(restClient);
 
@@ -84,7 +87,7 @@ public class ElasticClientHandlerTest {
         ClusterSettings clusterSettings = new ClusterSettings("H", 1, "U:P");
         when(configurationProperties.getDeploymentEnvironment()).thenReturn(DeploymentEnvironment.CLOUD);
         when(elasticSettingService.getElasticClusterInformation()).thenReturn(clusterSettings);
-        when(RestClient.builder(new HttpHost("H", 1, "https"))).thenReturn(builder);
+        when(RestClient.builder(new HttpHost("H", 1, "https"))).thenAnswer(invocation -> builder);
         when(builder.build()).thenReturn(null);
 
         this.elasticClientHandler.createRestClient();
@@ -94,7 +97,7 @@ public class ElasticClientHandlerTest {
     public void failed_createRestClientForSaaS_when_getcluster_info_throws_exception() {
         when(configurationProperties.getDeploymentEnvironment()).thenReturn(DeploymentEnvironment.CLOUD);
         when(elasticSettingService.getElasticClusterInformation()).thenThrow(new AppException(1, "", ""));
-        when(RestClient.builder(new HttpHost("H", 1, "https"))).thenReturn(builder);
+        when(RestClient.builder(new HttpHost("H", 1, "https"))).thenAnswer(invocation -> builder);
 
         this.elasticClientHandler.createRestClient();
     }
diff --git a/indexer-core/src/test/resources/converter/R3-json-schema/Generated/data-collection/DataCollection.1.0.0.json b/indexer-core/src/test/resources/converter/R3-json-schema/Generated/data-collection/DataCollection.1.0.0.json
new file mode 100644
index 0000000000000000000000000000000000000000..a1a0368eb20d203ccfcc27f06bd755cc019fa3eb
--- /dev/null
+++ b/indexer-core/src/test/resources/converter/R3-json-schema/Generated/data-collection/DataCollection.1.0.0.json
@@ -0,0 +1,198 @@
+{
+  "x-osdu-license": "Copyright 2020, The Open Group \\nLicensed 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.",
+  "$id": "https://schema.osdu.opengroup.org/json/data-collection/DataCollection.1.0.0.json",
+  "$schema": "http://json-schema.org/draft-07/schema#",
+  "title": "DataCollection",
+  "description": "A data collection entity.",
+  "type": "object",
+  "properties": {
+    "id": {
+      "description": "Previously called ResourceID or SRN which identifies this OSDU resource object without version.",
+      "title": "Entity ID",
+      "type": "string",
+      "pattern": "^srn:<namespace>:data-collection\\/DataCollection:[^:]+$",
+      "example": "srn:<namespace>:data-collection/DataCollection:38d256ba-2ac2-501d-8a05-4be98c245e0e"
+    },
+    "kind": {
+      "description": "The schema identification for the OSDU resource object following the pattern <Namespace>:<Source>:<Type>:<VersionMajor>.<VersionMinor>.<VersionPatch>. The versioning scheme follows the semantic versioning, https://semver.org/.",
+      "title": "Entity Kind",
+      "type": "string",
+      "pattern": "^[A-Za-z0-9-_]+:[A-Za-z0-9-_]+:[A-Za-z0-9-_]+:[0-9]+.[0-9]+.[0-9]+$",
+      "example": "namespace:osdu:DataCollection:2.7.112"
+    },
+    "groupType": {
+      "description": "The OSDU group-type assigned to this resource object.",
+      "title": "Group Type",
+      "const": "data-collection"
+    },
+    "version": {
+      "description": "The version number of this OSDU resource; set by the framework.",
+      "title": "Version Number",
+      "type": "integer",
+      "format": "int64",
+      "example": 1562066009929332
+    },
+    "acl": {
+      "description": "The access control tags associated with this entity.",
+      "title": "Access Control List",
+      "$ref": "../abstract/AbstractAccessControlList.1.0.0.json"
+    },
+    "legal": {
+      "description": "The entity's legal tags and compliance status. The actual contents associated with the legal tags is managed by the Compliance Service.",
+      "title": "Legal Tags",
+      "$ref": "../abstract/AbstractLegalTags.1.0.0.json"
+    },
+    "resourceHomeRegionID": {
+      "description": "The name of the home [cloud environment] region for this OSDU resource object.",
+      "title": "Resource Home Region ID",
+      "type": "string",
+      "pattern": "^srn:<namespace>:reference-data\\/OSDURegion:[^:]+:[0-9]*$"
+    },
+    "resourceHostRegionIDs": {
+      "description": "The name of the host [cloud environment] region(s) for this OSDU resource object.",
+      "title": "Resource Host Region ID",
+      "type": "array",
+      "items": {
+        "type": "string",
+        "pattern": "^srn:<namespace>:reference-data\\/OSDURegion:[^:]+:[0-9]*$"
+      }
+    },
+    "resourceObjectCreationDateTime": {
+      "description": "Timestamp of the time at which Version 1 of this OSDU resource object was originated.",
+      "title": "Resource Object Creation DateTime",
+      "type": "string",
+      "format": "date-time"
+    },
+    "resourceVersionCreationDateTime": {
+      "description": "Timestamp of the time when the current version of this resource entered the OSDU.",
+      "title": "Resource Version Creation DateTime",
+      "type": "string",
+      "format": "date-time"
+    },
+    "resourceCurationStatus": {
+      "description": "Describes the current Curation status.",
+      "title": "Resource Curation Status",
+      "type": "string",
+      "pattern": "^srn:<namespace>:reference-data\\/ResourceCurationStatus:[^:]+:[0-9]*$"
+    },
+    "resourceLifecycleStatus": {
+      "description": "Describes the current Resource Lifecycle status.",
+      "title": "Resource Lifecycle Status",
+      "type": "string",
+      "pattern": "^srn:<namespace>:reference-data\\/ResourceLifecycleStatus:[^:]+:[0-9]*$"
+    },
+    "resourceSecurityClassification": {
+      "description": "Classifies the security level of the resource.",
+      "title": "Resource Security Classification",
+      "type": "string",
+      "pattern": "^srn:<namespace>:reference-data\\/ResourceSecurityClassification:[^:]+:[0-9]*$"
+    },
+    "ancestry": {
+      "description": "The links to data, which constitute the inputs.",
+      "title": "Ancestry",
+      "$ref": "../abstract/AbstractLegalParentList.1.0.0.json"
+    },
+    "meta": {
+      "description": "The Frame of Reference meta data section linking the named properties to self-contained definitions.",
+      "title": "Frame of Reference Meta Data",
+      "type": "array",
+      "items": {
+        "$ref": "../abstract/AbstractMetaItem.1.0.0.json"
+      }
+    },
+    "source": {
+      "description": "The entity that produced the record, or from which it is received; could be an organization, agency, system, internal team, or individual. For informational purposes only, the list of sources is not governed.",
+      "title": "Data Source",
+      "type": "string"
+    },
+    "existenceKind": {
+      "description": "Where does this data resource sit in the cradle-to-grave span of its existence?",
+      "title": "Existence Kind",
+      "type": "string",
+      "pattern": "^srn:<namespace>:reference-data\\/ExistenceKind:[^:]+:[0-9]*$"
+    },
+    "data": {
+      "allOf": [
+        {
+          "type": "object",
+          "properties": {
+            "Resources": {
+              "description": "List of Resources",
+              "type": "array",
+              "items": {
+                "type": "string",
+                "pattern": "^srn:<namespace>:(?:work-product(?:-component)?|data-collection)\\/[A-Za-z0-9]+:[^:]+:[0-9]*$"
+              }
+            },
+            "Name": {
+              "type": "string",
+              "description": "Name"
+            },
+            "Description": {
+              "type": "string",
+              "description": "Description"
+            },
+            "CreationDateTime": {
+              "type": "string",
+              "format": "date-time",
+              "description": "Creation DateTime"
+            },
+            "Tags": {
+              "type": "array",
+              "description": "Array of Tag Names",
+              "items": {
+                "type": "string"
+              }
+            },
+            "SubmitterName": {
+              "type": "string",
+              "description": "Submitter Name"
+            },
+            "AuthorIDs": {
+              "type": "array",
+              "description": "Array of Author IDs",
+              "items": {
+                "type": "string"
+              }
+            },
+            "OwnerID": {
+              "description": "ID of the User who owns the Collection",
+              "type": "string"
+            },
+            "WorkSpaceID": {
+              "description": "Collection Workspace",
+              "type": "string",
+              "pattern": "^srn:<namespace>:workspace\\/[A-Za-z0-9]+:[^:]+:[0-9]*$"
+            },
+            "FilterSpecification": {
+              "description": "Collection Filter Specification",
+              "type": "object",
+              "properties": {}
+            }
+          },
+          "required": [
+            "Resources",
+            "Name",
+            "OwnerID"
+          ]
+        },
+        {
+          "type": "object",
+          "properties": {
+            "ExtensionProperties": {
+              "type": "object",
+              "properties": {}
+            }
+          }
+        }
+      ]
+    }
+  },
+  "required": [
+    "kind",
+    "acl",
+    "groupType",
+    "legal"
+  ],
+  "additionalProperties": false
+}
\ No newline at end of file
diff --git a/indexer-core/src/test/resources/converter/R3-json-schema/Generated/data-collection/DataCollection.1.0.0.json.res b/indexer-core/src/test/resources/converter/R3-json-schema/Generated/data-collection/DataCollection.1.0.0.json.res
new file mode 100644
index 0000000000000000000000000000000000000000..8d4bc4b7043ddb4c0f8cd8e254b1bedb757eb7ed
--- /dev/null
+++ b/indexer-core/src/test/resources/converter/R3-json-schema/Generated/data-collection/DataCollection.1.0.0.json.res
@@ -0,0 +1,41 @@
+{
+  "kind": "osdu:osdu:Wellbore:1.0.0",
+  "schema": [
+    {
+      "kind": "[]link",
+      "path": "Resources"
+    },
+    {
+      "kind": "string",
+      "path": "Name"
+    },
+    {
+      "kind": "string",
+      "path": "Description"
+    },
+    {
+      "kind": "datetime",
+      "path": "CreationDateTime"
+    },
+    {
+      "kind": "[]string",
+      "path": "Tags"
+    },
+    {
+      "kind": "string",
+      "path": "SubmitterName"
+    },
+    {
+      "kind": "[]string",
+      "path": "AuthorIDs"
+    },
+    {
+      "kind": "string",
+      "path": "OwnerID"
+    },
+    {
+      "kind": "link",
+      "path": "WorkSpaceID"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/indexer-core/src/test/resources/converter/R3-json-schema/Generated/file/File.1.0.0.json b/indexer-core/src/test/resources/converter/R3-json-schema/Generated/file/File.1.0.0.json
new file mode 100644
index 0000000000000000000000000000000000000000..737a51026038f90f657d2f7aba58a8c35fc107c8
--- /dev/null
+++ b/indexer-core/src/test/resources/converter/R3-json-schema/Generated/file/File.1.0.0.json
@@ -0,0 +1,233 @@
+{
+  "x-osdu-license": "Copyright 2020, The Open Group \\nLicensed 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.",
+  "$id": "https://schema.osdu.opengroup.org/json/file/File.1.0.0.json",
+  "$schema": "http://json-schema.org/draft-07/schema#",
+  "title": "File",
+  "description": "The generic file entity.",
+  "type": "object",
+  "properties": {
+    "id": {
+      "description": "Previously called ResourceID or SRN which identifies this OSDU resource object without version.",
+      "title": "Entity ID",
+      "type": "string",
+      "pattern": "^srn:<namespace>:file\\/File:[^:]+$",
+      "example": "srn:<namespace>:file/File:6039b91f-04a5-5c02-b4ed-413f565e561c"
+    },
+    "kind": {
+      "description": "The schema identification for the OSDU resource object following the pattern <Namespace>:<Source>:<Type>:<VersionMajor>.<VersionMinor>.<VersionPatch>. The versioning scheme follows the semantic versioning, https://semver.org/.",
+      "title": "Entity Kind",
+      "type": "string",
+      "pattern": "^[A-Za-z0-9-_]+:[A-Za-z0-9-_]+:[A-Za-z0-9-_]+:[0-9]+.[0-9]+.[0-9]+$",
+      "example": "namespace:osdu:File:2.7.112"
+    },
+    "groupType": {
+      "description": "The OSDU group-type assigned to this resource object.",
+      "title": "Group Type",
+      "const": "file"
+    },
+    "version": {
+      "description": "The version number of this OSDU resource; set by the framework.",
+      "title": "Version Number",
+      "type": "integer",
+      "format": "int64",
+      "example": 1562066009929332
+    },
+    "acl": {
+      "description": "The access control tags associated with this entity.",
+      "title": "Access Control List",
+      "$ref": "../abstract/AbstractAccessControlList.1.0.0.json"
+    },
+    "legal": {
+      "description": "The entity's legal tags and compliance status. The actual contents associated with the legal tags is managed by the Compliance Service.",
+      "title": "Legal Tags",
+      "$ref": "../abstract/AbstractLegalTags.1.0.0.json"
+    },
+    "resourceHomeRegionID": {
+      "description": "The name of the home [cloud environment] region for this OSDU resource object.",
+      "title": "Resource Home Region ID",
+      "type": "string",
+      "pattern": "^srn:<namespace>:reference-data\\/OSDURegion:[^:]+:[0-9]*$"
+    },
+    "resourceHostRegionIDs": {
+      "description": "The name of the host [cloud environment] region(s) for this OSDU resource object.",
+      "title": "Resource Host Region ID",
+      "type": "array",
+      "items": {
+        "type": "string",
+        "pattern": "^srn:<namespace>:reference-data\\/OSDURegion:[^:]+:[0-9]*$"
+      }
+    },
+    "resourceObjectCreationDateTime": {
+      "description": "Timestamp of the time at which Version 1 of this OSDU resource object was originated.",
+      "title": "Resource Object Creation DateTime",
+      "type": "string",
+      "format": "date-time"
+    },
+    "resourceVersionCreationDateTime": {
+      "description": "Timestamp of the time when the current version of this resource entered the OSDU.",
+      "title": "Resource Version Creation DateTime",
+      "type": "string",
+      "format": "date-time"
+    },
+    "resourceCurationStatus": {
+      "description": "Describes the current Curation status.",
+      "title": "Resource Curation Status",
+      "type": "string",
+      "pattern": "^srn:<namespace>:reference-data\\/ResourceCurationStatus:[^:]+:[0-9]*$"
+    },
+    "resourceLifecycleStatus": {
+      "description": "Describes the current Resource Lifecycle status.",
+      "title": "Resource Lifecycle Status",
+      "type": "string",
+      "pattern": "^srn:<namespace>:reference-data\\/ResourceLifecycleStatus:[^:]+:[0-9]*$"
+    },
+    "resourceSecurityClassification": {
+      "description": "Classifies the security level of the resource.",
+      "title": "Resource Security Classification",
+      "type": "string",
+      "pattern": "^srn:<namespace>:reference-data\\/ResourceSecurityClassification:[^:]+:[0-9]*$"
+    },
+    "ancestry": {
+      "description": "The links to data, which constitute the inputs.",
+      "title": "Ancestry",
+      "$ref": "../abstract/AbstractLegalParentList.1.0.0.json"
+    },
+    "meta": {
+      "description": "The Frame of Reference meta data section linking the named properties to self-contained definitions.",
+      "title": "Frame of Reference Meta Data",
+      "type": "array",
+      "items": {
+        "$ref": "../abstract/AbstractMetaItem.1.0.0.json"
+      }
+    },
+    "source": {
+      "description": "The entity that produced the record, or from which it is received; could be an organization, agency, system, internal team, or individual. For informational purposes only, the list of sources is not governed.",
+      "title": "Data Source",
+      "type": "string"
+    },
+    "existenceKind": {
+      "description": "Where does this data resource sit in the cradle-to-grave span of its existence?",
+      "title": "Existence Kind",
+      "type": "string",
+      "pattern": "^srn:<namespace>:reference-data\\/ExistenceKind:[^:]+:[0-9]*$"
+    },
+    "data": {
+      "allOf": [
+        {
+          "type": "object",
+          "properties": {
+            "SchemaFormatTypeID": {
+              "type": "string",
+              "description": "Schema Format Type ID",
+              "pattern": "^srn:<namespace>:reference-data\\/SchemaFormatType:[^:]+:[0-9]*$"
+            },
+            "PreLoadFilePath": {
+              "description": "File system path to the data file as it existed before loading to the data platform",
+              "type": "string"
+            },
+            "FileSource": {
+              "description": "URL or file path for the data in the file",
+              "type": "string"
+            },
+            "FileSize": {
+              "description": "Length of file in bytes",
+              "type": "integer"
+            },
+            "EncodingFormatTypeID": {
+              "type": "string",
+              "description": "Encoding Format Type ID",
+              "pattern": "^srn:<namespace>:reference-data\\/EncodingFormatType:[^:]+:[0-9]*$"
+            },
+            "Endian": {
+              "description": "Endianness of binary value.  Enumeration: \"BIG\", \"LITTLE\".  If absent, applications will need to interpret from context indicators.",
+              "type": "string",
+              "enum": [
+                "BIG",
+                "LITTLE"
+              ]
+            },
+            "LossyCompressionIndicator": {
+              "description": "Boolean that warns that an imperfect compression algorithm has been applied to the bulk binary data.  Details of the compression method need to be discovered from the format properties and file access methods.",
+              "type": "boolean"
+            },
+            "CompressionMethodTypeID": {
+              "type": "string",
+              "description": "Name of a compression algorithm applied to the data as stored.",
+              "pattern": "^srn:<namespace>:reference-data\\/CompressionMethodType:[^:]+:[0-9]*$"
+            },
+            "CompressionLevel": {
+              "description": "Number indicating degree of fidelity present in bulk data resulting from compression.  Meaning of number depends on algorithm.",
+              "type": "number"
+            },
+            "Checksum": {
+              "description": "MD5 checksum of file bytes - a 32 byte hexadecimal number",
+              "type": "string",
+              "pattern": "^[0-9a-fA-F]{32}$"
+            },
+            "VectorHeaderMapping": {
+              "description": "Array of objects which define the meaning and format of a tabular structure used in a binary file as a header.  The initial use case is the trace headers of a SEG-Y file.  Note that some of this information may be repeated in the SEG-Y EBCDIC header.",
+              "type": "array",
+              "items": {
+                "type": "object",
+                "properties": {
+                  "KeyName": {
+                    "description": "SRN of a reference value for a name of a property header such as INLINE, CDPX.",
+                    "type": "string",
+                    "pattern": "^srn:<namespace>:reference-data\\/HeaderKeyName:[^:]+:[0-9]*$"
+                  },
+                  "WordFormat": {
+                    "description": "SRN of a reference value for binary data types, such as INT, UINT, FLOAT, IBM_FLOAT, ASCII, EBCDIC.",
+                    "type": "string",
+                    "pattern": "^srn:<namespace>:reference-data\\/WordFormatType:[^:]+:[0-9]*$"
+                  },
+                  "WordWidth": {
+                    "description": "Size of the word in bytes.",
+                    "type": "integer"
+                  },
+                  "Position": {
+                    "description": "Beginning byte position of header value, 1 indexed.",
+                    "type": "integer"
+                  },
+                  "UoM": {
+                    "description": "SRN to units of measure reference if header standard is not followed.",
+                    "type": "string",
+                    "pattern": "^srn:<namespace>:reference-data\\/UnitOfMeasure:[^:]+:[0-9]*$"
+                  },
+                  "ScalarIndicator": {
+                    "description": "Enumerated string indicating whether to use the normal scalar field for scaling this field (STANDARD), no scaling (NOSCALE), or override scalar (OVERRIDE).  Default is current STANDARD (such as SEG-Y rev2).",
+                    "type": "string",
+                    "enum": [
+                      "STANDARD",
+                      "NOSCALE",
+                      "OVERRIDE"
+                    ]
+                  },
+                  "ScalarOverride": {
+                    "description": "Scalar value (as defined by standard) when a value present in the header needs to be overwritten for this value.",
+                    "type": "number"
+                  }
+                }
+              }
+            }
+          }
+        },
+        {
+          "type": "object",
+          "properties": {
+            "ExtensionProperties": {
+              "type": "object",
+              "properties": {}
+            }
+          }
+        }
+      ]
+    }
+  },
+  "required": [
+    "kind",
+    "acl",
+    "groupType",
+    "legal"
+  ],
+  "additionalProperties": false
+}
\ No newline at end of file
diff --git a/indexer-core/src/test/resources/converter/R3-json-schema/Generated/file/File.1.0.0.json.res b/indexer-core/src/test/resources/converter/R3-json-schema/Generated/file/File.1.0.0.json.res
new file mode 100644
index 0000000000000000000000000000000000000000..b0f71fc6fd26e27eb5dc2362e7667aa1d17c481e
--- /dev/null
+++ b/indexer-core/src/test/resources/converter/R3-json-schema/Generated/file/File.1.0.0.json.res
@@ -0,0 +1,45 @@
+{
+  "kind": "osdu:osdu:Wellbore:1.0.0",
+  "schema": [
+    {
+      "kind": "link",
+      "path": "SchemaFormatTypeID"
+    },
+    {
+      "kind": "string",
+      "path": "PreLoadFilePath"
+    },
+    {
+      "kind": "string",
+      "path": "FileSource"
+    },
+    {
+      "kind": "int",
+      "path": "FileSize"
+    },
+    {
+      "kind": "link",
+      "path": "EncodingFormatTypeID"
+    },
+    {
+      "kind": "string",
+      "path": "Endian"
+    },
+    {
+      "kind": "bool",
+      "path": "LossyCompressionIndicator"
+    },
+    {
+      "kind": "link",
+      "path": "CompressionMethodTypeID"
+    },
+    {
+      "kind": "double",
+      "path": "CompressionLevel"
+    },
+    {
+      "kind": "string",
+      "path": "Checksum"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/indexer-core/src/test/resources/converter/R3-json-schema/Generated/master-data/Agreement.1.0.0.json b/indexer-core/src/test/resources/converter/R3-json-schema/Generated/master-data/Agreement.1.0.0.json
new file mode 100644
index 0000000000000000000000000000000000000000..21fcb511d17f434eb7f1d8f9b4b413ca87a17b4d
--- /dev/null
+++ b/indexer-core/src/test/resources/converter/R3-json-schema/Generated/master-data/Agreement.1.0.0.json
@@ -0,0 +1,221 @@
+{
+  "x-osdu-license": "Copyright 2020, The Open Group \\nLicensed 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.",
+  "$id": "https://schema.osdu.opengroup.org/json/master-data/Agreement.1.0.0.json",
+  "$schema": "http://json-schema.org/draft-07/schema#",
+  "title": "Agreement",
+  "description": "A contract or other covenant between Company and counterparties which is relevant to the data universe because it includes terms governing use of data.",
+  "type": "object",
+  "properties": {
+    "id": {
+      "description": "Previously called ResourceID or SRN which identifies this OSDU resource object without version.",
+      "title": "Entity ID",
+      "type": "string",
+      "pattern": "^srn:<namespace>:master-data\\/Agreement:[^:]+$",
+      "example": "srn:<namespace>:master-data/Agreement:727de5db-ff06-53a8-95af-a24816e1e96a"
+    },
+    "kind": {
+      "description": "The schema identification for the OSDU resource object following the pattern <Namespace>:<Source>:<Type>:<VersionMajor>.<VersionMinor>.<VersionPatch>. The versioning scheme follows the semantic versioning, https://semver.org/.",
+      "title": "Entity Kind",
+      "type": "string",
+      "pattern": "^[A-Za-z0-9-_]+:[A-Za-z0-9-_]+:[A-Za-z0-9-_]+:[0-9]+.[0-9]+.[0-9]+$",
+      "example": "namespace:osdu:Agreement:2.7.112"
+    },
+    "groupType": {
+      "description": "The OSDU group-type assigned to this resource object.",
+      "title": "Group Type",
+      "const": "master-data"
+    },
+    "version": {
+      "description": "The version number of this OSDU resource; set by the framework.",
+      "title": "Version Number",
+      "type": "integer",
+      "format": "int64",
+      "example": 1562066009929332
+    },
+    "acl": {
+      "description": "The access control tags associated with this entity.",
+      "title": "Access Control List",
+      "$ref": "../abstract/AbstractAccessControlList.1.0.0.json"
+    },
+    "legal": {
+      "description": "The entity's legal tags and compliance status. The actual contents associated with the legal tags is managed by the Compliance Service.",
+      "title": "Legal Tags",
+      "$ref": "../abstract/AbstractLegalTags.1.0.0.json"
+    },
+    "resourceHomeRegionID": {
+      "description": "The name of the home [cloud environment] region for this OSDU resource object.",
+      "title": "Resource Home Region ID",
+      "type": "string",
+      "pattern": "^srn:<namespace>:reference-data\\/OSDURegion:[^:]+:[0-9]*$"
+    },
+    "resourceHostRegionIDs": {
+      "description": "The name of the host [cloud environment] region(s) for this OSDU resource object.",
+      "title": "Resource Host Region ID",
+      "type": "array",
+      "items": {
+        "type": "string",
+        "pattern": "^srn:<namespace>:reference-data\\/OSDURegion:[^:]+:[0-9]*$"
+      }
+    },
+    "resourceObjectCreationDateTime": {
+      "description": "Timestamp of the time at which Version 1 of this OSDU resource object was originated.",
+      "title": "Resource Object Creation DateTime",
+      "type": "string",
+      "format": "date-time"
+    },
+    "resourceVersionCreationDateTime": {
+      "description": "Timestamp of the time when the current version of this resource entered the OSDU.",
+      "title": "Resource Version Creation DateTime",
+      "type": "string",
+      "format": "date-time"
+    },
+    "resourceCurationStatus": {
+      "description": "Describes the current Curation status.",
+      "title": "Resource Curation Status",
+      "type": "string",
+      "pattern": "^srn:<namespace>:reference-data\\/ResourceCurationStatus:[^:]+:[0-9]*$"
+    },
+    "resourceLifecycleStatus": {
+      "description": "Describes the current Resource Lifecycle status.",
+      "title": "Resource Lifecycle Status",
+      "type": "string",
+      "pattern": "^srn:<namespace>:reference-data\\/ResourceLifecycleStatus:[^:]+:[0-9]*$"
+    },
+    "resourceSecurityClassification": {
+      "description": "Classifies the security level of the resource.",
+      "title": "Resource Security Classification",
+      "type": "string",
+      "pattern": "^srn:<namespace>:reference-data\\/ResourceSecurityClassification:[^:]+:[0-9]*$"
+    },
+    "ancestry": {
+      "description": "The links to data, which constitute the inputs.",
+      "title": "Ancestry",
+      "$ref": "../abstract/AbstractLegalParentList.1.0.0.json"
+    },
+    "meta": {
+      "description": "The Frame of Reference meta data section linking the named properties to self-contained definitions.",
+      "title": "Frame of Reference Meta Data",
+      "type": "array",
+      "items": {
+        "$ref": "../abstract/AbstractMetaItem.1.0.0.json"
+      }
+    },
+    "source": {
+      "description": "The entity that produced the record, or from which it is received; could be an organization, agency, system, internal team, or individual. For informational purposes only, the list of sources is not governed.",
+      "title": "Data Source",
+      "type": "string"
+    },
+    "existenceKind": {
+      "description": "Where does this data resource sit in the cradle-to-grave span of its existence?",
+      "title": "Existence Kind",
+      "type": "string",
+      "pattern": "^srn:<namespace>:reference-data\\/ExistenceKind:[^:]+:[0-9]*$"
+    },
+    "data": {
+      "allOf": [
+        {
+          "type": "object",
+          "properties": {
+            "AgreementIdentifier": {
+              "description": "Natural unique identifier of an agreement.",
+              "type": "string"
+            },
+            "AgreementName": {
+              "description": "Familiar name of agreement.  May be a code name for highly restricted agreements.",
+              "type": "string"
+            },
+            "AgreementExternalID": {
+              "description": "Unique identifier of agreement in Company contracts system of record.",
+              "type": "string"
+            },
+            "AgreementExternalSystem": {
+              "description": "Name of Company contracts system of record containing authorized version of agreement.",
+              "type": "string"
+            },
+            "AgreementParentID": {
+              "type": "string",
+              "description": "Reference to master agreement or other parental agreement in a hierarchy of related agreements.",
+              "pattern": "^srn:<namespace>:master-data\\/Agreement:[^:]+:[0-9]+$"
+            },
+            "AgreementTypeID": {
+              "type": "string",
+              "description": "General purpose of agreement, such as license, purchase, trade, NDA.",
+              "pattern": "^srn:<namespace>:reference-data\\/AgreementType:[^:]+:[0-9]*$"
+            },
+            "EffectiveDate": {
+              "description": "The Date when the agreement was put in force.",
+              "type": "string",
+              "format": "date-time"
+            },
+            "Counterparties": {
+              "description": "A list of references to legal entities which are party to the agreement in addition to Company.",
+              "type": "array",
+              "items": {
+                "type": "string",
+                "pattern": "^srn:<namespace>:master-data\\/Organisation:[^:]+:[0-9]*$"
+              }
+            },
+            "Terms": {
+              "description": "A list of obligations or allowed activities specified by the agreement that apply to stored resources.  These are translated into rules, which the Entitlement Rulebase enforces.  Each rule should reference the agreement it codifies.",
+              "type": "array",
+              "items": {
+                "type": "object",
+                "properties": {
+                  "ObligationTypeID": {
+                    "description": "Reference to the general class of obligation, such as nondisclosure, termination of use, non-assignment, export restriction, limitation on derivatives.",
+                    "type": "string",
+                    "pattern": "^srn:<namespace>:reference-data\\/ObligationType:[^:]+:[0-9]*$"
+                  },
+                  "ObligationDescription": {
+                    "description": "Lengthy description of a legal restriction imposed on data governed by the agreement.",
+                    "type": "string"
+                  },
+                  "StartDate": {
+                    "description": "The Date when the obligation becomes enforceable.",
+                    "type": "string",
+                    "format": "date-time"
+                  },
+                  "EndDate": {
+                    "description": "The Date when the obligation no longer needs to be fulfilled.",
+                    "type": "string",
+                    "format": "date-time"
+                  }
+                }
+              }
+            },
+            "RestrictedResources": {
+              "description": "A list of Resources that are governed by the agreement.  Note that different terms may apply to different resources, but that granularity is handled by the Entitlements Rulebase.",
+              "type": "array",
+              "items": {
+                "type": "object",
+                "properties": {
+                  "ResourceID": {
+                    "description": "Reference to an information Resource which is governed by the agreement.",
+                    "type": "string",
+                    "pattern": "^srn:<namespace>:[A-Za-z-]+\\/[A-Za-z0-9]+:[^:]+:[0-9]+$"
+                  }
+                }
+              }
+            }
+          }
+        },
+        {
+          "type": "object",
+          "properties": {
+            "ExtensionProperties": {
+              "type": "object",
+              "properties": {}
+            }
+          }
+        }
+      ]
+    }
+  },
+  "required": [
+    "kind",
+    "acl",
+    "groupType",
+    "legal"
+  ],
+  "additionalProperties": false
+}
\ No newline at end of file
diff --git a/indexer-core/src/test/resources/converter/R3-json-schema/Generated/master-data/Agreement.1.0.0.json.res b/indexer-core/src/test/resources/converter/R3-json-schema/Generated/master-data/Agreement.1.0.0.json.res
new file mode 100644
index 0000000000000000000000000000000000000000..136ed0b7ecb61b50f82b8d8e213db03ab410f8da
--- /dev/null
+++ b/indexer-core/src/test/resources/converter/R3-json-schema/Generated/master-data/Agreement.1.0.0.json.res
@@ -0,0 +1,37 @@
+{
+  "kind": "osdu:osdu:Wellbore:1.0.0",
+  "schema": [
+    {
+      "kind": "string",
+      "path": "AgreementIdentifier"
+    },
+    {
+      "kind": "string",
+      "path": "AgreementName"
+    },
+    {
+      "kind": "string",
+      "path": "AgreementExternalID"
+    },
+    {
+      "kind": "string",
+      "path": "AgreementExternalSystem"
+    },
+    {
+      "kind": "link",
+      "path": "AgreementParentID"
+    },
+    {
+      "kind": "link",
+      "path": "AgreementTypeID"
+    },
+    {
+      "kind": "datetime",
+      "path": "EffectiveDate"
+    },
+    {
+      "kind": "[]link",
+      "path": "Counterparties"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/indexer-core/src/test/resources/converter/R3-json-schema/Generated/type/Type.1.0.0.json b/indexer-core/src/test/resources/converter/R3-json-schema/Generated/type/Type.1.0.0.json
new file mode 100644
index 0000000000000000000000000000000000000000..1e888792bf841a13bc2989d3f721b46927b5a2c9
--- /dev/null
+++ b/indexer-core/src/test/resources/converter/R3-json-schema/Generated/type/Type.1.0.0.json
@@ -0,0 +1,202 @@
+{
+  "x-osdu-license": "Copyright 2020, The Open Group \\nLicensed 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.",
+  "$id": "https://schema.osdu.opengroup.org/json/type/Type.1.0.0.json",
+  "$schema": "http://json-schema.org/draft-07/schema#",
+  "title": "Type",
+  "description": "The generic type entity.",
+  "type": "object",
+  "properties": {
+    "id": {
+      "description": "Previously called ResourceID or SRN which identifies this OSDU resource object without version.",
+      "title": "Entity ID",
+      "type": "string",
+      "pattern": "^srn:<namespace>:type\\/Type:[^:]+$",
+      "example": "srn:<namespace>:type/Type:918547c4-9284-5211-afcf-dcb6e7ddc12b"
+    },
+    "kind": {
+      "description": "The schema identification for the OSDU resource object following the pattern <Namespace>:<Source>:<Type>:<VersionMajor>.<VersionMinor>.<VersionPatch>. The versioning scheme follows the semantic versioning, https://semver.org/.",
+      "title": "Entity Kind",
+      "type": "string",
+      "pattern": "^[A-Za-z0-9-_]+:[A-Za-z0-9-_]+:[A-Za-z0-9-_]+:[0-9]+.[0-9]+.[0-9]+$",
+      "example": "namespace:osdu:Type:2.7.112"
+    },
+    "groupType": {
+      "description": "The OSDU group-type assigned to this resource object.",
+      "title": "Group Type",
+      "const": "type"
+    },
+    "version": {
+      "description": "The version number of this OSDU resource; set by the framework.",
+      "title": "Version Number",
+      "type": "integer",
+      "format": "int64",
+      "example": 1562066009929332
+    },
+    "acl": {
+      "description": "The access control tags associated with this entity.",
+      "title": "Access Control List",
+      "$ref": "../abstract/AbstractAccessControlList.1.0.0.json"
+    },
+    "legal": {
+      "description": "The entity's legal tags and compliance status. The actual contents associated with the legal tags is managed by the Compliance Service.",
+      "title": "Legal Tags",
+      "$ref": "../abstract/AbstractLegalTags.1.0.0.json"
+    },
+    "resourceHomeRegionID": {
+      "description": "The name of the home [cloud environment] region for this OSDU resource object.",
+      "title": "Resource Home Region ID",
+      "type": "string",
+      "pattern": "^srn:<namespace>:reference-data\\/OSDURegion:[^:]+:[0-9]*$"
+    },
+    "resourceHostRegionIDs": {
+      "description": "The name of the host [cloud environment] region(s) for this OSDU resource object.",
+      "title": "Resource Host Region ID",
+      "type": "array",
+      "items": {
+        "type": "string",
+        "pattern": "^srn:<namespace>:reference-data\\/OSDURegion:[^:]+:[0-9]*$"
+      }
+    },
+    "resourceObjectCreationDateTime": {
+      "description": "Timestamp of the time at which Version 1 of this OSDU resource object was originated.",
+      "title": "Resource Object Creation DateTime",
+      "type": "string",
+      "format": "date-time"
+    },
+    "resourceVersionCreationDateTime": {
+      "description": "Timestamp of the time when the current version of this resource entered the OSDU.",
+      "title": "Resource Version Creation DateTime",
+      "type": "string",
+      "format": "date-time"
+    },
+    "resourceCurationStatus": {
+      "description": "Describes the current Curation status.",
+      "title": "Resource Curation Status",
+      "type": "string",
+      "pattern": "^srn:<namespace>:reference-data\\/ResourceCurationStatus:[^:]+:[0-9]*$"
+    },
+    "resourceLifecycleStatus": {
+      "description": "Describes the current Resource Lifecycle status.",
+      "title": "Resource Lifecycle Status",
+      "type": "string",
+      "pattern": "^srn:<namespace>:reference-data\\/ResourceLifecycleStatus:[^:]+:[0-9]*$"
+    },
+    "resourceSecurityClassification": {
+      "description": "Classifies the security level of the resource.",
+      "title": "Resource Security Classification",
+      "type": "string",
+      "pattern": "^srn:<namespace>:reference-data\\/ResourceSecurityClassification:[^:]+:[0-9]*$"
+    },
+    "ancestry": {
+      "description": "The links to data, which constitute the inputs.",
+      "title": "Ancestry",
+      "$ref": "../abstract/AbstractLegalParentList.1.0.0.json"
+    },
+    "meta": {
+      "description": "The Frame of Reference meta data section linking the named properties to self-contained definitions.",
+      "title": "Frame of Reference Meta Data",
+      "type": "array",
+      "items": {
+        "$ref": "../abstract/AbstractMetaItem.1.0.0.json"
+      }
+    },
+    "source": {
+      "description": "The entity that produced the record, or from which it is received; could be an organization, agency, system, internal team, or individual. For informational purposes only, the list of sources is not governed.",
+      "title": "Data Source",
+      "type": "string"
+    },
+    "existenceKind": {
+      "description": "Where does this data resource sit in the cradle-to-grave span of its existence?",
+      "title": "Existence Kind",
+      "type": "string",
+      "pattern": "^srn:<namespace>:reference-data\\/ExistenceKind:[^:]+:[0-9]*$"
+    },
+    "data": {
+      "allOf": [
+        {
+          "type": "object",
+          "properties": {
+            "Description": {
+              "title": "Concept Description",
+              "description": "A detailed description of the concept represented by the type and, if necessary, with relationships to other concepts/types defined in the ecosystem.",
+              "type": "string"
+            },
+            "Schema": {
+              "title": "JSON Schema",
+              "description": "The JSON schema version.",
+              "type": "string",
+              "example": "http://json-schema.org/draft-07/schema#"
+            },
+            "NaturalKeys": {
+              "title": "Natural Keys",
+              "description": "Identifies the natural keys if declared. The keys are identified via the dot notation; example: assume the ProjectName is the natural key for a SeismicAcquisitionProject then the natural key reference would be \"[Data.ProjectName]\".",
+              "type": "array",
+              "items": {
+                "type": "string"
+              }
+            },
+            "SchemaID": {
+              "title": "Schema ID",
+              "description": "The schema ID corresponding to the type",
+              "type": "string",
+              "example": "https://schema.osdu.opengroup.org/json/type/Type.1.0.0.json"
+            },
+            "Name": {
+              "title": "Type Name",
+              "x-osdu-natural-key": 0,
+              "description": "The name of the type, or entity type name. The name represents a concept. It is expected that the concept, e.g. Wellbore, can be described by multiple different schemas, which are closely associated with the original data source. Eventually one normalized schema kind is identified, into which the individual contributions can be merged. It is expected that this schema is or is close to the OSDU data definition where defined.",
+              "type": "string"
+            },
+            "SchemaKind": {
+              "title": "Schema Kind",
+              "description": "The latest schema kind as registered with the schema service. The evaluation is based on the semantic version number of the schema.",
+              "type": "string",
+              "example": "osdu:osdu:type/Type:1.0.0"
+            },
+            "IsReferenceValueType": {
+              "title": "Reference Value Type Flag",
+              "description": "The flag indicating that this type is a reference value type.",
+              "type": "boolean"
+            },
+            "GovernanceAuthorities": {
+              "title": "Governance Authorities",
+              "description": "The Authorities governing the contents.",
+              "type": "array",
+              "items": {
+                "type": "string",
+                "pattern": "^srn:<namespace>:reference-data\\/OrganisationType:[^:]+:[0-9]*$"
+              }
+            },
+            "GovernanceModel": {
+              "title": "Governance for Reference Values",
+              "description": "The style of governance (only relevant for IsReferenceValueType==true) - it can be FIXED (content must not be augmented), OPEN (additions and changes allowed) or LOCAL (content is exclusively governed by operator).",
+              "type": "string",
+              "enum": [
+                "FIXED",
+                "OPEN",
+                "LOCAL"
+              ]
+            }
+          }
+        },
+        {
+          "type": "object",
+          "properties": {
+            "ExtensionProperties": {
+              "type": "object",
+              "properties": {}
+            }
+          }
+        }
+      ]
+    }
+  },
+  "required": [
+    "kind",
+    "acl",
+    "groupType",
+    "legal"
+  ],
+  "additionalProperties": false,
+  "x-osdu-governance-model": "OPEN"
+}
\ No newline at end of file
diff --git a/indexer-core/src/test/resources/converter/R3-json-schema/Generated/type/Type.1.0.0.json.res b/indexer-core/src/test/resources/converter/R3-json-schema/Generated/type/Type.1.0.0.json.res
new file mode 100644
index 0000000000000000000000000000000000000000..a7ba6fd16702e164a45bf8332358280b9756f682
--- /dev/null
+++ b/indexer-core/src/test/resources/converter/R3-json-schema/Generated/type/Type.1.0.0.json.res
@@ -0,0 +1,41 @@
+{
+  "kind": "osdu:osdu:Wellbore:1.0.0",
+  "schema": [
+    {
+      "kind": "string",
+      "path": "Description"
+    },
+    {
+      "kind": "string",
+      "path": "Schema"
+    },
+    {
+      "kind": "[]string",
+      "path": "NaturalKeys"
+    },
+    {
+      "kind": "string",
+      "path": "SchemaID"
+    },
+    {
+      "kind": "string",
+      "path": "Name"
+    },
+    {
+      "kind": "string",
+      "path": "SchemaKind"
+    },
+    {
+      "kind": "bool",
+      "path": "IsReferenceValueType"
+    },
+    {
+      "kind": "[]link",
+      "path": "GovernanceAuthorities"
+    },
+    {
+      "kind": "string",
+      "path": "GovernanceModel"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/indexer-core/src/test/resources/converter/R3-json-schema/Generated/work-product-component/WellLog.1.0.0.json b/indexer-core/src/test/resources/converter/R3-json-schema/Generated/work-product-component/WellLog.1.0.0.json
new file mode 100644
index 0000000000000000000000000000000000000000..a7486367e98cae1ca66612cf7083a4ed872faa90
--- /dev/null
+++ b/indexer-core/src/test/resources/converter/R3-json-schema/Generated/work-product-component/WellLog.1.0.0.json
@@ -0,0 +1,327 @@
+{
+  "x-osdu-license": "Copyright 2020, The Open Group \\nLicensed 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.",
+  "$id": "https://schema.osdu.opengroup.org/json/work-product-component/WellLog.1.0.0.json",
+  "$schema": "http://json-schema.org/draft-07/schema#",
+  "title": "WellLog",
+  "description": "",
+  "type": "object",
+  "properties": {
+    "id": {
+      "description": "Previously called ResourceID or SRN which identifies this OSDU resource object without version.",
+      "title": "Entity ID",
+      "type": "string",
+      "pattern": "^srn:<namespace>:work-product-component\\/WellLog:[^:]+$",
+      "example": "srn:<namespace>:work-product-component/WellLog:d9ae27ff-8325-5b2a-b487-e42c9a87ce20"
+    },
+    "kind": {
+      "description": "The schema identification for the OSDU resource object following the pattern <Namespace>:<Source>:<Type>:<VersionMajor>.<VersionMinor>.<VersionPatch>. The versioning scheme follows the semantic versioning, https://semver.org/.",
+      "title": "Entity Kind",
+      "type": "string",
+      "pattern": "^[A-Za-z0-9-_]+:[A-Za-z0-9-_]+:[A-Za-z0-9-_]+:[0-9]+.[0-9]+.[0-9]+$",
+      "example": "namespace:osdu:WellLog:2.7.112"
+    },
+    "groupType": {
+      "description": "The OSDU group-type assigned to this resource object.",
+      "title": "Group Type",
+      "const": "work-product-component"
+    },
+    "version": {
+      "description": "The version number of this OSDU resource; set by the framework.",
+      "title": "Version Number",
+      "type": "integer",
+      "format": "int64",
+      "example": 1562066009929332
+    },
+    "acl": {
+      "description": "The access control tags associated with this entity.",
+      "title": "Access Control List",
+      "$ref": "../abstract/AbstractAccessControlList.1.0.0.json"
+    },
+    "legal": {
+      "description": "The entity's legal tags and compliance status. The actual contents associated with the legal tags is managed by the Compliance Service.",
+      "title": "Legal Tags",
+      "$ref": "../abstract/AbstractLegalTags.1.0.0.json"
+    },
+    "resourceHomeRegionID": {
+      "description": "The name of the home [cloud environment] region for this OSDU resource object.",
+      "title": "Resource Home Region ID",
+      "type": "string",
+      "pattern": "^srn:<namespace>:reference-data\\/OSDURegion:[^:]+:[0-9]*$"
+    },
+    "resourceHostRegionIDs": {
+      "description": "The name of the host [cloud environment] region(s) for this OSDU resource object.",
+      "title": "Resource Host Region ID",
+      "type": "array",
+      "items": {
+        "type": "string",
+        "pattern": "^srn:<namespace>:reference-data\\/OSDURegion:[^:]+:[0-9]*$"
+      }
+    },
+    "resourceObjectCreationDateTime": {
+      "description": "Timestamp of the time at which Version 1 of this OSDU resource object was originated.",
+      "title": "Resource Object Creation DateTime",
+      "type": "string",
+      "format": "date-time"
+    },
+    "resourceVersionCreationDateTime": {
+      "description": "Timestamp of the time when the current version of this resource entered the OSDU.",
+      "title": "Resource Version Creation DateTime",
+      "type": "string",
+      "format": "date-time"
+    },
+    "resourceCurationStatus": {
+      "description": "Describes the current Curation status.",
+      "title": "Resource Curation Status",
+      "type": "string",
+      "pattern": "^srn:<namespace>:reference-data\\/ResourceCurationStatus:[^:]+:[0-9]*$"
+    },
+    "resourceLifecycleStatus": {
+      "description": "Describes the current Resource Lifecycle status.",
+      "title": "Resource Lifecycle Status",
+      "type": "string",
+      "pattern": "^srn:<namespace>:reference-data\\/ResourceLifecycleStatus:[^:]+:[0-9]*$"
+    },
+    "resourceSecurityClassification": {
+      "description": "Classifies the security level of the resource.",
+      "title": "Resource Security Classification",
+      "type": "string",
+      "pattern": "^srn:<namespace>:reference-data\\/ResourceSecurityClassification:[^:]+:[0-9]*$"
+    },
+    "ancestry": {
+      "description": "The links to data, which constitute the inputs.",
+      "title": "Ancestry",
+      "$ref": "../abstract/AbstractLegalParentList.1.0.0.json"
+    },
+    "meta": {
+      "description": "The Frame of Reference meta data section linking the named properties to self-contained definitions.",
+      "title": "Frame of Reference Meta Data",
+      "type": "array",
+      "items": {
+        "$ref": "../abstract/AbstractMetaItem.1.0.0.json"
+      }
+    },
+    "source": {
+      "description": "The entity that produced the record, or from which it is received; could be an organization, agency, system, internal team, or individual. For informational purposes only, the list of sources is not governed.",
+      "title": "Data Source",
+      "type": "string"
+    },
+    "existenceKind": {
+      "description": "Where does this data resource sit in the cradle-to-grave span of its existence?",
+      "title": "Existence Kind",
+      "type": "string",
+      "pattern": "^srn:<namespace>:reference-data\\/ExistenceKind:[^:]+:[0-9]*$"
+    },
+    "data": {
+      "allOf": [
+        {
+          "$ref": "../abstract/AbstractWPCGroupType.1.0.0.json"
+        },
+        {
+          "$ref": "../abstract/AbstractWorkProductComponent.1.0.0.json"
+        },
+        {
+          "type": "object",
+          "properties": {
+            "WellboreID": {
+              "type": "string",
+              "pattern": "^srn:<namespace>:master-data\\/Wellbore:[^:]+:[0-9]*$",
+              "description": "The Wellbore where the Well Log Work Product Component was recorded"
+            },
+            "WellLogTypeID": {
+              "description": "Well Log Type short Description such as Raw; Evaluated; Composite;....",
+              "type": "string",
+              "pattern": "^srn:<namespace>:reference-data\\/LogType:[^:]+:[0-9]*$"
+            },
+            "TopMeasuredDepth": {
+              "title": "Top Measured Depth",
+              "description": "OSDU Native Top Measured Depth of the Well Log.",
+              "type": "number",
+              "x-osdu-frame-of-reference": "UOM:length"
+            },
+            "BottomMeasuredDepth": {
+              "title": "Bottom Measured Depth",
+              "description": "OSDU Native Bottom Measured Depth of the Well Log.",
+              "type": "number",
+              "x-osdu-frame-of-reference": "UOM:length"
+            },
+            "ServiceCompanyID": {
+              "description": "Service Company ID",
+              "type": "string",
+              "pattern": "^srn:<namespace>:master-data\\/Organisation:[^:]+:[0-9]*$"
+            },
+            "LogSource": {
+              "description": "OSDU Native Log Source - will be updated for later releases - not to be used yet ",
+              "type": "string"
+            },
+            "LogActivity": {
+              "description": "Log Activity, used to describe the type of pass such as Calibration Pass - Main Pass - Repeated Pass",
+              "type": "string"
+            },
+            "LogRun": {
+              "description": "Log Run - describe the run of the log - can be a number, but may be also a alphanumeric description such as a version name",
+              "type": "string"
+            },
+            "LogVersion": {
+              "description": "Log Version",
+              "type": "string"
+            },
+            "LoggingService": {
+              "description": "Logging Service - mainly a short concatenation of the names of the tools",
+              "type": "string"
+            },
+            "LogServiceDateInterval": {
+              "description": "An interval built from two nested values : StartDate and EndDate. It applies to the whole log services and may apply to composite logs as [start of the first run job] and [end of the last run job]Log Service Date",
+              "type": "object",
+              "properties": {
+                "StartDate": {
+                  "type": "string",
+                  "format": "date-time"
+                },
+                "EndDate": {
+                  "type": "string",
+                  "format": "date-time"
+                }
+              }
+            },
+            "ToolStringDescription": {
+              "description": "Tool String Description - a long concatenation of the tools used for logging services such as GammaRay+NeutronPorosity",
+              "type": "string"
+            },
+            "LoggingDirection": {
+              "description": "Specifies whether curves were collected downward or upward",
+              "type": "string"
+            },
+            "PassNumber": {
+              "description": "Indicates if the Pass is the Main one (1) or a repeated one - and it's level repetition",
+              "type": "integer"
+            },
+            "ActivityType": {
+              "description": "General method or circumstance of logging - MWD, completion, ...",
+              "type": "string"
+            },
+            "DrillingFluidProperty": {
+              "description": "Type of mud at time of logging (oil, water based,...)",
+              "type": "string"
+            },
+            "HoleTypeLogging": {
+              "description": "Description of the hole related type of logging - POSSIBLE VALUE : OpenHole / CasedHole / CementedHole",
+              "pattern": "^OPENHOLE|CASEDHOLE|CEMENTEDHOLE$",
+              "type": "string"
+            },
+            "VerticalMeasurementID": {
+              "type": "string",
+              "description": "References an entry in the Vertical Measurement array for the Wellbore identified by WellboreID, which defines the vertical reference datum for all curve measured depths."
+            },
+            "Curves": {
+              "type": "array",
+              "items": {
+                "type": "object",
+                "properties": {
+                  "CurveID": {
+                    "description": "The ID of the Well Log Curve",
+                    "type": "string"
+                  },
+                  "DateStamp": {
+                    "description": "Date curve was created in the database",
+                    "type": "string",
+                    "format": "date-time",
+                    "x-osdu-frame-of-reference": "DateTime"
+                  },
+                  "CurveVersion": {
+                    "description": "The Version of the Log Curve.",
+                    "type": "string"
+                  },
+                  "CurveQuality": {
+                    "description": "The Quality of the Log Curve.",
+                    "type": "string"
+                  },
+                  "InterpreterName": {
+                    "description": "The name of person who interpreted this Log Curve.",
+                    "type": "string"
+                  },
+                  "IsProcessed": {
+                    "description": "Indicates if the curve has been (pre)processed or if it is a raw recording",
+                    "type": "boolean"
+                  },
+                  "NullValue": {
+                    "description": "Indicates that there is no measurement within the curve",
+                    "type": "boolean"
+                  },
+                  "DepthCoding": {
+                    "description": "The Coding of the depth.",
+                    "type": "string",
+                    "pattern": "^REGULAR|DISCRETE$"
+                  },
+                  "Interpolate": {
+                    "description": "Whether curve can be interpolated or not",
+                    "type": "boolean"
+                  },
+                  "TopDepth": {
+                    "type": "number",
+                    "description": "Top Depth",
+                    "x-osdu-frame-of-reference": "UOM_via_property:DepthUnit"
+                  },
+                  "BaseDepth": {
+                    "type": "number",
+                    "description": "Base Depth",
+                    "x-osdu-frame-of-reference": "UOM_via_property:DepthUnit"
+                  },
+                  "DepthUnit": {
+                    "description": "Unit of Measure for Top and Base depth",
+                    "type": "string",
+                    "pattern": "^srn:<namespace>:reference-data\\/UnitOfMeasure:[^:]+:[0-9]*$"
+                  },
+                  "CurveUnit": {
+                    "description": "Unit of Measure for the Log Curve",
+                    "type": "string",
+                    "pattern": "^srn:<namespace>:reference-data\\/UnitOfMeasure:[^:]+:[0-9]*$"
+                  },
+                  "Mnemonic": {
+                    "description": "The Mnemonic of the Log Curve is the value as received either from Raw Providers or from Internal Processing team ",
+                    "type": "string"
+                  },
+                  "LogCurveTypeID": {
+                    "description": "The SRN of the Log Curve Type - which is the standard mnemonic chosen by the company - OSDU provides an initial list",
+                    "type": "string",
+                    "pattern": "^srn:<namespace>:reference-data\\/LogCurveType:[^:]+:[0-9]*$"
+                  },
+                  "LogCurveBusinessValueID": {
+                    "description": "The SRN of the Log Curve Business Value Type.",
+                    "type": "string",
+                    "pattern": "^srn:<namespace>:reference-data\\/LogCurveBusinessValue:[^:]+:[0-9]*$"
+                  },
+                  "LogCurveMainFamilyID": {
+                    "description": "The SRN of the Log Curve Main Family Type - which is the Geological Physical Quantity measured - such as porosity.",
+                    "type": "string",
+                    "pattern": "^srn:<namespace>:reference-data\\/LogCurveMainFamily:[^:]+:[0-9]*$"
+                  },
+                  "LogCurveFamilyID": {
+                    "description": "The SRN of the Log Curve Family - which is the detailed Geological Physical Quantity Measured - such as neutron porosity",
+                    "type": "string",
+                    "pattern": "^srn:<namespace>:reference-data\\/LogCurveFamily:[^:]+:[0-9]*$"
+                  }
+                }
+              }
+            }
+          }
+        },
+        {
+          "type": "object",
+          "properties": {
+            "ExtensionProperties": {
+              "type": "object",
+              "properties": {}
+            }
+          }
+        }
+      ]
+    }
+  },
+  "required": [
+    "kind",
+    "acl",
+    "groupType",
+    "legal"
+  ],
+  "additionalProperties": false
+}
\ No newline at end of file
diff --git a/indexer-core/src/test/resources/converter/R3-json-schema/Generated/work-product-component/WellLog.1.0.0.json.res b/indexer-core/src/test/resources/converter/R3-json-schema/Generated/work-product-component/WellLog.1.0.0.json.res
new file mode 100644
index 0000000000000000000000000000000000000000..517ca0395223bf432f8bc6b8c01bf7c768921532
--- /dev/null
+++ b/indexer-core/src/test/resources/converter/R3-json-schema/Generated/work-product-component/WellLog.1.0.0.json.res
@@ -0,0 +1,81 @@
+{
+  "kind": "osdu:osdu:Wellbore:1.0.0",
+  "schema": [
+    {
+      "kind": "link",
+      "path": "WellboreID"
+    },
+    {
+      "kind": "link",
+      "path": "WellLogTypeID"
+    },
+    {
+      "kind": "double",
+      "path": "TopMeasuredDepth"
+    },
+    {
+      "kind": "double",
+      "path": "BottomMeasuredDepth"
+    },
+    {
+      "kind": "link",
+      "path": "ServiceCompanyID"
+    },
+    {
+      "kind": "string",
+      "path": "LogSource"
+    },
+    {
+      "kind": "string",
+      "path": "LogActivity"
+    },
+    {
+      "kind": "string",
+      "path": "LogRun"
+    },
+    {
+      "kind": "string",
+      "path": "LogVersion"
+    },
+    {
+      "kind": "string",
+      "path": "LoggingService"
+    },
+    {
+      "kind": "datetime",
+      "path": "LogServiceDateInterval.StartDate"
+    },
+    {
+      "kind": "datetime",
+      "path": "LogServiceDateInterval.EndDate"
+    },
+    {
+      "kind": "string",
+      "path": "ToolStringDescription"
+    },
+    {
+      "kind": "string",
+      "path": "LoggingDirection"
+    },
+    {
+      "kind": "int",
+      "path": "PassNumber"
+    },
+    {
+      "kind": "string",
+      "path": "ActivityType"
+    },
+    {
+      "kind": "string",
+      "path": "DrillingFluidProperty"
+    },
+    {
+      "kind": "string",
+      "path": "HoleTypeLogging"
+    },
+    {
+      "kind": "string",
+      "path": "VerticalMeasurementID"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/indexer-core/src/test/resources/converter/R3-json-schema/Generated/work-product/WorkProduct.1.0.0.json b/indexer-core/src/test/resources/converter/R3-json-schema/Generated/work-product/WorkProduct.1.0.0.json
new file mode 100644
index 0000000000000000000000000000000000000000..bc1795ac985b92a955fe9bd75c8e6c09823d3759
--- /dev/null
+++ b/indexer-core/src/test/resources/converter/R3-json-schema/Generated/work-product/WorkProduct.1.0.0.json
@@ -0,0 +1,230 @@
+{
+  "x-osdu-license": "Copyright 2020, The Open Group \\nLicensed 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.",
+  "$id": "https://schema.osdu.opengroup.org/json/work-product/WorkProduct.1.0.0.json",
+  "$schema": "http://json-schema.org/draft-07/schema#",
+  "title": "WorkProduct",
+  "description": "A collection of work product components such as might be produced by a business activity and which is delivered to the data platform for loading.",
+  "type": "object",
+  "properties": {
+    "id": {
+      "description": "Previously called ResourceID or SRN which identifies this OSDU resource object without version.",
+      "title": "Entity ID",
+      "type": "string",
+      "pattern": "^srn:<namespace>:work-product\\/WorkProduct:[^:]+$",
+      "example": "srn:<namespace>:work-product/WorkProduct:146156b3-06aa-5195-b2f3-61c429f9f6ba"
+    },
+    "kind": {
+      "description": "The schema identification for the OSDU resource object following the pattern <Namespace>:<Source>:<Type>:<VersionMajor>.<VersionMinor>.<VersionPatch>. The versioning scheme follows the semantic versioning, https://semver.org/.",
+      "title": "Entity Kind",
+      "type": "string",
+      "pattern": "^[A-Za-z0-9-_]+:[A-Za-z0-9-_]+:[A-Za-z0-9-_]+:[0-9]+.[0-9]+.[0-9]+$",
+      "example": "namespace:osdu:WorkProduct:2.7.112"
+    },
+    "groupType": {
+      "description": "The OSDU group-type assigned to this resource object.",
+      "title": "Group Type",
+      "const": "work-product"
+    },
+    "version": {
+      "description": "The version number of this OSDU resource; set by the framework.",
+      "title": "Version Number",
+      "type": "integer",
+      "format": "int64",
+      "example": 1562066009929332
+    },
+    "acl": {
+      "description": "The access control tags associated with this entity.",
+      "title": "Access Control List",
+      "$ref": "../abstract/AbstractAccessControlList.1.0.0.json"
+    },
+    "legal": {
+      "description": "The entity's legal tags and compliance status. The actual contents associated with the legal tags is managed by the Compliance Service.",
+      "title": "Legal Tags",
+      "$ref": "../abstract/AbstractLegalTags.1.0.0.json"
+    },
+    "resourceHomeRegionID": {
+      "description": "The name of the home [cloud environment] region for this OSDU resource object.",
+      "title": "Resource Home Region ID",
+      "type": "string",
+      "pattern": "^srn:<namespace>:reference-data\\/OSDURegion:[^:]+:[0-9]*$"
+    },
+    "resourceHostRegionIDs": {
+      "description": "The name of the host [cloud environment] region(s) for this OSDU resource object.",
+      "title": "Resource Host Region ID",
+      "type": "array",
+      "items": {
+        "type": "string",
+        "pattern": "^srn:<namespace>:reference-data\\/OSDURegion:[^:]+:[0-9]*$"
+      }
+    },
+    "resourceObjectCreationDateTime": {
+      "description": "Timestamp of the time at which Version 1 of this OSDU resource object was originated.",
+      "title": "Resource Object Creation DateTime",
+      "type": "string",
+      "format": "date-time"
+    },
+    "resourceVersionCreationDateTime": {
+      "description": "Timestamp of the time when the current version of this resource entered the OSDU.",
+      "title": "Resource Version Creation DateTime",
+      "type": "string",
+      "format": "date-time"
+    },
+    "resourceCurationStatus": {
+      "description": "Describes the current Curation status.",
+      "title": "Resource Curation Status",
+      "type": "string",
+      "pattern": "^srn:<namespace>:reference-data\\/ResourceCurationStatus:[^:]+:[0-9]*$"
+    },
+    "resourceLifecycleStatus": {
+      "description": "Describes the current Resource Lifecycle status.",
+      "title": "Resource Lifecycle Status",
+      "type": "string",
+      "pattern": "^srn:<namespace>:reference-data\\/ResourceLifecycleStatus:[^:]+:[0-9]*$"
+    },
+    "resourceSecurityClassification": {
+      "description": "Classifies the security level of the resource.",
+      "title": "Resource Security Classification",
+      "type": "string",
+      "pattern": "^srn:<namespace>:reference-data\\/ResourceSecurityClassification:[^:]+:[0-9]*$"
+    },
+    "ancestry": {
+      "description": "The links to data, which constitute the inputs.",
+      "title": "Ancestry",
+      "$ref": "../abstract/AbstractLegalParentList.1.0.0.json"
+    },
+    "meta": {
+      "description": "The Frame of Reference meta data section linking the named properties to self-contained definitions.",
+      "title": "Frame of Reference Meta Data",
+      "type": "array",
+      "items": {
+        "$ref": "../abstract/AbstractMetaItem.1.0.0.json"
+      }
+    },
+    "source": {
+      "description": "The entity that produced the record, or from which it is received; could be an organization, agency, system, internal team, or individual. For informational purposes only, the list of sources is not governed.",
+      "title": "Data Source",
+      "type": "string"
+    },
+    "existenceKind": {
+      "description": "Where does this data resource sit in the cradle-to-grave span of its existence?",
+      "title": "Existence Kind",
+      "type": "string",
+      "pattern": "^srn:<namespace>:reference-data\\/ExistenceKind:[^:]+:[0-9]*$"
+    },
+    "data": {
+      "allOf": [
+        {
+          "type": "object",
+          "properties": {
+            "Components": {
+              "type": "array",
+              "items": {
+                "description": "The SRN which identifies this OSDU Work Product Component resource.",
+                "type": "string",
+                "pattern": "^srn:<namespace>:work-product-component\\/[A-Za-z0-9]+:[^:]+:[0-9]*$"
+              }
+            },
+            "IsExtendedLoad": {
+              "type": "boolean",
+              "description": "A flag that indicates if the work product is undergoing an extended load.  It reflects the fact that the work product is in an early stage and may be updated before finalization."
+            },
+            "IsDiscoverable": {
+              "type": "boolean",
+              "description": "A flag that indicates if the work product is searchable, which means covered in the search index."
+            },
+            "Name": {
+              "type": "string",
+              "description": "Name of the instance of Work Product - could be a shipment number."
+            },
+            "Description": {
+              "type": "string",
+              "description": "Description of the purpose of the work product."
+            },
+            "CreationDateTime": {
+              "type": "string",
+              "format": "date-time",
+              "description": "Date that a resource (work  product here) is formed outside of OSDU before loading (e.g. publication date, work product delivery package assembly date)."
+            },
+            "Tags": {
+              "type": "array",
+              "description": "Array of key words to identify the work product, especially to help in search.",
+              "items": {
+                "type": "string"
+              }
+            },
+            "SpatialPoint": {
+              "description": "A centroid point that reflects the locale of the content of the work product (location of the subject matter).",
+              "$ref": "../abstract/AbstractSpatialLocation.1.0.0.json"
+            },
+            "SpatialArea": {
+              "description": "A polygon boundary that reflects the locale of the content of the work product (location of the subject matter).",
+              "$ref": "../abstract/AbstractSpatialLocation.1.0.0.json"
+            },
+            "SubmitterName": {
+              "type": "string",
+              "description": "Name of the person that first submitted the work product package to OSDU."
+            },
+            "BusinessActivities": {
+              "type": "array",
+              "description": "Array of business processes/workflows that the work product has been through (ex. well planning, exploration).",
+              "items": {
+                "type": "string",
+                "description": "Business Activity"
+              }
+            },
+            "AuthorIDs": {
+              "type": "array",
+              "description": "Array of Authors' names of the work product.  Could be a person or company entity.",
+              "items": {
+                "type": "string"
+              }
+            },
+            "LineageAssertions": {
+              "type": "array",
+              "description": "Defines relationships with other objects (any kind of Resource) upon which this work product depends.  The assertion is directed only from the asserting WP to ancestor objects, not children.  It should not be used to refer to files or artefacts within the WP -- the association within the WP is sufficient and Artefacts are actually children of the main WP file. They should be recorded in the Data.Artefacts[] array.",
+              "items": {
+                "type": "object",
+                "title": "LineageAssertion",
+                "properties": {
+                  "ID": {
+                    "type": "string",
+                    "description": "The object reference identifying the DIRECT, INDIRECT, REFERENCE dependency.",
+                    "pattern": "^srn:<namespace>:[A-Za-z-]+\\/[A-Za-z0-9]+:[^:]+:[0-9]*$"
+                  },
+                  "LineageRelationshipType": {
+                    "type": "string",
+                    "description": "Used by LineageAssertion to describe the nature of the line of descent of a work product from a prior Resource, such as DIRECT, INDIRECT, REFERENCE.  It is not for proximity (number of nodes away), it is not to cover all the relationships in a full ontology or graph, and it is not to describe the type of activity that created the asserting WP.  LineageAssertion does not encompass a full provenance, process history, or activity model.",
+                    "pattern": "^srn:<namespace>:reference-data\\/LineageRelationshipType:[^:]+:[0-9]*$"
+                  }
+                }
+              }
+            },
+            "Annotations": {
+              "type": "array",
+              "description": "Array of Annotations",
+              "items": {
+                "type": "string"
+              }
+            }
+          }
+        },
+        {
+          "type": "object",
+          "properties": {
+            "ExtensionProperties": {
+              "type": "object",
+              "properties": {}
+            }
+          }
+        }
+      ]
+    }
+  },
+  "required": [
+    "kind",
+    "acl",
+    "groupType",
+    "legal"
+  ],
+  "additionalProperties": false
+}
\ No newline at end of file
diff --git a/indexer-core/src/test/resources/converter/R3-json-schema/Generated/work-product/WorkProduct.1.0.0.json.res b/indexer-core/src/test/resources/converter/R3-json-schema/Generated/work-product/WorkProduct.1.0.0.json.res
new file mode 100644
index 0000000000000000000000000000000000000000..0b807093bb76e1b01fa2c4d2753864bab6f52386
--- /dev/null
+++ b/indexer-core/src/test/resources/converter/R3-json-schema/Generated/work-product/WorkProduct.1.0.0.json.res
@@ -0,0 +1,49 @@
+{
+  "kind": "osdu:osdu:Wellbore:1.0.0",
+  "schema": [
+    {
+      "kind": "[]link",
+      "path": "Components"
+    },
+    {
+      "kind": "bool",
+      "path": "IsExtendedLoad"
+    },
+    {
+      "kind": "bool",
+      "path": "IsDiscoverable"
+    },
+    {
+      "kind": "string",
+      "path": "Name"
+    },
+    {
+      "kind": "string",
+      "path": "Description"
+    },
+    {
+      "kind": "datetime",
+      "path": "CreationDateTime"
+    },
+    {
+      "kind": "[]string",
+      "path": "Tags"
+    },
+    {
+      "kind": "string",
+      "path": "SubmitterName"
+    },
+    {
+      "kind": "[]string",
+      "path": "BusinessActivities"
+    },
+    {
+      "kind": "[]string",
+      "path": "AuthorIDs"
+    },
+    {
+      "kind": "[]string",
+      "path": "Annotations"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/indexer-core/src/test/resources/converter/README.md b/indexer-core/src/test/resources/converter/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..0f71a26b982695f3991e97c4094722f95fbfcab6
--- /dev/null
+++ b/indexer-core/src/test/resources/converter/README.md
@@ -0,0 +1,18 @@
+# Introduction 
+
+This document explains how to check R3 json schema set that is planned for the R3 delivery
+
+## Steps
+
+1) Put files with schemas to 'R3-json-schema/Generated' folder
+2) Run gen-for-folder.sh script. 
+It uses  StorageSchemaGenerator.py python script developed by Thomas Gehrmann <gehrmann@slb.com> to generate corresponding files in storage schema format with '.res' extension.
+You need python 3.6 for that.
+3) Run folderPassed() unit test. It generates schemas with Java converter and compares results with .res files.
+
+
+
+
+
+
+
diff --git a/indexer-core/src/test/resources/converter/StorageSchemaGenerator.py b/indexer-core/src/test/resources/converter/StorageSchemaGenerator.py
new file mode 100644
index 0000000000000000000000000000000000000000..b9161049d1fc540e0d1f6312f54d33628899ad98
--- /dev/null
+++ b/indexer-core/src/test/resources/converter/StorageSchemaGenerator.py
@@ -0,0 +1,259 @@
+import json
+import sys
+
+class StorageSchemaGenerator(object):
+    BASIC_TYPES = ['number', 'string', 'integer', 'boolean']
+    DEFINITIONS = 'definitions'
+    PROPERTIES = 'properties'
+    SPECIALS = ['AbstractFeatureCollection.1.0.0', 'AbstractAnyCrsFeatureCollection.1.0.0',
+                'geoJsonFeatureCollection', 'core_dl_geopoint']  # do not expand these
+    SKIP = ['AbstractAnyCrsFeatureCollection.1.0.0']  # this is irrelevant to the indexer
+    DE_TYPES = {'AbstractFeatureCollection.1.0.0': 'core:dl:geoshape:1.0.0',
+                'geoJsonFeatureCollection': 'core:dl:geoshape:1.0.0',
+                'core_dl_geopoint': 'core:dl:geopoint:1.0.0'}  # this ones is understood
+
+    def __init__(self, schema: dict, schema_id: str):
+        self.all_properties = list()
+        self.sub_schema_stack = list()
+        self.__where_we_have_been = list()
+        self.__schema = schema
+        self.__schema_id = schema_id
+        self.__definitions = dict()
+        self.__make_definitions_dictionary()
+        self.__scan_schema()
+
+    def __make_definitions_dictionary(self):
+        if isinstance(self.__schema, dict) and self.DEFINITIONS in self.__schema:
+            for key, definition in self.__schema[self.DEFINITIONS].items():
+                self.__definitions[key] = definition
+
+    def __scan_schema(self):
+        schema = self.__schema.get(self.PROPERTIES)
+        if schema is not None:
+            self.__aggregate_dictionary_or_string('', schema)
+
+    def de_schema(self) -> dict:
+        schema = list()
+        for prp in self.all_properties:
+            if 'kind' in prp and 'path' in prp and \
+                    (prp['key'].startswith('.data.') or prp['key'].startswith('.Data.')) \
+                    and prp['kind'] != 'object':
+                schema.append({'kind': prp['kind'], 'path': prp['key'][6:]})
+        return {'kind': self.__schema_id, 'schema': schema}
+
+    def property_list(self):
+        p_l = list()
+        last_sub_schema = ''
+        for prp in self.all_properties:
+            typ = prp['type']
+            if 'subSchema' in prp:
+                ss = prp['subSchema']
+            else:
+                ss = ''
+            if ss != last_sub_schema and ss != '':
+                k = self.__strip_last_property(prp['key'])
+                l_i = '\t'.join([k, ss, ''])
+                if l_i not in p_l:
+                    p_l.append(l_i)
+                last_sub_schema = ss
+            k = self.__keep_last_property(prp['key'])
+            if ss == '':
+                ss = [k]
+            else:
+                ss = [ss, k]
+            ss = '|'.join(ss)
+            p_l.append('\t'.join([prp['key'], typ, ss]))
+        return p_l
+
+    @staticmethod
+    def __strip_last_property(key):
+        parts = key.split('.')
+        stripped = '.'.join(parts[0:len(parts) - 1])
+        return stripped
+
+    @staticmethod
+    def __keep_last_property(key):
+        parts = key.split('.')
+        stripped = parts[len(parts) - 1]
+        return stripped
+
+    def __get_definition_by_ref(self, reference):
+        ref = reference.replace('#/definitions/', '')
+        if ref in self.__definitions:
+            return self.__definitions[ref]
+        else:
+            return None
+
+    @staticmethod
+    def __is_base_type_array_item(schema_fragment):
+        if isinstance(schema_fragment, dict) and \
+                'type' in schema_fragment and 'items' in schema_fragment and \
+                schema_fragment['type'] == 'array' and 'type' in schema_fragment['items'] and \
+                schema_fragment['items']['type'] in StorageSchemaGenerator.BASIC_TYPES:
+            return True
+        return False
+
+    @staticmethod
+    def __is_array_array_item(schema_fragment) -> bool:
+        if isinstance(schema_fragment, dict) and \
+                'type' in schema_fragment and 'items' in schema_fragment and \
+                schema_fragment['type'] == 'array' and 'type' in schema_fragment['items'] and \
+                'array' in schema_fragment['items']['type']:
+            return True
+        return False
+
+    @staticmethod
+    def __is_object_type_array_item(schema_fragment) -> bool:
+        if isinstance(schema_fragment, dict) and \
+                'type' in schema_fragment and 'items' in schema_fragment and \
+                schema_fragment['type'] == 'array' and 'type' in schema_fragment['items'] and \
+                schema_fragment['items']['type'] == 'object':
+            return isinstance(schema_fragment['items']['properties'], dict)
+        return False
+
+    @staticmethod
+    def __get_value_type_format(schema_fragment):
+        v_t = ''
+        if isinstance(schema_fragment, dict):
+            fmt = ''
+            if 'type' in schema_fragment:
+                v_t = schema_fragment['type']
+                if v_t == 'number':
+                    v_t = 'double'
+            if 'format' in schema_fragment:
+                fmt = schema_fragment['format']
+            if fmt == 'int64' and (v_t == 'integer' or v_t == 'number' or v_t == 'double'):
+                v_t = 'long'
+            elif (fmt.startswith('date') or fmt.startswith('time')) and v_t == 'string':
+                v_t = 'datetime'
+            if v_t == 'integer':
+                v_t = 'int'
+            elif v_t == 'boolean':
+                v_t = 'bool'
+        return v_t
+
+    def __aggregate_dictionary_or_string(self, key: str, schema_fragment):
+        if isinstance(schema_fragment, str) and schema_fragment == 'object':
+            self.__make_de_schema(key.replace('.type', ''), schema_fragment)
+        elif isinstance(schema_fragment, dict):
+            self.__aggregate_schema_fragment(key, schema_fragment)
+        else:
+            pass  # this is title, description, pattern, or custom JSON tag, etc.
+
+    def __aggregate_schema_fragment(self, key: str, schema_fragment):
+        if 'allOf' in schema_fragment or 'oneOf' in schema_fragment or 'anyOf' in schema_fragment:
+            self.__aggregate_all_any_one_of(key, schema_fragment)
+        elif 'const' in schema_fragment:
+            self.__make_de_schema(key, 'string')
+        elif 'properties' in schema_fragment:
+            for p_k, value in schema_fragment['properties'].items():
+                self.__aggregate_dictionary_or_string(key + '.' + p_k, value)
+        elif 'type' in schema_fragment and schema_fragment['type'] in self.BASIC_TYPES:
+            v_type = self.__get_value_type_format(schema_fragment)
+            pattern = schema_fragment.get('pattern', 'None')
+            self.__make_de_schema(key, v_type, pattern)
+        elif self.__is_base_type_array_item(schema_fragment):
+            self.__aggregate_simple_array(key + '[]', schema_fragment)
+        elif self.__is_array_array_item(schema_fragment):
+            for p_k, value in schema_fragment.items():
+                self.__aggregate_dictionary_or_string(key + '[]', value)
+        elif self.__is_object_type_array_item(schema_fragment):
+            self.__aggregate_array(key + '[]', schema_fragment)
+        else:  # this should only be a dictionary
+            self.__aggregate_dictionary(key, schema_fragment)
+
+    def __aggregate_all_any_one_of(self, key: str, schema_fragment):
+        if 'allOf' in schema_fragment:
+            for part in schema_fragment['allOf']:
+                self.__aggregate_dictionary_or_string(key, part)
+        elif 'oneOf' in schema_fragment or 'anyOf' in schema_fragment:
+            if 'oneOf' in schema_fragment:
+                what = 'oneOf'
+            else:
+                what = 'anyOf'
+            idx = min(len(schema_fragment[what]), 1)
+            self.__aggregate_dictionary_or_string(key, schema_fragment[what][idx])
+
+    def __aggregate_dictionary(self, key: str, schema_fragment: dict):
+        for p_k, value in schema_fragment.items():
+            if p_k == '$ref':
+                if value not in self.__where_we_have_been:
+                    self.__aggregate_d_ref(key, value)
+            elif p_k == 'items':  # array
+                if '$ref' in value:
+                    v = value['$ref']
+                    if v not in self.__where_we_have_been:
+                        self.__aggregate_d_ref(key + '[]', v)
+            else:
+                self.__aggregate_dictionary_or_string(key + '.' + p_k, value)
+
+    def __aggregate_array(self, key: str, schema_fragment):
+        for p_k, value in schema_fragment['items']['properties'].items():
+            v_type = self.__get_value_type_format(value)
+            k = '{}[].{}'.format(key, p_k)
+            if v_type == '':
+                self.__aggregate_dictionary_or_string(key + '.' + p_k, value)
+            else:
+                self.__make_de_schema(k, v_type)
+
+    def __aggregate_simple_array(self, key: str, schema_fragment):
+        v_type = ''
+        pattern = 'None'
+        if 'type' in schema_fragment['items']:
+            v_type = self.__get_value_type_format(schema_fragment['items'])
+            pattern = schema_fragment['items'].get('pattern', 'None')
+        self.__make_de_schema(key, v_type, pattern)
+
+    @staticmethod
+    def __get_sub_schema(value):
+        parts = value.split('/')
+        if len(parts) == 3:
+            return parts[len(parts) - 1]
+        else:
+            return None
+
+    def __aggregate_d_ref(self, key: str, value):
+        self.__where_we_have_been.append(value)
+        s_f = self.__get_definition_by_ref(value)
+        ss = self.__get_sub_schema(value)
+        if ss:
+            self.sub_schema_stack.append(ss)
+        if ss in self.SPECIALS:
+            self.__make_de_schema(key, ss)
+        else:
+            self.__aggregate_dictionary_or_string(key, s_f)
+        self.__where_we_have_been.pop()
+        if ss:
+            self.sub_schema_stack.pop()
+
+    def __make_de_schema(self, key_string, v_type, pattern='None'):
+        item = dict()
+        item['key'] = key_string.replace('[]', '', -1)
+        item['type'] = v_type
+        if v_type == 'string' and pattern.startswith('^srn:'):
+            kind = 'link'
+        else:
+            kind = self.DE_TYPES.get(v_type, v_type)
+        k = key_string.replace('.Data.', '')
+        if k.endswith('[]'):
+            if k.count('[]') == 1:
+                item['kind'] = '[]' + kind
+                item['path'] = k.replace('[]', '')
+            # else  ignore, nested arrays are not supported
+        elif '[]' not in k:
+            item['kind'] = kind
+            item['path'] = k
+        if len(self.sub_schema_stack) > 0:
+            item['subSchema'] = self.sub_schema_stack[len(self.sub_schema_stack) - 1]
+        if v_type not in self.SKIP:
+            self.all_properties.append(item)
+
+
+with open(sys.argv[1]) as json_file:
+    schema = json.load(json_file)
+    kind = 'osdu:osdu:Wellbore:1.0.0'
+    generator = StorageSchemaGenerator(schema, kind)
+    de_schema = generator.de_schema()
+
+with open(sys.argv[1] + '.res', 'w') as fp:
+    json.dump(de_schema, fp, indent = 2)
diff --git a/indexer-core/src/test/resources/converter/basic/schema.json b/indexer-core/src/test/resources/converter/basic/schema.json
new file mode 100644
index 0000000000000000000000000000000000000000..1c406a9e329acc9dca6c6e7f08088c52ab0f2195
--- /dev/null
+++ b/indexer-core/src/test/resources/converter/basic/schema.json
@@ -0,0 +1,1964 @@
+{
+  "$schema": "http://json-schema.org/draft-07/schema#",
+  "title": "Wellbore",
+  "description": "A hole in the ground extending from a point at the earth's surface to the maximum point of penetration.",
+  "type": "object",
+  "properties": {
+    "id": {
+      "description": "Previously called ResourceID or SRN which identifies this OSDU resource object without version.",
+      "title": "Entity ID",
+      "type": "string",
+      "pattern": "^srn:<namespace>:master-data\\/Wellbore:[^:]+$",
+      "example": "srn:<namespace>:master-data/Wellbore:2adac27b-5d84-5bcd-89f2-93ee709c06d9"
+    },
+    "kind": {
+      "description": "The schema identification for the OSDU resource object following the pattern <Namespace>:<Source>:<Type>:<VersionMajor>.<VersionMinor>.<VersionPatch>. The versioning scheme follows the semantic versioning, https://semver.org/.",
+      "title": "Entity Kind",
+      "type": "string",
+      "pattern": "^[A-Za-z0-9-_]+:[A-Za-z0-9-_]+:[A-Za-z0-9-_]+:[0-9]+.[0-9]+.[0-9]+$",
+      "example": "namespace:osdu:Wellbore:2.7.112"
+    },
+    "groupType": {
+      "description": "The OSDU group-type assigned to this resource object.",
+      "title": "Group Type",
+      "const": "master-data"
+    },
+    "version": {
+      "description": "The version number of this OSDU resource; set by the framework.",
+      "title": "Version Number",
+      "type": "integer",
+      "format": "int64",
+      "example": 1562066009929332
+    },
+    "resourceSecurityClassification": {
+      "description": "Classifies the security level of the resource.",
+      "title": "Resource Security Classification",
+      "type": "string",
+      "pattern": "^srn:<namespace>:reference-data\\/ResourceSecurityClassification:[^:]+:[0-9]*$"
+    },
+    "ancestry": {
+      "description": "The links to data, which constitute the inputs.",
+      "title": "Ancestry",
+      "$ref": "#/definitions/AbstractLegalParentList.1.0.0"
+    },
+    "meta": {
+      "description": "The Frame of Reference meta data section linking the named properties to self-contained definitions.",
+      "title": "Frame of Reference Meta Data",
+      "type": "array",
+      "items": {
+        "$ref": "#/definitions/AbstractMetaItem.1.0.0"
+      }
+    },
+    "source": {
+      "description": "The entity that produced the record, or from which it is received; could be an organization, agency, system, internal team, or individual. For informational purposes only, the list of sources is not governed.",
+      "title": "Data Source",
+      "type": "string"
+    },
+    "existenceKind": {
+      "description": "Where does this data resource sit in the cradle-to-grave span of its existence?",
+      "title": "Existence Kind",
+      "type": "string",
+      "pattern": "^srn:<namespace>:reference-data\\/ExistenceKind:[^:]+:[0-9]*$"
+    },
+    "data": {
+      "allOf": [
+        {
+          "$ref": "#/definitions/AbstractFacility.1.0.0"
+        },
+        {
+          "type": "object",
+          "properties": {
+            "WellID": {
+              "type": "string",
+              "pattern": "^srn:<namespace>:master-data\\/Well:[^:]+:[0-9]*$"
+            },
+            "SequenceNumber": {
+              "description": "A number that indicates the order in which wellbores were drilled.",
+              "type": "int"
+            },
+            "VerticalMeasurements": {
+              "description": "List of all depths and elevations pertaining to the wellbore, like, plug back measured depth, total measured depth, KB elevation",
+              "type": "array",
+              "items": {
+                "$ref": "#/definitions/AbstractFacilityVerticalMeasurement.1.0.0"
+              }
+            },
+            "DrillingReason": {
+              "description": "The history of drilling reasons of the wellbore.",
+              "type": "array",
+              "items": {
+                "$ref": "#/definitions/AbstractWellboreDrillingReason.1.0.0"
+              }
+            },
+            "KickOffWellbore": {
+              "description": "This is a pointer to the parent wellbore. The wellbore that starts from top has no parent.",
+              "type": "string",
+              "pattern": "^srn:<namespace>:master-data\\/Wellbore:[^:]+:[0-9]*$"
+            },
+            "TrajectoryTypeID": {
+              "description": "Describes the predominant shapes the wellbore path can follow if deviated from vertical. Sample Values: Horizontal, Vertical, Directional.",
+              "type": "string",
+              "pattern": "^srn:<namespace>:reference-data\\/WellboreTrajectoryType:[^:]+:[0-9]*$"
+            },
+            "DefinitiveTrajectoryID": {
+              "description": "SRN of Wellbore Trajectory which is considered the authoritative or preferred version.",
+              "type": "string",
+              "pattern": "^srn:<namespace>:work-product-component\\/WellboreTrajectory:[^:]+:[0-9]+$"
+            },
+            "TargetFormation": {
+              "description": "The Formation of interest for which the Wellbore is drilled to interact with. The Wellbore may terminate in a lower formation if the requirement is to drill through the entirety of the target formation, therefore this is not necessarily the Formation at TD.",
+              "type": "string",
+              "pattern": "^srn:<namespace>:reference-data\\/GeologicalFormation:[^:]+:[0-9]*$"
+            },
+            "PrimaryMaterialID": {
+              "description": "The primary material injected/produced from the wellbore.",
+              "type": "string",
+              "pattern": "^srn:<namespace>:reference-data\\/MaterialType:[^:]+:[0-9]*$"
+            },
+            "DefaultVerticalMeasurementID": {
+              "description": "The default datum reference point, or zero depth point, used to determine other points vertically in a wellbore.  References an entry in the Vertical Measurements array of this wellbore.",
+              "type": "string"
+            },
+            "ProjectedBottomHoleLocation": {
+              "description": "Projected location at total depth.",
+              "$ref": "#/definitions/AbstractSpatialLocation.1.0.0"
+            },
+            "GeographicBottomHoleLocation": {
+              "description": "Geographic location at total depth.",
+              "$ref": "#/definitions/AbstractSpatialLocation.1.0.0"
+            }
+          }
+        },
+        {
+          "type": "object",
+          "properties": {
+            "ExtensionProperties": {
+              "type": "object",
+              "properties": {}
+            }
+          }
+        }
+      ]
+    }
+  },
+  "required": [
+    "kind",
+    "acl",
+    "groupType",
+    "legal"
+  ],
+  "additionalProperties": false,
+  "definitions": {
+    "AbstractAccessControlList.1.0.0": {
+      "title": "Access Control List",
+      "description": "The access control tags associated with this entity. This structure is included by the SystemProperties \"acl\", which is part of all OSDU records. Not extensible.",
+      "type": "object",
+      "properties": {
+        "owners": {
+          "title": "List of Owners",
+          "description": "The list of owners of this data record formatted as an email (core.common.model.storage.validation.ValidationDoc.EMAIL_REGEX).",
+          "type": "array",
+          "items": {
+            "type": "string",
+            "pattern": "^[a-zA-Z0-9_+&*-]+(?:\\.[a-zA-Z0-9_+&*-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,7}$"
+          }
+        },
+        "viewers": {
+          "title": "List of Viewers",
+          "description": "The list of viewers to which this data record is accessible/visible/discoverable formatted as an email (core.common.model.storage.validation.ValidationDoc.EMAIL_REGEX).",
+          "type": "array",
+          "items": {
+            "type": "string",
+            "pattern": "^[a-zA-Z0-9_+&*-]+(?:\\.[a-zA-Z0-9_+&*-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,7}$"
+          }
+        }
+      },
+      "required": [
+        "owners",
+        "viewers"
+      ],
+      "additionalProperties": false
+    },
+    "AbstractLegalTags.1.0.0": {
+      "title": "Legal Meta Data",
+      "description": "Legal meta data like legal tags, relevant other countries, legal status. This structure is included by the SystemProperties \"legal\", which is part of all OSDU records. Not extensible.",
+      "type": "object",
+      "properties": {
+        "legaltags": {
+          "title": "Legal Tags",
+          "description": "The list of legal tags, which resolve to legal properties (like country of origin, export classification code, etc.) and rules with the help of the Compliance Service.",
+          "type": "array",
+          "items": {
+            "type": "string"
+          }
+        },
+        "otherRelevantDataCountries": {
+          "title": "Other Relevant Data Countries",
+          "description": "The list of other relevant data countries as an array of two-letter country codes, see https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2.",
+          "type": "array",
+          "items": {
+            "type": "string",
+            "pattern": "^[A-Z]{2}$"
+          }
+        },
+        "status": {
+          "title": "Legal Status",
+          "description": "The legal status. Set by the system after evaluation against the compliance rules associated with the \"legaltags\" using the Compliance Service.",
+          "type": "string",
+          "pattern": "^srn:<namespace>:reference-data\\/LegalStatus:[^:]+:[0-9]*$"
+        }
+      },
+      "required": [
+        "legaltags",
+        "otherRelevantDataCountries"
+      ],
+      "additionalProperties": false
+    },
+    "AbstractLegalParentList.1.0.0": {
+      "title": "Parent List",
+      "description": "A list of entity IDs in the data ecosystem, which act as legal parents to the current entity. This structure is included by the SystemProperties \"ancestry\", which is part of all OSDU records. Not extensible.",
+      "type": "object",
+      "properties": {
+        "parents": {
+          "description": "An array of none, one or many entity references in the data ecosystem, which identify the source of data in the legal sense. Example: the 'parents' will be queried when e.g. the subscription of source data services is terminated; access to the derivatives is also terminated.",
+          "items": {
+            "type": "string"
+          },
+          "example": [],
+          "title": "Parents",
+          "type": "array"
+        }
+      },
+      "additionalProperties": false
+    },
+    "AbstractMetaItem.1.0.0": {
+      "title": "Frame of Reference Meta Data Item",
+      "description": "A meta data item, which allows the association of named properties or property values to a Unit/Measurement/CRS/Azimuth/Time context.",
+      "oneOf": [
+        {
+          "title": "FrameOfReferenceUOM",
+          "type": "object",
+          "properties": {
+            "kind": {
+              "title": "UOM Reference Kind",
+              "description": "The kind of reference, 'Unit' for FrameOfReferenceUOM.",
+              "const": "Unit"
+            },
+            "name": {
+              "title": "UOM Unit Symbol",
+              "description": "The unit symbol or name of the unit.",
+              "type": "string",
+              "example": "ft[US]"
+            },
+            "persistableReference": {
+              "title": "UOM Persistable Reference",
+              "description": "The self-contained, persistable reference string uniquely identifying the Unit.",
+              "type": "string",
+              "example": "{\"abcd\":{\"a\":0.0,\"b\":1200.0,\"c\":3937.0,\"d\":0.0},\"symbol\":\"ft[US]\",\"baseMeasurement\":{\"ancestry\":\"L\",\"type\":\"UM\"},\"type\":\"UAD\"}"
+            },
+            "unitOfMeasureID": {
+              "description": "SRN to unit of measure reference.",
+              "type": "string",
+              "pattern": "^srn:<namespace>:reference-data\\/UnitOfMeasure:[^:]+:[0-9]*$",
+              "example": "srn:<namespace>:reference-data/UnitOfMeasure:Energistics_UoM_ftUS:"
+            },
+            "propertyNames": {
+              "title": "UOM Property Names",
+              "description": "The list of property names, to which this meta data item provides Unit context to. Data structures, which come in a single frame of reference, can register the property name, others require a full path like \"Data.StructureA.PropertyB\" to define a unique context.",
+              "type": "array",
+              "example": [
+                "HorizontalDeflection.EastWest",
+                "HorizontalDeflection.NorthSouth"
+              ],
+              "items": {
+                "type": "string"
+              }
+            }
+          },
+          "required": [
+            "kind",
+            "persistableReference"
+          ]
+        },
+        {
+          "title": "FrameOfReferenceCRS",
+          "type": "object",
+          "properties": {
+            "kind": {
+              "title": "CRS Reference Kind",
+              "description": "The kind of reference, constant 'CRS' for FrameOfReferenceCRS.",
+              "const": "CRS"
+            },
+            "name": {
+              "title": "CRS Name",
+              "description": "The name of the CRS.",
+              "type": "string",
+              "example": "NAD27 * OGP-Usa Conus / North Dakota South [32021,15851]"
+            },
+            "persistableReference": {
+              "title": "CRS Persistable Reference",
+              "description": "The self-contained, persistable reference string uniquely identifying the CRS.",
+              "type": "string",
+              "example": "{\"authCode\":{\"auth\":\"EPSG\",\"code\":\"32615\"},\"type\":\"LBC\",\"ver\":\"PE_10_3_1\",\"name\":\"WGS_1984_UTM_Zone_15N\",\"wkt\":\"PROJCS[\\\"WGS_1984_UTM_Zone_15N\\\",GEOGCS[\\\"GCS_WGS_1984\\\",DATUM[\\\"D_WGS_1984\\\",SPHEROID[\\\"WGS_1984\\\",6378137.0,298.257223563]],PRIMEM[\\\"Greenwich\\\",0.0],UNIT[\\\"Degree\\\",0.0174532925199433]],PROJECTION[\\\"Transverse_Mercator\\\"],PARAMETER[\\\"False_Easting\\\",500000.0],PARAMETER[\\\"False_Northing\\\",0.0],PARAMETER[\\\"Central_Meridian\\\",-93.0],PARAMETER[\\\"Scale_Factor\\\",0.9996],PARAMETER[\\\"Latitude_Of_Origin\\\",0.0],UNIT[\\\"Meter\\\",1.0],AUTHORITY[\\\"EPSG\\\",32615]]\"}"
+            },
+            "coordinateReferenceSystemID": {
+              "description": "SRN to CRS reference.",
+              "type": "string",
+              "pattern": "^srn:<namespace>:reference-data\\/CoordinateReferenceSystem:[^:]+:[0-9]*$",
+              "example": "srn:<namespace>:reference-data/CoordinateReferenceSystem:EPSG.32615:"
+            },
+            "propertyNames": {
+              "title": "CRS Property Names",
+              "description": "The list of property names, to which this meta data item provides CRS context to. Data structures, which come in a single frame of reference, can register the property name, others require a full path like \"Data.StructureA.PropertyB\" to define a unique context.",
+              "type": "array",
+              "example": [
+                "KickOffPosition.X",
+                "KickOffPosition.Y"
+              ],
+              "items": {
+                "type": "string"
+              }
+            }
+          },
+          "required": [
+            "kind",
+            "persistableReference"
+          ]
+        },
+        {
+          "title": "FrameOfReferenceDateTime",
+          "type": "object",
+          "properties": {
+            "kind": {
+              "title": "DateTime Reference Kind",
+              "description": "The kind of reference, constant 'DateTime', for FrameOfReferenceDateTime.",
+              "const": "DateTime"
+            },
+            "name": {
+              "title": "DateTime Name",
+              "description": "The name of the DateTime format and reference.",
+              "type": "string",
+              "example": "UTC"
+            },
+            "persistableReference": {
+              "title": "DateTime Persistable Reference",
+              "description": "The self-contained, persistable reference string uniquely identifying DateTime reference.",
+              "type": "string",
+              "example": "{\"format\":\"yyyy-MM-ddTHH:mm:ssZ\",\"timeZone\":\"UTC\",\"type\":\"DTM\"}"
+            },
+            "propertyNames": {
+              "title": "DateTime Property Names",
+              "description": "The list of property names, to which this meta data item provides DateTime context to. Data structures, which come in a single frame of reference, can register the property name, others require a full path like \"Data.StructureA.PropertyB\" to define a unique context.",
+              "type": "array",
+              "example": [
+                "Acquisition.StartTime",
+                "Acquisition.EndTime"
+              ],
+              "items": {
+                "type": "string"
+              }
+            }
+          },
+          "required": [
+            "kind",
+            "persistableReference"
+          ]
+        },
+        {
+          "title": "FrameOfReferenceAzimuthReference",
+          "type": "object",
+          "properties": {
+            "kind": {
+              "title": "AzimuthReference Reference Kind",
+              "description": "The kind of reference, constant 'AzimuthReference', for FrameOfReferenceAzimuthReference.",
+              "const": "AzimuthReference"
+            },
+            "name": {
+              "title": "AzimuthReference Name",
+              "description": "The name of the CRS or the symbol/name of the unit.",
+              "type": "string",
+              "example": "TrueNorth"
+            },
+            "persistableReference": {
+              "title": "AzimuthReference Persistable Reference",
+              "description": "The self-contained, persistable reference string uniquely identifying AzimuthReference.",
+              "type": "string",
+              "example": "{\"code\":\"TrueNorth\",\"type\":\"AZR\"}"
+            },
+            "propertyNames": {
+              "title": "AzimuthReference Property Names",
+              "description": "The list of property names, to which this meta data item provides AzimuthReference context to. Data structures, which come in a single frame of reference, can register the property name, others require a full path like \"Data.StructureA.PropertyB\" to define a unique context.",
+              "type": "array",
+              "example": [
+                "Bearing"
+              ],
+              "items": {
+                "type": "string"
+              }
+            }
+          },
+          "required": [
+            "kind",
+            "persistableReference"
+          ]
+        }
+      ]
+    },
+    "AbstractFacilityOperator.1.0.0": {
+      "title": "AbstractFacilityOperator",
+      "description": "The organisation that was responsible for a facility at some point in time.",
+      "type": "object",
+      "properties": {
+        "FacilityOperatorOrganisationID": {
+          "description": "The company that currently operates, or previously operated the facility",
+          "type": "string",
+          "pattern": "^srn:<namespace>:master-data\\/Organisation:[^:]+:[0-9]*$"
+        },
+        "EffectiveDateTime": {
+          "description": "The date and time at which the facility operator becomes effective.",
+          "type": "string",
+          "format": "date-time"
+        },
+        "TerminationDateTime": {
+          "description": "The date and time at which the facility operator is no longer in effect.",
+          "type": "string",
+          "format": "date-time"
+        }
+      }
+    },
+    "AbstractAnyCrsFeatureCollection.1.0.0": {
+      "title": "AbstractAnyCrsFeatureCollection",
+      "description": "A schema like GeoJSON FeatureCollection with a non-WGS 84 CRS context; based on https://geojson.org/schema/FeatureCollection.json. Attention: the coordinate order is fixed: Longitude/Easting/Westing/X first, followed by Latitude/Northing/Southing/Y, optionally height as third coordinate.",
+      "type": "object",
+      "required": [
+        "type",
+        "persistableReferenceCRS",
+        "features"
+      ],
+      "properties": {
+        "type": {
+          "type": "string",
+          "enum": [
+            "AnyCrsFeatureCollection"
+          ]
+        },
+        "CoordinateReferenceSystemID": {
+          "title": "Coordinate Reference System ID",
+          "description": "The CRS reference into the CoordinateReferenceSystem catalog.",
+          "type": "string",
+          "pattern": "^srn:<namespace>:reference-data\\/CoordinateReferenceSystem:[^:]+:[0-9]*$",
+          "example": "srn:<namespace>:reference-data/CoordinateReferenceSystem:BoundCRS.SLB.32021.15851:"
+        },
+        "VerticalCoordinateReferenceSystemID": {
+          "title": "Vertical Coordinate Reference System ID",
+          "description": "The explicit VerticalCRS reference into the CoordinateReferenceSystem catalog. This property stays empty for 2D geometries. Absent or empty values for 3D geometries mean the context may be provided by a CompoundCRS in 'CoordinateReferenceSystemID' or implicitly EPSG:5714 MSL height",
+          "type": "string",
+          "pattern": "^srn:<namespace>:reference-data\\/CoordinateReferenceSystem:[^:]+:[0-9]*$",
+          "example": "srn:<namespace>:reference-data/CoordinateReferenceSystem:VerticalCRS.EPSG.5773:"
+        },
+        "persistableReferenceCRS": {
+          "type": "string",
+          "title": "CRS Reference",
+          "description": "The CRS reference as persistableReference string. If populated, the CoordinateReferenceSystemID takes precedence.",
+          "example": "{\"lateBoundCRS\":{\"wkt\":\"PROJCS[\\\"NAD_1927_StatePlane_North_Dakota_South_FIPS_3302\\\",GEOGCS[\\\"GCS_North_American_1927\\\",DATUM[\\\"D_North_American_1927\\\",SPHEROID[\\\"Clarke_1866\\\",6378206.4,294.9786982]],PRIMEM[\\\"Greenwich\\\",0.0],UNIT[\\\"Degree\\\",0.0174532925199433]],PROJECTION[\\\"Lambert_Conformal_Conic\\\"],PARAMETER[\\\"False_Easting\\\",2000000.0],PARAMETER[\\\"False_Northing\\\",0.0],PARAMETER[\\\"Central_Meridian\\\",-100.5],PARAMETER[\\\"Standard_Parallel_1\\\",46.1833333333333],PARAMETER[\\\"Standard_Parallel_2\\\",47.4833333333333],PARAMETER[\\\"Latitude_Of_Origin\\\",45.6666666666667],UNIT[\\\"Foot_US\\\",0.304800609601219],AUTHORITY[\\\"EPSG\\\",32021]]\",\"ver\":\"PE_10_3_1\",\"name\":\"NAD_1927_StatePlane_North_Dakota_South_FIPS_3302\",\"authCode\":{\"auth\":\"EPSG\",\"code\":\"32021\"},\"type\":\"LBC\"},\"singleCT\":{\"wkt\":\"GEOGTRAN[\\\"NAD_1927_To_WGS_1984_79_CONUS\\\",GEOGCS[\\\"GCS_North_American_1927\\\",DATUM[\\\"D_North_American_1927\\\",SPHEROID[\\\"Clarke_1866\\\",6378206.4,294.9786982]],PRIMEM[\\\"Greenwich\\\",0.0],UNIT[\\\"Degree\\\",0.0174532925199433]],GEOGCS[\\\"GCS_WGS_1984\\\",DATUM[\\\"D_WGS_1984\\\",SPHEROID[\\\"WGS_1984\\\",6378137.0,298.257223563]],PRIMEM[\\\"Greenwich\\\",0.0],UNIT[\\\"Degree\\\",0.0174532925199433]],METHOD[\\\"NADCON\\\"],PARAMETER[\\\"Dataset_conus\\\",0.0],AUTHORITY[\\\"EPSG\\\",15851]]\",\"ver\":\"PE_10_3_1\",\"name\":\"NAD_1927_To_WGS_1984_79_CONUS\",\"authCode\":{\"auth\":\"EPSG\",\"code\":\"15851\"},\"type\":\"ST\"},\"ver\":\"PE_10_3_1\",\"name\":\"NAD27 * OGP-Usa Conus / North Dakota South [32021,15851]\",\"authCode\":{\"auth\":\"SLB\",\"code\":\"32021079\"},\"type\":\"EBC\"}"
+        },
+        "persistableReferenceVerticalCRS": {
+          "type": "string",
+          "title": "Vertical CRS Reference",
+          "description": "The VerticalCRS reference as persistableReference string. If populated, the VerticalCoordinateReferenceSystemID takes precedence. The property is null or empty for 2D geometries. For 3D geometries and absent or null persistableReferenceVerticalCRS the vertical CRS is either provided via persistableReferenceCRS's CompoundCRS or it is implicitly defined as EPSG:5714 MSL height.",
+          "example": "{\"authCode\":{\"auth\":\"EPSG\",\"code\":\"5773\"},\"type\":\"LBC\",\"ver\":\"PE_10_3_1\",\"name\":\"EGM96_Geoid\",\"wkt\":\"VERTCS[\\\"EGM96_Geoid\\\",VDATUM[\\\"EGM96_Geoid\\\"],PARAMETER[\\\"Vertical_Shift\\\",0.0],PARAMETER[\\\"Direction\\\",1.0],UNIT[\\\"Meter\\\",1.0],AUTHORITY[\\\"EPSG\\\",5773]]\"}"
+        },
+        "persistableReferenceUnitZ": {
+          "type": "string",
+          "title": "Z-Unit Reference",
+          "description": "The unit of measure for the Z-axis (only for 3-dimensional coordinates, where the CRS does not describe the vertical unit). Note that the direction is upwards positive, i.e. Z means height.",
+          "example": "{\"scaleOffset\":{\"scale\":1.0,\"offset\":0.0},\"symbol\":\"m\",\"baseMeasurement\":{\"ancestry\":\"Length\",\"type\":\"UM\"},\"type\":\"USO\"}"
+        },
+        "features": {
+          "type": "array",
+          "items": {
+            "title": "AnyCrsGeoJSON Feature",
+            "type": "object",
+            "required": [
+              "type",
+              "properties",
+              "geometry"
+            ],
+            "properties": {
+              "type": {
+                "type": "string",
+                "enum": [
+                  "AnyCrsFeature"
+                ]
+              },
+              "properties": {
+                "oneOf": [
+                  {
+                    "type": "null"
+                  },
+                  {
+                    "type": "object"
+                  }
+                ]
+              },
+              "geometry": {
+                "oneOf": [
+                  {
+                    "type": "null"
+                  },
+                  {
+                    "title": "AnyCrsGeoJSON Point",
+                    "type": "object",
+                    "required": [
+                      "type",
+                      "coordinates"
+                    ],
+                    "properties": {
+                      "type": {
+                        "type": "string",
+                        "enum": [
+                          "AnyCrsPoint"
+                        ]
+                      },
+                      "coordinates": {
+                        "type": "array",
+                        "minItems": 2,
+                        "items": {
+                          "type": "number"
+                        }
+                      },
+                      "bbox": {
+                        "type": "array",
+                        "minItems": 4,
+                        "items": {
+                          "type": "number"
+                        }
+                      }
+                    }
+                  },
+                  {
+                    "title": "AnyCrsGeoJSON LineString",
+                    "type": "object",
+                    "required": [
+                      "type",
+                      "coordinates"
+                    ],
+                    "properties": {
+                      "type": {
+                        "type": "string",
+                        "enum": [
+                          "AnyCrsLineString"
+                        ]
+                      },
+                      "coordinates": {
+                        "type": "array",
+                        "minItems": 2,
+                        "items": {
+                          "type": "array",
+                          "minItems": 2,
+                          "items": {
+                            "type": "number"
+                          }
+                        }
+                      },
+                      "bbox": {
+                        "type": "array",
+                        "minItems": 4,
+                        "items": {
+                          "type": "number"
+                        }
+                      }
+                    }
+                  },
+                  {
+                    "title": "AnyCrsGeoJSON Polygon",
+                    "type": "object",
+                    "required": [
+                      "type",
+                      "coordinates"
+                    ],
+                    "properties": {
+                      "type": {
+                        "type": "string",
+                        "enum": [
+                          "AnyCrsPolygon"
+                        ]
+                      },
+                      "coordinates": {
+                        "type": "array",
+                        "items": {
+                          "type": "array",
+                          "minItems": 4,
+                          "items": {
+                            "type": "array",
+                            "minItems": 2,
+                            "items": {
+                              "type": "number"
+                            }
+                          }
+                        }
+                      },
+                      "bbox": {
+                        "type": "array",
+                        "minItems": 4,
+                        "items": {
+                          "type": "number"
+                        }
+                      }
+                    }
+                  },
+                  {
+                    "title": "AnyCrsGeoJSON MultiPoint",
+                    "type": "object",
+                    "required": [
+                      "type",
+                      "coordinates"
+                    ],
+                    "properties": {
+                      "type": {
+                        "type": "string",
+                        "enum": [
+                          "AnyCrsMultiPoint"
+                        ]
+                      },
+                      "coordinates": {
+                        "type": "array",
+                        "items": {
+                          "type": "array",
+                          "minItems": 2,
+                          "items": {
+                            "type": "number"
+                          }
+                        }
+                      },
+                      "bbox": {
+                        "type": "array",
+                        "minItems": 4,
+                        "items": {
+                          "type": "number"
+                        }
+                      }
+                    }
+                  },
+                  {
+                    "title": "AnyCrsGeoJSON MultiLineString",
+                    "type": "object",
+                    "required": [
+                      "type",
+                      "coordinates"
+                    ],
+                    "properties": {
+                      "type": {
+                        "type": "string",
+                        "enum": [
+                          "AnyCrsMultiLineString"
+                        ]
+                      },
+                      "coordinates": {
+                        "type": "array",
+                        "items": {
+                          "type": "array",
+                          "minItems": 2,
+                          "items": {
+                            "type": "array",
+                            "minItems": 2,
+                            "items": {
+                              "type": "number"
+                            }
+                          }
+                        }
+                      },
+                      "bbox": {
+                        "type": "array",
+                        "minItems": 4,
+                        "items": {
+                          "type": "number"
+                        }
+                      }
+                    }
+                  },
+                  {
+                    "title": "AnyCrsGeoJSON MultiPolygon",
+                    "type": "object",
+                    "required": [
+                      "type",
+                      "coordinates"
+                    ],
+                    "properties": {
+                      "type": {
+                        "type": "string",
+                        "enum": [
+                          "AnyCrsMultiPolygon"
+                        ]
+                      },
+                      "coordinates": {
+                        "type": "array",
+                        "items": {
+                          "type": "array",
+                          "items": {
+                            "type": "array",
+                            "minItems": 4,
+                            "items": {
+                              "type": "array",
+                              "minItems": 2,
+                              "items": {
+                                "type": "number"
+                              }
+                            }
+                          }
+                        }
+                      },
+                      "bbox": {
+                        "type": "array",
+                        "minItems": 4,
+                        "items": {
+                          "type": "number"
+                        }
+                      }
+                    }
+                  },
+                  {
+                    "title": "AnyCrsGeoJSON GeometryCollection",
+                    "type": "object",
+                    "required": [
+                      "type",
+                      "geometries"
+                    ],
+                    "properties": {
+                      "type": {
+                        "type": "string",
+                        "enum": [
+                          "AnyCrsGeometryCollection"
+                        ]
+                      },
+                      "geometries": {
+                        "type": "array",
+                        "items": {
+                          "oneOf": [
+                            {
+                              "title": "AnyCrsGeoJSON Point",
+                              "type": "object",
+                              "required": [
+                                "type",
+                                "coordinates"
+                              ],
+                              "properties": {
+                                "type": {
+                                  "type": "string",
+                                  "enum": [
+                                    "AnyCrsPoint"
+                                  ]
+                                },
+                                "coordinates": {
+                                  "type": "array",
+                                  "minItems": 2,
+                                  "items": {
+                                    "type": "number"
+                                  }
+                                },
+                                "bbox": {
+                                  "type": "array",
+                                  "minItems": 4,
+                                  "items": {
+                                    "type": "number"
+                                  }
+                                }
+                              }
+                            },
+                            {
+                              "title": "AnyCrsGeoJSON LineString",
+                              "type": "object",
+                              "required": [
+                                "type",
+                                "coordinates"
+                              ],
+                              "properties": {
+                                "type": {
+                                  "type": "string",
+                                  "enum": [
+                                    "AnyCrsLineString"
+                                  ]
+                                },
+                                "coordinates": {
+                                  "type": "array",
+                                  "minItems": 2,
+                                  "items": {
+                                    "type": "array",
+                                    "minItems": 2,
+                                    "items": {
+                                      "type": "number"
+                                    }
+                                  }
+                                },
+                                "bbox": {
+                                  "type": "array",
+                                  "minItems": 4,
+                                  "items": {
+                                    "type": "number"
+                                  }
+                                }
+                              }
+                            },
+                            {
+                              "title": "AnyCrsGeoJSON Polygon",
+                              "type": "object",
+                              "required": [
+                                "type",
+                                "coordinates"
+                              ],
+                              "properties": {
+                                "type": {
+                                  "type": "string",
+                                  "enum": [
+                                    "AnyCrsPolygon"
+                                  ]
+                                },
+                                "coordinates": {
+                                  "type": "array",
+                                  "items": {
+                                    "type": "array",
+                                    "minItems": 4,
+                                    "items": {
+                                      "type": "array",
+                                      "minItems": 2,
+                                      "items": {
+                                        "type": "number"
+                                      }
+                                    }
+                                  }
+                                },
+                                "bbox": {
+                                  "type": "array",
+                                  "minItems": 4,
+                                  "items": {
+                                    "type": "number"
+                                  }
+                                }
+                              }
+                            },
+                            {
+                              "title": "AnyCrsGeoJSON MultiPoint",
+                              "type": "object",
+                              "required": [
+                                "type",
+                                "coordinates"
+                              ],
+                              "properties": {
+                                "type": {
+                                  "type": "string",
+                                  "enum": [
+                                    "AnyCrsMultiPoint"
+                                  ]
+                                },
+                                "coordinates": {
+                                  "type": "array",
+                                  "items": {
+                                    "type": "array",
+                                    "minItems": 2,
+                                    "items": {
+                                      "type": "number"
+                                    }
+                                  }
+                                },
+                                "bbox": {
+                                  "type": "array",
+                                  "minItems": 4,
+                                  "items": {
+                                    "type": "number"
+                                  }
+                                }
+                              }
+                            },
+                            {
+                              "title": "AnyCrsGeoJSON MultiLineString",
+                              "type": "object",
+                              "required": [
+                                "type",
+                                "coordinates"
+                              ],
+                              "properties": {
+                                "type": {
+                                  "type": "string",
+                                  "enum": [
+                                    "AnyCrsMultiLineString"
+                                  ]
+                                },
+                                "coordinates": {
+                                  "type": "array",
+                                  "items": {
+                                    "type": "array",
+                                    "minItems": 2,
+                                    "items": {
+                                      "type": "array",
+                                      "minItems": 2,
+                                      "items": {
+                                        "type": "number"
+                                      }
+                                    }
+                                  }
+                                },
+                                "bbox": {
+                                  "type": "array",
+                                  "minItems": 4,
+                                  "items": {
+                                    "type": "number"
+                                  }
+                                }
+                              }
+                            },
+                            {
+                              "title": "AnyCrsGeoJSON MultiPolygon",
+                              "type": "object",
+                              "required": [
+                                "type",
+                                "coordinates"
+                              ],
+                              "properties": {
+                                "type": {
+                                  "type": "string",
+                                  "enum": [
+                                    "AnyCrsMultiPolygon"
+                                  ]
+                                },
+                                "coordinates": {
+                                  "type": "array",
+                                  "items": {
+                                    "type": "array",
+                                    "items": {
+                                      "type": "array",
+                                      "minItems": 4,
+                                      "items": {
+                                        "type": "array",
+                                        "minItems": 2,
+                                        "items": {
+                                          "type": "number"
+                                        }
+                                      }
+                                    }
+                                  }
+                                },
+                                "bbox": {
+                                  "type": "array",
+                                  "minItems": 4,
+                                  "items": {
+                                    "type": "number"
+                                  }
+                                }
+                              }
+                            }
+                          ]
+                        }
+                      },
+                      "bbox": {
+                        "type": "array",
+                        "minItems": 4,
+                        "items": {
+                          "type": "number"
+                        }
+                      }
+                    }
+                  }
+                ]
+              },
+              "bbox": {
+                "type": "array",
+                "minItems": 4,
+                "items": {
+                  "type": "number"
+                }
+              }
+            }
+          }
+        },
+        "bbox": {
+          "type": "array",
+          "minItems": 4,
+          "items": {
+            "type": "number"
+          }
+        }
+      }
+    },
+    "AbstractFeatureCollection.1.0.0": {
+      "description": "GeoJSON feature collection as originally published in https://geojson.org/schema/FeatureCollection.json. Attention: the coordinate order is fixed: Longitude first, followed by Latitude, optionally height above MSL (EPSG:5714) as third coordinate.",
+      "title": "GeoJSON FeatureCollection",
+      "type": "object",
+      "required": [
+        "type",
+        "features"
+      ],
+      "properties": {
+        "type": {
+          "type": "string",
+          "enum": [
+            "FeatureCollection"
+          ]
+        },
+        "features": {
+          "type": "array",
+          "items": {
+            "title": "GeoJSON Feature",
+            "type": "object",
+            "required": [
+              "type",
+              "properties",
+              "geometry"
+            ],
+            "properties": {
+              "type": {
+                "type": "string",
+                "enum": [
+                  "Feature"
+                ]
+              },
+              "properties": {
+                "oneOf": [
+                  {
+                    "type": "null"
+                  },
+                  {
+                    "type": "object"
+                  }
+                ]
+              },
+              "geometry": {
+                "oneOf": [
+                  {
+                    "type": "null"
+                  },
+                  {
+                    "title": "GeoJSON Point",
+                    "type": "object",
+                    "required": [
+                      "type",
+                      "coordinates"
+                    ],
+                    "properties": {
+                      "type": {
+                        "type": "string",
+                        "enum": [
+                          "Point"
+                        ]
+                      },
+                      "coordinates": {
+                        "type": "array",
+                        "minItems": 2,
+                        "items": {
+                          "type": "number"
+                        }
+                      },
+                      "bbox": {
+                        "type": "array",
+                        "minItems": 4,
+                        "items": {
+                          "type": "number"
+                        }
+                      }
+                    }
+                  },
+                  {
+                    "title": "GeoJSON LineString",
+                    "type": "object",
+                    "required": [
+                      "type",
+                      "coordinates"
+                    ],
+                    "properties": {
+                      "type": {
+                        "type": "string",
+                        "enum": [
+                          "LineString"
+                        ]
+                      },
+                      "coordinates": {
+                        "type": "array",
+                        "minItems": 2,
+                        "items": {
+                          "type": "array",
+                          "minItems": 2,
+                          "items": {
+                            "type": "number"
+                          }
+                        }
+                      },
+                      "bbox": {
+                        "type": "array",
+                        "minItems": 4,
+                        "items": {
+                          "type": "number"
+                        }
+                      }
+                    }
+                  },
+                  {
+                    "title": "GeoJSON Polygon",
+                    "type": "object",
+                    "required": [
+                      "type",
+                      "coordinates"
+                    ],
+                    "properties": {
+                      "type": {
+                        "type": "string",
+                        "enum": [
+                          "Polygon"
+                        ]
+                      },
+                      "coordinates": {
+                        "type": "array",
+                        "items": {
+                          "type": "array",
+                          "minItems": 4,
+                          "items": {
+                            "type": "array",
+                            "minItems": 2,
+                            "items": {
+                              "type": "number"
+                            }
+                          }
+                        }
+                      },
+                      "bbox": {
+                        "type": "array",
+                        "minItems": 4,
+                        "items": {
+                          "type": "number"
+                        }
+                      }
+                    }
+                  },
+                  {
+                    "title": "GeoJSON MultiPoint",
+                    "type": "object",
+                    "required": [
+                      "type",
+                      "coordinates"
+                    ],
+                    "properties": {
+                      "type": {
+                        "type": "string",
+                        "enum": [
+                          "MultiPoint"
+                        ]
+                      },
+                      "coordinates": {
+                        "type": "array",
+                        "items": {
+                          "type": "array",
+                          "minItems": 2,
+                          "items": {
+                            "type": "number"
+                          }
+                        }
+                      },
+                      "bbox": {
+                        "type": "array",
+                        "minItems": 4,
+                        "items": {
+                          "type": "number"
+                        }
+                      }
+                    }
+                  },
+                  {
+                    "title": "GeoJSON MultiLineString",
+                    "type": "object",
+                    "required": [
+                      "type",
+                      "coordinates"
+                    ],
+                    "properties": {
+                      "type": {
+                        "type": "string",
+                        "enum": [
+                          "MultiLineString"
+                        ]
+                      },
+                      "coordinates": {
+                        "type": "array",
+                        "items": {
+                          "type": "array",
+                          "minItems": 2,
+                          "items": {
+                            "type": "array",
+                            "minItems": 2,
+                            "items": {
+                              "type": "number"
+                            }
+                          }
+                        }
+                      },
+                      "bbox": {
+                        "type": "array",
+                        "minItems": 4,
+                        "items": {
+                          "type": "number"
+                        }
+                      }
+                    }
+                  },
+                  {
+                    "title": "GeoJSON MultiPolygon",
+                    "type": "object",
+                    "required": [
+                      "type",
+                      "coordinates"
+                    ],
+                    "properties": {
+                      "type": {
+                        "type": "string",
+                        "enum": [
+                          "MultiPolygon"
+                        ]
+                      },
+                      "coordinates": {
+                        "type": "array",
+                        "items": {
+                          "type": "array",
+                          "items": {
+                            "type": "array",
+                            "minItems": 4,
+                            "items": {
+                              "type": "array",
+                              "minItems": 2,
+                              "items": {
+                                "type": "number"
+                              }
+                            }
+                          }
+                        }
+                      },
+                      "bbox": {
+                        "type": "array",
+                        "minItems": 4,
+                        "items": {
+                          "type": "number"
+                        }
+                      }
+                    }
+                  },
+                  {
+                    "title": "GeoJSON GeometryCollection",
+                    "type": "object",
+                    "required": [
+                      "type",
+                      "geometries"
+                    ],
+                    "properties": {
+                      "type": {
+                        "type": "string",
+                        "enum": [
+                          "GeometryCollection"
+                        ]
+                      },
+                      "geometries": {
+                        "type": "array",
+                        "items": {
+                          "oneOf": [
+                            {
+                              "title": "GeoJSON Point",
+                              "type": "object",
+                              "required": [
+                                "type",
+                                "coordinates"
+                              ],
+                              "properties": {
+                                "type": {
+                                  "type": "string",
+                                  "enum": [
+                                    "Point"
+                                  ]
+                                },
+                                "coordinates": {
+                                  "type": "array",
+                                  "minItems": 2,
+                                  "items": {
+                                    "type": "number"
+                                  }
+                                },
+                                "bbox": {
+                                  "type": "array",
+                                  "minItems": 4,
+                                  "items": {
+                                    "type": "number"
+                                  }
+                                }
+                              }
+                            },
+                            {
+                              "title": "GeoJSON LineString",
+                              "type": "object",
+                              "required": [
+                                "type",
+                                "coordinates"
+                              ],
+                              "properties": {
+                                "type": {
+                                  "type": "string",
+                                  "enum": [
+                                    "LineString"
+                                  ]
+                                },
+                                "coordinates": {
+                                  "type": "array",
+                                  "minItems": 2,
+                                  "items": {
+                                    "type": "array",
+                                    "minItems": 2,
+                                    "items": {
+                                      "type": "number"
+                                    }
+                                  }
+                                },
+                                "bbox": {
+                                  "type": "array",
+                                  "minItems": 4,
+                                  "items": {
+                                    "type": "number"
+                                  }
+                                }
+                              }
+                            },
+                            {
+                              "title": "GeoJSON Polygon",
+                              "type": "object",
+                              "required": [
+                                "type",
+                                "coordinates"
+                              ],
+                              "properties": {
+                                "type": {
+                                  "type": "string",
+                                  "enum": [
+                                    "Polygon"
+                                  ]
+                                },
+                                "coordinates": {
+                                  "type": "array",
+                                  "items": {
+                                    "type": "array",
+                                    "minItems": 4,
+                                    "items": {
+                                      "type": "array",
+                                      "minItems": 2,
+                                      "items": {
+                                        "type": "number"
+                                      }
+                                    }
+                                  }
+                                },
+                                "bbox": {
+                                  "type": "array",
+                                  "minItems": 4,
+                                  "items": {
+                                    "type": "number"
+                                  }
+                                }
+                              }
+                            },
+                            {
+                              "title": "GeoJSON MultiPoint",
+                              "type": "object",
+                              "required": [
+                                "type",
+                                "coordinates"
+                              ],
+                              "properties": {
+                                "type": {
+                                  "type": "string",
+                                  "enum": [
+                                    "MultiPoint"
+                                  ]
+                                },
+                                "coordinates": {
+                                  "type": "array",
+                                  "items": {
+                                    "type": "array",
+                                    "minItems": 2,
+                                    "items": {
+                                      "type": "number"
+                                    }
+                                  }
+                                },
+                                "bbox": {
+                                  "type": "array",
+                                  "minItems": 4,
+                                  "items": {
+                                    "type": "number"
+                                  }
+                                }
+                              }
+                            },
+                            {
+                              "title": "GeoJSON MultiLineString",
+                              "type": "object",
+                              "required": [
+                                "type",
+                                "coordinates"
+                              ],
+                              "properties": {
+                                "type": {
+                                  "type": "string",
+                                  "enum": [
+                                    "MultiLineString"
+                                  ]
+                                },
+                                "coordinates": {
+                                  "type": "array",
+                                  "items": {
+                                    "type": "array",
+                                    "minItems": 2,
+                                    "items": {
+                                      "type": "array",
+                                      "minItems": 2,
+                                      "items": {
+                                        "type": "number"
+                                      }
+                                    }
+                                  }
+                                },
+                                "bbox": {
+                                  "type": "array",
+                                  "minItems": 4,
+                                  "items": {
+                                    "type": "number"
+                                  }
+                                }
+                              }
+                            },
+                            {
+                              "title": "GeoJSON MultiPolygon",
+                              "type": "object",
+                              "required": [
+                                "type",
+                                "coordinates"
+                              ],
+                              "properties": {
+                                "type": {
+                                  "type": "string",
+                                  "enum": [
+                                    "MultiPolygon"
+                                  ]
+                                },
+                                "coordinates": {
+                                  "type": "array",
+                                  "items": {
+                                    "type": "array",
+                                    "items": {
+                                      "type": "array",
+                                      "minItems": 4,
+                                      "items": {
+                                        "type": "array",
+                                        "minItems": 2,
+                                        "items": {
+                                          "type": "number"
+                                        }
+                                      }
+                                    }
+                                  }
+                                },
+                                "bbox": {
+                                  "type": "array",
+                                  "minItems": 4,
+                                  "items": {
+                                    "type": "number"
+                                  }
+                                }
+                              }
+                            }
+                          ]
+                        }
+                      },
+                      "bbox": {
+                        "type": "array",
+                        "minItems": 4,
+                        "items": {
+                          "type": "number"
+                        }
+                      }
+                    }
+                  }
+                ]
+              },
+              "bbox": {
+                "type": "array",
+                "minItems": 4,
+                "items": {
+                  "type": "number"
+                }
+              }
+            }
+          }
+        },
+        "bbox": {
+          "type": "array",
+          "minItems": 4,
+          "items": {
+            "type": "number"
+          }
+        }
+      }
+    },
+    "AbstractSpatialLocation.1.0.0": {
+      "title": "AbstractSpatialLocation",
+      "description": "A geographic object which can be described by a set of points.",
+      "type": "object",
+      "properties": {
+        "SpatialLocationCoordinatesDate": {
+          "description": "Date when coordinates were measured or retrieved.",
+          "type": "string",
+          "format": "date-time"
+        },
+        "QuantitativeAccuracyBandID": {
+          "description": "An approximate quantitative assessment of the quality of a location (accurate to > 500 m (i.e. not very accurate)), to < 1 m, etc.",
+          "type": "string",
+          "pattern": "^srn:<namespace>:reference-data\\/QuantitativeAccuracyBand:[^:]+:[0-9]*$"
+        },
+        "QualitativeSpatialAccuracyTypeID": {
+          "description": "A qualitative description of the quality of a spatial location, e.g. unverifiable, not verified, basic validation.",
+          "type": "string",
+          "pattern": "^srn:<namespace>:reference-data\\/QualitativeSpatialAccuracyType:[^:]+:[0-9]*$"
+        },
+        "CoordinateQualityCheckPerformedBy": {
+          "description": "The user who performed the Quality Check.",
+          "type": "string"
+        },
+        "CoordinateQualityCheckDateTime": {
+          "description": "The date of the Quality Check.",
+          "type": "string",
+          "format": "date-time"
+        },
+        "CoordinateQualityCheckRemarks": {
+          "description": "Freetext remarks on Quality Check.",
+          "type": "array",
+          "items": {
+            "type": "string"
+          }
+        },
+        "AsIngestedCoordinates": {
+          "title": "As Ingested Coordinates",
+          "description": "The original or 'as ingested' coordinates (Point, MultiPoint, LineString, MultiLineString, Polygon or MultiPolygon). The name 'AsIngestedCoordinates' was chosen to contrast it to 'OriginalCoordinates', which carries the uncertainty whether any coordinate operations took place before ingestion. In cases where the original CRS is different from the as-ingested CRS, the OperationsApplied can also contain the list of operations applied to the coordinate prior to ingestion. The data structure is similar to GeoJSON FeatureCollection, however in a CRS context explicitly defined within the AbstractAnyCrsFeatureCollection. The coordinate sequence follows GeoJSON standard, i.e. 'eastward/longitude', 'northward/latitude' {, 'upward/height' unless overridden by an explicit direction in the AsIngestedCoordinates.VerticalCoordinateReferenceSystemID}.",
+          "$ref": "#/definitions/AbstractAnyCrsFeatureCollection.1.0.0",
+          "x-osdu-frame-of-reference": "CRS:"
+        },
+        "Wgs84Coordinates": {
+          "title": "WGS 84 Coordinates",
+          "description": "The normalized coordinates (Point, MultiPoint, LineString, MultiLineString, Polygon or MultiPolygon) based on WGS 84 (EPSG:4326 for 2-dimensional coordinates, EPSG:4326 + EPSG:5714 (MSL) for 3-dimensional coordinates). This derived coordinate representation is intended for global discoverability only. The schema of this substructure is identical to the GeoJSON FeatureCollection https://geojson.org/schema/FeatureCollection.json. The coordinate sequence follows GeoJSON standard, i.e. longitude, latitude {, height}",
+          "$ref": "#/definitions/AbstractFeatureCollection.1.0.0"
+        },
+        "OperationsApplied": {
+          "title": "Operations Applied",
+          "description": "The audit trail of operations applied to the coordinates from the original state to the current state. The list may contain operations applied prior to ingestion as well as the operations applied to produce the Wgs84Coordinates. The text elements refer to ESRI style CRS and Transformation names, which may have to be translated to EPSG standard names.",
+          "type": "array",
+          "items": {
+            "type": "string"
+          },
+          "example": [
+            "conversion from ED_1950_UTM_Zone_31N to GCS_European_1950; 1 points converted",
+            "transformation GCS_European_1950 to GCS_WGS_1984 using ED_1950_To_WGS_1984_24; 1 points successfully transformed"
+          ]
+        },
+        "SpatialParameterTypeID": {
+          "description": "A type of spatial representation of an object, often general (e.g. an Outline, which could be applied to Field, Reservoir, Facility, etc.) or sometimes specific (e.g. Onshore Outline, State Offshore Outline, Federal Offshore Outline, 3 spatial representations that may be used by Countries).",
+          "type": "string",
+          "pattern": "^srn:<namespace>:reference-data\\/SpatialParameterType:[^:]+:[0-9]*$"
+        },
+        "SpatialGeometryTypeID": {
+          "description": "Indicates the expected look of the SpatialParameterType, e.g. Point, MultiPoint, LineString, MultiLineString, Polygon, MultiPolygon. The value constrains the type of geometries in the GeoJSON Wgs84Coordinates and AsIngestedCoordinates.",
+          "type": "string",
+          "pattern": "^srn:<namespace>:reference-data\\/SpatialGeometryType:[^:]+:[0-9]*$"
+        }
+      }
+    },
+    "AbstractGeoPoliticalContext.1.0.0": {
+      "title": "AbstractGeoPoliticalContext",
+      "description": "A single, typed geo-political entity reference, which is 'abstracted' to AbstractGeoContext and then aggregated by GeoContexts properties.",
+      "type": "object",
+      "properties": {
+        "GeoPoliticalEntityID": {
+          "type": "string",
+          "description": "Reference to GeoPoliticalEntity.",
+          "pattern": "^srn:<namespace>:master-data\\/GeoPoliticalEntity:[^:]+:[0-9]*$"
+        },
+        "GeoTypeID": {
+          "type": "string",
+          "description": "The GeoPoliticalEntityType reference of the GeoPoliticalEntity (via GeoPoliticalEntityID) for application convenience.",
+          "pattern": "^srn:<namespace>:reference-data\\/GeoPoliticalEntityType:[^:]+:[0-9]*$"
+        }
+      }
+    },
+    "AbstractGeoBasinContext.1.0.0": {
+      "title": "AbstractGeoBasinContext",
+      "description": "A single, typed basin entity reference, which is 'abstracted' to AbstractGeoContext and then aggregated by GeoContexts properties.",
+      "type": "object",
+      "properties": {
+        "BasinID": {
+          "type": "string",
+          "description": "Reference to Basin.",
+          "pattern": "^srn:<namespace>:master-data\\/Basin:[^:]+:[0-9]*$"
+        },
+        "GeoTypeID": {
+          "description": "The BasinType reference of the Basin (via BasinID) for application convenience.",
+          "type": "string",
+          "pattern": "^srn:<namespace>:reference-data\\/BasinType:[^:]+:[0-9]*$"
+        }
+      }
+    },
+    "AbstractGeoFieldContext.1.0.0": {
+      "title": "AbstractGeoFieldContext",
+      "description": "A single, typed field entity reference, which is 'abstracted' to AbstractGeoContext and then aggregated by GeoContexts properties.",
+      "type": "object",
+      "properties": {
+        "FieldID": {
+          "type": "string",
+          "description": "Reference to Field.",
+          "pattern": "^srn:<namespace>:master-data\\/Field:[^:]+:[0-9]*$"
+        },
+        "GeoTypeID": {
+          "const": "Field",
+          "description": "The fixed type 'Field' for this AbstractGeoFieldContext."
+        }
+      }
+    },
+    "AbstractGeoPlayContext.1.0.0": {
+      "title": "AbstractGeoPlayContext",
+      "description": "A single, typed Play entity reference, which is 'abstracted' to AbstractGeoContext and then aggregated by GeoContexts properties.",
+      "type": "object",
+      "properties": {
+        "PlayID": {
+          "type": "string",
+          "description": "Reference to the play.",
+          "pattern": "^srn:<namespace>:master-data\\/Play:[^:]+:[0-9]*$"
+        },
+        "GeoTypeID": {
+          "type": "string",
+          "description": "The PlayType reference of the Play (via PlayID) for application convenience.",
+          "pattern": "^srn:<namespace>:reference-data\\/PlayType:[^:]+:[0-9]*$"
+        }
+      }
+    },
+    "AbstractGeoProspectContext.1.0.0": {
+      "title": "AbstractGeoProspectContext",
+      "description": "A single, typed Prospect entity reference, which is 'abstracted' to AbstractGeoContext and then aggregated by GeoContexts properties.",
+      "type": "object",
+      "properties": {
+        "ProspectID": {
+          "type": "string",
+          "description": "Reference to the prospect.",
+          "pattern": "^srn:<namespace>:master-data\\/Prospect:[^:]+:[0-9]*$"
+        },
+        "GeoTypeID": {
+          "type": "string",
+          "description": "The ProspectType reference of the Prospect (via ProspectID) for application convenience.",
+          "pattern": "^srn:<namespace>:reference-data\\/ProspectType:[^:]+:[0-9]*$"
+        }
+      }
+    },
+    "AbstractGeoContext.1.0.0": {
+      "title": "AbstractGeoContext",
+      "description": "A geographic context to an entity. It can be either a reference to a GeoPoliticalEntity, Basin, Field, Play or Prospect.",
+      "oneOf": [
+        {
+          "$ref": "#/definitions/AbstractGeoPoliticalContext.1.0.0"
+        },
+        {
+          "$ref": "#/definitions/AbstractGeoBasinContext.1.0.0"
+        },
+        {
+          "$ref": "#/definitions/AbstractGeoFieldContext.1.0.0"
+        },
+        {
+          "$ref": "#/definitions/AbstractGeoPlayContext.1.0.0"
+        },
+        {
+          "$ref": "#/definitions/AbstractGeoProspectContext.1.0.0"
+        }
+      ]
+    },
+    "AbstractAliasNames.1.0.0": {
+      "title": "AbstractAliasNames",
+      "description": "A list of alternative names for an object.  The preferred name is in a separate, scalar property.  It may or may not be repeated in the alias list, though a best practice is to include it if the list is present, but to omit the list if there are no other names.  Note that the abstract entity is an array so the $ref to it is a simple property reference.",
+      "type": "object",
+      "properties": {
+        "AliasName": {
+          "description": "Alternative Name value of defined name type for an object.",
+          "type": "string"
+        },
+        "AliasNameTypeID": {
+          "description": "A classification of alias names such as by role played or type of source, such as regulatory name, regulatory code, company code, international standard name, etc.",
+          "type": "string",
+          "pattern": "^srn:<namespace>:reference-data\\/AliasNameType:[^:]+:[0-9]*$"
+        },
+        "DefinitionOrganisationID": {
+          "description": "Organisation that provided the name (the source).",
+          "type": "string",
+          "pattern": "^srn:<namespace>:master-data\\/Organisation:[^:]+:[0-9]*$"
+        },
+        "EffectiveDateTime": {
+          "description": "The date and time when an alias name becomes effective.",
+          "type": "string",
+          "format": "date-time"
+        },
+        "TerminationDateTime": {
+          "description": "The data and time when an alias name is no longer in effect.",
+          "type": "string",
+          "format": "date-time"
+        }
+      }
+    },
+    "AbstractFacilityState.1.0.0": {
+      "title": "AbstractFacilityState",
+      "description": "The life cycle status of a facility at some point in time.",
+      "type": "object",
+      "properties": {
+        "EffectiveDateTime": {
+          "description": "The date and time at which the facility state becomes effective.",
+          "type": "string",
+          "format": "date-time"
+        },
+        "TerminationDateTime": {
+          "description": "The date and time at which the facility state is no longer in effect.",
+          "type": "string",
+          "format": "date-time"
+        },
+        "FacilityStateTypeID": {
+          "description": "The facility life cycle state from planning to abandonment.",
+          "type": "string",
+          "pattern": "^srn:<namespace>:reference-data\\/FacilityStateType:[^:]+:[0-9]*$"
+        }
+      }
+    },
+    "AbstractFacilityEvent.1.0.0": {
+      "title": "AbstractFacilityEvent",
+      "description": "A significant occurrence in the life of a facility, which often changes its state, or the state of one of its components.",
+      "type": "object",
+      "properties": {
+        "FacilityEventTypeID": {
+          "description": "The facility event type is a picklist. Examples: Propose, Completion, Entry Date etc.",
+          "type": "string",
+          "pattern": "^srn:<namespace>:reference-data\\/FacilityEventType:[^:]+:[0-9]*$"
+        },
+        "EffectiveDateTime": {
+          "description": "The date and time at which the event becomes effective.",
+          "type": "string",
+          "format": "date-time"
+        },
+        "TerminationDateTime": {
+          "description": "The date and time at which the event is no longer in effect.",
+          "type": "string",
+          "format": "date-time"
+        }
+      }
+    },
+    "AbstractFacilitySpecification.1.0.0": {
+      "title": "AbstractFacilitySpecification",
+      "description": "A property, characteristic, or attribute about a facility that is not described explicitly elsewhere.",
+      "type": "object",
+      "properties": {
+        "EffectiveDateTime": {
+          "description": "The date and time at which the facility specification instance becomes effective.",
+          "type": "string",
+          "format": "date-time"
+        },
+        "TerminationDateTime": {
+          "description": "The date and time at which the facility specification instance is no longer in effect.",
+          "format": "date-time",
+          "type": "string"
+        },
+        "FacilitySpecificationQuantity": {
+          "description": "The value for the specified parameter type.",
+          "type": "number",
+          "x-osdu-frame-of-reference": "UOM_via_property:UnitOfMeasureID"
+        },
+        "FacilitySpecificationDateTime": {
+          "description": "The actual date and time value of the parameter.",
+          "type": "string",
+          "format": "date-time"
+        },
+        "FacilitySpecificationIndicator": {
+          "description": "The actual indicator value of the parameter.",
+          "type": "bool"
+        },
+        "FacilitySpecificationText": {
+          "description": "The actual text value of the parameter.",
+          "type": "string"
+        },
+        "UnitOfMeasureID": {
+          "description": "The unit for the quantity parameter, like metre (m in SI units system) for quantity Length.",
+          "type": "string",
+          "pattern": "^srn:<namespace>:reference-data\\/UnitOfMeasure:[^:]+:[0-9]*$"
+        },
+        "ParameterTypeID": {
+          "description": "Parameter type of property or characteristic.",
+          "type": "string",
+          "pattern": "^srn:<namespace>:reference-data\\/ParameterType:[^:]+:[0-9]*$"
+        }
+      }
+    },
+    "AbstractFacility.1.0.0": {
+      "title": "AbstractFacility",
+      "description": "",
+      "type": "object",
+      "properties": {
+        "FacilityID": {
+          "description": "A system-specified unique identifier of a Facility.",
+          "type": "string"
+        },
+        "FacilityTypeID": {
+          "description": "The definition of a kind of capability to perform a business function or a service.",
+          "type": "string",
+          "pattern": "^srn:<namespace>:reference-data\\/FacilityType:[^:]+:[0-9]*$"
+        },
+        "FacilityOperator": {
+          "description": "The history of operator organizations of the facility.",
+          "type": "array",
+          "items": {
+            "$ref": "#/definitions/AbstractFacilityOperator.1.0.0"
+          }
+        },
+        "DataSourceOrganisationID": {
+          "description": "The main source of the header information.",
+          "type": "string",
+          "pattern": "^srn:<namespace>:master-data\\/Organisation:[^:]+:[0-9]*$"
+        },
+        "SpatialLocation": {
+          "description": "The spatial location information such as coordinates,CRS information.",
+          "type": "array",
+          "items": {
+            "$ref": "#/definitions/AbstractSpatialLocation.1.0.0"
+          }
+        },
+        "GeoContexts": {
+          "description": "List of geographic entities which provide context to the facility.  This may include multiple types or multiple values of the same type.",
+          "type": "array",
+          "items": {
+            "$ref": "#/definitions/AbstractGeoContext.1.0.0"
+          }
+        },
+        "OperatingEnvironmentID": {
+          "description": "Identifies the Facility's general location as being onshore vs. offshore.",
+          "type": "string",
+          "pattern": "^srn:<namespace>:reference-data\\/OperatingEnvironment:[^:]+:[0-9]*$"
+        },
+        "FacilityName": {
+          "description": "Name of the Facility.",
+          "type": "string"
+        },
+        "FacilityNameAlias": {
+          "description": "Alternative names, including historical, by which this facility is/has been known.",
+          "type": "array",
+          "items": {
+            "$ref": "#/definitions/AbstractAliasNames.1.0.0"
+          }
+        },
+        "FacilityState": {
+          "description": "The history of life cycle states the facility has been through.",
+          "type": "array",
+          "items": {
+            "$ref": "#/definitions/AbstractFacilityState.1.0.0"
+          }
+        },
+        "FacilityEvent": {
+          "description": "A list of key facility events.",
+          "type": "array",
+          "items": {
+            "$ref": "#/definitions/AbstractFacilityEvent.1.0.0"
+          }
+        },
+        "FacilitySpecification": {
+          "description": "facilitySpecification maintains the specification like slot name, wellbore drilling permit number, rig name etc.",
+          "type": "array",
+          "items": {
+            "$ref": "#/definitions/AbstractFacilitySpecification.1.0.0"
+          }
+        }
+      }
+    },
+    "AbstractFacilityVerticalMeasurement.1.0.0": {
+      "title": "AbstractFacilityVerticalMeasurement",
+      "description": "A location along a wellbore, _usually_ associated with some aspect of the drilling of the wellbore, but not with any intersecting _subsurface_ natural surfaces.",
+      "type": "object",
+      "properties": {
+        "VerticalMeasurementID": {
+          "description": "The ID for a distinct vertical measurement within the Facility array so that it may be referenced by other vertical measurements if necessary.",
+          "type": "string"
+        },
+        "EffectiveDateTime": {
+          "description": "The date and time at which a vertical measurement instance becomes effective.",
+          "type": "string",
+          "format": "date-time"
+        },
+        "VerticalMeasurement": {
+          "description": "The value of the elevation or depth. Depth is positive downwards from a vertical reference or geodetic datum along a path, which can be vertical; elevation is positive upwards from a geodetic datum along a vertical path. Either can be negative.",
+          "type": "number",
+          "x-osdu-frame-of-reference": "UOM_via_property:VerticalMeasurementUnitOfMeasureID"
+        },
+        "TerminationDateTime": {
+          "description": "The date and time at which a vertical measurement instance is no longer in effect.",
+          "type": "string",
+          "format": "date-time"
+        },
+        "VerticalMeasurementTypeID": {
+          "description": "Specifies the type of vertical measurement (TD, Plugback, Kickoff, Drill Floor, Rotary Table...).",
+          "type": "string",
+          "pattern": "^srn:<namespace>:reference-data\\/VerticalMeasurementType:[^:]+:[0-9]*$"
+        },
+        "VerticalMeasurementPathID": {
+          "description": "Specifies Measured Depth, True Vertical Depth, or Elevation.",
+          "type": "string",
+          "pattern": "^srn:<namespace>:reference-data\\/VerticalMeasurementPath:[^:]+:[0-9]*$"
+        },
+        "VerticalMeasurementSourceID": {
+          "description": "Specifies Driller vs Logger.",
+          "type": "string",
+          "pattern": "^srn:<namespace>:reference-data\\/VerticalMeasurementSource:[^:]+:[0-9]*$"
+        },
+        "WellboreTVDTrajectoryID": {
+          "description": "Specifies what directional survey or wellpath was used to calculate the TVD.",
+          "type": "string",
+          "pattern": "^srn:<namespace>:work-product-component\\/WellboreTrajectory:[^:]+:[0-9]*$"
+        },
+        "VerticalMeasurementUnitOfMeasureID": {
+          "description": "The unit of measure for the vertical measurement. If a unit of measure and a vertical CRS are provided, the unit of measure provided is taken over the unit of measure from the CRS.",
+          "type": "string",
+          "pattern": "^srn:<namespace>:reference-data\\/UnitOfMeasure:[^:]+:[0-9]*$"
+        },
+        "VerticalCRSID": {
+          "description": "Vertical CRS. It is expected that a Vertical CRS or a Vertical Reference is provided, but not both.",
+          "type": "string",
+          "pattern": "^srn:<namespace>:reference-data\\/CoordinateReferenceSystem:[^:]+:[0-9]*$"
+        },
+        "VerticalReferenceID": {
+          "description": "The reference point from which the vertical measurement is made. Must resolve ultimately to a vertical CRS. It is expected that a Vertical CRS or a Vertical Reference is provided, but not both.",
+          "type": "string"
+        },
+        "VerticalMeasurementDescription": {
+          "description": "Text which describes a vertical measurement in detail.",
+          "type": "string"
+        }
+      }
+    },
+    "AbstractWellboreDrillingReason.1.0.0": {
+      "title": "AbstractWellboreDrillingReason",
+      "description": "Purpose for drilling a wellbore, which often is an indication of the level of risk.",
+      "type": "object",
+      "properties": {
+        "DrillingReasonTypeID": {
+          "description": "Identifier of the drilling reason type for the corresponding time period.",
+          "type": "string",
+          "pattern": "^srn:<namespace>:reference-data\\/DrillingReasonType:[^:]+:[0-9]*$"
+        },
+        "EffectiveDateTime": {
+          "description": "The date and time at which the event becomes effective.",
+          "type": "string",
+          "format": "date-time"
+        },
+        "TerminationDateTime": {
+          "description": "The date and time at which the event is no longer in effect.",
+          "type": "string",
+          "format": "date-time"
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/indexer-core/src/test/resources/converter/basic/schema.json.res b/indexer-core/src/test/resources/converter/basic/schema.json.res
new file mode 100644
index 0000000000000000000000000000000000000000..416ac54e5d60a96858525c138d92186109a1f97e
--- /dev/null
+++ b/indexer-core/src/test/resources/converter/basic/schema.json.res
@@ -0,0 +1,137 @@
+{
+  "kind": "osdu:osdu:Wellbore:1.0.0",
+  "schema": [
+    {
+      "kind": "string",
+      "path": "FacilityID"
+    },
+    {
+      "kind": "link",
+      "path": "FacilityTypeID"
+    },
+    {
+      "kind": "link",
+      "path": "DataSourceOrganisationID"
+    },
+    {
+      "kind": "link",
+      "path": "OperatingEnvironmentID"
+    },
+    {
+      "kind": "string",
+      "path": "FacilityName"
+    },
+    {
+      "kind": "link",
+      "path": "WellID"
+    },
+    {
+      "path" : "SequenceNumber",
+      "kind" : "int"
+    },
+    {
+      "kind": "link",
+      "path": "KickOffWellbore"
+    },
+    {
+      "kind": "link",
+      "path": "TrajectoryTypeID"
+    },
+    {
+      "kind": "link",
+      "path": "DefinitiveTrajectoryID"
+    },
+    {
+      "kind": "link",
+      "path": "TargetFormation"
+    },
+    {
+      "kind": "link",
+      "path": "PrimaryMaterialID"
+    },
+    {
+      "kind": "string",
+      "path": "DefaultVerticalMeasurementID"
+    },
+    {
+      "kind": "datetime",
+      "path": "ProjectedBottomHoleLocation.SpatialLocationCoordinatesDate"
+    },
+    {
+      "kind": "link",
+      "path": "ProjectedBottomHoleLocation.QuantitativeAccuracyBandID"
+    },
+    {
+      "kind": "link",
+      "path": "ProjectedBottomHoleLocation.QualitativeSpatialAccuracyTypeID"
+    },
+    {
+      "kind": "string",
+      "path": "ProjectedBottomHoleLocation.CoordinateQualityCheckPerformedBy"
+    },
+    {
+      "kind": "datetime",
+      "path": "ProjectedBottomHoleLocation.CoordinateQualityCheckDateTime"
+    },
+    {
+      "kind": "[]string",
+      "path": "ProjectedBottomHoleLocation.CoordinateQualityCheckRemarks"
+    },
+    {
+      "kind": "core:dl:geoshape:1.0.0",
+      "path": "ProjectedBottomHoleLocation.Wgs84Coordinates"
+    },
+    {
+      "kind": "[]string",
+      "path": "ProjectedBottomHoleLocation.OperationsApplied"
+    },
+    {
+      "kind": "link",
+      "path": "ProjectedBottomHoleLocation.SpatialParameterTypeID"
+    },
+    {
+      "kind": "link",
+      "path": "ProjectedBottomHoleLocation.SpatialGeometryTypeID"
+    },
+    {
+      "kind": "datetime",
+      "path": "GeographicBottomHoleLocation.SpatialLocationCoordinatesDate"
+    },
+    {
+      "kind": "link",
+      "path": "GeographicBottomHoleLocation.QuantitativeAccuracyBandID"
+    },
+    {
+      "kind": "link",
+      "path": "GeographicBottomHoleLocation.QualitativeSpatialAccuracyTypeID"
+    },
+    {
+      "kind": "string",
+      "path": "GeographicBottomHoleLocation.CoordinateQualityCheckPerformedBy"
+    },
+    {
+      "kind": "datetime",
+      "path": "GeographicBottomHoleLocation.CoordinateQualityCheckDateTime"
+    },
+    {
+      "kind": "[]string",
+      "path": "GeographicBottomHoleLocation.CoordinateQualityCheckRemarks"
+    },
+    {
+      "kind": "core:dl:geoshape:1.0.0",
+      "path": "GeographicBottomHoleLocation.Wgs84Coordinates"
+    },
+    {
+      "kind": "[]string",
+      "path": "GeographicBottomHoleLocation.OperationsApplied"
+    },
+    {
+      "kind": "link",
+      "path": "GeographicBottomHoleLocation.SpatialParameterTypeID"
+    },
+    {
+      "kind": "link",
+      "path": "GeographicBottomHoleLocation.SpatialGeometryTypeID"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/indexer-core/src/test/resources/converter/gen-for-folder.sh b/indexer-core/src/test/resources/converter/gen-for-folder.sh
new file mode 100755
index 0000000000000000000000000000000000000000..776b7eea84b1ca904c521760def935c25f169b1e
--- /dev/null
+++ b/indexer-core/src/test/resources/converter/gen-for-folder.sh
@@ -0,0 +1,5 @@
+#/bin/bash
+
+for f in $(find R3-json-schema -name '*.json');
+  do python3 StorageSchemaGenerator.py $f;
+done
diff --git a/indexer-core/src/test/resources/converter/integration-tests/index_records_1.schema b/indexer-core/src/test/resources/converter/integration-tests/index_records_1.schema
new file mode 100644
index 0000000000000000000000000000000000000000..672c3d965d50194ac5c80adecfddbeb24d51a856
--- /dev/null
+++ b/indexer-core/src/test/resources/converter/integration-tests/index_records_1.schema
@@ -0,0 +1,67 @@
+{
+  "properties": {
+    "data": {
+      "allOf": [
+        {
+          "type": "object",
+          "properties": {
+            "Field": {
+              "type": "string"
+            },
+            "Location": {
+              "$ref": "#/definitions/core_dl_geopoint",
+              "description": "The wellbore's position .",
+              "format": "core:dl:geopoint:1.0.0",
+              "title": "WGS 84 Position",
+              "type": "object"
+            },
+            "Basin": {
+              "type": "string"
+            },
+            "County": {
+              "type": "string"
+            },
+            "State": {
+              "type": "string"
+            },
+            "Country": {
+              "type": "string"
+            },
+            "WellStatus": {
+              "type": "string"
+            },
+            "OriginalOperator": {
+              "type": "string"
+            },
+            "WellName": {
+              "type": "string"
+            },
+            "WellType": {
+              "type": "string"
+            },
+            "EmptyAttribute": {
+              "type": "string"
+            },
+            "Rank": {
+              "type": "integer"
+            },
+            "Score": {
+              "type": "integer"
+            },
+            "Established": {
+              "type": "date-time"
+            },
+            "DblArray": {
+              "description": "The name of the host [cloud environment] region(s) for this OSDU resource object.",
+              "title": "Resource Host Region ID",
+              "type": "array",
+              "items": {
+                "type": "number"
+              }
+            }
+          }
+        }
+      ]
+    }
+  }
+}
diff --git a/indexer-core/src/test/resources/converter/integration-tests/index_records_1.schema.res b/indexer-core/src/test/resources/converter/integration-tests/index_records_1.schema.res
new file mode 100644
index 0000000000000000000000000000000000000000..a67be0f5383d708571bcbc03b69cb7c818d860d4
--- /dev/null
+++ b/indexer-core/src/test/resources/converter/integration-tests/index_records_1.schema.res
@@ -0,0 +1,65 @@
+{
+  "kind": "KIND_VAL",
+  "schema": [
+    {
+       "path": "Field",
+       "kind": "string"
+    },
+    {
+      "path": "Location",
+      "kind": "core:dl:geopoint:1.0.0"
+    },
+    {
+      "path": "Basin",
+      "kind": "string"
+    },
+    {
+      "path": "County",
+      "kind": "string"
+    },
+    {
+      "path": "State",
+      "kind": "string"
+    },
+    {
+      "path": "Country",
+      "kind": "string"
+    },
+    {
+      "path": "WellStatus",
+      "kind": "string"
+    },
+    {
+      "path": "OriginalOperator",
+      "kind": "string"
+    },
+    {
+      "path": "WellName",
+      "kind": "string"
+    },
+    {
+      "path": "WellType",
+      "kind": "string"
+    },
+    {
+      "path": "EmptyAttribute",
+      "kind": "string"
+    },
+    {
+      "path": "Rank",
+      "kind": "int"
+    },
+    {
+      "path": "Score",
+       "kind": "int"
+    },
+    {
+      "path": "Established",
+      "kind": "datetime"
+    },
+    {
+       "path": "DblArray",
+       "kind": "[]double"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/indexer-core/src/test/resources/converter/integration-tests/index_records_2.schema b/indexer-core/src/test/resources/converter/integration-tests/index_records_2.schema
new file mode 100644
index 0000000000000000000000000000000000000000..cf5f858c3e9b8b04b9bca08c1b834de2b784bf6a
--- /dev/null
+++ b/indexer-core/src/test/resources/converter/integration-tests/index_records_2.schema
@@ -0,0 +1,62 @@
+{
+  "properties": {
+    "data": {
+      "allOf": [
+        {
+          "type": "object",
+          "properties": {
+            "Field": {
+              "type": "string"
+            },
+            "Location": {
+              "$ref": "#/definitions/core_dl_geopoint",
+              "description": "The wellbore's position .",
+              "format": "core:dl:geopoint:1.0.0",
+              "title": "WGS 84 Position",
+              "type": "object"
+            },
+            "Basin": {
+              "type": "string"
+            },
+            "County": {
+              "type": "string"
+            },
+            "State": {
+              "type": "string"
+            },
+            "Country": {
+              "type": "string"
+            },
+            "WellStatus": {
+              "type": "string"
+            },
+            "OriginalOperator": {
+              "type": "string"
+            },
+            "WellName": {
+              "type": "string"
+            },
+            "WellType": {
+              "type": "string"
+            },
+            "EmptyAttribute": {
+              "type": "string"
+            },
+            "Rank": {
+              "type": "integer"
+            },
+            "Score": {
+              "type": "integer"
+            },
+            "Established": {
+              "type": "date-time"
+            },
+            "InvalidInteger": {
+              "type": "integer"
+            }
+          }
+        }
+      ]
+    }
+  }
+}
diff --git a/indexer-core/src/test/resources/converter/integration-tests/index_records_2.schema.res b/indexer-core/src/test/resources/converter/integration-tests/index_records_2.schema.res
new file mode 100644
index 0000000000000000000000000000000000000000..2d272b735099a5d36d2e50a56b6da8e303f36e50
--- /dev/null
+++ b/indexer-core/src/test/resources/converter/integration-tests/index_records_2.schema.res
@@ -0,0 +1,65 @@
+{
+  "kind": "KIND_VAL",
+  "schema": [
+    {
+       "path": "Field",
+       "kind": "string"
+    },
+    {
+      "path": "Location",
+      "kind": "core:dl:geopoint:1.0.0"
+    },
+    {
+      "path": "Basin",
+      "kind": "string"
+    },
+    {
+      "path": "County",
+      "kind": "string"
+    },
+    {
+      "path": "State",
+      "kind": "string"
+    },
+    {
+      "path": "Country",
+      "kind": "string"
+    },
+    {
+      "path": "WellStatus",
+      "kind": "string"
+    },
+    {
+      "path": "OriginalOperator",
+      "kind": "string"
+    },
+    {
+      "path": "WellName",
+      "kind": "string"
+    },
+    {
+      "path": "WellType",
+      "kind": "string"
+    },
+    {
+      "path": "EmptyAttribute",
+      "kind": "string"
+    },
+    {
+      "path": "Rank",
+      "kind": "int"
+    },
+    {
+      "path": "Score",
+       "kind": "int"
+    },
+    {
+      "path": "Established",
+      "kind": "datetime"
+    },
+    {
+       "path": "InvalidInteger",
+       "kind": "int"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/indexer-core/src/test/resources/converter/integration-tests/index_records_3.schema b/indexer-core/src/test/resources/converter/integration-tests/index_records_3.schema
new file mode 100644
index 0000000000000000000000000000000000000000..802d4493804948ecd9b896af700cbfaa8f00939d
--- /dev/null
+++ b/indexer-core/src/test/resources/converter/integration-tests/index_records_3.schema
@@ -0,0 +1,23 @@
+{
+  "properties": {
+    "data": {
+      "allOf": [
+        {
+          "type": "object",
+          "properties": {
+            "GeoShape": {
+              "$ref": "#/definitions/geoJsonFeatureCollection",
+              "description": "The wellbore's position .",
+              "format": "core:dl:geopoint:1.0.0",
+              "title": "WGS 84 Position",
+              "type": "object"
+            },
+            "WellName": {
+              "type": "string"
+            }
+          }
+        }
+      ]
+    }
+  }
+}
diff --git a/indexer-core/src/test/resources/converter/integration-tests/index_records_3.schema.res b/indexer-core/src/test/resources/converter/integration-tests/index_records_3.schema.res
new file mode 100644
index 0000000000000000000000000000000000000000..bc347c7d037542ca59243e5162bb7ec08e7af2da
--- /dev/null
+++ b/indexer-core/src/test/resources/converter/integration-tests/index_records_3.schema.res
@@ -0,0 +1,13 @@
+{
+  "kind": "KIND_VAL",
+  "schema": [
+    {
+      "path": "GeoShape",
+      "kind": "core:dl:geoshape:1.0.0"
+    },
+    {
+      "path": "WellName",
+      "kind": "string"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/indexer-core/src/test/resources/converter/wks/slb_wke_wellbore.json b/indexer-core/src/test/resources/converter/wks/slb_wke_wellbore.json
new file mode 100644
index 0000000000000000000000000000000000000000..4750faf2cd40de8a375ee67350af2f6eea1fe295
--- /dev/null
+++ b/indexer-core/src/test/resources/converter/wks/slb_wke_wellbore.json
@@ -0,0 +1,1422 @@
+{
+  "$id": "https://slb-swt.visualstudio.com/data-management/Ingestion%20Services/_git/wke-schema?path=%2Fdomains%2Fwell%2Fjson_schema%2Fslb_wke_wellbore.json&version=GBmaster",
+  "$license": "Copyright 2017-2020, Schlumberger\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\nhttp://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n",
+  "$schema": "http://json-schema.org/draft-07/schema#",
+  "definitions": {
+    "core_dl_geopoint": {
+      "description": "A 2D point location in latitude and longitude referenced to WGS 84 if not specified otherwise.",
+      "properties": {
+        "latitude": {
+          "description": "The latitude value in degrees of arc (dega). Value range [-90, 90].",
+          "maximum": 90,
+          "minimum": -90,
+          "title": "Latitude",
+          "type": "number"
+        },
+        "longitude": {
+          "description": "The longitude value in degrees of arc (dega). Value range [-180, 180]",
+          "maximum": 180,
+          "minimum": -180,
+          "title": "Longitude",
+          "type": "number"
+        }
+      },
+      "required": [
+        "latitude",
+        "longitude"
+      ],
+      "title": "2D Map Location",
+      "type": "object"
+    },
+    "geoJsonFeature": {
+      "properties": {
+        "bbox": {
+          "items": {
+            "type": "number"
+          },
+          "minItems": 4,
+          "type": "array"
+        },
+        "geometry": {
+          "oneOf": [
+            {
+              "$ref": "#/definitions/geoJsonPoint",
+              "title": "GeoJSON Point"
+            },
+            {
+              "$ref": "#/definitions/geoJsonMultiPoint",
+              "title": "GeoJSON MultiPoint"
+            },
+            {
+              "$ref": "#/definitions/geoJsonLineString",
+              "title": "GeoJSON LineString"
+            },
+            {
+              "$ref": "#/definitions/geoJsonMultiLineString",
+              "title": "GeoJSON MultiLineString"
+            },
+            {
+              "$ref": "#/definitions/polygon",
+              "title": "GeoJSON Polygon"
+            },
+            {
+              "$ref": "#/definitions/geoJsonMultiPolygon",
+              "title": "GeoJSON MultiPolygon"
+            },
+            {
+              "properties": {
+                "bbox": {
+                  "items": {
+                    "type": "number"
+                  },
+                  "minItems": 4,
+                  "type": "array"
+                },
+                "geometries": {
+                  "items": {
+                    "oneOf": [
+                      {
+                        "$ref": "#/definitions/geoJsonPoint",
+                        "title": "GeoJSON Point"
+                      },
+                      {
+                        "$ref": "#/definitions/geoJsonMultiPoint",
+                        "title": "GeoJSON MultiPoint"
+                      },
+                      {
+                        "$ref": "#/definitions/geoJsonLineString",
+                        "title": "GeoJSON LineString"
+                      },
+                      {
+                        "$ref": "#/definitions/geoJsonMultiLineString",
+                        "title": "GeoJSON MultiLineString"
+                      },
+                      {
+                        "$ref": "#/definitions/polygon",
+                        "title": "GeoJSON Polygon"
+                      },
+                      {
+                        "$ref": "#/definitions/geoJsonMultiPolygon",
+                        "title": "GeoJSON MultiPolygon"
+                      }
+                    ]
+                  },
+                  "type": "array"
+                },
+                "type": {
+                  "enum": [
+                    "GeometryCollection"
+                  ],
+                  "type": "string"
+                }
+              },
+              "required": [
+                "type",
+                "geometries"
+              ],
+              "title": "GeoJSON GeometryCollection",
+              "type": "object"
+            }
+          ]
+        },
+        "properties": {
+          "oneOf": [
+            {
+              "type": "null"
+            },
+            {
+              "type": "object"
+            }
+          ]
+        },
+        "type": {
+          "enum": [
+            "Feature"
+          ],
+          "type": "string"
+        }
+      },
+      "required": [
+        "type",
+        "properties",
+        "geometry"
+      ],
+      "title": "GeoJSON Feature",
+      "type": "object"
+    },
+    "geoJsonFeatureCollection": {
+      "properties": {
+        "bbox": {
+          "items": {
+            "type": "number"
+          },
+          "minItems": 4,
+          "type": "array"
+        },
+        "features": {
+          "items": {
+            "$ref": "#/definitions/geoJsonFeature",
+            "title": "GeoJSON Feature"
+          },
+          "type": "array"
+        },
+        "type": {
+          "enum": [
+            "FeatureCollection"
+          ],
+          "type": "string"
+        }
+      },
+      "required": [
+        "type",
+        "features"
+      ],
+      "title": "GeoJSON FeatureCollection",
+      "type": "object"
+    },
+    "geoJsonLineString": {
+      "description": "GeoJSON LineString as defined in http://geojson.org/schema/LineString.json.",
+      "properties": {
+        "bbox": {
+          "items": {
+            "type": "number"
+          },
+          "minItems": 4,
+          "type": "array"
+        },
+        "coordinates": {
+          "items": {
+            "items": {
+              "type": "number"
+            },
+            "minItems": 2,
+            "type": "array"
+          },
+          "minItems": 2,
+          "type": "array"
+        },
+        "type": {
+          "enum": [
+            "LineString"
+          ],
+          "type": "string"
+        }
+      },
+      "required": [
+        "type",
+        "coordinates"
+      ],
+      "title": "GeoJSON LineString",
+      "type": "object"
+    },
+    "geoJsonMultiLineString": {
+      "$schema": "http://json-schema.org/draft-07/schema#",
+      "properties": {
+        "bbox": {
+          "items": {
+            "type": "number"
+          },
+          "minItems": 4,
+          "type": "array"
+        },
+        "coordinates": {
+          "items": {
+            "items": {
+              "items": {
+                "type": "number"
+              },
+              "minItems": 2,
+              "type": "array"
+            },
+            "minItems": 2,
+            "type": "array"
+          },
+          "type": "array"
+        },
+        "type": {
+          "enum": [
+            "MultiLineString"
+          ],
+          "type": "string"
+        }
+      },
+      "required": [
+        "type",
+        "coordinates"
+      ],
+      "title": "GeoJSON MultiLineString",
+      "type": "object"
+    },
+    "geoJsonMultiPoint": {
+      "properties": {
+        "bbox": {
+          "items": {
+            "type": "number"
+          },
+          "minItems": 4,
+          "type": "array"
+        },
+        "coordinates": {
+          "items": {
+            "items": {
+              "type": "number"
+            },
+            "minItems": 2,
+            "type": "array"
+          },
+          "type": "array"
+        },
+        "type": {
+          "enum": [
+            "MultiPoint"
+          ],
+          "type": "string"
+        }
+      },
+      "required": [
+        "type",
+        "coordinates"
+      ],
+      "title": "GeoJSON Point",
+      "type": "object"
+    },
+    "geoJsonMultiPolygon": {
+      "description": "GeoJSON MultiPolygon derived from http://geojson.org/schema/MultiPolygon.json",
+      "properties": {
+        "bbox": {
+          "description": "Bounding box in longitude, latitude WGS 84.",
+          "items": {
+            "type": "number"
+          },
+          "minItems": 4,
+          "type": "array"
+        },
+        "coordinates": {
+          "description": "Array of polygons (minimum 2D), containing an array of point coordinates (longitude, latitude, (optionally elevation and other properties).",
+          "items": {
+            "items": {
+              "items": {
+                "items": {
+                  "type": "number"
+                },
+                "minItems": 2,
+                "type": "array"
+              },
+              "minItems": 4,
+              "type": "array"
+            },
+            "type": "array"
+          },
+          "type": "array"
+        },
+        "type": {
+          "enum": [
+            "MultiPolygon"
+          ],
+          "type": "string"
+        }
+      },
+      "required": [
+        "type",
+        "coordinates"
+      ],
+      "title": "MultiPolygon",
+      "type": "object"
+    },
+    "geoJsonPoint": {
+      "properties": {
+        "bbox": {
+          "items": {
+            "type": "number"
+          },
+          "minItems": 4,
+          "type": "array"
+        },
+        "coordinates": {
+          "items": {
+            "type": "number"
+          },
+          "minItems": 2,
+          "type": "array"
+        },
+        "type": {
+          "enum": [
+            "Point"
+          ],
+          "type": "string"
+        }
+      },
+      "required": [
+        "type",
+        "coordinates"
+      ],
+      "title": "GeoJSON Point",
+      "type": "object"
+    },
+    "geographicPosition": {
+      "description": "A position in the native geographic CRS (latitude and longitude) combined with an elevation from mean seal level (MSL)",
+      "properties": {
+        "crsKey": {
+          "description": "The 'crsKey', which can be looked up in the 'frameOfReference.crs' for further details.",
+          "title": "CRS Key",
+          "type": "string"
+        },
+        "elevationFromMsl": {
+          "$ref": "#/definitions/valueWithUnit",
+          "description": "Elevation from Mean Seal Level, downwards negative. The unit definition is found via 'elevationFromMsl.unitKey' in 'frameOfReference.units' dictionary.",
+          "title": "Elevation from MSL"
+        },
+        "latitude": {
+          "description": "Native or original latitude (unit defined by CRS)",
+          "title": "Native Latitude",
+          "type": "number"
+        },
+        "longitude": {
+          "description": "Native or original longitude (unit defined by CRS)",
+          "title": "Native Longitude",
+          "type": "number"
+        }
+      },
+      "required": [
+        "latitude",
+        "longitude",
+        "elevationFromMsl",
+        "crsKey"
+      ],
+      "title": "Geographic Position",
+      "type": "object"
+    },
+    "legal": {
+      "description": "Legal meta data like legal tags, relevant other countries, legal status.",
+      "properties": {
+        "legaltags": {
+          "description": "The list of legal tags, see compliance API.",
+          "items": {
+            "type": "string"
+          },
+          "title": "Legal Tags",
+          "type": "array"
+        },
+        "otherRelevantDataCountries": {
+          "description": "The list of other relevant data countries using the ISO 2-letter codes, see compliance API.",
+          "items": {
+            "type": "string"
+          },
+          "title": "Other Relevant Data Countries",
+          "type": "array"
+        },
+        "status": {
+          "description": "The legal status.",
+          "title": "Legal Status",
+          "type": "string"
+        }
+      },
+      "title": "Legal Meta Data",
+      "type": "object"
+    },
+    "linkList": {
+      "additionalProperties": {
+        "description": "An array of one or more entity references in the data lake.",
+        "items": {
+          "type": "string"
+        },
+        "title": "Link List",
+        "type": "array"
+      },
+      "description": "A named list of entities in the data lake as a dictionary item.",
+      "title": "Link List",
+      "type": "object"
+    },
+    "metaItem": {
+      "description": "A meta data item, which allows the association of named properties or property values to a Unit/Measurement/CRS/Azimuth/Time context.",
+      "properties": {
+        "kind": {
+          "description": "The kind of reference, unit, measurement, CRS or azimuth reference.",
+          "enum": [
+            "CRS",
+            "Unit",
+            "Measurement",
+            "AzimuthReference",
+            "DateTime"
+          ],
+          "title": "Reference Kind",
+          "type": "string"
+        },
+        "name": {
+          "description": "The name of the CRS or the symbol/name of the unit",
+          "example": [
+            "NAD27 * OGP-Usa Conus / North Dakota South [32021,15851]",
+            "ft"
+          ],
+          "title": "Name or Symbol",
+          "type": "string"
+        },
+        "persistableReference": {
+          "description": "The persistable reference string uniquely identifying the CRS or Unit",
+          "example": "{\"scaleOffset\":{\"scale\":0.3048006096012192,\"offset\":0.0},\"symbol\":\"ftUS\",\"baseMeasurement\":{\"ancestry\":\"Length\",\"type\":\"UM\"},\"type\":\"USO\"}",
+          "title": "Persistable Reference",
+          "type": "string"
+        },
+        "propertyNames": {
+          "description": "The list of property names, to which this meta data item provides Unit/CRS context to. Data structures, which come in a single frame of reference, can register the property name, others require a full path like \"data.structureA.propertyB\" to define a unique context.",
+          "example": [
+            "elevationFromMsl",
+            "totalDepthMdDriller",
+            "wellHeadProjected"
+          ],
+          "items": {
+            "type": "string"
+          },
+          "title": "Attribute Names",
+          "type": "array"
+        },
+        "propertyValues": {
+          "description": "The list of property values, to which this meta data item provides Unit/CRS context to. Typically a unit symbol is a value to a data structure; this symbol is then registered in this propertyValues array and the persistableReference provides the absolute reference.",
+          "example": [
+            "F",
+            "ftUS",
+            "deg"
+          ],
+          "items": {
+            "type": "string"
+          },
+          "title": "Attribute Names",
+          "type": "array"
+        },
+        "uncertainty": {
+          "description": "The uncertainty of the values measured given the unit or CRS unit.",
+          "title": "Uncertainty",
+          "type": "number"
+        }
+      },
+      "required": [
+        "kind",
+        "persistableReference"
+      ],
+      "title": "Frame of Reference Meta Data Item",
+      "type": "object"
+    },
+    "plssLocation": {
+      "$id": "definitions/plssLocation",
+      "description": "A location described by the Public Land Survey System (United States)",
+      "properties": {
+        "aliquotPart": {
+          "description": "A terse, hierarchical reference to a piece of land, in which successive subdivisions of some larger area.",
+          "example": "NWNE",
+          "title": "Aliquot Part",
+          "type": "string"
+        },
+        "range": {
+          "description": "Range, also known as Rng, R; a measure of the distance east or west from a referenced principal meridian, in units of six miles.",
+          "example": "93W",
+          "title": "Range",
+          "type": "string",
+          "x-slb-aliasProperties": [
+            "witsml:Range+witsml:RangeDir"
+          ]
+        },
+        "section": {
+          "description": "Section number (between 1 and 36)",
+          "example": "30",
+          "title": "Section Number",
+          "type": "integer",
+          "x-slb-aliasProperties": [
+            "witsml:Section"
+          ]
+        },
+        "township": {
+          "description": "Township, also known as T or Twp; (1) Synonym for survey township, i.e., a square parcel of land of 36 square miles, or (2) A measure of the distance north or south from a referenced baseline, in units of six miles",
+          "example": "149N",
+          "title": "Township",
+          "type": "string",
+          "x-slb-aliasProperties": [
+            "witsml:Section+witsml:TownshipDir"
+          ]
+        }
+      },
+      "required": [
+        "township",
+        "range",
+        "section"
+      ],
+      "title": "US PLSS Location",
+      "type": "object"
+    },
+    "point3dNonGeoJson": {
+      "description": "A 3-dimensional point with a CRS key, which is further described in 'frameOfReference.crs' and a unitKey for the z or 3rd coordinate; the unit key is further described in 'frameOfReference.units'.",
+      "properties": {
+        "coordinates": {
+          "description": "3-dimensional point; the first coordinate is typically pointing east (easting or longitude), the second coordinate typically points north (northing or latitude). The third coordinate is an elevation (upwards positive, downwards negative). The point's CRS is given by the container.",
+          "items": {
+            "type": "number"
+          },
+          "maxItems": 3,
+          "minItems": 3,
+          "title": "3D Point",
+          "type": "array"
+        },
+        "crsKey": {
+          "description": "The 'crsKey', which can be looked up in the 'frameOfReference.crs' for further details.",
+          "title": "CRS Key",
+          "type": "string"
+        },
+        "unitKey": {
+          "description": "The 'unitKey' for the 3rd coordinate, which can be looked up in the 'frameOfReference.unit' for further details.",
+          "title": "Unit Key",
+          "type": "string"
+        }
+      },
+      "required": [
+        "coordinates",
+        "crsKey",
+        "unitKey"
+      ],
+      "title": "3D Point with CRS/Unit key",
+      "type": "object"
+    },
+    "polygon": {
+      "$schema": "http://json-schema.org/draft-07/schema#",
+      "description": "GeoJSON Polygon derived from http://geojson.org/schema/Polygon.json",
+      "properties": {
+        "bbox": {
+          "items": {
+            "type": "number"
+          },
+          "minItems": 4,
+          "type": "array"
+        },
+        "coordinates": {
+          "items": {
+            "items": {
+              "items": {
+                "type": "number"
+              },
+              "minItems": 2,
+              "type": "array"
+            },
+            "minItems": 4,
+            "type": "array"
+          },
+          "type": "array"
+        },
+        "type": {
+          "enum": [
+            "Polygon"
+          ],
+          "type": "string"
+        }
+      },
+      "required": [
+        "type",
+        "coordinates"
+      ],
+      "title": "GeoJSON Polygon",
+      "type": "object"
+    },
+    "projectedPosition": {
+      "description": "A position in the native CRS in Cartesian coordinates combined with an elevation from mean seal level (MSL)",
+      "properties": {
+        "crsKey": {
+          "description": "The 'crsKey', which can be looked up in the 'frameOfReference.crs' for further details.",
+          "title": "CRS Key",
+          "type": "string"
+        },
+        "elevationFromMsl": {
+          "$ref": "#/definitions/valueWithUnit",
+          "description": "Elevation from Mean Seal Level, downwards negative. The unit definition is found via 'elevationFromMsl.unitKey' in 'frameOfReference.units' dictionary.",
+          "title": "Elevation from MSL"
+        },
+        "x": {
+          "description": "X-coordinate value in native or original projected CRS",
+          "title": "X Coordinate",
+          "type": "number"
+        },
+        "y": {
+          "description": "Y-coordinate value in native or original projected CRS",
+          "title": "Y Coordinate",
+          "type": "number"
+        }
+      },
+      "required": [
+        "x",
+        "y",
+        "elevationFromMsl",
+        "crsKey"
+      ],
+      "title": "Projected Position",
+      "type": "object"
+    },
+    "relationships": {
+      "description": "All relationships from this entity.",
+      "properties": {
+        "definitiveTimeDepthRelation": {
+          "$ref": "#/definitions/toOneRelationship",
+          "description": "The definitive tome-depth relation providing the MD to seismic travel-time transformation.",
+          "title": "Definitive Time-Depth Relation",
+          "x-slb-targetEntity": "timeDepthRelation_logSet"
+        },
+        "definitiveTrajectory": {
+          "$ref": "#/definitions/toOneRelationship",
+          "description": "The definitive trajectory providing the MD to 3D space transformation.",
+          "title": "Definitive Trajectory",
+          "x-slb-targetEntity": "trajectory"
+        },
+        "tieInWellbore": {
+          "$ref": "#/definitions/toOneRelationship",
+          "description": "The tie-in wellbore if this wellbore is a side-track.",
+          "title": "Tie-in Wellbore",
+          "x-slb-aliasProperties": [
+            "witsml:ParentWellbore"
+          ],
+          "x-slb-annotation": "aggregation",
+          "x-slb-targetEntity": "wellbore"
+        },
+        "well": {
+          "$ref": "#/definitions/toOneRelationship",
+          "description": "The well to which this wellbore belongs.",
+          "title": "Well",
+          "x-slb-aliasProperties": [
+            "witsml:Well"
+          ],
+          "x-slb-annotation": "aggregation",
+          "x-slb-targetEntity": "well"
+        }
+      },
+      "title": "Relationships",
+      "type": "object"
+    },
+    "simpleElevationReference": {
+      "description": "The entity's elevation reference, the elevation above MSL where vertical property is 0. Examples: MD==0, Elevation_Depth==0, TVD==0.",
+      "properties": {
+        "elevationFromMsl": {
+          "$ref": "#/definitions/valueWithUnit",
+          "description": "The elevation above mean sea level (MSL), at which the vertical origin is 0.0. The 'unitKey' is further defined in 'frameOfReference.units'.",
+          "example": 123.45,
+          "title": "Elevation from MSL",
+          "x-slb-measurement": "Standard_Depth_Index"
+        },
+        "name": {
+          "description": "The name of the Elevation Reference.",
+          "example": [
+            "MSL",
+            "MD",
+            "GL",
+            "KB"
+          ],
+          "title": "Elevation Reference Name",
+          "type": "string"
+        }
+      },
+      "required": [
+        "elevationFromMsl"
+      ],
+      "title": "Simple Elevation Reference",
+      "type": "object"
+    },
+    "tagDictionary": {
+      "additionalProperties": {
+        "description": "An array of one or more tag items, e.g. access control list tags, legal tags, etc.",
+        "items": {
+          "type": "string"
+        },
+        "title": "Tag Dictionary",
+        "type": "array"
+      },
+      "description": "A tagged list of string arrays, e.g. access control list tags, legal tags, etc.",
+      "title": "Tag Dictionary",
+      "type": "object"
+    },
+    "toManyRelationship": {
+      "description": "A relationship from this entity to many other entities either by natural key (name) or explicit id, optionally classified by confidence level.",
+      "properties": {
+        "confidences": {
+          "description": "The confidences of the relationships. Keep all the arrays ordered and aligned.",
+          "items": {
+            "type": "number"
+          },
+          "title": "Relationship Confidences",
+          "type": "array"
+        },
+        "ids": {
+          "description": "The ids of the related objects. It is populated for an explicit relationship where the target entity is present as a record in the data ecosystem. Keep all the arrays ordered and aligned.",
+          "format": "link",
+          "items": {
+            "type": "string"
+          },
+          "title": "Related Object Id",
+          "type": "array"
+        },
+        "names": {
+          "description": "The names or natural keys of the related objects. Keep all the arrays ordered and aligned.",
+          "items": {
+            "type": "string"
+          },
+          "title": "Related Object Names",
+          "type": "array"
+        },
+        "versions": {
+          "description": "The specific version numbers of the related instances. This is only specified if a specific version is required. If not populated the last version is implied. Keep all the arrays ordered and aligned.",
+          "items": {
+            "format": "int64",
+            "type": "number"
+          },
+          "title": "To Many Relationship",
+          "type": "array"
+        }
+      }
+    },
+    "toOneRelationship": {
+      "description": "A relationship from this entity to one other entity either by natural key (name) or id, optionally classified by confidence level",
+      "properties": {
+        "confidence": {
+          "description": "The confidence of the relationship. If the property is absent a well-known relation is implied.",
+          "example": 1,
+          "title": "Relationship Confidence",
+          "type": "number"
+        },
+        "id": {
+          "description": "The id of the related object in the Data Ecosystem. If set, the id has priority over the natural key in the name property.",
+          "example": "data_partition:namespace:entity_845934c40e8d922bc57b678990d55722",
+          "format": "link",
+          "title": "Related Object Id",
+          "type": "string"
+        },
+        "name": {
+          "description": "The name or natural key of the related object. This property is required if the target object id could not (yet) be identified.",
+          "example": "Survey ST2016",
+          "title": "Related Object Name",
+          "type": "string"
+        },
+        "version": {
+          "description": "The version number of the related entity. If no version number is specified, the last version is implied.",
+          "format": "int64",
+          "title": "Entity Version Number",
+          "type": "number"
+        }
+      },
+      "title": "To One Relationship",
+      "type": "object"
+    },
+    "valueArrayWithUnit": {
+      "description": "Array of values associated with unit context. The 'unitKey' can be looked up in the 'frameOfReference.units'.",
+      "properties": {
+        "unitKey": {
+          "description": "Unit for the array values of the corresponding attribute for the domain object in question. The key can be looked up in the meta[] array under the root. It will be an array item with meta[i].kind == 'Unit' and meta[i].name == valueWithUnit.unitKey. The meta[i].propertyNames[] array will have to contain the name of the property including valueArrayWithUnit to enable the normalizer to act on it.",
+          "example": "ft",
+          "title": "Unit Key",
+          "type": "string"
+        },
+        "values": {
+          "description": "Value of the corresponding attribute for the domain object in question.",
+          "example": [
+            30.2,
+            23.8
+          ],
+          "items": {
+            "type": "number"
+          },
+          "title": "Value",
+          "type": "array"
+        }
+      },
+      "required": [
+        "values",
+        "unitKey"
+      ],
+      "title": "Values with unitKey",
+      "type": "object"
+    },
+    "valueWithUnit": {
+      "description": "Number value associated with unit context. The 'unitKey' can be looked up in the root property meta[] array.",
+      "properties": {
+        "unitKey": {
+          "description": "Unit for the value of the corresponding attribute for the domain object in question. The key can be looked up in the meta[] array under the root. It will be an array item with meta[i].kind == 'Unit' and meta[i].name == valueWithUnit.unitKey. The meta[i].propertyNames[] array will have to contain the name of the property including valueWithUnit to enable the normalizer to act on it.",
+          "example": "ft",
+          "title": "Unit Key",
+          "type": "string"
+        },
+        "value": {
+          "description": "Value of the corresponding attribute for the domain object in question.",
+          "example": 30.2,
+          "title": "Value",
+          "type": "number"
+        }
+      },
+      "required": [
+        "value",
+        "unitKey"
+      ],
+      "title": "Value with unitKey",
+      "type": "object"
+    },
+    "wellboreData": {
+      "$id": "definitions/wellboreData",
+      "description": "The domain specific data container for a wellbore.",
+      "properties": {
+        "airGap": {
+          "$ref": "#/definitions/valueWithUnit",
+          "description": "The gap between water surface and offshore drilling platform.",
+          "example": [
+            11,
+            "ft"
+          ],
+          "title": "Air Gap",
+          "x-slb-aliasProperties": [
+            "drillplan:air_gap"
+          ],
+          "x-slb-measurement": "Standard_Depth_Index"
+        },
+        "block": {
+          "description": "The block name, in which the wellbore is located.",
+          "example": "Block 11/8",
+          "title": "Block",
+          "type": "string",
+          "x-slb-aliasProperties": [
+            "witsml:Block"
+          ]
+        },
+        "country": {
+          "description": "The country, in which the wellbore is located. The country name follows the convention in ISO 3166-1 'English short country name', see https://en.wikipedia.org/wiki/ISO_3166-1",
+          "example": [
+            "United States of America",
+            "Bolivia (Plurinational State of)"
+          ],
+          "title": "Country",
+          "type": "string",
+          "x-slb-aliasProperties": [
+            "witsml:Country"
+          ]
+        },
+        "county": {
+          "description": "The county name, in which the wellbore is located.",
+          "example": "Stark",
+          "title": "County",
+          "type": "string",
+          "x-slb-aliasProperties": [
+            "witsml:County"
+          ]
+        },
+        "dateCreated": {
+          "description": "The UTC date time of the entity creation",
+          "example": "2013-03-22T11:16:03.123Z",
+          "format": "date-time",
+          "title": "Creation Date and Time",
+          "type": "string"
+        },
+        "dateModified": {
+          "description": "The UTC date time of the last entity modification",
+          "example": "2013-03-22T11:16:03.123Z",
+          "format": "date-time",
+          "title": "Last Modification Date and Time",
+          "type": "string"
+        },
+        "drillingDaysTarget": {
+          "$ref": "#/definitions/valueWithUnit",
+          "description": "Target days for drilling wellbore.",
+          "example": [
+            12.5,
+            "days"
+          ],
+          "title": "Target Drilling Days",
+          "x-slb-aliasProperties": [
+            "witsml:DayTarget"
+          ],
+          "x-slb-measurement": "Time"
+        },
+        "elevationReference": {
+          "$ref": "#/definitions/simpleElevationReference",
+          "description": "The wellbore's elevation reference from mean sea level (MSL), positive above MSL. This is where MD == 0 and TVD == 0",
+          "title": "Elevation Reference",
+          "type": "object"
+        },
+        "externalIds": {
+          "description": "An array of identities (e.g. some kind if URL to be resolved in an external data store), which links to external realizations of the same entity.",
+          "format": "link",
+          "items": {
+            "type": "string"
+          },
+          "title": "Array of External IDs",
+          "type": "array"
+        },
+        "field": {
+          "description": "The field name, to which the wellbore belongs.",
+          "example": "Fryburg",
+          "title": "Field",
+          "type": "string",
+          "x-slb-aliasProperties": [
+            "witsml:Field"
+          ]
+        },
+        "formationAtTd": {
+          "description": "The name of the formation at the wellbore's total depth.",
+          "example": "Bakken",
+          "title": "Formation at TD",
+          "type": "string",
+          "x-slb-aliasProperties": [
+            "seabed:borehole.Formation_At_TD"
+          ]
+        },
+        "formationProjected": {
+          "description": "The name of the formation at the wellbore's projected depth. This property is questionable as there is not precise documentation available.",
+          "example": "Bakken",
+          "title": "Formation Projected",
+          "type": "string"
+        },
+        "hasAchievedTotalDepth": {
+          "default": true,
+          "description": "True (\"true\" of \"1\") indicates that the wellbore has acheieved total depth. That is, drilling has completed. False (\"false\" or \"0\") indicates otherwise. Not given indicates that it is not known whether total depth has been reached.",
+          "example": true,
+          "title": "Has Total Depth Been Achieved Flag",
+          "type": "bool",
+          "x-slb-aliasProperties": [
+            "witsml:AchievedTD"
+          ]
+        },
+        "isActive": {
+          "description": "True (=\"1\" or \"true\") indicates that the wellbore is active. False (=\"0\" or \"false\") indicates otherwise. It is the servers responsibility to set this value based on its available internal data (e.g., what objects are changing).",
+          "example": true,
+          "title": "Is Active Flag",
+          "type": "bool",
+          "x-slb-aliasProperties": [
+            "witsml:IsActive"
+          ]
+        },
+        "kickOffMd": {
+          "$ref": "#/definitions/valueWithUnit",
+          "description": "The kick-off point in measured depth (MD); for the main well the kickOffMd is set to 0.",
+          "example": [
+            6543.2,
+            "ft"
+          ],
+          "title": "Kick-off MD",
+          "x-slb-aliasProperties": [
+            "witsml:MdKickoff"
+          ],
+          "x-slb-measurement": "Standard_Depth_Index"
+        },
+        "kickOffTvd": {
+          "$ref": "#/definitions/valueWithUnit",
+          "description": "Kickoff true vertical depth of the wellbore; for the main wellbore the kickOffMd is set to 0.",
+          "example": [
+            6543.2,
+            "ft"
+          ],
+          "title": "Kick-off MD",
+          "x-slb-aliasProperties": [
+            "witsml:TvdKickoff"
+          ],
+          "x-slb-measurement": "Standard_Depth_Index"
+        },
+        "locationWGS84": {
+          "$ref": "#/definitions/geoJsonFeatureCollection",
+          "description": "A 2D GeoJSON FeatureCollection defining wellbore location or trajectory in WGS 84 CRS.",
+          "title": "Wellbore Shape WGS 84",
+          "type": "object"
+        },
+        "name": {
+          "description": "The wellbore name",
+          "title": "Wellbore Name",
+          "type": "string",
+          "x-slb-aliasProperties": [
+            "ocean:BoreholeName"
+          ]
+        },
+        "operator": {
+          "description": "The operator of the wellbore.",
+          "example": "Anadarko Petroleum",
+          "title": "Operator",
+          "type": "string",
+          "x-slb-aliasProperties": [
+            "ocean:Operator",
+            "witsml:Operator"
+          ]
+        },
+        "permitDate": {
+          "description": "The wellbore's permit date.",
+          "example": "2013-01-15",
+          "format": "date",
+          "title": "Permit Date",
+          "type": "string"
+        },
+        "permitNumber": {
+          "description": "The wellbore's permit number or permit ID.",
+          "example": "608020",
+          "title": "Permit Number",
+          "type": "string"
+        },
+        "plssLocation": {
+          "$ref": "#/definitions/plssLocation",
+          "description": "A location described by the Public Land Survey System (United States)",
+          "title": "US PLSS Location",
+          "type": "object"
+        },
+        "propertyDictionary": {
+          "additionalProperties": {
+            "type": "string"
+          },
+          "description": "A dictionary structure, i.e. key/string value pairs, to carry additional wellbore properties.",
+          "title": "Property Dictionary",
+          "type": "string"
+        },
+        "relationships": {
+          "$ref": "#/definitions/relationships",
+          "description": "The related entities.",
+          "title": "Relationships"
+        },
+        "shape": {
+          "description": "POSC wellbore trajectory shape.",
+          "enum": [
+            "build and hold",
+            "deviated",
+            "double kickoff",
+            "horizontal",
+            "S-shaped",
+            "vertical",
+            "unknown"
+          ],
+          "example": "deviated",
+          "title": "Wellbore Shape",
+          "type": "string",
+          "x-slb-aliasProperties": [
+            "witsml:Shape"
+          ]
+        },
+        "spudDate": {
+          "description": "The date and time when activities to drill the borehole begin to create a hole in the earth. For a sidetrack, this is the date kickoff operations began. The format follows ISO 8601 YYYY-MM-DD extended format",
+          "example": "2013-03-22",
+          "format": "date",
+          "title": "Spud Date",
+          "type": "string",
+          "x-slb-aliasProperties": [
+            "witsml:DTimKickoff",
+            "ocean:SpudDate",
+            "drillplan:spud_date"
+          ]
+        },
+        "state": {
+          "description": "The state name, in which the wellbore is located.",
+          "example": "North Dakota",
+          "title": "State",
+          "type": "string"
+        },
+        "totalDepthMd": {
+          "$ref": "#/definitions/valueWithUnit",
+          "description": "The measured depth of the borehole. If status is plugged, indicates the maximum depth reached before plugging. It is recommended that this value be updated about every 10 minutes by an assigned raw data provider at a site.",
+          "example": [
+            13200,
+            "ft"
+          ],
+          "title": "Total MD",
+          "x-slb-aliasProperties": [
+            "witsml:Md",
+            "ocean:TDMD"
+          ],
+          "x-slb-measurement": "Standard_Depth_Index"
+        },
+        "totalDepthMdDriller": {
+          "$ref": "#/definitions/valueWithUnit",
+          "description": "The total depth along the wellbore as reported by the drilling contractor from 'elevationReference'. The unit definition is found via the property's unitKey' in 'frameOfReference.units' dictionary..",
+          "example": [
+            13200.23,
+            "ft"
+          ],
+          "title": "Total MD Drilled",
+          "x-slb-aliasProperties": [
+            "witsml:MdBit"
+          ],
+          "x-slb-measurement": "Standard_Depth_Index"
+        },
+        "totalDepthMdPlanned": {
+          "$ref": "#/definitions/valueWithUnit",
+          "description": "Planned measured depth for the wellbore total depth.",
+          "example": [
+            13200,
+            "ft"
+          ],
+          "title": "Total MD Planned",
+          "x-slb-aliasProperties": [
+            "witsml:MdPlanned"
+          ],
+          "x-slb-measurement": "Standard_Depth_Index"
+        },
+        "totalDepthMdSubSeaPlanned": {
+          "$ref": "#/definitions/valueWithUnit",
+          "description": "Planned measured for the wellbore total depth - with respect to seabed.",
+          "example": [
+            13100,
+            "ft"
+          ],
+          "title": "Total MD Sub Sea Planned",
+          "x-slb-aliasProperties": [
+            "witsml:MdSubSeaPlanned"
+          ],
+          "x-slb-measurement": "Standard_Depth_Index"
+        },
+        "totalDepthProjectedMd": {
+          "$ref": "#/definitions/valueWithUnit",
+          "description": "The projected total measured depth of the borehole. This property is questionable as there is not precise documentation available.",
+          "example": [
+            13215,
+            "ft"
+          ],
+          "title": "Total MD Projected",
+          "x-slb-measurement": "Standard_Depth_Index"
+        },
+        "totalDepthTvd": {
+          "$ref": "#/definitions/valueWithUnit",
+          "description": "The true vertical depth of the borehole. If status is plugged, indicates the maximum depth reached before plugging. It is recommended that this value be updated about every 10 minutes by an assigned raw data provider at a site.",
+          "example": [
+            12200.23,
+            "ft"
+          ],
+          "title": "Total TVD",
+          "x-slb-aliasProperties": [
+            "witsml:Tvd"
+          ],
+          "x-slb-measurement": "Standard_Depth_Index"
+        },
+        "totalDepthTvdDriller": {
+          "$ref": "#/definitions/valueWithUnit",
+          "description": "The total depth true vertical as reported by the drilling contractor from 'elevationReference', Downwards increasing. The unit definition is found via the property's unitKey' in 'frameOfReference.units' dictionary.",
+          "example": [
+            12200.23,
+            "ft"
+          ],
+          "title": "Total TVD Drilled",
+          "x-slb-aliasProperties": [
+            "witsml:TvdBit"
+          ],
+          "x-slb-measurement": "Standard_Depth_Index"
+        },
+        "totalDepthTvdPlanned": {
+          "$ref": "#/definitions/valueWithUnit",
+          "description": "Planned true vertical depth for the wellbore total depth.",
+          "example": [
+            12200.23,
+            "ft"
+          ],
+          "title": "Total TVD Planned",
+          "x-slb-aliasProperties": [
+            "witsml:TvdPlanned"
+          ],
+          "x-slb-measurement": "Standard_Depth_Index"
+        },
+        "totalDepthTvdSubSeaPlanned": {
+          "$ref": "#/definitions/valueWithUnit",
+          "description": "Planned true vertical depth for the wellbore total depth - with respect to seabed.",
+          "example": [
+            12100.23,
+            "ft"
+          ],
+          "title": "Total TVD Sub Sea Planned",
+          "x-slb-aliasProperties": [
+            "witsml:TvdSubSeaPlanned"
+          ],
+          "x-slb-measurement": "Standard_Depth_Index"
+        },
+        "uwi": {
+          "description": "The unique wellbore identifier, aka. API number, US well number or UBHI. Codes can have 10, 12 or 14 digits depending on the availability of directional sidetrack (2 digits) and event sequence codes (2 digits).",
+          "example": [
+            "42-501-20130",
+            "42-501-20130-01-02"
+          ],
+          "title": "Unique Wellbore Identifier",
+          "type": "string",
+          "x-slb-aliasProperties": [
+            "ocean:UWI",
+            "witsml:SuffixAPI",
+            "drillplan:uwi"
+          ]
+        },
+        "wellHeadElevation": {
+          "$ref": "#/definitions/valueWithUnit",
+          "description": "The wellbore's vertical position is an elevation from mean sea level (MSL), positive above MSL.",
+          "title": "Well Head Elevation",
+          "x-slb-measurement": "Standard_Depth_Index"
+        },
+        "wellHeadGeographic": {
+          "$ref": "#/definitions/geographicPosition",
+          "description": "The wellbore's well head position in the native, geographic CRS; vertical position is an elevation from mean sea level (MSL), positive above MSL.",
+          "title": "Well Head Position, Geographic",
+          "type": "object"
+        },
+        "wellHeadProjected": {
+          "$ref": "#/definitions/projectedPosition",
+          "description": "The wellbore's well head position in the native, projected CRS; vertical position is an elevation from mean sea level (MSL), positive above MSL.",
+          "title": "Well Head Position, Projected",
+          "type": "object"
+        },
+        "wellHeadWgs84": {
+          "$ref": "#/definitions/core_dl_geopoint",
+          "description": "The wellbore's position in WGS 84 latitude and longitude.",
+          "format": "core:dl:geopoint:1.0.0",
+          "title": "WGS 84 Position",
+          "type": "object",
+          "x-slb-aliasProperties": [
+            "witsml:GeographicLocationWGS84"
+          ]
+        },
+        "wellboreNumberGovernment": {
+          "description": "Government assigned wellbore number.",
+          "example": "42-501-20130-P",
+          "title": "Government Number",
+          "type": "string",
+          "x-slb-aliasProperties": [
+            "witsml:NumGovt"
+          ]
+        },
+        "wellboreNumberOperator": {
+          "description": "Operator wellbore number.",
+          "example": "12399-001",
+          "title": "Operator Number",
+          "type": "string",
+          "x-slb-aliasProperties": [
+            "witsml:Number"
+          ]
+        },
+        "wellborePurpose": {
+          "description": "POSC wellbore purpose",
+          "enum": [
+            "appraisal",
+            "appraisal -- confirmation appraisal",
+            "appraisal -- exploratory appraisal",
+            "exploration",
+            "exploration -- deeper-pool wildcat",
+            "exploration -- new-field wildcat",
+            "exploration -- new-pool wildcat",
+            "exploration -- outpost wildcat",
+            "exploration -- shallower-pool wildcat",
+            "development",
+            "development -- infill development",
+            "development -- injector",
+            "development -- producer",
+            "fluid storage",
+            "fluid storage -- gas storage",
+            "general srvc",
+            "general srvc -- borehole re-acquisition",
+            "general srvc -- observation",
+            "general srvc -- relief",
+            "general srvc -- research",
+            "general srvc -- research -- drill test",
+            "general srvc -- research -- strat test",
+            "general srvc -- waste disposal",
+            "mineral",
+            "unknown"
+          ],
+          "example": "development -- producer",
+          "title": "Wellbore Purpose",
+          "type": "string",
+          "x-slb-aliasProperties": [
+            "witsml:PurposeWellbore",
+            "drillplan:well_purpose"
+          ]
+        },
+        "wellboreStatus": {
+          "description": "POSC wellbore status.",
+          "enum": [
+            "abandoned",
+            "active",
+            "active -- injecting",
+            "active -- producing",
+            "completed",
+            "drilling",
+            "partially plugged",
+            "permitted",
+            "plugged and abandoned",
+            "proposed",
+            "sold",
+            "suspended",
+            "temporarily abandoned",
+            "testing",
+            "tight",
+            "working over",
+            "unknown"
+          ],
+          "example": "active -- producing",
+          "title": "Wellbore Status",
+          "type": "string",
+          "x-slb-aliasProperties": [
+            "witsml:StatusWellbore"
+          ]
+        },
+        "wellboreType": {
+          "description": "Type of wellbore.",
+          "enum": [
+            "bypass",
+            "initial",
+            "redrill",
+            "reentry",
+            "respud",
+            "sidetrack",
+            "unknown"
+          ],
+          "example": "sidetrack",
+          "title": "Wellbore Type",
+          "type": "string",
+          "x-slb-aliasProperties": [
+            "witsml:TypeWellbore",
+            "drillplan:well_type"
+          ]
+        }
+      },
+      "title": "Wellbore Data",
+      "type": "object"
+    }
+  },
+  "description": "The well-known wellbore schema. Used to capture the general information about a wellbore. This information is sometimes called a \"wellbore header\". A wellbore represents the path from surface to a unique bottomhole location. The wellbore object is uniquely identified within the context of one well object.",
+  "properties": {
+    "acl": {
+      "$ref": "#/definitions/tagDictionary",
+      "description": "The access control tags associated with this entity.",
+      "title": "Access Control List"
+    },
+    "ancestry": {
+      "$ref": "#/definitions/linkList",
+      "description": "The links to data, which constitute the inputs.",
+      "title": "Ancestry"
+    },
+    "data": {
+      "$ref": "#/definitions/wellboreData",
+      "description": "Wellbore data container",
+      "title": "Wellbore Data"
+    },
+    "id": {
+      "description": "The unique identifier of the wellbore",
+      "title": "Wellbore ID",
+      "type": "string"
+    },
+    "kind": {
+      "default": "slb:wks:wellbore:1.0.6",
+      "description": "Well-known wellbore kind specification",
+      "title": "Wellbore Kind",
+      "type": "string"
+    },
+    "legal": {
+      "$ref": "#/definitions/legal",
+      "description": "The geological interpretation's legal tags",
+      "title": "Legal Tags"
+    },
+    "meta": {
+      "description": "The meta data section linking the 'unitKey', 'crsKey' to self-contained definitions (persistableReference)",
+      "items": {
+        "$ref": "#/definitions/metaItem"
+      },
+      "title": "Frame of Reference Meta Data",
+      "type": "array"
+    },
+    "type": {
+      "description": "The reference entity type as declared in common:metadata:entity:*.",
+      "title": "Entity Type",
+      "type": "string"
+    },
+    "version": {
+      "description": "The version number of this wellbore; set by the framework.",
+      "example": "1040815391631285",
+      "format": "int64",
+      "title": "Entity Version Number",
+      "type": "number"
+    }
+  },
+  "title": "Wellbore",
+  "type": "object"
+}
\ No newline at end of file
diff --git a/indexer-core/src/test/resources/converter/wks/slb_wke_wellbore.json.res b/indexer-core/src/test/resources/converter/wks/slb_wke_wellbore.json.res
new file mode 100644
index 0000000000000000000000000000000000000000..4b4b9b61d8bdd5cb6ab5575ea72e4bc611ebfbac
--- /dev/null
+++ b/indexer-core/src/test/resources/converter/wks/slb_wke_wellbore.json.res
@@ -0,0 +1,357 @@
+{
+  "kind": "slb:wks:wellbore:1.0.6",
+  "schema": [
+    {
+      "kind": "string",
+      "path": "airGap.unitKey"
+    },
+    {
+      "kind": "double",
+      "path": "airGap.value"
+    },
+    {
+      "kind": "string",
+      "path": "block"
+    },
+    {
+      "kind": "string",
+      "path": "country"
+    },
+    {
+      "kind": "string",
+      "path": "county"
+    },
+    {
+      "kind": "datetime",
+      "path": "dateCreated"
+    },
+    {
+      "kind": "datetime",
+      "path": "dateModified"
+    },
+    {
+      "kind": "string",
+      "path": "drillingDaysTarget.unitKey"
+    },
+    {
+      "kind": "double",
+      "path": "drillingDaysTarget.value"
+    },
+    {
+      "kind": "string",
+      "path": "elevationReference.elevationFromMsl.unitKey"
+    },
+    {
+      "kind": "double",
+      "path": "elevationReference.elevationFromMsl.value"
+    },
+    {
+      "kind": "string",
+      "path": "elevationReference.name"
+    },
+    {
+      "kind": "[]link",
+      "path": "externalIds"
+    },
+    {
+      "kind": "string",
+      "path": "field"
+    },
+    {
+      "kind": "string",
+      "path": "formationAtTd"
+    },
+    {
+      "kind": "string",
+      "path": "formationProjected"
+    },
+    {
+      "kind": "bool",
+      "path": "hasAchievedTotalDepth"
+    },
+    {
+      "kind": "bool",
+      "path": "isActive"
+    },
+    {
+      "kind": "string",
+      "path": "kickOffMd.unitKey"
+    },
+    {
+      "kind": "double",
+      "path": "kickOffMd.value"
+    },
+    {
+      "kind": "string",
+      "path": "kickOffTvd.unitKey"
+    },
+    {
+      "kind": "double",
+      "path": "kickOffTvd.value"
+    },
+    {
+      "kind": "core:dl:geoshape:1.0.0",
+      "path": "locationWGS84"
+    },
+    {
+      "kind": "string",
+      "path": "name"
+    },
+    {
+      "kind": "string",
+      "path": "operator"
+    },
+    {
+      "kind": "datetime",
+      "path": "permitDate"
+    },
+    {
+      "kind": "string",
+      "path": "permitNumber"
+    },
+    {
+      "kind": "string",
+      "path": "plssLocation.aliquotPart"
+    },
+    {
+      "kind": "string",
+      "path": "plssLocation.range"
+    },
+    {
+      "kind": "int",
+      "path": "plssLocation.section"
+    },
+    {
+      "kind": "string",
+      "path": "plssLocation.township"
+    },
+    {
+      "kind": "string",
+      "path": "propertyDictionary"
+    },
+    {
+      "kind": "double",
+      "path": "relationships.definitiveTimeDepthRelation.confidence"
+    },
+    {
+      "kind": "link",
+      "path": "relationships.definitiveTimeDepthRelation.id"
+    },
+    {
+      "kind": "string",
+      "path": "relationships.definitiveTimeDepthRelation.name"
+    },
+    {
+      "kind": "long",
+      "path": "relationships.definitiveTimeDepthRelation.version"
+    },
+    {
+      "kind": "double",
+      "path": "relationships.definitiveTrajectory.confidence"
+    },
+    {
+      "kind": "link",
+      "path": "relationships.definitiveTrajectory.id"
+    },
+    {
+      "kind": "string",
+      "path": "relationships.definitiveTrajectory.name"
+    },
+    {
+      "kind": "long",
+      "path": "relationships.definitiveTrajectory.version"
+    },
+    {
+      "kind": "double",
+      "path": "relationships.tieInWellbore.confidence"
+    },
+    {
+      "kind": "link",
+      "path": "relationships.tieInWellbore.id"
+    },
+    {
+      "kind": "string",
+      "path": "relationships.tieInWellbore.name"
+    },
+    {
+      "kind": "long",
+      "path": "relationships.tieInWellbore.version"
+    },
+    {
+      "kind": "double",
+      "path": "relationships.well.confidence"
+    },
+    {
+      "kind": "link",
+      "path": "relationships.well.id"
+    },
+    {
+      "kind": "string",
+      "path": "relationships.well.name"
+    },
+    {
+      "kind": "long",
+      "path": "relationships.well.version"
+    },
+    {
+      "kind": "string",
+      "path": "shape"
+    },
+    {
+      "kind": "datetime",
+      "path": "spudDate"
+    },
+    {
+      "kind": "string",
+      "path": "state"
+    },
+    {
+      "kind": "string",
+      "path": "totalDepthMd.unitKey"
+    },
+    {
+      "kind": "double",
+      "path": "totalDepthMd.value"
+    },
+    {
+      "kind": "string",
+      "path": "totalDepthMdDriller.unitKey"
+    },
+    {
+      "kind": "double",
+      "path": "totalDepthMdDriller.value"
+    },
+    {
+      "kind": "string",
+      "path": "totalDepthMdPlanned.unitKey"
+    },
+    {
+      "kind": "double",
+      "path": "totalDepthMdPlanned.value"
+    },
+    {
+      "kind": "string",
+      "path": "totalDepthMdSubSeaPlanned.unitKey"
+    },
+    {
+      "kind": "double",
+      "path": "totalDepthMdSubSeaPlanned.value"
+    },
+    {
+      "kind": "string",
+      "path": "totalDepthProjectedMd.unitKey"
+    },
+    {
+      "kind": "double",
+      "path": "totalDepthProjectedMd.value"
+    },
+    {
+      "kind": "string",
+      "path": "totalDepthTvd.unitKey"
+    },
+    {
+      "kind": "double",
+      "path": "totalDepthTvd.value"
+    },
+    {
+      "kind": "string",
+      "path": "totalDepthTvdDriller.unitKey"
+    },
+    {
+      "kind": "double",
+      "path": "totalDepthTvdDriller.value"
+    },
+    {
+      "kind": "string",
+      "path": "totalDepthTvdPlanned.unitKey"
+    },
+    {
+      "kind": "double",
+      "path": "totalDepthTvdPlanned.value"
+    },
+    {
+      "kind": "string",
+      "path": "totalDepthTvdSubSeaPlanned.unitKey"
+    },
+    {
+      "kind": "double",
+      "path": "totalDepthTvdSubSeaPlanned.value"
+    },
+    {
+      "kind": "string",
+      "path": "uwi"
+    },
+    {
+      "kind": "string",
+      "path": "wellHeadElevation.unitKey"
+    },
+    {
+      "kind": "double",
+      "path": "wellHeadElevation.value"
+    },
+    {
+      "kind": "string",
+      "path": "wellHeadGeographic.crsKey"
+    },
+    {
+      "kind": "string",
+      "path": "wellHeadGeographic.elevationFromMsl.unitKey"
+    },
+    {
+      "kind": "double",
+      "path": "wellHeadGeographic.elevationFromMsl.value"
+    },
+    {
+      "kind": "double",
+      "path": "wellHeadGeographic.latitude"
+    },
+    {
+      "kind": "double",
+      "path": "wellHeadGeographic.longitude"
+    },
+    {
+      "kind": "string",
+      "path": "wellHeadProjected.crsKey"
+    },
+    {
+      "kind": "string",
+      "path": "wellHeadProjected.elevationFromMsl.unitKey"
+    },
+    {
+      "kind": "double",
+      "path": "wellHeadProjected.elevationFromMsl.value"
+    },
+    {
+      "kind": "double",
+      "path": "wellHeadProjected.x"
+    },
+    {
+      "kind": "double",
+      "path": "wellHeadProjected.y"
+    },
+    {
+      "kind": "core:dl:geopoint:1.0.0",
+      "path": "wellHeadWgs84"
+    },
+    {
+      "kind": "string",
+      "path": "wellboreNumberGovernment"
+    },
+    {
+      "kind": "string",
+      "path": "wellboreNumberOperator"
+    },
+    {
+      "kind": "string",
+      "path": "wellborePurpose"
+    },
+    {
+      "kind": "string",
+      "path": "wellboreStatus"
+    },
+    {
+      "kind": "string",
+      "path": "wellboreType"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 463794ff03568206e6348128bf108e965315e728..eef38efd9dc660066d903e17802171631c6f969e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -7,7 +7,7 @@
     <parent>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-parent</artifactId>
-        <version>2.1.16.RELEASE</version>
+        <version>2.1.18.RELEASE</version>
         <relativePath/>
     </parent>
 
@@ -30,6 +30,7 @@
         <elasticsearch.version>6.8.1</elasticsearch.version>
         <netty.version>4.1.51.Final</netty.version>
         <reactor-netty.version>0.8.20.RELEASE</reactor-netty.version>
+        <woodstox-core.version>6.2.3</woodstox-core.version>
         <!--        <maven.compiler.target>1.8</maven.compiler.target>-->
 <!--        <maven.compiler.source>1.8</maven.compiler.source>-->
 <!--        <maven.war.plugin>2.6</maven.war.plugin>-->
@@ -112,6 +113,11 @@
                 <artifactId>reactor-netty</artifactId>
                 <version>${reactor-netty.version}</version>
             </dependency>
+            <dependency>
+                <groupId>com.fasterxml.woodstox</groupId>
+                <artifactId>woodstox-core</artifactId>
+                <version>${woodstox-core.version}</version>
+            </dependency>
         </dependencies>
     </dependencyManagement>
 
diff --git a/provider/indexer-aws/azure-build.yml b/provider/indexer-aws/azure-build.yml
deleted file mode 100644
index 8379aecec711c68a49e528be0d21e0cd9d809bc7..0000000000000000000000000000000000000000
--- a/provider/indexer-aws/azure-build.yml
+++ /dev/null
@@ -1,50 +0,0 @@
-# Maven
-# Build your Java project and run tests with Apache Maven.
-# Add steps that analyze code, save build artifacts, deploy, and more:
-# https://docs.microsoft.com/azure/devops/pipelines/languages/java
-trigger:
-  branches:
-    include:
-      - master
-  paths:
-    exclude:
-      - README.md
-      - .gitignore
-pool:
-  name: dps-build
-  demands: maven
-steps:
-  - task: Maven@3
-    displayName: 'build, test, code coverage'
-    inputs:
-      mavenPomFile: 'pom.xml'
-      options: '--settings ./indexer-core/maven/settings.xml -DVSTS_FEED_TOKEN=$(VSTS_FEED_TOKEN) -U'
-      testResultsFiles: '**/*/TEST-*.xml'
-      codeCoverageToolOption: JaCoCo
-      goals: 'install'
-  - task: Maven@3
-    displayName: 'build, test, code coverage'
-    inputs:
-      mavenPomFile: 'pom.xml'
-      options: '--settings ./provider/indexer-aws/maven/settings.xml -DVSTS_FEED_TOKEN=$(VSTS_FEED_TOKEN) -U -P indexer-aws'
-      testResultsFiles: '**/*/TEST-*.xml'
-      codeCoverageToolOption: JaCoCo
-      goals: 'install'
-  - task: CopyFiles@2
-    displayName: 'Copy AWS artifacts for maven deploy to: $(build.artifactstagingdirectory)'
-    inputs:
-      SourceFolder:
-      Contents: |
-        provider/indexer-aws/CloudFormation
-        provider/indexer-aws/buildspec-post-deploy.yml
-        provider/indexer-aws/buildspec-pre-deploy.yml
-        provider/indexer-aws/target/*-spring-boot.jar
-      TargetFolder: '$(build.artifactstagingdirectory)'
-
-  - task: PublishBuildArtifacts@1
-    displayName: 'Publish Artifact: drop'
-    inputs:
-      PathtoPublish: '$(build.artifactstagingdirectory)'
-      ArtifactName: 'drop'
-      publishLocation: 'Container'
-    condition: succeededOrFailed()
diff --git a/provider/indexer-aws/build-aws/buildspec.yaml b/provider/indexer-aws/build-aws/buildspec.yaml
index fb477f3c39eeac97271a57d50f2712855d9df6fc..7f263524ddd942206451b15dfd7aea7b09a6442f 100644
--- a/provider/indexer-aws/build-aws/buildspec.yaml
+++ b/provider/indexer-aws/build-aws/buildspec.yaml
@@ -17,6 +17,11 @@
 # https://docs.aws.amazon.com/codebuild/latest/userguide/build-env-ref-env-vars.html
 version: 0.2
 
+env:
+  secrets-manager:
+    DOCKER_USERNAME: /osdu/devops/docker_credentials:username
+    DOCKER_PASSWORD: /osdu/devops/docker_credentials:password
+
 phases:
   install:
     runtime-versions:
@@ -52,7 +57,7 @@ phases:
       - printenv
 
       - echo "Building primary service assemblies..."
-      - mvn -B test install -pl indexer-core,provider/indexer-aws -Ddeployment.environment=prod
+      - mvn -ntp -B test install -pl indexer-core,provider/indexer-aws -Ddeployment.environment=prod
 
 
 #      - echo "Copying assemblies to dist..."
@@ -62,6 +67,9 @@ phases:
       - echo "Building integration testing assemblies and gathering artifacts..."
       - ./testing/indexer-test-aws/build-aws/prepare-dist.sh
 
+      - echo "Logging into Docker Hub..."
+      - docker login -u ${DOCKER_USERNAME} -p ${DOCKER_PASSWORD}
+
       - echo "Building docker image..."
       - docker build -f provider/indexer-aws/build-aws/Dockerfile -t ${ECR_IMAGE} .
       - docker tag  ${ECR_IMAGE} ${ECR_IMAGE_BRANCH_LATEST}
@@ -87,4 +95,4 @@ artifacts:
   name: ${REPO_NAME}_${BRANCH_NAME}_$(date +%F)_${CODEBUILD_BUILD_NUMBER}.zip
 cache:
   paths:
-    - "/root/.m2/**/*"
\ No newline at end of file
+    - "/root/.m2/**/*"
diff --git a/provider/indexer-aws/maven/settings.xml b/provider/indexer-aws/maven/settings.xml
index 629bc28df98790e725de6fde8a67a99a38965232..2e357eff2cf88c10c9be823ab99c56b069c38384 100644
--- a/provider/indexer-aws/maven/settings.xml
+++ b/provider/indexer-aws/maven/settings.xml
@@ -34,6 +34,10 @@
           <id>gitlab-os-core-common-maven</id>
           <url>https://community.opengroup.org/api/v4/projects/67/packages/maven</url>
         </repository>
+         <repository>
+                    <id>gitlab-os-core-lib-aws-maven</id>
+                    <url>https://community.opengroup.org/api/v4/projects/68/packages/maven</url>
+                </repository>
       </repositories>
     </profile>
     <profile>
diff --git a/provider/indexer-aws/pom.xml b/provider/indexer-aws/pom.xml
index bc756ab12a0c4f87fd4c3f345b46ba274b03b81b..b8e13f22e2f628b220360494943833840cdcca1a 100644
--- a/provider/indexer-aws/pom.xml
+++ b/provider/indexer-aws/pom.xml
@@ -49,7 +49,7 @@
     <dependency>
         <groupId>org.opengroup.osdu.core.aws</groupId>
         <artifactId>os-core-lib-aws</artifactId>
-        <version>0.3.7</version>
+        <version>0.3.16</version>
     </dependency>
 
     <!-- AWS managed packages -->
diff --git a/provider/indexer-aws/src/main/java/org/opengroup/osdu/indexer/aws/di/EntitlementsClientFactory.java b/provider/indexer-aws/src/main/java/org/opengroup/osdu/indexer/aws/di/EntitlementsClientFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..dd7cbd1efa355aebf59aab8b148371afa29f8569
--- /dev/null
+++ b/provider/indexer-aws/src/main/java/org/opengroup/osdu/indexer/aws/di/EntitlementsClientFactory.java
@@ -0,0 +1,58 @@
+// Copyright © Amazon Web Services
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+
+package org.opengroup.osdu.indexer.aws.di;
+
+import org.opengroup.osdu.core.common.entitlements.EntitlementsAPIConfig;
+import org.opengroup.osdu.core.common.entitlements.EntitlementsFactory;
+import org.opengroup.osdu.core.common.entitlements.IEntitlementsFactory;
+import org.opengroup.osdu.core.common.http.json.HttpResponseBodyMapper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.beans.factory.config.AbstractFactoryBean;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.stereotype.Component;
+import org.springframework.web.context.annotation.RequestScope;
+
+@Component
+@RequestScope
+@Lazy
+public class EntitlementsClientFactory extends AbstractFactoryBean<IEntitlementsFactory> {
+
+	@Value("${AUTHORIZE_API}")
+	private String AUTHORIZE_API;
+
+	@Value("${AUTHORIZE_API_KEY:}")
+	private String AUTHORIZE_API_KEY;
+
+	@Autowired
+	private HttpResponseBodyMapper mapper;
+
+	@Override
+	protected IEntitlementsFactory createInstance() throws Exception {
+
+		return new EntitlementsFactory(EntitlementsAPIConfig
+				.builder()
+				.rootUrl(AUTHORIZE_API)
+				.apiKey(AUTHORIZE_API_KEY)
+				.build(),
+				mapper);
+	}
+
+	@Override
+	public Class<?> getObjectType() {
+		return IEntitlementsFactory.class;
+	}
+}
\ No newline at end of file
diff --git a/provider/indexer-aws/src/main/resources/application.properties b/provider/indexer-aws/src/main/resources/application.properties
index 6e7d9c6f32304d2fb255c95e63239ec8f2964a55..77f80a34f9d23307e59202daf13fd6f047bd5ace 100644
--- a/provider/indexer-aws/src/main/resources/application.properties
+++ b/provider/indexer-aws/src/main/resources/application.properties
@@ -22,6 +22,9 @@ aws.es.serviceName=es
 
 GAE_SERVICE=indexer
 
+#reusing STORAGE_HOST variable here as the base url to point to schema service
+SCHEMA_HOST=${STORAGE_HOST}/api/schema-service/v1/schema
+
 STORAGE_SCHEMA_HOST=${STORAGE_HOST}/api/storage/v2/schemas
 STORAGE_QUERY_RECORD_HOST=${STORAGE_HOST}/api/storage/v2/query/records
 STORAGE_QUERY_RECORD_FOR_CONVERSION_HOST=${STORAGE_HOST}/api/storage/v2/query/records:batch
@@ -39,7 +42,7 @@ aws.elasticache.cluster.schema.expiration=60
 MAX_CACHE_VALUE_SIZE=1000
 
 ## AWS Lambda configuration
-aws.lambda.get-groups-function-name=${ENVIRONMENT}-os-entitlements-GroupsFunction
+#aws.lambda.get-groups-function-name=${ENVIRONMENT}-os-entitlements-GroupsFunction
 
 
 ## Default DynamoDB Settings
diff --git a/provider/indexer-azure/.envrc.template b/provider/indexer-azure/.envrc.template
index e07a7890090f4b5af016ff3c7161c9b5aefb2065..153291ee94ad2bd56f7863314d628f96e84d0384 100644
--- a/provider/indexer-azure/.envrc.template
+++ b/provider/indexer-azure/.envrc.template
@@ -1,8 +1,9 @@
 ##
 # Needed to run the service
 ##
+export schema_service_url=
+export SCHEMA_HOST=
 export storage_service_url=
-export STORAGE_SCHEMA_HOST=
 export STORAGE_QUERY_RECORD_HOST=
 export STORAGE_QUERY_RECORD_FOR_CONVERSION_HOST=
 export servicebus_namespace_name=
diff --git a/provider/indexer-azure/README.md b/provider/indexer-azure/README.md
index 6772abca8ff69d7dc5f90e8456805f5ee709a734..fc52a8e9698754035054a79e0bd1656d2a02575d 100644
--- a/provider/indexer-azure/README.md
+++ b/provider/indexer-azure/README.md
@@ -40,6 +40,8 @@ az keyvault secret show --vault-name $KEY_VAULT_NAME --name $KEY_VAULT_SECRET_NA
 | name | value | description | sensitive? | source |
 | ---  | ---   | ---         | ---        | ---    |
 | `server.servlet.contextPath` | `/api/indexer/v2/` | Servlet context path | no | - |
+| `schema_service_url` | ex `https://schema.azurewebsites.net` | Endpoint of schema service | no | output of infrastructure deployments |
+| `SCHEMA_HOST` | `${schema_service_url}/schema` | Endpoint of schema API | no | - |
 | `storage_service_url` | ex `https://storage.azurewebsites.net` | Endpoint of storage service | no | output of infrastructure deployments |
 | `STORAGE_SCHEMA_HOST` | `${storage_service_url}/schemas` | Endpoint of schema API | no | - |
 | `STORAGE_QUERY_RECORD_HOST` | `${storage_service_url}/query/records` | Endpoint of records API | no | - |
@@ -73,6 +75,7 @@ az keyvault secret show --vault-name $KEY_VAULT_NAME --name $KEY_VAULT_SECRET_NA
 | `DEFAULT_DATA_PARTITION_ID_TENANT1` | ex `opendes` | Primary data partition for queries | no | Data in search index |
 | `DEFAULT_DATA_PARTITION_ID_TENANT2` | ex `common` | Secondary data partition for queries | no | Data in search index |
 | `STORAGE_HOST` | ex `https://storage.azurewebsites.net/` | Storage service endpoint | no | output of infrastructure deployment |
+| `SCHEMA_HOST` | ex `https://schema.azurewebsites.net/` | Endpoint of schema API | no | - |
 | `ENVIRONMENT` | `CLOUD` | Deployment environment | no | - |
 | `ENTITLEMENTS_DOMAIN` | `contoso.com` | OSDU R2 service domain | no | - |
 | `LEGAL_TAG` | `opendes-public-usa-dataset-7643990` | Legal tag used for test records | no | Needs to be in DB. The referenced tag should already exist. |
diff --git a/provider/indexer-azure/pom.xml b/provider/indexer-azure/pom.xml
index 62d8f1d15aa415a25cd0ab27dd9520791527e502..8a5f33513d0b6db572b7410418684c8afea0927f 100644
--- a/provider/indexer-azure/pom.xml
+++ b/provider/indexer-azure/pom.xml
@@ -43,8 +43,35 @@
         <nimbus-jose-jwt.version>8.2</nimbus-jose-jwt.version>
         <indexer-core.version>1.0.6-SNAPSHOT</indexer-core.version>
         <spring-security-jwt.version>1.1.1.RELEASE</spring-security-jwt.version>
+        <osdu.corelibazure.version>0.0.42</osdu.corelibazure.version>
+        <osdu.oscorecommon.version>0.3.12</osdu.oscorecommon.version>
+        <reactor-netty.version>0.9.12.RELEASE</reactor-netty.version>
+        <java-jwt.version>3.8.1</java-jwt.version>
+        <powermock.version>2.0.2</powermock.version>
+        <mockito.version>3.0.0</mockito.version>
+        <cobertura-maven-plugin.version>2.7</cobertura-maven-plugin.version>
+        <spring-security-oauth2.version>2.3.6.RELEASE</spring-security-oauth2.version>
     </properties>
 
+    <dependencyManagement>
+        <dependencies>
+            <!-- Override version defined in parent's POM -->
+            <dependency>
+                <groupId>io.projectreactor.netty</groupId>
+                <artifactId>reactor-netty</artifactId>
+                <version>${reactor-netty.version}</version>
+            </dependency>
+            <!-- Inherit managed dependencies from core-lib-azure -->
+            <dependency>
+                <groupId>org.opengroup.osdu</groupId>
+                <artifactId>core-lib-azure</artifactId>
+                <version>${osdu.corelibazure.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
     <dependencies>
         <dependency>
             <groupId>org.yaml</groupId>
@@ -97,7 +124,12 @@
         <dependency>
             <groupId>com.microsoft.azure</groupId>
             <artifactId>azure-active-directory-spring-boot-starter</artifactId>
-            <version>${azure.version}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-starter-logging</artifactId>
+                </exclusion>
+            </exclusions>
         </dependency>
         <dependency>
             <groupId>org.springframework.boot</groupId>
@@ -112,7 +144,7 @@
         <dependency>
             <groupId>org.springframework.security.oauth</groupId>
             <artifactId>spring-security-oauth2</artifactId>
-            <version>2.3.6.RELEASE</version>
+            <version>${spring-security-oauth2.version}</version>
             <exclusions>
             <exclusion>
                 <groupId>org.codehaus.jackson</groupId>
@@ -142,18 +174,17 @@
         <dependency>
             <groupId>org.opengroup.osdu</groupId>
             <artifactId>os-core-common</artifactId>
-            <version>0.3.12</version>
+            <version>${osdu.oscorecommon.version}</version>
         </dependency>
         <dependency>
             <groupId>org.opengroup.osdu</groupId>
             <artifactId>core-lib-azure</artifactId>
-            <version>0.0.33</version>
+            <version>${osdu.corelibazure.version}</version>
         </dependency>
 
         <dependency>
             <groupId>com.microsoft.azure</groupId>
             <artifactId>msal4j</artifactId>
-            <version>0.5.0-preview</version>
         </dependency>
 
         <dependency>
@@ -184,19 +215,18 @@
         <dependency>
             <groupId>com.auth0</groupId>
             <artifactId>java-jwt</artifactId>
-            <version>3.8.1</version>
+            <version>${java-jwt.version}</version>
         </dependency>
         <dependency>
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>
-            <version>4.12</version>
             <scope>test</scope>
         </dependency>
         <!-- https://mvnrepository.com/artifact/org.powermock/powermock-api-mockito2 -->
         <dependency>
             <groupId>org.powermock</groupId>
             <artifactId>powermock-api-mockito2</artifactId>
-            <version>2.0.2</version>
+            <version>${powermock.version}</version>
             <scope>test</scope>
         </dependency>
 
@@ -204,19 +234,19 @@
         <dependency>
             <groupId>org.powermock</groupId>
             <artifactId>powermock-module-junit4</artifactId>
-            <version>2.0.2</version>
+            <version>${powermock.version}</version>
             <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>org.mockito</groupId>
             <artifactId>mockito-core</artifactId>
-            <version>3.0.0</version>
+            <version>${mockito.version}</version>
             <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>org.codehaus.mojo</groupId>
             <artifactId>cobertura-maven-plugin</artifactId>
-            <version>2.7</version>
+            <version>${cobertura-maven-plugin.version}</version>
             <scope>test</scope>
         </dependency>
 
diff --git a/provider/indexer-azure/src/main/resources/application.properties b/provider/indexer-azure/src/main/resources/application.properties
index ad3d128f3d44475fa041143acb1b5df1f2860af8..a334813afb2b5cccfe9127b0cf95a9730f9e4f81 100644
--- a/provider/indexer-azure/src/main/resources/application.properties
+++ b/provider/indexer-azure/src/main/resources/application.properties
@@ -36,6 +36,8 @@ KINDS_REDIS_DATABASE=1
 CRON_INDEX_CLEANUP_THRESHOLD_DAYS=3
 CRON_EMPTY_INDEX_CLEANUP_THRESHOLD_DAYS=7
 
+SCHEMA_HOST=${schema_service_url}/schema
+
 storage_service_url=${storage_service_endpoint}
 STORAGE_SCHEMA_HOST=${storage_service_url}/schemas
 STORAGE_QUERY_RECORD_HOST=${storage_service_url}/query/records
@@ -78,3 +80,6 @@ logging.mdccontext.enabled=true
 
 # core-lib-azure configuration
 tenantFactoryImpl.required=true
+
+# Disable keyVault for actuator health check
+management.health.azure-key-vault.enabled=false
\ No newline at end of file
diff --git a/provider/indexer-azure/src/test/java/org/opengroup/osdu/indexer/azure/service/IndexerSchemaServiceTest.java b/provider/indexer-azure/src/test/java/org/opengroup/osdu/indexer/azure/service/IndexerSchemaServiceTest.java
index bc640485be50de6f1727e4f9bc16306ec01ea1b0..9cc054aaaa67619bd8631e00b74fc4d330bad954 100644
--- a/provider/indexer-azure/src/test/java/org/opengroup/osdu/indexer/azure/service/IndexerSchemaServiceTest.java
+++ b/provider/indexer-azure/src/test/java/org/opengroup/osdu/indexer/azure/service/IndexerSchemaServiceTest.java
@@ -23,18 +23,18 @@ import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
+import org.opengroup.osdu.core.common.logging.JaxRsDpsLog;
+import org.opengroup.osdu.core.common.model.http.AppException;
+import org.opengroup.osdu.core.common.model.http.RequestStatus;
 import org.opengroup.osdu.core.common.model.indexer.IndexSchema;
 import org.opengroup.osdu.core.common.model.indexer.OperationType;
-import org.opengroup.osdu.core.common.logging.JaxRsDpsLog;
+import org.opengroup.osdu.core.common.search.ElasticIndexNameResolver;
+import org.opengroup.osdu.core.common.search.IndicesService;
 import org.opengroup.osdu.indexer.provider.interfaces.ISchemaCache;
 import org.opengroup.osdu.indexer.service.IndexSchemaServiceImpl;
 import org.opengroup.osdu.indexer.service.IndexerMappingService;
-import org.opengroup.osdu.indexer.service.StorageService;
-import org.opengroup.osdu.core.common.model.http.RequestStatus;
-import org.opengroup.osdu.core.common.search.IndicesService;
-import org.opengroup.osdu.core.common.model.http.AppException;
+import org.opengroup.osdu.indexer.service.SchemaService;
 import org.opengroup.osdu.indexer.util.ElasticClientHandler;
-import org.opengroup.osdu.core.common.search.ElasticIndexNameResolver;
 import org.powermock.core.classloader.annotations.PrepareForTest;
 import org.springframework.test.context.junit4.SpringRunner;
 
@@ -62,8 +62,6 @@ public class IndexerSchemaServiceTest {
     @Mock
     private JaxRsDpsLog log;
     @Mock
-    private StorageService storageService;
-    @Mock
     private ElasticClientHandler elasticClientHandler;
     @Mock
     private ElasticIndexNameResolver elasticIndexNameResolver;
@@ -72,6 +70,8 @@ public class IndexerSchemaServiceTest {
     @Mock
     private IndicesService indicesService;
     @Mock
+    private SchemaService schemaService;
+    @Mock
     private ISchemaCache schemaCache;
     @InjectMocks
     private IndexSchemaServiceImpl sut;
@@ -85,7 +85,7 @@ public class IndexerSchemaServiceTest {
 
     @Test
     public void should_returnNull_givenEmptySchema_getIndexerInputSchemaSchemaTest() throws Exception {
-        when(storageService.getStorageSchema(any())).thenReturn(emptySchema);
+        when(schemaService.getSchema(any())).thenReturn(emptySchema);
 
         IndexSchema indexSchema = this.sut.getIndexerInputSchema(kind, false);
 
@@ -94,7 +94,7 @@ public class IndexerSchemaServiceTest {
 
     @Test
     public void should_returnValidResponse_givenValidSchema_getIndexerInputSchemaTest() throws Exception {
-        when(storageService.getStorageSchema(any())).thenReturn(someSchema);
+        when(schemaService.getSchema(any())).thenReturn(someSchema);
 
         IndexSchema indexSchema = this.sut.getIndexerInputSchema(kind, false);
 
@@ -103,7 +103,7 @@ public class IndexerSchemaServiceTest {
 
     @Test
     public void should_returnValidResponse_givenValidSchemaWithCacheHit_getIndexerInputSchemaTest() throws Exception {
-        when(storageService.getStorageSchema(any())).thenReturn(someSchema);
+        when(schemaService.getSchema(any())).thenReturn(someSchema);
         when(this.schemaCache.get(kind + "_flattened")).thenReturn(someSchema);
 
         IndexSchema indexSchema = this.sut.getIndexerInputSchema(kind, false);
@@ -115,7 +115,7 @@ public class IndexerSchemaServiceTest {
     public void should_throw500_givenInvalidSchemaCacheHit_getIndexerInputSchemaTest() {
         try {
             String invalidSchema = "{}}";
-            when(storageService.getStorageSchema(any())).thenReturn(invalidSchema);
+            when(schemaService.getSchema(any())).thenReturn(invalidSchema);
 
             this.sut.getIndexerInputSchema(kind, false);
             fail("Should throw exception");
@@ -170,7 +170,7 @@ public class IndexerSchemaServiceTest {
         when(this.elasticIndexNameResolver.getIndexNameFromKind(kind)).thenReturn(kind.replace(":", "-"));
         when(this.schemaCache.get(kind)).thenReturn(null);
         when(this.indicesService.isIndexExist(any(), any())).thenReturn(false);
-        when(this.storageService.getStorageSchema(kind)).thenReturn(storageSchema);
+        when(this.schemaService.getSchema(kind)).thenReturn(storageSchema);
 
         this.sut.processSchemaMessages(schemaMessages);
 
@@ -201,7 +201,7 @@ public class IndexerSchemaServiceTest {
         when(this.elasticIndexNameResolver.getIndexNameFromKind(kind)).thenReturn(kind.replace(":", "-"));
         when(this.schemaCache.get(kind)).thenReturn(null);
         when(this.indicesService.isIndexExist(any(), any())).thenReturn(true);
-        when(this.storageService.getStorageSchema(kind)).thenReturn(storageSchema);
+        when(this.schemaService.getSchema(kind)).thenReturn(storageSchema);
 
         this.sut.processSchemaMessages(schemaMessages);
 
@@ -229,7 +229,7 @@ public class IndexerSchemaServiceTest {
         when(this.elasticIndexNameResolver.getIndexNameFromKind(kind)).thenReturn(kind.replace(":", "-"));
         when(this.schemaCache.get(kind)).thenReturn(null);
         when(this.indicesService.isIndexExist(any(), any())).thenReturn(true);
-        when(this.storageService.getStorageSchema(kind)).thenReturn(storageSchema);
+        when(this.schemaService.getSchema(kind)).thenReturn(storageSchema);
         when(this.mappingService.createMapping(any(), any(), any(), anyBoolean())).thenThrow(new AppException(HttpStatus.SC_BAD_REQUEST, reason, ""));
 
         try {
@@ -262,7 +262,7 @@ public class IndexerSchemaServiceTest {
         when(this.elasticIndexNameResolver.getIndexNameFromKind(kind)).thenReturn(kind.replace(":", "-"));
         when(this.schemaCache.get(kind)).thenReturn(null);
         when(this.indicesService.isIndexExist(any(), any())).thenReturn(true);
-        when(this.storageService.getStorageSchema(kind)).thenReturn(storageSchema);
+        when(this.schemaService.getSchema(kind)).thenReturn(storageSchema);
         when(this.mappingService.createMapping(any(), any(), any(), anyBoolean())).thenThrow(new AppException(HttpStatus.SC_FORBIDDEN, reason, "blah"));
 
         try {
@@ -289,7 +289,7 @@ public class IndexerSchemaServiceTest {
         when(this.elasticIndexNameResolver.getIndexNameFromKind(kind)).thenReturn(kind.replace(":", "-"));
         when(this.schemaCache.get(kind)).thenReturn(null);
         when(this.indicesService.isIndexExist(any(), any())).thenReturn(true);
-        when(this.storageService.getStorageSchema(kind)).thenReturn(storageSchema);
+        when(this.schemaService.getSchema(kind)).thenReturn(storageSchema);
 
         this.sut.processSchemaMessages(schemaMessages);
 
@@ -343,7 +343,7 @@ public class IndexerSchemaServiceTest {
         when(this.schemaCache.get(kind)).thenReturn(null);
         when(this.indicesService.isIndexExist(any(), any())).thenReturn(true);
         when(this.indicesService.deleteIndex(any(), any())).thenReturn(true);
-        when(this.storageService.getStorageSchema(kind)).thenReturn(storageSchema);
+        when(this.schemaService.getSchema(kind)).thenReturn(storageSchema);
 
         this.sut.syncIndexMappingWithStorageSchema(kind);
 
diff --git a/provider/indexer-gcp/cloudbuild/Dockerfile.cloudbuild b/provider/indexer-gcp/cloudbuild/Dockerfile.cloudbuild
new file mode 100644
index 0000000000000000000000000000000000000000..59c9b5dafcf6824308be6cf80357a887ac75bd36
--- /dev/null
+++ b/provider/indexer-gcp/cloudbuild/Dockerfile.cloudbuild
@@ -0,0 +1,13 @@
+# Use the official AdoptOpenJDK for a base image.
+# https://hub.docker.com/_/openjdk
+FROM openjdk:8-slim
+WORKDIR /app
+ARG PROVIDER_NAME
+ENV PROVIDER_NAME $PROVIDER_NAME
+ARG PORT
+ENV PORT $PORT
+# Copy the jar to the production image from the builder stage.
+COPY provider/indexer-${PROVIDER_NAME}/target/indexer-${PROVIDER_NAME}-*-SNAPSHOT-spring-boot.jar indexer-${PROVIDER_NAME}.jar
+# Run the web service on container startup.
+CMD java -Djava.security.egd=indexer:/dev/./urandom -Dserver.port=${PORT} -jar /app/indexer-${PROVIDER_NAME}.jar
+
diff --git a/provider/indexer-gcp/cloudbuild/cloudbuild.yaml b/provider/indexer-gcp/cloudbuild/cloudbuild.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..a0839623e8b0b66a821dd324a3e5bfeff8d2ab98
--- /dev/null
+++ b/provider/indexer-gcp/cloudbuild/cloudbuild.yaml
@@ -0,0 +1,31 @@
+# Copyright 2020 Google LLC
+# Copyright 2017-2019, Schlumberger
+# Copyright 2020 EPAM
+#
+# 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.
+
+steps:
+  - name: 'gcr.io/cloud-builders/docker'
+    args: [
+            'build',
+            '--build-arg', 'PROVIDER_NAME=${_PROVIDER_NAME}',
+            '--build-arg', 'PORT=${_PORT}',
+            '-t', 'gcr.io/$PROJECT_ID/${_APPLICATION_NAME}/${_GCP_SERVICE}-${_PROVIDER_NAME}:${_SHORT_SHA}',
+            '-t', 'gcr.io/$PROJECT_ID/${_APPLICATION_NAME}/${_GCP_SERVICE}-${_PROVIDER_NAME}:latest',
+            '-f', 'provider/${_GCP_SERVICE}-${_PROVIDER_NAME}/cloudbuild/Dockerfile.cloudbuild',
+            '.'
+    ]
+
+images:
+  - 'gcr.io/$PROJECT_ID/${_APPLICATION_NAME}/${_GCP_SERVICE}-${_PROVIDER_NAME}'
+
diff --git a/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/IndexerGcpApplication.java b/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/IndexerGcpApplication.java
index f72e93440739667f6f7ad9a5694a39e32eedf4aa..6ee70305369eba6f03ef966ce1d442f336eaa87b 100644
--- a/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/IndexerGcpApplication.java
+++ b/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/IndexerGcpApplication.java
@@ -1,3 +1,20 @@
+/*
+  Copyright 2020 Google LLC
+  Copyright 2020 EPAM Systems, Inc
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
 package org.opengroup.osdu.indexer;
 
 import org.springframework.boot.SpringApplication;
diff --git a/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/ServletInitializer.java b/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/ServletInitializer.java
index 0e5ee0a8243d6365fac37b98f0a4a42b2368e85b..dd76cbdb7cc7fa44954c59b4a0e69088dc532f55 100644
--- a/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/ServletInitializer.java
+++ b/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/ServletInitializer.java
@@ -1,3 +1,20 @@
+/*
+  Copyright 2020 Google LLC
+  Copyright 2020 EPAM Systems, Inc
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
 package org.opengroup.osdu.indexer;
 
 import org.springframework.boot.builder.SpringApplicationBuilder;
diff --git a/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/cache/AttributesCache.java b/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/cache/AttributesCache.java
index 889e4476794ea42013afbb1a0ecb49e09e5f0371..0f66e377bb331e53a55b16c5cfceae4895dd9684 100644
--- a/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/cache/AttributesCache.java
+++ b/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/cache/AttributesCache.java
@@ -14,13 +14,12 @@
 
 package org.opengroup.osdu.indexer.cache;
 
-import javax.inject.Inject;
 import org.opengroup.osdu.core.common.cache.RedisCache;
-import org.opengroup.osdu.core.common.model.search.ClusterSettings;
 import org.opengroup.osdu.core.common.provider.interfaces.IAttributesCache;
 import org.opengroup.osdu.indexer.config.IndexerConfigurationProperties;
-import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Component;
+
+import javax.inject.Inject;
 import java.util.Set;
 
 @Component
diff --git a/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/cache/DatastoreCredentialCache.java b/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/cache/DatastoreCredentialCache.java
index 0084dcb2c5e729066923b880108071e527e41b1d..6a3b330aad0dcc5a7ba09687a82e0c5e1f53548c 100644
--- a/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/cache/DatastoreCredentialCache.java
+++ b/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/cache/DatastoreCredentialCache.java
@@ -18,14 +18,13 @@ import com.google.auth.oauth2.AccessToken;
 import org.opengroup.osdu.core.common.cache.RedisCache;
 import org.opengroup.osdu.indexer.config.IndexerConfigurationProperties;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Component;
 
 @Component
 public class DatastoreCredentialCache extends RedisCache<String, AccessToken> {
 
-	@Autowired
-	public DatastoreCredentialCache(final IndexerConfigurationProperties configurationProperties) {
-		super(configurationProperties.getRedisSearchHost(), Integer.parseInt(configurationProperties.getRedisSearchPort()), 58 * 60, String.class, AccessToken.class);
-	}
+    @Autowired
+    public DatastoreCredentialCache(final IndexerConfigurationProperties configurationProperties) {
+        super(configurationProperties.getRedisSearchHost(), Integer.parseInt(configurationProperties.getRedisSearchPort()), 58 * 60, String.class, AccessToken.class);
+    }
 }
\ No newline at end of file
diff --git a/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/cache/ElasticCredentialsCache.java b/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/cache/ElasticCredentialsCache.java
index 8a5e763e783d01b0c4696d9ebc77a51e50ba3c7f..720d21c7256f4bbd838431de4b9e25336587035e 100644
--- a/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/cache/ElasticCredentialsCache.java
+++ b/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/cache/ElasticCredentialsCache.java
@@ -1,13 +1,30 @@
+/*
+  Copyright 2020 Google LLC
+  Copyright 2020 EPAM Systems, Inc
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
 package org.opengroup.osdu.indexer.cache;
 
-import javax.inject.Inject;
 import org.opengroup.osdu.core.common.cache.RedisCache;
 import org.opengroup.osdu.core.common.model.search.ClusterSettings;
 import org.opengroup.osdu.core.common.provider.interfaces.IElasticCredentialsCache;
 import org.opengroup.osdu.indexer.config.IndexerConfigurationProperties;
-import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Component;
 
+import javax.inject.Inject;
+
 @Component
 public class ElasticCredentialsCache implements IElasticCredentialsCache<String, ClusterSettings>, AutoCloseable {
 
diff --git a/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/cache/IndexCache.java b/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/cache/IndexCache.java
index 2e8ead781a1f5e0b9b303ee411b953057696dbe2..7f7911db5d70cf5a5c34c77c828fa67e68adbc8d 100644
--- a/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/cache/IndexCache.java
+++ b/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/cache/IndexCache.java
@@ -1,13 +1,29 @@
+/*
+  Copyright 2020 Google LLC
+  Copyright 2020 EPAM Systems, Inc
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
 package org.opengroup.osdu.indexer.cache;
 
-import javax.inject.Inject;
 import org.opengroup.osdu.core.common.cache.RedisCache;
-import org.opengroup.osdu.core.common.model.search.ClusterSettings;
 import org.opengroup.osdu.core.common.provider.interfaces.IIndexCache;
 import org.opengroup.osdu.indexer.config.IndexerConfigurationProperties;
-import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Component;
 
+import javax.inject.Inject;
+
 @Component
 public class IndexCache implements IIndexCache<String, Boolean>, AutoCloseable {
     private RedisCache<String, Boolean> cache;
diff --git a/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/cache/JwtCache.java b/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/cache/JwtCache.java
index a44747cd6426255bd90d3085e95b04c182b84186..4ba364f5bd4523a44e07f74ec5dcd18c10f4ed11 100644
--- a/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/cache/JwtCache.java
+++ b/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/cache/JwtCache.java
@@ -1,20 +1,37 @@
+/*
+  Copyright 2020 Google LLC
+  Copyright 2020 EPAM Systems, Inc
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
 package org.opengroup.osdu.indexer.cache;
 
-import javax.inject.Inject;
 import org.opengroup.osdu.core.common.cache.RedisCache;
 import org.opengroup.osdu.core.common.model.search.IdToken;
 import org.opengroup.osdu.core.common.provider.interfaces.IJwtCache;
 import org.opengroup.osdu.indexer.config.IndexerConfigurationProperties;
-import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Component;
 
+import javax.inject.Inject;
+
 @Component
 public class JwtCache implements IJwtCache<String, IdToken>, AutoCloseable {
     RedisCache<String, IdToken> cache;
 
 
     // google service account id_token can be requested only for 1 hr
-    private final static int EXPIRED_AFTER = 59;
+    private static final int EXPIRED_AFTER = 59;
     @Inject
     public JwtCache(final IndexerConfigurationProperties properties) {
         cache = new RedisCache<>(properties.getRedisSearchHost(), Integer.parseInt(properties.getRedisSearchPort()),
diff --git a/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/cache/KindsCache.java b/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/cache/KindsCache.java
index 92481f2418fd238c7c051d5c39a6d0b8becd50c0..e20d2f3ca240d33b44cc3bb9261593cae657f8ee 100644
--- a/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/cache/KindsCache.java
+++ b/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/cache/KindsCache.java
@@ -1,12 +1,28 @@
+/*
+  Copyright 2020 Google LLC
+  Copyright 2020 EPAM Systems, Inc
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
 package org.opengroup.osdu.indexer.cache;
 
-import javax.inject.Inject;
 import org.opengroup.osdu.core.common.cache.RedisCache;
 import org.opengroup.osdu.core.common.provider.interfaces.IKindsCache;
 import org.opengroup.osdu.indexer.config.IndexerConfigurationProperties;
-import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Component;
 
+import javax.inject.Inject;
 import java.util.Set;
 
 @Component
diff --git a/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/cache/SchemaCache.java b/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/cache/SchemaCache.java
index 04f69cded8bea50fe3486349182a4d3e80a8bd01..0ee20756541b14b4c8a6d94fb153317722c233df 100644
--- a/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/cache/SchemaCache.java
+++ b/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/cache/SchemaCache.java
@@ -1,13 +1,29 @@
+/*
+  Copyright 2020 Google LLC
+  Copyright 2020 EPAM Systems, Inc
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
 package org.opengroup.osdu.indexer.cache;
 
-import javax.inject.Inject;
 import org.opengroup.osdu.core.common.cache.RedisCache;
-import org.opengroup.osdu.core.common.model.search.ClusterSettings;
 import org.opengroup.osdu.indexer.config.IndexerConfigurationProperties;
 import org.opengroup.osdu.indexer.provider.interfaces.ISchemaCache;
-import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Component;
 
+import javax.inject.Inject;
+
 @Component
 public class SchemaCache implements ISchemaCache<String, String>, AutoCloseable {
     private RedisCache<String, String> cache;
diff --git a/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/di/DatastoreCredentialsCacheFactory.java b/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/di/DatastoreCredentialsCacheFactory.java
index 94e9d343b980c905ff0b72941e5232e40ff42e8d..6f4d9b7505504f259ceca3d3b8e1834dc53f91ba 100644
--- a/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/di/DatastoreCredentialsCacheFactory.java
+++ b/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/di/DatastoreCredentialsCacheFactory.java
@@ -1,3 +1,20 @@
+/*
+  Copyright 2020 Google LLC
+  Copyright 2020 EPAM Systems, Inc
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
 package org.opengroup.osdu.indexer.di;
 
 import org.opengroup.osdu.core.common.cache.ICache;
diff --git a/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/di/EntitlementsClientFactory.java b/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/di/EntitlementsClientFactory.java
index debcc593970c05f7d4b7291de7519e99c7155890..37e23c94763621e6b06123f2e51cdfd74f7f1507 100644
--- a/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/di/EntitlementsClientFactory.java
+++ b/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/di/EntitlementsClientFactory.java
@@ -31,10 +31,10 @@ import org.springframework.web.context.annotation.RequestScope;
 public class EntitlementsClientFactory extends AbstractFactoryBean<IEntitlementsFactory> {
 
 	@Value("${AUTHORIZE_API}")
-	private String AUTHORIZE_API;
+	private String authorizeApi;
 
 	@Value("${AUTHORIZE_API_KEY:}")
-	private String AUTHORIZE_API_KEY;
+	private String authorizeApiKey;
 
 	@Autowired
 	private HttpResponseBodyMapper mapper;
@@ -44,8 +44,8 @@ public class EntitlementsClientFactory extends AbstractFactoryBean<IEntitlements
 
 		return new EntitlementsFactory(EntitlementsAPIConfig
 				.builder()
-				.rootUrl(AUTHORIZE_API)
-				.apiKey(AUTHORIZE_API_KEY)
+				.rootUrl(authorizeApi)
+				.apiKey(authorizeApiKey)
 				.build(),
 				mapper);
 	}
diff --git a/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/di/PubSubExtensionsFactory.java b/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/di/PubSubExtensionsFactory.java
index 256686206ea33b431d869cbb14b7c41cea009fc9..c0995677c674dc1192b4c9533903454af441cfeb 100644
--- a/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/di/PubSubExtensionsFactory.java
+++ b/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/di/PubSubExtensionsFactory.java
@@ -1,3 +1,20 @@
+/*
+  Copyright 2020 Google LLC
+  Copyright 2020 EPAM Systems, Inc
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
 package org.opengroup.osdu.indexer.di;
 
 import org.opengroup.osdu.core.gcp.PubSub.PubSubExtensions;
diff --git a/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/middleware/IndexFilter.java b/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/middleware/IndexFilter.java
index 5bdf78f04d24485d4678cb3cb227b42df62dfe62..cd7d4622c847e13f109c6ee89adc8c679b645144 100644
--- a/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/middleware/IndexFilter.java
+++ b/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/middleware/IndexFilter.java
@@ -1,15 +1,31 @@
+/*
+  Copyright 2020 Google LLC
+  Copyright 2020 EPAM Systems, Inc
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
 package org.opengroup.osdu.indexer.middleware;
 
 import com.google.common.base.Strings;
 import lombok.extern.java.Log;
 import org.apache.http.HttpStatus;
-import org.opengroup.osdu.core.common.model.http.DpsHeaders;
-import org.opengroup.osdu.core.common.model.http.AppException;
 import org.opengroup.osdu.core.common.http.ResponseHeaders;
+import org.opengroup.osdu.core.common.model.http.AppException;
+import org.opengroup.osdu.core.common.model.http.DpsHeaders;
 import org.opengroup.osdu.core.common.model.search.DeploymentEnvironment;
 import org.opengroup.osdu.core.common.provider.interfaces.IRequestInfo;
 import org.opengroup.osdu.indexer.config.IndexerConfigurationProperties;
-import org.springframework.beans.factory.annotation.Value;
 import org.springframework.http.HttpMethod;
 import org.springframework.stereotype.Component;
 
@@ -35,14 +51,11 @@ public class IndexFilter implements Filter {
     @Inject
     private IndexerConfigurationProperties properties;
 
-    private FilterConfig filterConfig;
-
-    private static final String PATH_SWAGGER = "/swagger.json";
     private static final String PATH_TASK_HANDLERS = "task-handlers";
     private static final String PATH_CRON_HANDLERS = "cron-handlers";
 
     @Override
-    public void init(FilterConfig filterConfig) throws ServletException {
+    public void init(FilterConfig filterConfig) {
     }
 
     @Override
@@ -61,10 +74,6 @@ public class IndexFilter implements Filter {
             checkWorkerApiAccess(requestInfo);
         }
 
-//        if (!httpRequest.isSecure()) {
-//            throw new AppException(302, "Redirect", "HTTP is not supported. Use HTTPS.");
-//        }
-
         filterChain.doFilter(servletRequest, servletResponse);
 
         HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;
diff --git a/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/persistence/ElasticRepositoryDatastore.java b/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/persistence/ElasticRepositoryDatastore.java
index 0c70475ae974c1fc47f52b926519b4a124ef20dd..7e773c20b9c7f12bec2878c7c3ef4d3d349f8ab1 100644
--- a/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/persistence/ElasticRepositoryDatastore.java
+++ b/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/persistence/ElasticRepositoryDatastore.java
@@ -20,16 +20,16 @@ import com.google.cloud.datastore.Entity;
 import com.google.cloud.datastore.Key;
 import lombok.extern.java.Log;
 import org.apache.http.HttpStatus;
+import org.opengroup.osdu.core.common.model.http.AppException;
 import org.opengroup.osdu.core.common.model.search.ClusterSettings;
 import org.opengroup.osdu.core.common.model.tenant.TenantInfo;
-import org.opengroup.osdu.core.common.model.http.AppException;
-import org.opengroup.osdu.core.common.provider.interfaces.IKmsClient;
 import org.opengroup.osdu.core.common.provider.interfaces.IElasticRepository;
+import org.opengroup.osdu.core.common.provider.interfaces.IKmsClient;
 import org.opengroup.osdu.core.common.search.Preconditions;
 import org.opengroup.osdu.core.gcp.multitenancy.DatastoreFactory;
 import org.opengroup.osdu.indexer.config.IndexerConfigurationProperties;
-import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Component;
+
 import javax.inject.Inject;
 
 @Log
diff --git a/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/publish/PublisherImpl.java b/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/publish/PublisherImpl.java
index 32d2dd6fc394eca3a11a95339cc9eca5599ddb2e..31d242cd46515f9b37907e458b510dd7a37557bd 100644
--- a/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/publish/PublisherImpl.java
+++ b/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/publish/PublisherImpl.java
@@ -26,18 +26,16 @@ import com.google.pubsub.v1.PubsubMessage;
 import lombok.extern.java.Log;
 import org.apache.http.HttpStatus;
 import org.elasticsearch.common.Strings;
-
-import org.opengroup.osdu.core.common.model.http.DpsHeaders;
-import org.opengroup.osdu.core.common.provider.interfaces.ITenantFactory;
-import org.opengroup.osdu.core.common.model.tenant.TenantInfo;
 import org.opengroup.osdu.core.common.model.http.AppException;
+import org.opengroup.osdu.core.common.model.http.DpsHeaders;
 import org.opengroup.osdu.core.common.model.indexer.JobStatus;
 import org.opengroup.osdu.core.common.model.indexer.RecordStatus;
+import org.opengroup.osdu.core.common.model.search.DeploymentEnvironment;
+import org.opengroup.osdu.core.common.model.tenant.TenantInfo;
+import org.opengroup.osdu.core.common.provider.interfaces.ITenantFactory;
+import org.opengroup.osdu.core.gcp.PubSub.PubSubExtensions;
 import org.opengroup.osdu.indexer.config.IndexerConfigurationProperties;
 import org.opengroup.osdu.indexer.provider.interfaces.IPublisher;
-import org.opengroup.osdu.core.gcp.PubSub.PubSubExtensions;
-import org.opengroup.osdu.core.common.model.search.DeploymentEnvironment;
-import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Component;
 import org.springframework.web.context.annotation.RequestScope;
 import org.threeten.bp.Duration;
diff --git a/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/security/GSuiteSecurityConfig.java b/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/security/GSuiteSecurityConfig.java
index c57564a198aae80b5cf4c8316488533467cbbc04..8be38e24bb075a6042ecf6aaafe312d97bb177b1 100644
--- a/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/security/GSuiteSecurityConfig.java
+++ b/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/security/GSuiteSecurityConfig.java
@@ -1,3 +1,20 @@
+/*
+  Copyright 2020 Google LLC
+  Copyright 2020 EPAM Systems, Inc
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
 package org.opengroup.osdu.indexer.security;
 
 import org.springframework.context.annotation.Configuration;
diff --git a/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/util/RequestInfoImpl.java b/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/util/RequestInfoImpl.java
index 03fddbbfa7f3df968506a2c609f2818fe4c10130..dffa1d5e0cb84f93b0d93d103a11738e10ed07a6 100644
--- a/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/util/RequestInfoImpl.java
+++ b/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/util/RequestInfoImpl.java
@@ -1,3 +1,20 @@
+/*
+  Copyright 2020 Google LLC
+  Copyright 2020 EPAM Systems, Inc
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
 package org.opengroup.osdu.indexer.util;
 
 import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken;
@@ -50,7 +67,7 @@ public class RequestInfoImpl implements IRequestInfo {
     @Value("${indexer.que.service.mail}")
     private String indexerQueServiceMail;
 
-    private static final String expectedCronHeaderValue = "true";
+    private static final String EXPECTED_CRON_HEADER_VALUE = "true";
 
     @Override
     public DpsHeaders getHeaders() {
@@ -83,7 +100,7 @@ public class RequestInfoImpl implements IRequestInfo {
     @Override
     public boolean isCronRequest() {
         String appEngineCronHeader = this.dpsHeaders.getHeaders().getOrDefault(CloudTaskHeaders.CLOUD_CRON_SERVICE, null);
-        return expectedCronHeaderValue.equalsIgnoreCase(appEngineCronHeader);
+        return EXPECTED_CRON_HEADER_VALUE.equalsIgnoreCase(appEngineCronHeader);
     }
 
     @Override
diff --git a/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/util/ServiceAccountJwtGcpClientImpl.java b/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/util/ServiceAccountJwtGcpClientImpl.java
index 6e946ac37ab029c2d0b8b718776bd28da71ad6b1..21af7655f45f1dcc797b5b819c2f10120067a3ba 100644
--- a/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/util/ServiceAccountJwtGcpClientImpl.java
+++ b/provider/indexer-gcp/src/main/java/org/opengroup/osdu/indexer/util/ServiceAccountJwtGcpClientImpl.java
@@ -38,16 +38,15 @@ import org.apache.http.impl.client.CloseableHttpClient;
 import org.apache.http.impl.client.HttpClients;
 import org.apache.http.message.BasicNameValuePair;
 import org.apache.http.util.EntityUtils;
-import org.opengroup.osdu.core.common.model.http.DpsHeaders;
-import org.opengroup.osdu.core.common.provider.interfaces.ITenantFactory;
-import org.opengroup.osdu.core.common.model.tenant.TenantInfo;
+import org.opengroup.osdu.core.common.logging.JaxRsDpsLog;
 import org.opengroup.osdu.core.common.model.http.AppException;
+import org.opengroup.osdu.core.common.model.http.DpsHeaders;
 import org.opengroup.osdu.core.common.model.search.IdToken;
-import org.opengroup.osdu.core.common.logging.JaxRsDpsLog;
+import org.opengroup.osdu.core.common.model.tenant.TenantInfo;
 import org.opengroup.osdu.core.common.provider.interfaces.IJwtCache;
+import org.opengroup.osdu.core.common.provider.interfaces.ITenantFactory;
 import org.opengroup.osdu.core.common.util.IServiceAccountJwtClient;
 import org.opengroup.osdu.indexer.config.IndexerConfigurationProperties;
-import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Component;
 import org.springframework.web.context.annotation.RequestScope;
 
@@ -64,7 +63,7 @@ public class ServiceAccountJwtGcpClientImpl implements IServiceAccountJwtClient
     private static final String JWT_AUDIENCE = "https://www.googleapis.com/oauth2/v4/token";
     private static final String SERVICE_ACCOUNT_NAME_FORMAT = "projects/%s/serviceAccounts/%s";
 
-    private final JsonFactory JSON_FACTORY = new JacksonFactory();
+    private final JsonFactory jsonFactory = new JacksonFactory();
 
     private Iam iam;
 
@@ -100,7 +99,7 @@ public class ServiceAccountJwtGcpClientImpl implements IServiceAccountJwtClient
             Map<String, Object> signJwtPayload = this.getJWTCreationPayload(tenant);
 
             SignJwtRequest signJwtRequest = new SignJwtRequest();
-            signJwtRequest.setPayload(JSON_FACTORY.toString(signJwtPayload));
+            signJwtRequest.setPayload(jsonFactory.toString(signJwtPayload));
 
             String serviceAccountName = String.format(SERVICE_ACCOUNT_NAME_FORMAT, tenant.getProjectId(), tenant.getServiceAccount());
 
@@ -157,7 +156,7 @@ public class ServiceAccountJwtGcpClientImpl implements IServiceAccountJwtClient
             }
 
             // Create IAM API object associated with the authenticated transport.
-            this.iam = new Iam.Builder(httpTransport, JSON_FACTORY, credential)
+            this.iam = new Iam.Builder(httpTransport, jsonFactory, credential)
                     .setApplicationName(properties.getIndexerHost())
                     .build();
         }
diff --git a/provider/indexer-gcp/src/main/resources/application.properties b/provider/indexer-gcp/src/main/resources/application.properties
index 06d81a1e4504e68c74c75c5e5c3caefd470b4eab..06ba9d9417769af49ad5b9d364fa5cdecbb398da 100644
--- a/provider/indexer-gcp/src/main/resources/application.properties
+++ b/provider/indexer-gcp/src/main/resources/application.properties
@@ -40,3 +40,5 @@ elastic-datastore-id=indexer-service
 
 security.https.certificate.trust=false
 indexer.que.service.mail=default@iam.gserviceaccount.com
+
+SCHEMA_HOST=${HOST}/api/schema-service/v1/schema
diff --git a/provider/indexer-gcp/src/test/java/org/opengroup/osdu/indexer/service/IndexerSchemaServiceTest.java b/provider/indexer-gcp/src/test/java/org/opengroup/osdu/indexer/service/IndexerSchemaServiceTest.java
index 434e9bc803383e3034c65b4d8ea66fccd60fb25c..6bae37e26cfb840db56275fe1a42f0afa8557677 100644
--- a/provider/indexer-gcp/src/test/java/org/opengroup/osdu/indexer/service/IndexerSchemaServiceTest.java
+++ b/provider/indexer-gcp/src/test/java/org/opengroup/osdu/indexer/service/IndexerSchemaServiceTest.java
@@ -29,6 +29,7 @@ import org.opengroup.osdu.indexer.provider.interfaces.ISchemaCache;
 import org.opengroup.osdu.core.common.model.indexer.IndexSchema;
 import org.opengroup.osdu.core.common.model.http.RequestStatus;
 import org.opengroup.osdu.core.common.search.IndicesService;
+import org.opengroup.osdu.indexer.service.impl.SchemaProviderImpl;
 import org.opengroup.osdu.indexer.util.ElasticClientHandler;
 import org.opengroup.osdu.core.common.search.ElasticIndexNameResolver;
 import org.powermock.core.classloader.annotations.PrepareForTest;
@@ -56,7 +57,7 @@ public class IndexerSchemaServiceTest {
     @Mock
     private JaxRsDpsLog log;
     @Mock
-    private StorageService storageService;
+    private SchemaProviderImpl schemaProvider;
     @Mock
     private ElasticClientHandler elasticClientHandler;
     @Mock
@@ -79,7 +80,7 @@ public class IndexerSchemaServiceTest {
 
     @Test
     public void should_returnNull_givenEmptySchema_getIndexerInputSchemaSchemaTest() throws Exception {
-        when(storageService.getStorageSchema(any())).thenReturn(emptySchema);
+        when(schemaProvider.getSchema(any())).thenReturn(emptySchema);
 
         IndexSchema indexSchema = this.sut.getIndexerInputSchema(kind, false);
 
@@ -88,7 +89,7 @@ public class IndexerSchemaServiceTest {
 
     @Test
     public void should_returnValidResponse_givenValidSchema_getIndexerInputSchemaTest() throws Exception {
-        when(storageService.getStorageSchema(any())).thenReturn(someSchema);
+        when(schemaProvider.getSchema(any())).thenReturn(someSchema);
 
         IndexSchema indexSchema = this.sut.getIndexerInputSchema(kind, false);
 
@@ -97,7 +98,7 @@ public class IndexerSchemaServiceTest {
 
     @Test
     public void should_returnValidResponse_givenValidSchemaWithCacheHit_getIndexerInputSchemaTest() throws Exception {
-        when(storageService.getStorageSchema(any())).thenReturn(someSchema);
+        when(schemaProvider.getSchema(any())).thenReturn(someSchema);
         when(this.schemaCache.get(kind + "_flattened")).thenReturn(someSchema);
 
         IndexSchema indexSchema = this.sut.getIndexerInputSchema(kind, false);
@@ -109,7 +110,7 @@ public class IndexerSchemaServiceTest {
     public void should_throw500_givenInvalidSchemaCacheHit_getIndexerInputSchemaTest() {
         try {
             String invalidSchema = "{}}";
-            when(storageService.getStorageSchema(any())).thenReturn(invalidSchema);
+            when(schemaProvider.getSchema(any())).thenReturn(invalidSchema);
 
             this.sut.getIndexerInputSchema(kind, false);
             fail("Should throw exception");
@@ -164,7 +165,7 @@ public class IndexerSchemaServiceTest {
         when(this.elasticIndexNameResolver.getIndexNameFromKind(kind)).thenReturn(kind.replace(":", "-"));
         when(this.schemaCache.get(kind)).thenReturn(null);
         when(this.indicesService.isIndexExist(any(), any())).thenReturn(false);
-        when(this.storageService.getStorageSchema(kind)).thenReturn(storageSchema);
+        when(this.schemaProvider.getSchema(kind)).thenReturn(storageSchema);
 
         this.sut.processSchemaMessages(schemaMessages);
 
@@ -195,7 +196,7 @@ public class IndexerSchemaServiceTest {
         when(this.elasticIndexNameResolver.getIndexNameFromKind(kind)).thenReturn(kind.replace(":", "-"));
         when(this.schemaCache.get(kind)).thenReturn(null);
         when(this.indicesService.isIndexExist(any(), any())).thenReturn(true);
-        when(this.storageService.getStorageSchema(kind)).thenReturn(storageSchema);
+        when(this.schemaProvider.getSchema(kind)).thenReturn(storageSchema);
 
         this.sut.processSchemaMessages(schemaMessages);
 
@@ -223,15 +224,15 @@ public class IndexerSchemaServiceTest {
         when(this.elasticIndexNameResolver.getIndexNameFromKind(kind)).thenReturn(kind.replace(":", "-"));
         when(this.schemaCache.get(kind)).thenReturn(null);
         when(this.indicesService.isIndexExist(any(), any())).thenReturn(true);
-        when(this.storageService.getStorageSchema(kind)).thenReturn(storageSchema);
+        when(this.schemaProvider.getSchema(kind)).thenReturn(storageSchema);
         when(this.mappingService.createMapping(any(), any(), any(), anyBoolean())).thenThrow(new AppException(HttpStatus.SC_BAD_REQUEST, reason, ""));
 
         try {
             this.sut.processSchemaMessages(schemaMessages);
         } catch (AppException e) {
-            assertEquals(e.getError().getCode(), RequestStatus.SCHEMA_CONFLICT);
-            assertEquals(e.getError().getMessage(), "error creating or merging index mapping");
-            assertEquals(e.getError().getReason(), reason);
+            assertEquals(RequestStatus.SCHEMA_CONFLICT, e.getError().getCode());
+            assertEquals("error creating or merging index mapping", e.getError().getMessage());
+            assertEquals(reason, e.getError().getReason());
         } catch (Exception e) {
             fail("Should not throw this exception " + e.getMessage());
         }
@@ -256,15 +257,15 @@ public class IndexerSchemaServiceTest {
         when(this.elasticIndexNameResolver.getIndexNameFromKind(kind)).thenReturn(kind.replace(":", "-"));
         when(this.schemaCache.get(kind)).thenReturn(null);
         when(this.indicesService.isIndexExist(any(), any())).thenReturn(true);
-        when(this.storageService.getStorageSchema(kind)).thenReturn(storageSchema);
+        when(this.schemaProvider.getSchema(kind)).thenReturn(storageSchema);
         when(this.mappingService.createMapping(any(), any(), any(), anyBoolean())).thenThrow(new AppException(HttpStatus.SC_FORBIDDEN, reason, "blah"));
 
         try {
             this.sut.processSchemaMessages(schemaMessages);
         } catch (AppException e) {
-            assertEquals(e.getError().getCode(), HttpStatus.SC_FORBIDDEN);
-            assertEquals(e.getError().getMessage(), "blah");
-            assertEquals(e.getError().getReason(), reason);
+            assertEquals(HttpStatus.SC_FORBIDDEN, e.getError().getCode());
+            assertEquals("blah", e.getError().getMessage());
+            assertEquals(reason, e.getError().getReason());
         } catch (Exception e) {
             fail("Should not throw this exception " + e.getMessage());
         }
@@ -282,7 +283,7 @@ public class IndexerSchemaServiceTest {
         when(this.elasticIndexNameResolver.getIndexNameFromKind(kind)).thenReturn(kind.replace(":", "-"));
         when(this.schemaCache.get(kind)).thenReturn(null);
         when(this.indicesService.isIndexExist(any(), any())).thenReturn(true);
-        when(this.storageService.getStorageSchema(kind)).thenReturn(storageSchema);
+        when(this.schemaProvider.getSchema(kind)).thenReturn(storageSchema);
 
         this.sut.processSchemaMessages(schemaMessages);
 
@@ -336,7 +337,7 @@ public class IndexerSchemaServiceTest {
         when(this.schemaCache.get(kind)).thenReturn(null);
         when(this.indicesService.isIndexExist(any(), any())).thenReturn(true);
         when(this.indicesService.deleteIndex(any(), any())).thenReturn(true);
-        when(this.storageService.getStorageSchema(kind)).thenReturn(storageSchema);
+        when(this.schemaProvider.getSchema(kind)).thenReturn(storageSchema);
 
         this.sut.syncIndexMappingWithStorageSchema(kind);
 
@@ -358,9 +359,9 @@ public class IndexerSchemaServiceTest {
         try {
             this.sut.syncIndexMappingWithStorageSchema(kind);
         } catch (AppException e) {
-            assertEquals(e.getError().getCode(), HttpStatus.SC_CONFLICT);
-            assertEquals(e.getError().getMessage(), "blah");
-            assertEquals(e.getError().getReason(), "Index deletion error");
+            assertEquals(HttpStatus.SC_CONFLICT, e.getError().getCode());
+            assertEquals("blah", e.getError().getMessage());
+            assertEquals("Index deletion error", e.getError().getReason());
         } catch (Exception e) {
             fail("Should not throw this exception " + e.getMessage());
         }
diff --git a/provider/indexer-ibm/src/main/resources/application.properties b/provider/indexer-ibm/src/main/resources/application.properties
index 9a7a16cc4942744aea51f9e54bc4bae855892b8d..def41568078ca252d54986a5eebde71a2fbc62d8 100644
--- a/provider/indexer-ibm/src/main/resources/application.properties
+++ b/provider/indexer-ibm/src/main/resources/application.properties
@@ -26,6 +26,8 @@ KINDS_REDIS_DATABASE=1
 CRON_INDEX_CLEANUP_THRESHOLD_DAYS=3
 CRON_EMPTY_INDEX_CLEANUP_THRESHOLD_DAYS=7
 
+SCHEMA_HOST=${HOST}/api/schema-service/v1/schema
+
 storage_service_url=http://localhost:8082
 #storage_service_url=https://os-storage-ibm-osdu-r2.osduadev-a1c3eaf78a86806e299f5f3f207556f0-0000.us-south.containers.appdomain.cloud
 STORAGE_SCHEMA_HOST=${storage_service_url}/api/storage/v2/schemas
@@ -64,3 +66,5 @@ ELASTIC_DATASTORE_ID=indexer-service
 ELASTIC_HOST=elasticsearch.com
 ELASTIC_PORT=443
 ELASTIC_USER_PASSWORD=REPLACE_ME:REPLACE_ME
+
+
diff --git a/testing/indexer-test-aws/build-aws/prepare-dist.sh b/testing/indexer-test-aws/build-aws/prepare-dist.sh
index f0451cabc005a3b79eb27c897c294a11fda496b0..ee2afc827faf14de099f941104984bec9aaa6ae8 100755
--- a/testing/indexer-test-aws/build-aws/prepare-dist.sh
+++ b/testing/indexer-test-aws/build-aws/prepare-dist.sh
@@ -21,11 +21,13 @@ echo $INTEGRATION_TEST_OUTPUT_BIN_DIR
 rm -rf "$INTEGRATION_TEST_OUTPUT_DIR"
 mkdir -p "$INTEGRATION_TEST_OUTPUT_DIR" && mkdir -p "$INTEGRATION_TEST_OUTPUT_BIN_DIR"
 echo "Building integration testing assemblies and gathering artifacts..."
-mvn install -f "$INTEGRATION_TEST_SOURCE_DIR_CORE"/pom.xml
-mvn install dependency:copy-dependencies -DskipTests -f "$INTEGRATION_TEST_SOURCE_DIR_AWS"/pom.xml -DincludeGroupIds=org.opengroup.osdu -Dmdep.copyPom
+mvn -ntp install -f "$INTEGRATION_TEST_SOURCE_DIR_CORE"/pom.xml
+mvn -ntp install dependency:copy-dependencies -DskipTests -f "$INTEGRATION_TEST_SOURCE_DIR_AWS"/pom.xml -DincludeGroupIds=org.opengroup.osdu -Dmdep.copyPom
 cp "$INTEGRATION_TEST_SOURCE_DIR_AWS"/target/dependency/* "${INTEGRATION_TEST_OUTPUT_BIN_DIR}"
-(cd "${INTEGRATION_TEST_OUTPUT_BIN_DIR}" && ls *.jar | sed -e 's/\.jar$//' | xargs -I {} echo mvn install:install-file -Dfile={}.jar -DpomFile={}.pom >> install-deps.sh)
+(cd "${INTEGRATION_TEST_OUTPUT_BIN_DIR}" && ls *.jar | sed -e 's/\.jar$//' | xargs -I {} echo mvn -ntp install:install-file -Dfile={}.jar -DpomFile={}.pom >> install-deps.sh)
 chmod +x "${INTEGRATION_TEST_OUTPUT_BIN_DIR}"/install-deps.sh
-mvn clean -f "$INTEGRATION_TEST_SOURCE_DIR_AWS"/pom.xml
+mvn -ntp clean -f "$INTEGRATION_TEST_SOURCE_DIR_AWS"/pom.xml
 cp -R "$INTEGRATION_TEST_SOURCE_DIR_AWS"/* "${INTEGRATION_TEST_OUTPUT_DIR}"/
 
+#copy testing parent pom to output
+cp "$INTEGRATION_TEST_SOURCE_DIR/pom.xml" "${OUTPUT_DIR}/testing"
diff --git a/testing/indexer-test-aws/build-aws/run-tests.sh b/testing/indexer-test-aws/build-aws/run-tests.sh
index f1124ee28e1cb85b4a4c675f46ea627eb3e04412..78c727bd4a85a1fb99adb1988fd997f19c853de0 100755
--- a/testing/indexer-test-aws/build-aws/run-tests.sh
+++ b/testing/indexer-test-aws/build-aws/run-tests.sh
@@ -27,10 +27,11 @@ export DEFAULT_DATA_PARTITION_ID_TENANT2=common
 export ENTITLEMENTS_DOMAIN=testing.com
 export OTHER_RELEVANT_DATA_COUNTRIES=US
 export STORAGE_HOST=$STORAGE_URL
+export HOST=$SCHEMA_URL
 
 #### RUN INTEGRATION TEST #########################################################################
 
-mvn test -f "$SCRIPT_SOURCE_DIR"/../pom.xml -Dcucumber.options="--plugin junit:target/junit-report.xml"
+mvn -ntp test -f "$SCRIPT_SOURCE_DIR"/../pom.xml -Dcucumber.options="--plugin junit:target/junit-report.xml"
 TEST_EXIT_CODE=$?
 
 #### COPY TEST REPORTS #########################################################################
@@ -39,6 +40,7 @@ if [ -n "$1" ]
   then
     mkdir -p "$1"
     cp "$SCRIPT_SOURCE_DIR"/../target/junit-report.xml "$1"/os-indexer-junit-report.xml
+    cp  -R "$SCRIPT_SOURCE_DIR"/../target/surefire-reports "$1"
 fi
 
 exit $TEST_EXIT_CODE
diff --git a/testing/indexer-test-aws/pom.xml b/testing/indexer-test-aws/pom.xml
index b6f709f74b4fb8bb4e53255838575ed8e4ef8954..e31c28157f62c209cf96815321dd459f1d8e7419 100644
--- a/testing/indexer-test-aws/pom.xml
+++ b/testing/indexer-test-aws/pom.xml
@@ -51,7 +51,7 @@
         <dependency>
             <groupId>org.opengroup.osdu.core.aws</groupId>
             <artifactId>os-core-lib-aws</artifactId>
-            <version>0.3.7</version>
+            <version>0.3.16</version>
         </dependency>
 
         <!-- Testing -->
@@ -138,4 +138,4 @@
         </dependency>
 
     </dependencies>
-</project>
\ No newline at end of file
+</project>
diff --git a/testing/indexer-test-aws/src/test/java/org/opengroup/osdu/step_definitions/index/cleanup/RunTest.java b/testing/indexer-test-aws/src/test/java/org/opengroup/osdu/step_definitions/index/cleanup/RunTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..ccf35e02cffb041fdf0582ae87e6891028947543
--- /dev/null
+++ b/testing/indexer-test-aws/src/test/java/org/opengroup/osdu/step_definitions/index/cleanup/RunTest.java
@@ -0,0 +1,27 @@
+// Copyright © Amazon Web Services
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.opengroup.osdu.step_definitions.index.cleanup;
+
+import cucumber.api.CucumberOptions;
+import cucumber.api.junit.Cucumber;
+import org.junit.runner.RunWith;
+
+@RunWith(Cucumber.class)
+@CucumberOptions(
+        features = "classpath:features/indexcleanup/IndexCleanup.feature",
+        glue = {"classpath:org.opengroup.osdu.step_definitions/index/cleanup"},
+        plugin = {"pretty", "junit:target/cucumber-reports/TEST-indexcleanup.xml"})
+public class RunTest {
+}
\ No newline at end of file
diff --git a/testing/indexer-test-aws/src/test/java/org/opengroup/osdu/step_definitions/index/cleanup/Steps.java b/testing/indexer-test-aws/src/test/java/org/opengroup/osdu/step_definitions/index/cleanup/Steps.java
new file mode 100644
index 0000000000000000000000000000000000000000..b69fd683d35214a73fd9c268e6dcb879d95f97c8
--- /dev/null
+++ b/testing/indexer-test-aws/src/test/java/org/opengroup/osdu/step_definitions/index/cleanup/Steps.java
@@ -0,0 +1,113 @@
+// Copyright © Amazon Web Services
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+
+package org.opengroup.osdu.step_definitions.index.cleanup;
+
+import cucumber.api.DataTable;
+import cucumber.api.Scenario;
+import cucumber.api.java.Before;
+import cucumber.api.java.en.Given;
+import cucumber.api.java.en.Then;
+import cucumber.api.java.en.When;
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Set;
+
+import lombok.extern.java.Log;
+import org.opengroup.osdu.common.CleanupIndiciesSteps;
+import org.opengroup.osdu.core.common.model.legal.Legal;
+import org.opengroup.osdu.util.AWSHTTPClient;
+import org.opengroup.osdu.util.LegalTagUtilsAws;
+import org.opengroup.osdu.util.ElasticUtilsAws;
+
+import static org.opengroup.osdu.util.Config.getOtherRelevantDataCountries;
+
+@Log
+public class Steps extends CleanupIndiciesSteps {
+
+    protected LegalTagUtilsAws legalTagUtils;
+    private String legalTagName;
+
+    public Steps() {
+        super(new AWSHTTPClient(), new ElasticUtilsAws());
+    }
+
+    @Before
+    public void before(Scenario scenario) throws Exception {
+        this.scenario = scenario;
+        this.httpClient = new AWSHTTPClient();
+        legalTagUtils = new LegalTagUtilsAws(this.httpClient);
+        this.legalTagName = this.legalTagUtils.createRandomName();
+        this.legalTagUtils.create(this.legalTagName);
+    }
+
+    @Override
+    public void tearDown() {
+        super.tearDown();
+        this.legalTagUtils.delete(this.legalTagName);
+    }
+
+    @Override
+    protected Legal generateLegalTag() {
+        Legal legal = new Legal();
+        Set<String> legalTags = new HashSet<>();
+        legalTags.add(this.legalTagName);
+        legal.setLegaltags(legalTags);
+        Set<String> otherRelevantCountries = new HashSet<>();
+        otherRelevantCountries.add(getOtherRelevantDataCountries());
+        legal.setOtherRelevantDataCountries(otherRelevantCountries);
+        return legal;
+    }
+
+    @Given("^the schema is created with the following kind$")
+    public void theSchemaIsCreatedWithTheFollowingKind(DataTable dataTable) {
+        super.theSchemaIsCreatedWithTheFollowingKind(dataTable);
+    }
+
+    @When("^I ingest records with the \"(.*?)\" with \"(.*?)\" for a given \"(.*?)\"$")
+    public void iIngestRecordsWithTheforAGiven(String record, String dataGroup, String kind) {
+        super.iIngestRecordsWithTheforAGiven(record, dataGroup, kind);
+    }
+
+    @Then("^I check that the index for \"(.*?)\" has been created$")
+    public void iCheckThatTheIndexForHasBeenCreated(String kind) throws IOException, InterruptedException {
+        super.iCheckThatTheIndexForHasBeenCreated(kind);
+    }
+
+    @Then("^I should delete the records I created earlier$")
+    public void iShouldDeleteTheRecordsForICreatedEarlier() {
+        super.iShouldDeleteTheRecordsForICreatedEarlier();
+    }
+
+    @Then("^I should delete the schema for \"(.*?)\" I created earlier$")
+    public void iShouldDeleteTheSchemaForICreatedEarlier(String kind) {
+        super.iShouldDeleteTheSchemaForICreatedEarlier(kind);
+    }
+
+    @Then("^I should check that the index for \"(.*?)\" has not been deleted$")
+    public void iShouldCheckThetTheIndexforHasNotBeenDeleted(String kind) throws IOException, InterruptedException {
+        super.iShouldCheckThetTheIndexforHasNotBeenDeleted(kind);
+    }
+
+    @Then("^I should to run cleanup of indexes for \"(.*?)\" and \"(.*?)\"$")
+    public void iShouldToRunCleanupOfIndexesForAnd(String kind, String message) {
+        super.iShouldToRunCleanupOfIndexesForAnd(kind, message);
+    }
+
+    @Then("^I should check that the index for \"(.*?)\" has been deleted$")
+    public void iShouldCheckThatTheIndexForHasBeenDeleted(String kind) throws IOException, InterruptedException {
+        super.iShouldCheckThatTheIndexForHasBeenDeleted(kind);
+    }
+}
\ No newline at end of file
diff --git a/testing/indexer-test-aws/src/test/java/org/opengroup/osdu/step_definitions/index/record/RunTest.java b/testing/indexer-test-aws/src/test/java/org/opengroup/osdu/step_definitions/index/record/RunTest.java
index e6887ea5ef12afed8d4d7904796ae70d6a4ccada..e2ba02423742ea3861e9425e4902f30a0bdf33dd 100644
--- a/testing/indexer-test-aws/src/test/java/org/opengroup/osdu/step_definitions/index/record/RunTest.java
+++ b/testing/indexer-test-aws/src/test/java/org/opengroup/osdu/step_definitions/index/record/RunTest.java
@@ -20,7 +20,7 @@ import org.junit.runner.RunWith;
 
 @RunWith(Cucumber.class)
 @CucumberOptions(
-        features = "classpath:features/indexrecord/IndexRecord.feature",
+        features = "classpath:features/indexrecord/indexRecord-schema-service.feature",
         glue = {"classpath:org.opengroup.osdu.step_definitions/index/record"},
         plugin = {"pretty", "junit:target/cucumber-reports/TEST-indexrecord.xml"})
 public class RunTest {
diff --git a/testing/indexer-test-aws/src/test/java/org/opengroup/osdu/step_definitions/index/record/Steps.java b/testing/indexer-test-aws/src/test/java/org/opengroup/osdu/step_definitions/index/record/Steps.java
index 7b1c280c6b9bd96a111c8cfcdfffcefc3c60f09d..7539fe6bf4ecb5818479952dd92cf5b2aea54a17 100644
--- a/testing/indexer-test-aws/src/test/java/org/opengroup/osdu/step_definitions/index/record/Steps.java
+++ b/testing/indexer-test-aws/src/test/java/org/opengroup/osdu/step_definitions/index/record/Steps.java
@@ -15,7 +15,6 @@
 package org.opengroup.osdu.step_definitions.index.record;
 
 import lombok.extern.java.Log;
-import org.opengroup.osdu.common.RecordSteps;
 import org.opengroup.osdu.core.common.model.legal.Legal;
 import org.opengroup.osdu.util.AWSHTTPClient;
 
@@ -27,15 +26,15 @@ import cucumber.api.java.en.Then;
 import cucumber.api.java.en.When;
 import org.opengroup.osdu.util.ElasticUtilsAws;
 import org.opengroup.osdu.util.LegalTagUtilsAws;
+import org.opengroup.osdu.common.SchemaServiceRecordSteps;
 
 import java.util.HashSet;
 import java.util.Set;
 
-import static org.opengroup.osdu.util.Config.getLegalTag;
 import static org.opengroup.osdu.util.Config.getOtherRelevantDataCountries;
 
 @Log
-public class Steps extends RecordSteps {
+public class Steps extends SchemaServiceRecordSteps {
 
     protected LegalTagUtilsAws legalTagUtils;
     private String legalTagName;
diff --git a/testing/indexer-test-azure/src/test/java/org/opengroup/osdu/step_definitions/index/record/RunTest.java b/testing/indexer-test-azure/src/test/java/org/opengroup/osdu/step_definitions/index/record/RunTest.java
index ac4cc160e9b77c8bd38cd73824e4d9957cd4a939..77b0a633b439b900d5e617dc05b4ba74774b007a 100644
--- a/testing/indexer-test-azure/src/test/java/org/opengroup/osdu/step_definitions/index/record/RunTest.java
+++ b/testing/indexer-test-azure/src/test/java/org/opengroup/osdu/step_definitions/index/record/RunTest.java
@@ -20,7 +20,7 @@ import org.junit.runner.RunWith;
 
 @RunWith(Cucumber.class)
 @CucumberOptions(
-        features = "classpath:features/indexrecord/IndexRecord.feature",
+        features = "classpath:features/indexrecord/indexRecord-schema-service.feature",
         glue = {"classpath:org.opengroup.osdu.step_definitions/index/record"},
         plugin = {"pretty", "junit:target/cucumber-reports/TEST-indexrecord.xml"})
 public class RunTest {
diff --git a/testing/indexer-test-azure/src/test/java/org/opengroup/osdu/step_definitions/index/record/Steps.java b/testing/indexer-test-azure/src/test/java/org/opengroup/osdu/step_definitions/index/record/Steps.java
index dfff25eca03a6821678144595fb589418f5d7ae1..5cc775b83d14dabb626710768d74ac837783822e 100644
--- a/testing/indexer-test-azure/src/test/java/org/opengroup/osdu/step_definitions/index/record/Steps.java
+++ b/testing/indexer-test-azure/src/test/java/org/opengroup/osdu/step_definitions/index/record/Steps.java
@@ -14,20 +14,21 @@
 
 package org.opengroup.osdu.step_definitions.index.record;
 
-import lombok.extern.java.Log;
-
 import cucumber.api.Scenario;
 import cucumber.api.java.Before;
+import lombok.extern.java.Log;
+
 import cucumber.api.DataTable;
 import cucumber.api.java.en.Given;
 import cucumber.api.java.en.Then;
 import cucumber.api.java.en.When;
-import org.opengroup.osdu.common.RecordSteps;
+import org.opengroup.osdu.common.SchemaServiceRecordSteps;
 import org.opengroup.osdu.util.AzureHTTPClient;
 import org.opengroup.osdu.util.ElasticUtils;
 
+
 @Log
-public class Steps extends RecordSteps {
+public class Steps extends SchemaServiceRecordSteps {
 
     public Steps() {
         super(new AzureHTTPClient(), new ElasticUtils());
@@ -36,7 +37,6 @@ public class Steps extends RecordSteps {
     @Before
     public void before(Scenario scenario) {
         this.scenario = scenario;
-        this.httpClient = new AzureHTTPClient();
     }
 
     @Given("^the schema is created with the following kind$")
diff --git a/testing/indexer-test-azure/src/test/java/org/opengroup/osdu/util/AzureHTTPClient.java b/testing/indexer-test-azure/src/test/java/org/opengroup/osdu/util/AzureHTTPClient.java
index d6c57ae848c583e0a90d33bac7f9794da665aaf1..954f3acb24c7fde5fa13682a17f1eddc3eae7721 100644
--- a/testing/indexer-test-azure/src/test/java/org/opengroup/osdu/util/AzureHTTPClient.java
+++ b/testing/indexer-test-azure/src/test/java/org/opengroup/osdu/util/AzureHTTPClient.java
@@ -17,7 +17,6 @@ package org.opengroup.osdu.util;
 import lombok.ToString;
 import lombok.extern.java.Log;
 
-import java.io.IOException;
 
 @Log
 @ToString
diff --git a/testing/indexer-test-core/pom.xml b/testing/indexer-test-core/pom.xml
index 1a31fdd1830f64cf62cbdc471981ad9a36087a23..d61bc6a5bb57e7d89dbeb5b8a13a4db14719daaf 100644
--- a/testing/indexer-test-core/pom.xml
+++ b/testing/indexer-test-core/pom.xml
@@ -129,5 +129,10 @@
             <artifactId>guava</artifactId>
             <version>27.1-jre</version>
         </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+            <version>2.11.3</version>
+        </dependency>
     </dependencies>
 </project>
diff --git a/testing/indexer-test-core/src/main/java/org/opengroup/osdu/common/CleanupIndiciesSteps.java b/testing/indexer-test-core/src/main/java/org/opengroup/osdu/common/CleanupIndiciesSteps.java
index d6324b425e2a51c858d97f513fee8a58b2f25062..d15a6668d90540a862167070018333599feb1143 100644
--- a/testing/indexer-test-core/src/main/java/org/opengroup/osdu/common/CleanupIndiciesSteps.java
+++ b/testing/indexer-test-core/src/main/java/org/opengroup/osdu/common/CleanupIndiciesSteps.java
@@ -1,16 +1,19 @@
-/* Copyright 2017-2019, Schlumberger
+/*
+  Copyright 2020 Google LLC
+  Copyright 2020 EPAM Systems, Inc
 
- 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
+  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
+    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.*/
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
 
 package org.opengroup.osdu.common;
 
@@ -39,6 +42,7 @@ import org.opengroup.osdu.models.Setup;
 import org.opengroup.osdu.models.TestIndex;
 import org.opengroup.osdu.util.FileHandler;
 import org.opengroup.osdu.util.HTTPClient;
+import org.opengroup.osdu.util.ElasticUtils;
 
 @Log
 public class CleanupIndiciesSteps extends TestsBase {
@@ -52,7 +56,12 @@ public class CleanupIndiciesSteps extends TestsBase {
     super(httpClient);
   }
 
-  public void the_schema_is_created_with_the_following_kind(DataTable dataTable) {
+  public CleanupIndiciesSteps(HTTPClient httpClient, ElasticUtils elasticUtils) {
+    super(httpClient, elasticUtils);
+  }
+
+
+  public void theSchemaIsCreatedWithTheFollowingKind(DataTable dataTable) {
     List<Setup> inputList = dataTable.asList(Setup.class);
     for (Setup input : inputList) {
       TestIndex testIndex = getTextIndex();
@@ -71,7 +80,7 @@ public class CleanupIndiciesSteps extends TestsBase {
     }
   }
 
-  public void i_ingest_records_with_the_for_a_given(String record, String dataGroup, String kind) {
+  public void iIngestRecordsWithTheforAGiven(String record, String dataGroup, String kind) {
     String actualKind = generateActualName(kind, timeStamp);
     try {
       String fileContent = FileHandler.readFile(String.format("%s.%s", record, "json"));
@@ -93,11 +102,11 @@ public class CleanupIndiciesSteps extends TestsBase {
     }
   }
 
-  public void i_check_that_the_index_for_has_been_created(String kind) throws IOException, InterruptedException {
+  public void iCheckThatTheIndexForHasBeenCreated(String kind) throws IOException, InterruptedException {
     assertTrue(isNewIndexCreated(generateActualName(kind, timeStamp)));
   }
 
-  public void i_should_delete_the_records_for_i_created_earlier() {
+  public void iShouldDeleteTheRecordsForICreatedEarlier() {
     List<Map<String, Object>> deletedRecords = new ArrayList<>();
     if (records != null && !records.isEmpty()) {
       for (Map<String, Object> testRecord : records) {
@@ -113,25 +122,27 @@ public class CleanupIndiciesSteps extends TestsBase {
     }
   }
 
-  public void i_should_delete_the_schema_for_i_created_earlier(String kind) {
+  public void iShouldDeleteTheSchemaForICreatedEarlier(String kind) {
     ClientResponse response = httpClient.send(HttpMethod.DELETE,
         String.format("%sschemas%s", getStorageBaseURL(), "/" + generateActualName(kind, timeStamp)),null,
-          headers, httpClient.getAccessToken());
+        headers, httpClient.getAccessToken());
     assertEquals(HttpStatus.SC_NO_CONTENT, response.getStatus());
   }
 
-  public void i_should_check_that_the_index_for_has_not_been_deleted(String kind) throws IOException, InterruptedException {
+  public void iShouldCheckThetTheIndexforHasNotBeenDeleted(String kind) throws IOException, InterruptedException {
     assertTrue(isNewIndexExist(generateActualName(kind, timeStamp)));
   }
 
-  public void i_should_to_run_cleanup_of_indexes_for_and(String kind, String message) {
+  public void iShouldToRunCleanupOfIndexesForAnd(String kind, String message) {
 
-    ClientResponse response = httpClient.send(HttpMethod.POST, String.format("%sindex-cleanup", getIndexerBaseURL()),
+    String url = getIndexerBaseURL() + "index-cleanup";
+    log.info("URL: " + url);
+    ClientResponse response = httpClient.send(HttpMethod.POST, url,
         convertMessageIntoJson(kind, message), headers, httpClient.getAccessToken());
     assertEquals(HttpStatus.SC_OK, response.getStatus());
   }
 
-  public void i_should_check_that_the_index_for_has_been_deleted(String kind) throws IOException, InterruptedException {
+  public void iShouldCheckThatTheIndexForHasBeenDeleted(String kind) throws IOException, InterruptedException {
     assertFalse(isNewIndexExist(generateActualName(kind, timeStamp)));
   }
 
diff --git a/testing/indexer-test-core/src/main/java/org/opengroup/osdu/common/RecordSteps.java b/testing/indexer-test-core/src/main/java/org/opengroup/osdu/common/RecordSteps.java
index a58c18461e0008ba32fa2622f48995fcfc9eee9e..3a013e1530b093e9c779890c5a12b230257028b4 100644
--- a/testing/indexer-test-core/src/main/java/org/opengroup/osdu/common/RecordSteps.java
+++ b/testing/indexer-test-core/src/main/java/org/opengroup/osdu/common/RecordSteps.java
@@ -15,6 +15,7 @@ import org.opengroup.osdu.models.TestIndex;
 import org.opengroup.osdu.util.ElasticUtils;
 import org.opengroup.osdu.util.FileHandler;
 import org.opengroup.osdu.util.HTTPClient;
+import org.springframework.util.CollectionUtils;
 
 import javax.ws.rs.HttpMethod;
 import java.io.IOException;
@@ -22,6 +23,7 @@ import java.lang.reflect.Type;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.logging.Level;
 
 import static org.junit.Assert.*;
 import static org.opengroup.osdu.util.Config.getEntitlementsDomain;
@@ -51,12 +53,17 @@ public class RecordSteps extends TestsBase {
             testIndex.cleanupIndex();
             testIndex.deleteSchema(kind);
         }
-        if (records != null && records.size() > 0) {
-            for (Map<String, Object> testRecord : records) {
-                String id = testRecord.get("id").toString();
-                httpClient.send(HttpMethod.DELETE, getStorageBaseURL() + "records/" + id, null, headers, httpClient.getAccessToken());
-                log.info("Deleted the records");
-            }
+
+        if (!CollectionUtils.isEmpty(records)) {
+            cleanupRecords();
+        }
+    }
+
+    protected void cleanupRecords() {
+        for (Map<String, Object> testRecord : records) {
+            String id = testRecord.get("id").toString();
+            httpClient.send(HttpMethod.DELETE, getStorageBaseURL() + "records/" + id, null, headers, httpClient.getAccessToken());
+            log.info("Deleted the records");
         }
     }
 
@@ -74,17 +81,12 @@ public class RecordSteps extends TestsBase {
 
         /******************One time setup for whole feature**************/
         if (!shutDownHookAdded) {
-            Runtime.getRuntime().addShutdownHook(new Thread() {
-                public void run() {
-                    tearDown();
-                }
-            });
-            shutDownHookAdded = true;
             for (String kind : inputIndexMap.keySet()) {
                 TestIndex testIndex = inputIndexMap.get(kind);
                 testIndex.setupSchema();
             }
         }
+        addShutDownHook();
     }
 
     public void i_ingest_records_with_the_for_a_given(String record, String dataGroup, String kind) {
@@ -95,7 +97,7 @@ public class RecordSteps extends TestsBase {
             records = new Gson().fromJson(fileContent, new TypeToken<List<Map<String, Object>>>() {}.getType());
 
             for (Map<String, Object> testRecord : records) {
-                testRecord.put("id", generateActualName(testRecord.get("id").toString(), timeStamp));
+                testRecord.put("id", generateRecordId(testRecord));
                 testRecord.put("kind", actualKind);
                 testRecord.put("legal", generateLegalTag());
                 String[] x_acl = {generateActualName(dataGroup,timeStamp)+"."+getEntitlementsDomain()};
@@ -103,6 +105,7 @@ public class RecordSteps extends TestsBase {
                 testRecord.put("acl", acl);
             }
             String payLoad = new Gson().toJson(records);
+            log.log(Level.INFO, "Start ingesting records={0}", payLoad);
             ClientResponse clientResponse = httpClient.send(HttpMethod.PUT, getStorageBaseURL() + "records", payLoad, headers, httpClient.getAccessToken());
             assertEquals(201, clientResponse.getStatus());
         } catch (Exception ex) {
@@ -110,6 +113,10 @@ public class RecordSteps extends TestsBase {
         }
     }
 
+    protected String generateRecordId(Map<String, Object> testRecord) {
+        return generateActualName(testRecord.get("id").toString(), timeStamp);
+    }
+
     public void i_should_get_the_documents_for_the_in_the_Elastic_Search(int expectedCount, String index) throws Throwable {
         index = generateActualName(index, timeStamp);
         long numOfIndexedDocuments = createIndex(index);
@@ -182,4 +189,18 @@ public class RecordSteps extends TestsBase {
         return null;
     }
 
+    public Map<String, TestIndex> getInputIndexMap() {
+        return inputIndexMap;
+    }
+
+    public String getTimeStamp() {
+        return timeStamp;
+    }
+
+    protected void addShutDownHook() {
+        if (!shutDownHookAdded) {
+            Runtime.getRuntime().addShutdownHook(new Thread(this::tearDown));
+            shutDownHookAdded = true;
+        }
+    }
 }
\ No newline at end of file
diff --git a/testing/indexer-test-core/src/main/java/org/opengroup/osdu/common/SchemaServiceRecordSteps.java b/testing/indexer-test-core/src/main/java/org/opengroup/osdu/common/SchemaServiceRecordSteps.java
new file mode 100644
index 0000000000000000000000000000000000000000..fb7a03e1e3866ae034e6b4cd032d57ba530ac09e
--- /dev/null
+++ b/testing/indexer-test-core/src/main/java/org/opengroup/osdu/common/SchemaServiceRecordSteps.java
@@ -0,0 +1,50 @@
+package org.opengroup.osdu.common;
+
+import cucumber.api.DataTable;
+import org.opengroup.osdu.models.Setup;
+import org.opengroup.osdu.models.schema.PersistentSchemaTestIndex;
+import org.opengroup.osdu.util.ElasticUtils;
+import org.opengroup.osdu.util.HTTPClient;
+
+import java.util.List;
+import java.util.Map;
+
+public class SchemaServiceRecordSteps extends RecordSteps {
+
+    public SchemaServiceRecordSteps(HTTPClient httpClient, ElasticUtils elasticUtils) {
+        super(httpClient, elasticUtils);
+    }
+
+    public void the_schema_is_created_with_the_following_kind(DataTable dataTable) {
+        List<Setup> inputList = dataTable.asList(Setup.class);
+        inputList.forEach(this::createSchema);
+        inputList.forEach(s -> deleteIndex(generateActualNameWithoutTs(s.getIndex())));
+        super.addShutDownHook();
+    }
+
+    private void createSchema(Setup input) {
+        PersistentSchemaTestIndex testIndex = new PersistentSchemaTestIndex(super.elasticUtils, super.httpClient, this);
+        testIndex.setIndex(generateActualName(input.getIndex(), super.getTimeStamp()));
+        testIndex.setSchemaFile(input.getSchemaFile());
+        testIndex.setHttpClient(super.httpClient);
+        testIndex.setupSchema();
+        testIndex.setKind(testIndex.getSchemaModel().getSchemaInfo().getSchemaIdentity().getId());
+
+        super.getInputIndexMap().put(testIndex.getKind(), testIndex);
+    }
+
+    private void deleteIndex(String index) {
+        this.elasticUtils.deleteIndex(index);
+    }
+
+    @Override
+    protected String generateRecordId(Map<String, Object> testRecord) {
+        return generateActualNameWithoutTs(testRecord.get("id").toString());
+    }
+
+    @Override
+    public void i_ingest_records_with_the_for_a_given(String record, String dataGroup, String kind) {
+        super.i_ingest_records_with_the_for_a_given(record.replaceFirst("_schema", ""), dataGroup, kind);
+    }
+
+}
diff --git a/testing/indexer-test-core/src/main/java/org/opengroup/osdu/common/TestsBase.java b/testing/indexer-test-core/src/main/java/org/opengroup/osdu/common/TestsBase.java
index e24a19da82531608b8609f3543013bf2576e0e17..53f9e877ae2389457a187d9adc58675dad358d3d 100644
--- a/testing/indexer-test-core/src/main/java/org/opengroup/osdu/common/TestsBase.java
+++ b/testing/indexer-test-core/src/main/java/org/opengroup/osdu/common/TestsBase.java
@@ -123,18 +123,18 @@ public abstract class TestsBase {
         log.info(String.format("Scenario Name: %s, Correlation-Id: %s", scenario.getId(), headers.get("correlation-id")));
     }
 
-    protected String getTenantMapping(String tenant) {
-        if (tenantMap.containsKey(tenant)) {
-            return tenantMap.get(tenant);
+    protected String generateActualName(String rawName, String timeStamp) {
+        for (Map.Entry<String, String> tenant : tenantMap.entrySet()) {
+            rawName = rawName.replaceAll(tenant.getKey(), tenant.getValue());
         }
-        return null;
+        return rawName.replaceAll("<timestamp>", timeStamp);
     }
 
-    protected String generateActualName(String rawName, String timeStamp) {
-        for (String tenant : tenantMap.keySet()) {
-            rawName = rawName.replaceAll(tenant, getTenantMapping(tenant));
+    public String generateActualNameWithoutTs(String rawName) {
+        for (Map.Entry<String, String> tenant : tenantMap.entrySet()) {
+            rawName = rawName.replaceAll(tenant.getKey(), tenant.getValue());
         }
-        return rawName.replaceAll("<timestamp>", timeStamp);
+        return rawName.replaceAll("<timestamp>", "");
     }
 
     protected Legal generateLegalTag() {
diff --git a/testing/indexer-test-core/src/main/java/org/opengroup/osdu/models/TestIndex.java b/testing/indexer-test-core/src/main/java/org/opengroup/osdu/models/TestIndex.java
index efd8d1960362fabd2b7ee3da55903816f49c3e20..d10712707e051e24f5fb8c79d9d500cf653d5646 100644
--- a/testing/indexer-test-core/src/main/java/org/opengroup/osdu/models/TestIndex.java
+++ b/testing/indexer-test-core/src/main/java/org/opengroup/osdu/models/TestIndex.java
@@ -84,7 +84,7 @@ public class TestIndex {
         return String.format("%s.mapping", this.mappingFile);
     }
 
-    private String getSchemaFile() {
+    protected String getSchemaFile() {
         return String.format("%s.schema", this.schemaFile);
     }
 
diff --git a/testing/indexer-test-core/src/main/java/org/opengroup/osdu/models/schema/PersistentSchemaTestIndex.java b/testing/indexer-test-core/src/main/java/org/opengroup/osdu/models/schema/PersistentSchemaTestIndex.java
new file mode 100644
index 0000000000000000000000000000000000000000..c930508d274ef8b79dc43dd32e36f6e65405beea
--- /dev/null
+++ b/testing/indexer-test-core/src/main/java/org/opengroup/osdu/models/schema/PersistentSchemaTestIndex.java
@@ -0,0 +1,64 @@
+package org.opengroup.osdu.models.schema;
+
+import org.opengroup.osdu.common.SchemaServiceRecordSteps;
+import org.opengroup.osdu.models.TestIndex;
+import org.opengroup.osdu.util.ElasticUtils;
+import org.opengroup.osdu.util.FileHandler;
+import org.opengroup.osdu.util.HTTPClient;
+import org.opengroup.osdu.util.SchemaServiceClient;
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+
+public class PersistentSchemaTestIndex extends TestIndex {
+
+    private static final Logger LOGGER = Logger.getLogger(PersistentSchemaTestIndex.class.getName());
+    private final SchemaServiceClient schemaServiceClient;
+    private final SchemaServiceRecordSteps recordSteps;
+    private SchemaModel schemaModel;
+
+    public PersistentSchemaTestIndex(ElasticUtils elasticUtils, HTTPClient client, SchemaServiceRecordSteps recordSteps) {
+        super(elasticUtils);
+        this.schemaServiceClient = new SchemaServiceClient(client);
+        this.recordSteps = recordSteps;
+    }
+
+    @Override
+    public void setupSchema() {
+        this.schemaModel = readSchemaFromJson();
+        SchemaIdentity schemaIdentity = schemaModel.getSchemaInfo().getSchemaIdentity();
+        LOGGER.log(Level.INFO, "Read the schema={0}", schemaIdentity);
+        schemaIdentity.setAuthority(recordSteps.generateActualNameWithoutTs(schemaIdentity.getAuthority()));
+        LOGGER.log(Level.INFO, "Updated the schema={0}", schemaIdentity);
+        schemaServiceClient.createIfNotExist(schemaModel);
+        LOGGER.log(Level.INFO, "Finished setting up the schema={0}", schemaIdentity);
+    }
+
+    @Override
+    public void deleteSchema(String kind) {
+        // The DELETE API is not supported in the Schema service.
+        // In order not to overwhelm a DB with a lots of test schemas
+        // the integration tests create/update a schema per schema file if the schema does not exists
+        // If a developer updates the schema manually, the developer is supposed to update its version as well
+    }
+
+    private SchemaModel readSchemaFromJson(){
+        try {
+            return FileHandler.readFile(getSchemaFile(), SchemaModel.class);
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
+        }
+    }
+
+    public SchemaModel getSchemaModel() {
+        return schemaModel;
+    }
+
+    @Override
+    protected String getSchemaFile() {
+        return super.getSchemaFile() + ".json";
+    }
+}
diff --git a/testing/indexer-test-core/src/main/java/org/opengroup/osdu/models/schema/SchemaIdentity.java b/testing/indexer-test-core/src/main/java/org/opengroup/osdu/models/schema/SchemaIdentity.java
new file mode 100644
index 0000000000000000000000000000000000000000..7a16af67fc6d644970d82aa025ab00addd502656
--- /dev/null
+++ b/testing/indexer-test-core/src/main/java/org/opengroup/osdu/models/schema/SchemaIdentity.java
@@ -0,0 +1,81 @@
+package org.opengroup.osdu.models.schema;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+
+import java.util.StringJoiner;
+
+public class SchemaIdentity {
+
+    private  String authority;
+    private  String source;
+    private  String entityType;
+    private String schemaVersionMajor;
+    private String schemaVersionMinor;
+    private String schemaVersionPatch;
+
+    public String getAuthority() {
+        return authority;
+    }
+
+    public void setAuthority(String authority) {
+        this.authority = authority;
+    }
+
+    public String getSource() {
+        return source;
+    }
+
+    public void setSource(String source) {
+        this.source = source;
+    }
+
+    public String getEntityType() {
+        return entityType;
+    }
+
+    public void setEntityType(String entityType) {
+        this.entityType = entityType;
+    }
+
+    public String getSchemaVersionMajor() {
+        return schemaVersionMajor;
+    }
+
+    public void setSchemaVersionMajor(String schemaVersionMajor) {
+        this.schemaVersionMajor = schemaVersionMajor;
+    }
+
+    public String getSchemaVersionMinor() {
+        return schemaVersionMinor;
+    }
+
+    public void setSchemaVersionMinor(String schemaVersionMinor) {
+        this.schemaVersionMinor = schemaVersionMinor;
+    }
+
+    public String getSchemaVersionPatch() {
+        return schemaVersionPatch;
+    }
+
+    public void setSchemaVersionPatch(String schemaVersionPatch) {
+        this.schemaVersionPatch = schemaVersionPatch;
+    }
+
+    @JsonIgnore
+    public String getId() {
+        return authority + ":" + source + ":" + entityType + ":" +
+                schemaVersionMajor + "." + schemaVersionMinor + "." + schemaVersionPatch;
+    }
+
+    @Override
+    public String toString() {
+        return new StringJoiner(", ", SchemaIdentity.class.getSimpleName() + "[", "]")
+                .add("AUTHORITY='" + authority + "'")
+                .add("SOURCE='" + source + "'")
+                .add("ENTITY_TYPE='" + entityType + "'")
+                .add("schemaVersionMajor='" + schemaVersionMajor + "'")
+                .add("schemaVersionMinor='" + schemaVersionMinor + "'")
+                .add("schemaVersionPatch='" + schemaVersionPatch + "'")
+                .toString();
+    }
+}
diff --git a/testing/indexer-test-core/src/main/java/org/opengroup/osdu/models/schema/SchemaInfo.java b/testing/indexer-test-core/src/main/java/org/opengroup/osdu/models/schema/SchemaInfo.java
new file mode 100644
index 0000000000000000000000000000000000000000..88904aac2163db1215c35d53942d4b8cf5fea9ce
--- /dev/null
+++ b/testing/indexer-test-core/src/main/java/org/opengroup/osdu/models/schema/SchemaInfo.java
@@ -0,0 +1,37 @@
+package org.opengroup.osdu.models.schema;
+
+import java.util.StringJoiner;
+
+public class SchemaInfo {
+
+    private SchemaIdentity schemaIdentity;
+    private SchemaStatus status;
+
+    public SchemaIdentity getSchemaIdentity() {
+        return schemaIdentity;
+    }
+
+    public void setSchemaIdentity(SchemaIdentity schemaIdentity) {
+        this.schemaIdentity = schemaIdentity;
+    }
+
+    public SchemaStatus getStatus() {
+        return status;
+    }
+
+    public void setStatus(SchemaStatus status) {
+        this.status = status;
+    }
+
+    @Override
+    public String toString() {
+        return new StringJoiner(", ", SchemaInfo.class.getSimpleName() + "[", "]")
+                .add("schemaIdentity=" + schemaIdentity)
+                .add("status=" + status)
+                .toString();
+    }
+
+    public enum SchemaStatus {
+        PUBLISHED, OBSOLETE, DEVELOPMENT
+    }
+}
diff --git a/testing/indexer-test-core/src/main/java/org/opengroup/osdu/models/schema/SchemaModel.java b/testing/indexer-test-core/src/main/java/org/opengroup/osdu/models/schema/SchemaModel.java
new file mode 100644
index 0000000000000000000000000000000000000000..2a15bc3f903149f595fc0fd34dae8404401d140f
--- /dev/null
+++ b/testing/indexer-test-core/src/main/java/org/opengroup/osdu/models/schema/SchemaModel.java
@@ -0,0 +1,33 @@
+package org.opengroup.osdu.models.schema;
+
+import java.util.StringJoiner;
+
+public class SchemaModel {
+
+    private SchemaInfo schemaInfo;
+    private Object schema;
+
+    public Object getSchema() {
+        return schema;
+    }
+
+    public void setSchema(Object schema) {
+        this.schema = schema;
+    }
+
+    public SchemaInfo getSchemaInfo() {
+        return schemaInfo;
+    }
+
+    public void setSchemaInfo(SchemaInfo schemaInfo) {
+        this.schemaInfo = schemaInfo;
+    }
+
+    @Override
+    public String toString() {
+        return new StringJoiner(", ", SchemaModel.class.getSimpleName() + "[", "]")
+                .add("schemaInfo=" + schemaInfo)
+                .add("schema=" + schema)
+                .toString();
+    }
+}
diff --git a/testing/indexer-test-core/src/main/java/org/opengroup/osdu/util/Config.java b/testing/indexer-test-core/src/main/java/org/opengroup/osdu/util/Config.java
index 6568a88fd091f2dbf455d72ee5484d6a3c1115d0..3d97833f4f9edeaf3fb5d530d3136b9640ab7ad6 100644
--- a/testing/indexer-test-core/src/main/java/org/opengroup/osdu/util/Config.java
+++ b/testing/indexer-test-core/src/main/java/org/opengroup/osdu/util/Config.java
@@ -11,6 +11,7 @@ public class Config {
     private static final String DEFAULT_INDEXER_HOST = "";
     private static final String DEFAULT_SEARCH_HOST = "";
     private static final String DEFAULT_STORAGE_HOST = "";
+    private static final String DEFAULT_HOST = "";
     private static final String DEFAULT_DATA_PARTITION_ID_TENANT1 = "";
     private static final String DEFAULT_DATA_PARTITION_ID_TENANT2 = "";
     private static final String DEFAULT_SEARCH_INTEGRATION_TESTER = "";
@@ -22,6 +23,7 @@ public class Config {
 
     private static final String DEFAULT_ENTITLEMENTS_DOMAIN = "";
 
+    private static final String SCHEMA_PATH = "/api/schema-service/v1";
 
     public static int getPort() {
         return Integer.parseInt(getEnvironmentVariableOrDefaultValue("ELASTIC_PORT", String.valueOf(PORT)));
@@ -79,6 +81,10 @@ public class Config {
         return getEnvironmentVariableOrDefaultValue("STORAGE_HOST", DEFAULT_STORAGE_HOST);
     }
 
+    public static String getSchemaBaseURL() {
+        return getEnvironmentVariableOrDefaultValue("HOST", DEFAULT_HOST) + SCHEMA_PATH;
+    }
+
     public static String getEntitlementsDomain() {
         return getEnvironmentVariableOrDefaultValue("ENTITLEMENTS_DOMAIN", DEFAULT_ENTITLEMENTS_DOMAIN);
     }
diff --git a/testing/indexer-test-core/src/main/java/org/opengroup/osdu/util/ElasticUtils.java b/testing/indexer-test-core/src/main/java/org/opengroup/osdu/util/ElasticUtils.java
index f6d7ac6ad5596d81e20203997cfcdb542ded04c6..4612f07cf3efd111c178ef607c6d1af2789d60dd 100644
--- a/testing/indexer-test-core/src/main/java/org/opengroup/osdu/util/ElasticUtils.java
+++ b/testing/indexer-test-core/src/main/java/org/opengroup/osdu/util/ElasticUtils.java
@@ -1,3 +1,20 @@
+/*
+  Copyright 2020 Google LLC
+  Copyright 2020 EPAM Systems, Inc
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
 package org.opengroup.osdu.util;
 
 import com.google.gson.Gson;
@@ -298,17 +315,24 @@ public class ElasticUtils {
         return builder;
     }
 
-    public boolean isIndexExist(String index) throws IOException {
+    public boolean isIndexExist(String index) {
         boolean exists = false;
         try {
-            try (RestHighLevelClient client = this.createClient(username, password, host)) {
-                GetIndexRequest request = new GetIndexRequest();
-                request.indices(index);
-                exists = client.indices().exists(request, RequestOptions.DEFAULT);
-            }
+            exists = createRestClientAndCheckIndexExist(index);
         } catch (ElasticsearchStatusException e) {
-            log.log(Level.INFO, String.format("Error getting index: %s status", index));
+            log.log(Level.INFO, String.format("Error getting index: %s %s", index, e.getMessage()));
         }
         return exists;
     }
+
+    private boolean createRestClientAndCheckIndexExist(String index) {
+        try (RestHighLevelClient client = this.createClient(username, password, host)) {
+            GetIndexRequest request = new GetIndexRequest();
+            request.indices(index);
+            return client.indices().exists(request, RequestOptions.DEFAULT);
+        } catch (IOException e) {
+            log.log(Level.INFO, String.format("Error getting index: %s %s", index, e.getMessage()));
+        }
+        return false;
+    }
 }
\ No newline at end of file
diff --git a/testing/indexer-test-core/src/main/java/org/opengroup/osdu/util/FileHandler.java b/testing/indexer-test-core/src/main/java/org/opengroup/osdu/util/FileHandler.java
index 678cb91204d3f786437090737dc9a29d1e1acfc7..38a5a507e776224a19ffc687e79f4c3deec16202 100644
--- a/testing/indexer-test-core/src/main/java/org/opengroup/osdu/util/FileHandler.java
+++ b/testing/indexer-test-core/src/main/java/org/opengroup/osdu/util/FileHandler.java
@@ -1,5 +1,7 @@
 package org.opengroup.osdu.util;
 
+import com.fasterxml.jackson.databind.ObjectMapper;
+
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
@@ -7,8 +9,12 @@ import java.nio.charset.StandardCharsets;
 
 public class FileHandler {
 
+    private static final ObjectMapper mapper = new ObjectMapper();
+
+    private FileHandler(){}
+
     public static String readFile(String fileName) throws IOException {
-        InputStream inputStream = FileHandler.class.getClass().getResourceAsStream(String.format("/testData/%s",fileName));
+        InputStream inputStream = getFileStream(fileName);
         if(inputStream == null) {
             throw new IOException();
         }
@@ -20,5 +26,13 @@ public class FileHandler {
         }
         return outputStream.toString(StandardCharsets.UTF_8.toString());
     }
-    
+
+    public static <T> T readFile(String fileName, Class<T> targetClass) throws IOException {
+        InputStream is = getFileStream(fileName);
+        return mapper.readValue(is, targetClass);
+    }
+
+    private static InputStream getFileStream(String fileName) {
+        return FileHandler.class.getResourceAsStream(String.format("/testData/%s", fileName));
+    }
 }
diff --git a/testing/indexer-test-core/src/main/java/org/opengroup/osdu/util/NotFoundIgnoringResponseErrorHandler.java b/testing/indexer-test-core/src/main/java/org/opengroup/osdu/util/NotFoundIgnoringResponseErrorHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..5d23c809cc926769de437240baba1fd2464c09fa
--- /dev/null
+++ b/testing/indexer-test-core/src/main/java/org/opengroup/osdu/util/NotFoundIgnoringResponseErrorHandler.java
@@ -0,0 +1,20 @@
+package org.opengroup.osdu.util;
+
+import org.springframework.http.HttpStatus;
+import org.springframework.http.client.ClientHttpResponse;
+import org.springframework.web.client.DefaultResponseErrorHandler;
+
+import java.io.IOException;
+
+public class NotFoundIgnoringResponseErrorHandler extends DefaultResponseErrorHandler {
+
+    @Override
+    public boolean hasError(ClientHttpResponse response) throws IOException {
+        return super.hasError(response) && response.getRawStatusCode() != HttpStatus.NOT_FOUND.value();
+    }
+
+    @Override
+    protected boolean hasError(HttpStatus statusCode) {
+        return super.hasError(statusCode) && statusCode != HttpStatus.NOT_FOUND;
+    }
+}
diff --git a/testing/indexer-test-core/src/main/java/org/opengroup/osdu/util/SchemaServiceClient.java b/testing/indexer-test-core/src/main/java/org/opengroup/osdu/util/SchemaServiceClient.java
new file mode 100644
index 0000000000000000000000000000000000000000..5a1a90a0241a1b279c2b57ecfb5fe48c840a519e
--- /dev/null
+++ b/testing/indexer-test-core/src/main/java/org/opengroup/osdu/util/SchemaServiceClient.java
@@ -0,0 +1,72 @@
+package org.opengroup.osdu.util;
+
+import org.opengroup.osdu.models.schema.SchemaIdentity;
+import org.opengroup.osdu.models.schema.SchemaModel;
+import org.springframework.boot.web.client.RestTemplateBuilder;
+import org.springframework.http.*;
+import org.springframework.web.client.RestTemplate;
+import org.springframework.web.util.UriComponentsBuilder;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import static java.util.Collections.singletonList;
+
+
+public class SchemaServiceClient {
+
+    private static final Logger LOGGER = Logger.getLogger(SchemaServiceClient.class.getName());
+
+    private final RestTemplate template;
+    private final String schemaBaseUrl;
+
+    public SchemaServiceClient(HTTPClient client) {
+        template = new RestTemplateBuilder()
+                .errorHandler(new NotFoundIgnoringResponseErrorHandler())
+                .additionalInterceptors((request, body, execution) -> {
+                    request.getHeaders().add(HttpHeaders.AUTHORIZATION, client.getAccessToken());
+                    request.getHeaders().put(HttpHeaders.ACCEPT, singletonList(MediaType.APPLICATION_JSON_VALUE));
+                    request.getHeaders().add("data-partition-id", Config.getDataPartitionIdTenant1());
+                    return execution.execute(request, body);
+                })
+                .build();
+        schemaBaseUrl = Config.getSchemaBaseURL();
+    }
+
+    public boolean exists(SchemaIdentity identity) {
+        String uri = buildSchemaUri(identity.getId());
+        LOGGER.log(Level.INFO, "Checking whether the schema exists having identity={0}", identity);
+        ResponseEntity<?> response = template.exchange(uri, HttpMethod.GET, null, Object.class);
+        LOGGER.log(Level.INFO, "Finished checking whether the schema exists having identity={0}, response={1}", new Object[]{identity, response});
+        return response.getStatusCode() == HttpStatus.OK;
+    }
+
+    public void create(SchemaModel schema) {
+        String uri = buildSchemaUri();
+        LOGGER.log(Level.INFO, "Creating the schema={0}", schema);
+        HttpHeaders headers = new HttpHeaders();
+        headers.put(HttpHeaders.CONTENT_TYPE, singletonList(MediaType.APPLICATION_JSON_VALUE));
+        HttpEntity<SchemaModel> httpEntity = new HttpEntity<>(schema, headers);
+        template.exchange(uri, HttpMethod.PUT, httpEntity, Object.class);
+        LOGGER.log(Level.INFO, "Finished creating the schema={0}", schema);
+    }
+
+    public void createIfNotExist(SchemaModel schema) {
+        if (!exists(schema.getSchemaInfo().getSchemaIdentity())) {
+            create(schema);
+        }
+    }
+
+    private String buildSchemaUri(String id) {
+        return UriComponentsBuilder.fromHttpUrl(schemaBaseUrl)
+                .path("/schema/{schema-id}")
+                .buildAndExpand(id).toUriString();
+    }
+
+    private String buildSchemaUri() {
+        return UriComponentsBuilder.fromHttpUrl(schemaBaseUrl)
+                .path("/schema/")
+                .build().toUriString();
+    }
+
+}
diff --git a/testing/indexer-test-core/src/main/resources/features/indexrecord/indexRecord-schema-service.feature b/testing/indexer-test-core/src/main/resources/features/indexrecord/indexRecord-schema-service.feature
new file mode 100644
index 0000000000000000000000000000000000000000..096f997f790e98f69559e074a549a77cb340d488
--- /dev/null
+++ b/testing/indexer-test-core/src/main/resources/features/indexrecord/indexRecord-schema-service.feature
@@ -0,0 +1,28 @@
+Feature: Indexing of the documents
+  This feature deals with validation of the documents in Elastic Search ingested with different kinds and attributes.
+
+  Background:
+    Given the schema is created with the following kind
+      | kind                                           | index                                          | schemaFile      |
+      | tenant1:indexer-int-test:sample-schema-1:1.0.4 | tenant1-indexer-int-test:sample-schema-1-1.0.4 | index_records_1 |
+      | tenant1:indexer-int-test:sample-schema-2:1.0.4 | tenant1-indexer-int-test:sample-schema-2-1.0.4 | index_records_2 |
+      | tenant1:indexer-int-test:sample-schema-3:1.0.4 | tenant1-indexer-int-test:sample-schema-3-1.0.4 | index_records_3 |
+
+  Scenario Outline: Ingest the record and Index in the Elastic Search
+    When I ingest records with the <recordFile> with <acl> for a given <kind>
+    Then I should get the <number> documents for the <index> in the Elastic Search
+    Then I should get the elastic <mapping> for the <type> and <index> in the Elastic Search
+
+    Examples:
+      | kind                                             | recordFile               | number | index                                            | type   | acl                            | mapping                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
+      | "tenant1:indexer-int-test:sample-schema-1:1.0.4" | "index_records_schema_1" | 5      | "tenant1-indexer-int-test-sample-schema-1-1.0.4" | "sample-schema-1" | "data.default.viewers@tenant1" | "{"mappings":{"well":{"dynamic":"false","properties":{"acl":{"properties":{"owners":{"type":"keyword"},"viewers":{"type":"keyword"}}},"ancestry":{"properties":{"parents":{"type":"keyword"}}},"data":{"properties":{"Basin":{"type":"text"},"Country":{"type":"text"},"County":{"type":"text"},"EmptyAttribute":{"type":"text"},"Established":{"type":"date"},"Field":{"type":"text"},"Location":{"type":"geo_point"},"OriginalOperator":{"type":"text"},"Rank":{"type":"integer"},"Score":{"type":"integer"},"State":{"type":"text"},"WellName":{"type":"text"},"WellStatus":{"type":"text"},"WellType":{"type":"text"},"DblArray":{"type":"double"}}},"id":{"type":"keyword"},"index":{"properties":{"lastUpdateTime":{"type":"date"},"statusCode":{"type":"integer"},"trace":{"type":"text"}}},"kind":{"type":"keyword"},"legal":{"properties":{"legaltags":{"type":"keyword"},"otherRelevantDataCountries":{"type":"keyword"},"status":{"type":"keyword"}}},"namespace":{"type":"keyword"},"type":{"type":"keyword"},"version":{"type":"long"},"x-acl":{"type":"keyword"}}}}}" |
+      | "tenant1:indexer-int-test:sample-schema-3:1.0.4" | "index_records_schema_1" | 5      | "tenant1-indexer-int-test-sample-schema-3-1.0.4" | "sample-schema-3" | "data.default.viewers@tenant1" | "{"mappings":{"well":{"dynamic":"false","properties":{"acl":{"properties":{"owners":{"type":"keyword"},"viewers":{"type":"keyword"}}},"ancestry":{"properties":{"parents":{"type":"keyword"}}},"data":{"properties":{"Basin":{"type":"text"},"Country":{"type":"text"},"County":{"type":"text"},"EmptyAttribute":{"type":"text"},"Established":{"type":"date"},"Field":{"type":"text"},"Location":{"type":"geo_point"},"OriginalOperator":{"type":"text"},"Rank":{"type":"integer"},"Score":{"type":"integer"},"State":{"type":"text"},"WellName":{"type":"text"},"WellStatus":{"type":"text"},"WellType":{"type":"text"},"DblArray":{"type":"double"}}},"id":{"type":"keyword"},"index":{"properties":{"lastUpdateTime":{"type":"date"},"statusCode":{"type":"integer"},"trace":{"type":"text"}}},"kind":{"type":"keyword"},"legal":{"properties":{"legaltags":{"type":"keyword"},"otherRelevantDataCountries":{"type":"keyword"},"status":{"type":"keyword"}}},"namespace":{"type":"keyword"},"type":{"type":"keyword"},"version":{"type":"long"},"x-acl":{"type":"keyword"}}}}}" |
+
+  Scenario Outline: Ingest the record and Index in the Elastic Search with bad attribute
+    When I ingest records with the <recordFile> with <acl> for a given <kind>
+    Then I should get the <number> documents for the <index> in the Elastic Search with out <skippedAttribute>
+
+    Examples:
+      | kind                                             | recordFile        | number | index                                            | skippedAttribute | acl                            |
+      | "tenant1:indexer-int-test:sample-schema-2:1.0.4" | "index_records_2" | 4      | "tenant1-indexer-int-test-sample-schema-2-1.0.4" | "data.Location"  | "data.default.viewers@tenant1" |
+      | "tenant1:indexer-int-test:sample-schema-3:1.0.4" | "index_records_3" | 7      | "tenant1-indexer-int-test-sample-schema-3-1.0.4" | "data.GeoShape"  | "data.default.viewers@tenant1" |
diff --git a/testing/indexer-test-core/src/main/resources/testData/index_records_1.schema.json b/testing/indexer-test-core/src/main/resources/testData/index_records_1.schema.json
new file mode 100644
index 0000000000000000000000000000000000000000..2a6e6301a41b6b4f8d82839c2faca994336a46a3
--- /dev/null
+++ b/testing/indexer-test-core/src/main/resources/testData/index_records_1.schema.json
@@ -0,0 +1,80 @@
+{
+  "schemaInfo": {
+    "schemaIdentity": {
+      "authority": "tenant1",
+      "source": "indexer-int-test",
+      "entityType": "sample-schema-1",
+      "schemaVersionMajor": "1",
+      "schemaVersionMinor": "0",
+      "schemaVersionPatch": "4"
+    },
+    "status": "DEVELOPMENT"
+  },
+  "schema": {
+    "properties": {
+      "data": {
+        "allOf": [
+          {
+            "type": "object",
+            "properties": {
+              "Field": {
+                "type": "string"
+              },
+              "Location": {
+                "$ref": "#/definitions/core_dl_geopoint",
+                "description": "The wellbore's position .",
+                "format": "core:dl:geopoint:1.0.0",
+                "title": "WGS 84 Position",
+                "type": "object"
+              },
+              "Basin": {
+                "type": "string"
+              },
+              "County": {
+                "type": "string"
+              },
+              "State": {
+                "type": "string"
+              },
+              "Country": {
+                "type": "string"
+              },
+              "WellStatus": {
+                "type": "string"
+              },
+              "OriginalOperator": {
+                "type": "string"
+              },
+              "WellName": {
+                "type": "string"
+              },
+              "WellType": {
+                "type": "string"
+              },
+              "EmptyAttribute": {
+                "type": "string"
+              },
+              "Rank": {
+                "type": "integer"
+              },
+              "Score": {
+                "type": "integer"
+              },
+              "Established": {
+                "type": "date-time"
+              },
+              "DblArray": {
+                "description": "The name of the host [cloud environment] region(s) for this OSDU resource object.",
+                "title": "Resource Host Region ID",
+                "type": "array",
+                "items": {
+                  "type": "number"
+                }
+              }
+            }
+          }
+        ]
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/testing/indexer-test-core/src/main/resources/testData/index_records_2.schema.json b/testing/indexer-test-core/src/main/resources/testData/index_records_2.schema.json
new file mode 100644
index 0000000000000000000000000000000000000000..869df29b7a4c99aa8ffb38adfe18d1e6faa707ff
--- /dev/null
+++ b/testing/indexer-test-core/src/main/resources/testData/index_records_2.schema.json
@@ -0,0 +1,75 @@
+{
+  "schemaInfo": {
+    "schemaIdentity": {
+      "authority": "tenant1",
+      "source": "indexer-int-test",
+      "entityType": "sample-schema-2",
+      "schemaVersionMajor": "1",
+      "schemaVersionMinor": "0",
+      "schemaVersionPatch": "4"
+    },
+    "status": "DEVELOPMENT"
+  },
+  "schema": {
+    "properties": {
+      "data": {
+        "allOf": [
+          {
+            "type": "object",
+            "properties": {
+              "Field": {
+                "type": "string"
+              },
+              "Location": {
+                "$ref": "#/definitions/core_dl_geopoint",
+                "description": "The wellbore's position .",
+                "format": "core:dl:geopoint:1.0.0",
+                "title": "WGS 84 Position",
+                "type": "object"
+              },
+              "Basin": {
+                "type": "string"
+              },
+              "County": {
+                "type": "string"
+              },
+              "State": {
+                "type": "string"
+              },
+              "Country": {
+                "type": "string"
+              },
+              "WellStatus": {
+                "type": "string"
+              },
+              "OriginalOperator": {
+                "type": "string"
+              },
+              "WellName": {
+                "type": "string"
+              },
+              "WellType": {
+                "type": "string"
+              },
+              "EmptyAttribute": {
+                "type": "string"
+              },
+              "Rank": {
+                "type": "integer"
+              },
+              "Score": {
+                "type": "integer"
+              },
+              "Established": {
+                "type": "date-time"
+              },
+              "InvalidInteger": {
+                "type": "integer"
+              }
+            }
+          }
+        ]
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/testing/indexer-test-core/src/main/resources/testData/index_records_3.schema.json b/testing/indexer-test-core/src/main/resources/testData/index_records_3.schema.json
new file mode 100644
index 0000000000000000000000000000000000000000..bb5d2e9c5ce9fd0a376f6849028007b6d912da60
--- /dev/null
+++ b/testing/indexer-test-core/src/main/resources/testData/index_records_3.schema.json
@@ -0,0 +1,36 @@
+{
+  "schemaInfo": {
+    "schemaIdentity": {
+      "authority": "tenant1",
+      "source": "indexer-int-test",
+      "entityType": "sample-schema-3",
+      "schemaVersionMajor": "1",
+      "schemaVersionMinor": "0",
+      "schemaVersionPatch": "4"
+    },
+    "status": "DEVELOPMENT"
+  },
+  "schema": {
+    "properties": {
+      "data": {
+        "allOf": [
+          {
+            "type": "object",
+            "properties": {
+              "GeoShape": {
+                "$ref": "#/definitions/geoJsonFeatureCollection",
+                "description": "The wellbore's position .",
+                "format": "core:dl:geopoint:1.0.0",
+                "title": "WGS 84 Position",
+                "type": "object"
+              },
+              "WellName": {
+                "type": "string"
+              }
+            }
+          }
+        ]
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/testing/indexer-test-gcp/src/test/java/org/opengroup/osdu/step_definitions/index/cleanup/RunTest.java b/testing/indexer-test-gcp/src/test/java/org/opengroup/osdu/step_definitions/index/cleanup/RunTest.java
index f01c141fa43122aa39e1632336bcf6530514baff..baa367cab29a6bda105b22654ee69d5850033bec 100644
--- a/testing/indexer-test-gcp/src/test/java/org/opengroup/osdu/step_definitions/index/cleanup/RunTest.java
+++ b/testing/indexer-test-gcp/src/test/java/org/opengroup/osdu/step_definitions/index/cleanup/RunTest.java
@@ -1,3 +1,20 @@
+/*
+  Copyright 2020 Google LLC
+  Copyright 2020 EPAM Systems, Inc
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
 package org.opengroup.osdu.step_definitions.index.cleanup;
 
 import cucumber.api.CucumberOptions;
diff --git a/testing/indexer-test-gcp/src/test/java/org/opengroup/osdu/step_definitions/index/cleanup/Steps.java b/testing/indexer-test-gcp/src/test/java/org/opengroup/osdu/step_definitions/index/cleanup/Steps.java
index 017ca4df69ba0bf4229f76bd8d9aca489622ff7c..d40b77949c357be505521d5207e176ac4698f5fb 100644
--- a/testing/indexer-test-gcp/src/test/java/org/opengroup/osdu/step_definitions/index/cleanup/Steps.java
+++ b/testing/indexer-test-gcp/src/test/java/org/opengroup/osdu/step_definitions/index/cleanup/Steps.java
@@ -1,3 +1,20 @@
+/*
+  Copyright 2020 Google LLC
+  Copyright 2020 EPAM Systems, Inc
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
 package org.opengroup.osdu.step_definitions.index.cleanup;
 
 import cucumber.api.DataTable;
@@ -25,42 +42,42 @@ public class Steps extends CleanupIndiciesSteps {
     }
 
     @Given("^the schema is created with the following kind$")
-    public void the_schema_is_created_with_the_following_kind(DataTable dataTable) {
-        super.the_schema_is_created_with_the_following_kind(dataTable);
+    public void theSchemaIsCreatedWithTheFollowingKind(DataTable dataTable) {
+        super.theSchemaIsCreatedWithTheFollowingKind(dataTable);
     }
 
     @When("^I ingest records with the \"(.*?)\" with \"(.*?)\" for a given \"(.*?)\"$")
-    public void i_ingest_records_with_the_for_a_given(String record, String dataGroup, String kind) {
-        super.i_ingest_records_with_the_for_a_given(record, dataGroup, kind);
+    public void iIngestRecordsWithTheforAGiven(String record, String dataGroup, String kind) {
+        super.iIngestRecordsWithTheforAGiven(record, dataGroup, kind);
     }
 
     @Then("^I check that the index for \"(.*?)\" has been created$")
-    public void i_check_that_the_index_for_has_been_created(String kind) throws IOException, InterruptedException {
-        super.i_check_that_the_index_for_has_been_created(kind);
+    public void iCheckThatTheIndexForHasBeenCreated(String kind) throws IOException, InterruptedException {
+        super.iCheckThatTheIndexForHasBeenCreated(kind);
     }
 
     @Then("^I should delete the records I created earlier$")
-    public void i_should_delete_the_records_for_i_created_earlier() {
-        super.i_should_delete_the_records_for_i_created_earlier();
+    public void iShouldDeleteTheRecordsForICreatedEarlier() {
+        super.iShouldDeleteTheRecordsForICreatedEarlier();
     }
 
     @Then("^I should delete the schema for \"(.*?)\" I created earlier$")
-    public void i_should_delete_the_schema_for_i_created_earlier(String kind) {
-        super.i_should_delete_the_schema_for_i_created_earlier(kind);
+    public void iShouldDeleteTheSchemaForICreatedEarlier(String kind) {
+        super.iShouldDeleteTheSchemaForICreatedEarlier(kind);
     }
 
     @Then("^I should check that the index for \"(.*?)\" has not been deleted$")
-    public void i_should_check_that_the_index_for_has_not_been_deleted(String kind) throws IOException, InterruptedException {
-        super.i_should_check_that_the_index_for_has_not_been_deleted(kind);
+    public void iShouldCheckThetTheIndexforHasNotBeenDeleted(String kind) throws IOException, InterruptedException {
+        super.iShouldCheckThetTheIndexforHasNotBeenDeleted(kind);
     }
 
     @Then("^I should to run cleanup of indexes for \"(.*?)\" and \"(.*?)\"$")
-    public void i_should_to_run_cleanup_of_indexes_for_and(String kind, String message) {
-        super.i_should_to_run_cleanup_of_indexes_for_and(kind, message);
+    public void iShouldToRunCleanupOfIndexesForAnd(String kind, String message) {
+        super.iShouldToRunCleanupOfIndexesForAnd(kind, message);
     }
 
     @Then("^I should check that the index for \"(.*?)\" has been deleted$")
-    public void i_should_check_that_the_index_for_has_been_deleted(String kind) throws IOException, InterruptedException {
-        super.i_should_check_that_the_index_for_has_been_deleted(kind);
+    public void iShouldCheckThatTheIndexForHasBeenDeleted(String kind) throws IOException, InterruptedException {
+        super.iShouldCheckThatTheIndexForHasBeenDeleted(kind);
     }
 }
\ No newline at end of file
diff --git a/testing/indexer-test-ibm/pom.xml b/testing/indexer-test-ibm/pom.xml
index 110d8aa46ceb0e9082ed733b02f3a0a8d91d5fe2..edfe569b62f6f59ee25dd422170682f03ab2c68e 100644
--- a/testing/indexer-test-ibm/pom.xml
+++ b/testing/indexer-test-ibm/pom.xml
@@ -42,7 +42,13 @@
             <artifactId>indexer-test-core</artifactId>
             <version>0.0.2-SNAPSHOT</version>
         </dependency>
-        
+
+        <dependency>
+            <groupId>org.opengroup.osdu</groupId>
+            <artifactId>os-core-common</artifactId>
+            <version>0.3.8</version>
+        </dependency>
+
         <dependency>
 			<groupId>org.opengroup.osdu</groupId>
 			<artifactId>os-core-lib-ibm</artifactId>
diff --git a/testing/pom.xml b/testing/pom.xml
index 4ffdbe986ba60cdb8923a7ef92f9acd6b974ed2a..742fcdfc699312d137db006d325881da06ed2768 100644
--- a/testing/pom.xml
+++ b/testing/pom.xml
@@ -21,6 +21,9 @@
 	<artifactId>indexer-test</artifactId>
 	<version>0.0.5-SNAPSHOT</version>
 	<description>Indexer Service Integration Test Root Project</description>
+	<properties>
+		<spring.version>5.1.19.RELEASE</spring.version>
+	</properties>
 	<packaging>pom</packaging>
 
 	<licenses>
@@ -46,6 +49,26 @@
 		</repository>
 	</repositories>
 
+	<dependencyManagement>
+		<dependencies>
+			<dependency>
+				<groupId>org.springframework</groupId>
+				<artifactId>spring-core</artifactId>
+				<version>${spring.version}</version>
+			</dependency>
+			<dependency>
+				<groupId>org.springframework</groupId>
+				<artifactId>spring-web</artifactId>
+				<version>${spring.version}</version>
+			</dependency>
+			<dependency>
+				<groupId>org.springframework</groupId>
+				<artifactId>spring-webmvc</artifactId>
+				<version>${spring.version}</version>
+			</dependency>
+		</dependencies>
+	</dependencyManagement>
+
 	<distributionManagement>
 		<repository>
 			<id>${publish.releases.id}</id>