diff --git a/ImportFromOSDU.md b/ImportFromOSDU.md new file mode 100644 index 0000000000000000000000000000000000000000..f10b37a903b06b7ad11367439adc90603a0745f0 --- /dev/null +++ b/ImportFromOSDU.md @@ -0,0 +1,36 @@ +#### The following updates need to be made when code is merged from OSDU: +1. Please update the repo names in `devops/azure/pipeline.yml` file: +``` +resources: + repositories: + - repository: FluxRepo + type: git + name: r3-gitops-manifests + - repository: TemplateRepo + type: git + name: r3-infra-azure-provisioning + - repository: security-templates + type: git + name: osdu-delfi/security-infrastructure +``` +2. Update the variable groups in the `devops/azure/pipeline.yml` file: + +``` +variables: + - group: 'R3MVP - Azure - OSDU' + - group: 'R3MVP - Azure - OSDU Secrets' +``` +3. Update the env. names in the `devops/azure/pipeline.yml` file: +``` + providers: + - name: Azure + environments: ['dev'] +``` + +4. Disable AAD filer and use externalized Auth form Istio: remove following two settings if they are present from 'devops/azure/chart/templates/deployment.yaml' +``` + - name: azure_activedirectory_session_stateless + value: "true" + - name: azure_activedirectory_AppIdUri + value: "api://$(aad_client_id)" +``` diff --git a/devops/azure/release.yaml b/devops/azure/release.yaml index 540d39689a9503daf6db8fa8529570eeca3deb5e..ef866679befeeba3c3e67cfb88bfe2147d6b4762 100644 --- a/devops/azure/release.yaml +++ b/devops/azure/release.yaml @@ -154,6 +154,8 @@ spec: value: "OBSOLETE" - name: storage_service_url value: http://storage/api/storage/v2 + - name: SCHEMA_HOST + value: http://schema/api/schema-service/v1/schema - name: STORAGE_SCHEMA_HOST value: http://storage/api/storage/v2/schemas - name: STORAGE_QUERY_RECORD_FOR_CONVERSION_HOST 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..643d5304584773d855ced3964f2d7f27855ca284 --- /dev/null +++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/schema/converter/PropertiesProcessor.java @@ -0,0 +1,165 @@ +// 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 lombok.AccessLevel; +import lombok.experimental.FieldDefaults; +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.search.Preconditions; +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.stream.Stream; + +@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) +@Log +class PropertiesProcessor { + static String DEF_PREFIX = "#/definitions/"; + + static Set<String> SKIP_DEFINITIONS = new HashSet<>( + Arrays.asList("AbstractAnyCrsFeatureCollection.1.0.0", + "anyCrsGeoJsonFeatureCollection")); + + static Set<String> ARRAY_SUPPORTED_SIMPLE_TYPES = new HashSet<>( + Arrays.asList("boolean", "integer", "number", "string")); + + static Map<String, String> SPEC_DEFINITION_TYPES = new HashMap<String, String>() {{ + put("AbstractFeatureCollection.1.0.0", "core:dl:geoshape:1.0.0"); + put("core_dl_geopoint", "core:dl:geopoint:1.0.0"); + put("geoJsonFeatureCollection", "core:dl:geoshape:1.0.0"); + }}; + + static Map<String, String> PRIMITIVE_TYPES_MAP = new HashMap<String, String>() {{ + put("boolean", "bool"); + put("number", "double"); + put("date-time", "datetime"); + put("date", "datetime"); + put("time", "datetime"); + put("int32", "int"); + put("integer", "int"); + put("int64", "long"); + }}; + + Definitions definitions; + String pathPrefix; + String pathPrefixWithDot; + + public PropertiesProcessor(Definitions definitions) { + this(definitions, null); + } + + public PropertiesProcessor(Definitions definitions, String pathPrefix) { + this.definitions = definitions; + this.pathPrefix = pathPrefix; + this.pathPrefixWithDot = Objects.isNull(pathPrefix) || pathPrefix.isEmpty() ? "" : pathPrefix + "."; + } + + protected Stream<Map<String, Object>> processItem(AllOfItem allOfItem) { + Preconditions.checkNotNull(allOfItem, "ref 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, "allOfItem cannot be null"); + + if (!ref.contains(DEF_PREFIX)) { + log.warning("Unknown definition:" + ref); + return Stream.empty(); + } + + String definitionSubRef = ref.substring(DEF_PREFIX.length()); + + if (SKIP_DEFINITIONS.contains(definitionSubRef)) { + return Stream.empty(); + } + + if (!Objects.isNull(SPEC_DEFINITION_TYPES.get(definitionSubRef))) { + return storageSchemaEntry(SPEC_DEFINITION_TYPES.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); + } + + protected 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 (ARRAY_SUPPORTED_SIMPLE_TYPES.contains(entry.getValue().getItems().getType())) { + return storageSchemaEntry("[]" + getTypeByDefinitionProperty(entry.getValue()), pathPrefixWithDot + entry.getKey()); + } + + return Stream.empty(); + } + + if (!Objects.isNull(entry.getValue().getProperties())) { + PropertiesProcessor propertiesProcessor = new PropertiesProcessor(definitions, pathPrefixWithDot + entry.getKey()); + return entry.getValue().getProperties().entrySet().stream().flatMap(propertiesProcessor::processPropertyEntry); + } + + if (!Objects.isNull(entry.getValue().getRef())) { + return new PropertiesProcessor(definitions, pathPrefixWithDot + entry.getKey()) + .processRef(entry.getValue().getRef()); + } + + return storageSchemaEntry(getTypeByDefinitionProperty(entry.getValue()), pathPrefixWithDot + entry.getKey()); + } + + protected 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); + } + + protected String getTypeByDefinitionProperty(TypeProperty definitionProperty) { + Preconditions.checkNotNull(definitionProperty, "definitionProperty cannot be null"); + + String pattern = definitionProperty.getPattern(); + String format = definitionProperty.getFormat(); + String type = definitionProperty.getType(); + String itemsType = definitionProperty.getItems() != null ? definitionProperty.getItems().getType() : null; + String itemsPattern = definitionProperty.getItems() != null ? definitionProperty.getItems().getPattern() : null; + + return !Objects.isNull(pattern) && pattern.startsWith("^srn") ? "link" : + !Objects.isNull(itemsPattern) && itemsPattern.startsWith("^srn") ? "link" : + !Objects.isNull(format) ? PRIMITIVE_TYPES_MAP.getOrDefault(format, format) : + !Objects.isNull(itemsType) ? PRIMITIVE_TYPES_MAP.getOrDefault(itemsType, itemsType) : + PRIMITIVE_TYPES_MAP.getOrDefault(type, type); + } +} 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..155b8bf385046281d69bcc2a2be1ed7845608b47 --- /dev/null +++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/schema/converter/SchemaToStorageFormatImpl.java @@ -0,0 +1,114 @@ +// 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.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.AccessLevel; +import lombok.experimental.FieldDefaults; +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.search.Preconditions; +import org.opengroup.osdu.indexer.schema.converter.interfaces.SchemaToStorageFormat; +import org.opengroup.osdu.indexer.schema.converter.tags.*; +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 +@FieldDefaults(makeFinal=true, level= AccessLevel.PRIVATE) +@Log +public class SchemaToStorageFormatImpl implements SchemaToStorageFormat { + + ObjectMapper objectMapper; + + @Inject + public SchemaToStorageFormatImpl(ObjectMapper objectMapper) { + Preconditions.checkNotNull(objectMapper, "objectMapper cannot be null"); + + this.objectMapper = objectMapper; + } + + @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); + } + + protected 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); + } + } + + protected 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); + } + } + + public 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()); + + 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/interfaces/SchemaToStorageFormat.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/schema/converter/interfaces/SchemaToStorageFormat.java new file mode 100644 index 0000000000000000000000000000000000000000..41fe22b7ca06af59c52f51f0044160d4a310a10f --- /dev/null +++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/schema/converter/interfaces/SchemaToStorageFormat.java @@ -0,0 +1,5 @@ +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..8630e1f06b565662c026f6c3ae13f5420d8d78d6 --- /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: +---------------------------------------------------------------------------- + +```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..8305d2604a366f7a76b17466f7ef2f2e4f214be3 --- /dev/null +++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/schema/converter/tags/AllOfItem.java @@ -0,0 +1,31 @@ +// 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.tags; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AccessLevel; +import lombok.Data; +import lombok.experimental.FieldDefaults; + +import java.util.Map; + +@Data +@FieldDefaults(level= AccessLevel.PRIVATE) +public class AllOfItem { + @JsonProperty("$ref") + String ref; + String type; + 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..bf4e0f00b89f1344ecd66dc9f07683067dc6d0f2 --- /dev/null +++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/schema/converter/tags/Definition.java @@ -0,0 +1,28 @@ +// 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.tags; + +import lombok.AccessLevel; +import lombok.Data; +import lombok.experimental.FieldDefaults; + +import java.util.Map; + +@Data +@FieldDefaults(level= AccessLevel.PRIVATE) +public class Definition { + String type; + 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..25c019c0a2bb263b00449f2caab199412046e2c5 --- /dev/null +++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/schema/converter/tags/Definitions.java @@ -0,0 +1,42 @@ +// 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.tags; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonAnySetter; +import lombok.AccessLevel; +import lombok.experimental.FieldDefaults; + +import java.util.HashMap; +import java.util.Map; + +@FieldDefaults(level= AccessLevel.PRIVATE) +public class Definitions { + 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..7316987882f20fe2beaa5aebc1b6d682421f6d59 --- /dev/null +++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/schema/converter/tags/Items.java @@ -0,0 +1,26 @@ +// 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.tags; + +import lombok.AccessLevel; +import lombok.Data; +import lombok.experimental.FieldDefaults; + +@Data +@FieldDefaults(level= AccessLevel.PRIVATE) +public class Items { + String type; + 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..f50c1f0dad50e18cd121b5a2d2a79ebb73ea8e15 --- /dev/null +++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/schema/converter/tags/Properties.java @@ -0,0 +1,28 @@ +// 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.tags; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AccessLevel; +import lombok.Data; +import lombok.experimental.FieldDefaults; + +@Data +@FieldDefaults(level= AccessLevel.PRIVATE) +public class Properties { + PropertiesData data; + @JsonProperty("$ref") + 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..d970bdc72fcf6ba2ef6de783d7d1235a0236e0a0 --- /dev/null +++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/schema/converter/tags/PropertiesData.java @@ -0,0 +1,30 @@ +// 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.tags; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AccessLevel; +import lombok.Data; +import lombok.experimental.FieldDefaults; + +import java.util.List; + +@Data +@FieldDefaults(level= AccessLevel.PRIVATE) +public class PropertiesData { + List<AllOfItem> allOf; + @JsonProperty("$ref") + 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..a06d82efc36ef560619ef37a7618a405a0f7b6b7 --- /dev/null +++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/schema/converter/tags/SchemaRoot.java @@ -0,0 +1,26 @@ +// 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.tags; + +import lombok.AccessLevel; +import lombok.Data; +import lombok.experimental.FieldDefaults; + +@Data +@FieldDefaults(level= AccessLevel.PRIVATE) +public class SchemaRoot { + Definitions definitions; + 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..284d00a63c5215717f64deb52d6a2a6eadf8da29 --- /dev/null +++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/schema/converter/tags/TypeProperty.java @@ -0,0 +1,34 @@ +// 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.tags; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AccessLevel; +import lombok.Data; +import lombok.experimental.FieldDefaults; + +import java.util.Map; + +@Data +@FieldDefaults(level= AccessLevel.PRIVATE) +public class TypeProperty { + String type; + String pattern; + String format; + @JsonProperty("$ref") + String ref; + Items items; + 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..c27c76e6da5a71fdcc0b14901e160ad1dc9d8ff0 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 @@ -39,6 +39,8 @@ 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; @@ -129,7 +131,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 +161,10 @@ public class IndexSchemaServiceImpl implements IndexSchemaService { } } + protected String getSchema(String kind) throws URISyntaxException, UnsupportedEncodingException { + return this.storageService.getStorageSchema(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..9a948287eb22e4dba1a9c4b43b8644b66d518129 --- /dev/null +++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/service/SchemaService.java @@ -0,0 +1,32 @@ +// 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.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/SchemaServiceImpl.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/service/impl/SchemaServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..22600ae59c4e276d877fe3383d96968109f757a6 --- /dev/null +++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/service/impl/SchemaServiceImpl.java @@ -0,0 +1,83 @@ +// 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.service.impl; + +import com.google.api.client.http.HttpMethods; +import lombok.extern.java.Log; +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.model.http.HttpResponse; +import org.opengroup.osdu.core.common.provider.interfaces.IRequestInfo; +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.beans.factory.annotation.Value; +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 +@Log +public class SchemaServiceImpl implements SchemaService { + @Inject + private IUrlFetchService urlFetchService; + + @Value("${SCHEMA_HOST}") + private String SCHEMA_HOST; + + @Inject + private IRequestInfo requestInfo; + + @Inject + private SchemaToStorageFormat schemaToStorageFormat; + + @Inject + private StorageService storageService; + + @Override + public String getSchema(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); + + String url = String.format("%s/%s", SCHEMA_HOST, URLEncoder.encode(kind, StandardCharsets.UTF_8.toString())); + FetchServiceHttpRequest request = FetchServiceHttpRequest.builder() + .httpMethod(HttpMethods.GET) + .headers(this.requestInfo.getHeadersMap()) + .url(url) + .build(); + HttpResponse response = this.urlFetchService.sendRequest(request); + + 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); + } +} 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/SchemaToStorageFormatImplTest.java b/indexer-core/src/test/java/org/opengroup/osdu/indexer/schema/converter/SchemaToStorageFormatImplTest.java new file mode 100644 index 0000000000000000000000000000000000000000..844ea6c4dcc749f0e84cfcccebfc852461b15cf9 --- /dev/null +++ b/indexer-core/src/test/java/org/opengroup/osdu/indexer/schema/converter/SchemaToStorageFormatImplTest.java @@ -0,0 +1,132 @@ +// 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.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; + +import java.io.File; +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 SchemaToStorageFormatImpl schemaToStorageFormatImpl = new SchemaToStorageFormatImpl(objectMapper); + + @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/SchemaServiceImplTest.java b/indexer-core/src/test/java/org/opengroup/osdu/indexer/service/impl/SchemaServiceImplTest.java new file mode 100644 index 0000000000000000000000000000000000000000..74228df4ea6339baf1dc5b7b8ce3fac1852c4fe0 --- /dev/null +++ b/indexer-core/src/test/java/org/opengroup/osdu/indexer/service/impl/SchemaServiceImplTest.java @@ -0,0 +1,75 @@ +// 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.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.InjectMocks; +import org.mockito.Mock; +import org.mockito.Spy; +import org.opengroup.osdu.core.common.http.HttpResponse; +import org.opengroup.osdu.core.common.http.IUrlFetchService; +import org.opengroup.osdu.core.common.provider.interfaces.IRequestInfo; +import org.opengroup.osdu.indexer.schema.converter.SchemaToStorageFormatImpl; +import org.opengroup.osdu.indexer.schema.converter.interfaces.SchemaToStorageFormat; +import org.opengroup.osdu.indexer.service.StorageService; +import org.opengroup.osdu.indexer.service.impl.SchemaServiceImpl; +import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; +import org.springframework.test.context.junit4.SpringRunner; + +import java.io.UnsupportedEncodingException; +import java.net.URISyntaxException; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +@RunWith(SpringRunner.class) +public class SchemaServiceImplTest { + + private ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json().build(); + + @Spy + private SchemaToStorageFormatImpl schemaToStorageFormat = new SchemaToStorageFormatImpl(objectMapper); + + @Mock + private IUrlFetchService urlFetchService; + + @Mock + private IRequestInfo requestInfo; + + @Mock + private StorageService storageService; + + @InjectMocks + private SchemaServiceImpl 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); + + } +} \ 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 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/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..bdbfd7a21bcd931c9401681398a6737d7a730827 --- /dev/null +++ b/indexer-core/src/test/resources/converter/integration-tests/index_records_1.schema @@ -0,0 +1,70 @@ +{ + "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", + "x-slb-aliasProperties": [ + "witsml:GeographicLocationWGS84" + ] + }, + "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..47f2afdeec69897656ccff479735a593d7b3b5a3 --- /dev/null +++ b/indexer-core/src/test/resources/converter/integration-tests/index_records_2.schema @@ -0,0 +1,65 @@ +{ + "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", + "x-slb-aliasProperties": [ + "witsml:GeographicLocationWGS84" + ] + }, + "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..4b11c71a27aabf540833cefd31ecdbc1b54502b2 --- /dev/null +++ b/indexer-core/src/test/resources/converter/integration-tests/index_records_3.schema @@ -0,0 +1,26 @@ +{ + "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", + "x-slb-aliasProperties": [ + "witsml:GeographicLocationWGS84" + ] + }, + "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/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..3151ea79d665a6c90d414be1e67f64294ca61f1a 100644 --- a/provider/indexer-azure/README.md +++ b/provider/indexer-azure/README.md @@ -40,8 +40,9 @@ 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}/api/schema-service/v1/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 | - | | `STORAGE_QUERY_RECORD_FOR_CONVERSION_HOST` | `${storage_service_url}/query/records:batch` | Endpoint of records batch API | no | - | | `KEYVAULT_URI` | ex `https://foo-kv.vault.azure.net/` | . | . | . | diff --git a/provider/indexer-azure/src/main/java/org/opengroup/osdu/indexer/azure/di/IndexSchemaServiceOverrideImpl.java b/provider/indexer-azure/src/main/java/org/opengroup/osdu/indexer/azure/di/IndexSchemaServiceOverrideImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..82a9a05841b69d7907a9e4b3f39320f1853d09b2 --- /dev/null +++ b/provider/indexer-azure/src/main/java/org/opengroup/osdu/indexer/azure/di/IndexSchemaServiceOverrideImpl.java @@ -0,0 +1,29 @@ +package org.opengroup.osdu.indexer.azure.di; + +import lombok.AccessLevel; +import lombok.experimental.FieldDefaults; +import org.opengroup.osdu.indexer.service.IndexSchemaServiceImpl; +import org.opengroup.osdu.indexer.service.SchemaService; +import org.springframework.context.annotation.Primary; +import org.springframework.stereotype.Service; + +import javax.inject.Inject; +import java.io.UnsupportedEncodingException; +import java.net.URISyntaxException; + +@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) +@Primary +@Service +public class IndexSchemaServiceOverrideImpl extends IndexSchemaServiceImpl { + + private SchemaService schemaService; + + @Inject + public IndexSchemaServiceOverrideImpl(SchemaService schemaService) { + this.schemaService = schemaService; + } + + protected String getSchema(String kind) throws URISyntaxException, UnsupportedEncodingException { + return this.schemaService.getSchema(kind); + } +} diff --git a/provider/indexer-azure/src/main/resources/application.properties b/provider/indexer-azure/src/main/resources/application.properties index 65847276eef1fd919d77b81b5c24761661d03d05..5740f5badd3fa92579b7c50bb2ef14a4bfd56a4d 100644 --- a/provider/indexer-azure/src/main/resources/application.properties +++ b/provider/indexer-azure/src/main/resources/application.properties @@ -36,6 +36,9 @@ KINDS_REDIS_DATABASE=1 CRON_INDEX_CLEANUP_THRESHOLD_DAYS=3 CRON_EMPTY_INDEX_CLEANUP_THRESHOLD_DAYS=7 +schema_service_url=${schema_service_endpoint} +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 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..65e6b0d8f5b19e36b9d191d41dfec1e9c89aada1 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 @@ -29,6 +29,7 @@ import org.opengroup.osdu.core.common.logging.JaxRsDpsLog; 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.SchemaService; import org.opengroup.osdu.indexer.service.StorageService; import org.opengroup.osdu.core.common.model.http.RequestStatus; import org.opengroup.osdu.core.common.search.IndicesService; @@ -72,6 +73,8 @@ public class IndexerSchemaServiceTest { @Mock private IndicesService indicesService; @Mock + private SchemaService schemaService; + @Mock private ISchemaCache schemaCache; @InjectMocks private IndexSchemaServiceImpl sut; @@ -85,7 +88,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 +97,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 +106,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 +118,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 +173,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 +204,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 +232,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 +265,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 +292,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 +346,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-azure/src/test/java/org/opengroup/osdu/indexer/azure/service/SchemaServiceTest.java b/provider/indexer-azure/src/test/java/org/opengroup/osdu/indexer/azure/service/SchemaServiceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..a875ff17df26da4e2faf69dc8cf0f9a9d8374c1d --- /dev/null +++ b/provider/indexer-azure/src/test/java/org/opengroup/osdu/indexer/azure/service/SchemaServiceTest.java @@ -0,0 +1,109 @@ +// 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.azure.service; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentMatchers; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Spy; +import org.opengroup.osdu.core.common.http.IUrlFetchService; +import org.opengroup.osdu.core.common.model.http.HttpResponse; +import org.opengroup.osdu.core.common.provider.interfaces.IRequestInfo; +import org.opengroup.osdu.indexer.schema.converter.SchemaToStorageFormatImpl; +import org.opengroup.osdu.indexer.service.StorageService; +import org.opengroup.osdu.indexer.service.impl.SchemaServiceImpl; +import org.springframework.http.HttpStatus; +import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; +import org.springframework.test.context.junit4.SpringRunner; + +import javax.inject.Inject; +import java.util.HashMap; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.powermock.api.mockito.PowerMockito.when; + +@RunWith(SpringRunner.class) +public class SchemaServiceTest { + + private ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json().build(); + + @Spy + private SchemaToStorageFormatImpl schemaToStorageFormatImpl = new SchemaToStorageFormatImpl(objectMapper); + @Mock + private IUrlFetchService urlFetchService; + @Mock + private IRequestInfo requestInfo; + @Mock + private StorageService storageService; + @InjectMocks + private SchemaServiceImpl sut; + + @Before + public void setup() { + when(this.requestInfo.getHeadersMap()).thenReturn(new HashMap<>()); + } + + @Test + public void should_returnValidResponse_givenValidKind_getSchemaByKind() throws Exception { + + String validSchemaFromSchemaService = "{\n" + + " \"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" + + "}"; + String kind = "tenant:test:test:1.0.0"; + + HttpResponse httpResponse = new HttpResponse(); + httpResponse.setResponseCode(HttpStatus.OK.value()); + httpResponse.setBody(validSchemaFromSchemaService); + + when(this.urlFetchService.sendRequest(ArgumentMatchers.any())).thenReturn(httpResponse); + + String recordSchemaResponse = this.sut.getSchema(kind); + + 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(HttpStatus.NOT_FOUND.value()); + + when(this.urlFetchService.sendRequest(ArgumentMatchers.any())).thenReturn(httpResponse); + + String recordSchemaResponse = this.sut.getSchema(kind); + + assertNull(recordSchemaResponse); + } + +} diff --git a/provider/indexer-azure/src/test/java/org/opengroup/osdu/indexer/azure/service/StorageServiceTest.java b/provider/indexer-azure/src/test/java/org/opengroup/osdu/indexer/azure/service/StorageServiceTest.java index d32955169190c779486a55fe6b549b7ef7b20c09..035b64283f6bd4a7e47c94d4582547f580b39073 100644 --- a/provider/indexer-azure/src/test/java/org/opengroup/osdu/indexer/azure/service/StorageServiceTest.java +++ b/provider/indexer-azure/src/test/java/org/opengroup/osdu/indexer/azure/service/StorageServiceTest.java @@ -169,51 +169,6 @@ public class StorageServiceTest { assertNull(recordQueryResponse.getResults()); } - @Test - public void should_returnValidResponse_givenValidKind_getSchemaByKind() throws Exception { - - String validSchemaFromStorage = "{" + - " \"kind\": \"tenant:test:test:1.0.0\"," + - " \"schema\": [" + - " {" + - " \"path\": \"msg\"," + - " \"kind\": \"string\"" + - " }," + - " {" + - " \"path\": \"references.entity\"," + - " \"kind\": \"string\"" + - " }" + - " ]," + - " \"ext\": null" + - "}"; - String kind = "tenant:test:test:1.0.0"; - - HttpResponse httpResponse = new HttpResponse(); - httpResponse.setResponseCode(HttpStatus.OK.value()); - httpResponse.setBody(validSchemaFromStorage); - - when(this.urlFetchService.sendRequest(ArgumentMatchers.any())).thenReturn(httpResponse); - - String recordSchemaResponse = this.sut.getStorageSchema(kind); - - 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(HttpStatus.NOT_FOUND.value()); - - when(this.urlFetchService.sendRequest(ArgumentMatchers.any())).thenReturn(httpResponse); - - String recordSchemaResponse = this.sut.getStorageSchema(kind); - - assertNull(recordSchemaResponse); - } - @Test public void should_returnOneValidRecords_givenValidData_getValidStorageRecordsWithInvalidConversionTest() throws URISyntaxException { 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..1e2f1d82d7b02a4085a11c62daaeeb64a654d50c 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 @@ -28,7 +28,6 @@ import org.opengroup.osdu.core.common.provider.interfaces.IElasticRepository; 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; 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..f68dfa9479849060754ef75138fef5756f23421b 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 @@ -31,7 +31,6 @@ import org.opengroup.osdu.util.LegalTagUtilsAws; 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 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/src/main/java/org/opengroup/osdu/common/CleanupIndiciesSteps.java b/testing/indexer-test-core/src/main/java/org/opengroup/osdu/common/CleanupIndiciesSteps.java index b1f4377b50e9fc71d76e064b91bd716dcbc0d5dc..c87daa7ceb00dda7e1b2239f9ea95292de0d0ff9 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 @@ -60,8 +60,8 @@ public class CleanupIndiciesSteps extends TestsBase { for (Setup input : inputList) { TestIndex testIndex = getTextIndex(); testIndex.setHttpClient(httpClient); - testIndex.setIndex(generateActualName(input.getIndex(), timeStamp)); - testIndex.setKind(generateActualName(input.getKind(), timeStamp)); + testIndex.setIndex(generateActualNameWithTS(input.getIndex(), timeStamp)); + testIndex.setKind(generateActualNameWithTS(input.getKind(), timeStamp)); testIndex.setSchemaFile(input.getSchemaFile()); inputIndexMap.put(testIndex.getKind(), testIndex); } @@ -75,16 +75,16 @@ public class CleanupIndiciesSteps extends TestsBase { } public void iIngestRecordsWithTheforAGiven(String record, String dataGroup, String kind) { - String actualKind = generateActualName(kind, timeStamp); + String actualKind = generateActualNameWithTS(kind, timeStamp); try { String fileContent = FileHandler.readFile(String.format("%s.%s", record, "json")); 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", generateActualNameWithTS(testRecord.get("id").toString(), timeStamp)); testRecord.put("kind", actualKind); testRecord.put("legal", generateLegalTag()); - String[] x_acl = {generateActualName(dataGroup,timeStamp)+"."+getEntitlementsDomain()}; + String[] x_acl = {generateActualNameWithTS(dataGroup,timeStamp)+"."+getEntitlementsDomain()}; Acl acl = Acl.builder().viewers(x_acl).owners(x_acl).build(); testRecord.put("acl", acl); } @@ -97,7 +97,7 @@ public class CleanupIndiciesSteps extends TestsBase { } public void iCheckThatTheIndexForHasBeenCreated(String kind) throws IOException, InterruptedException { - assertTrue(isNewIndexCreated(generateActualName(kind, timeStamp))); + assertTrue(isNewIndexCreated(generateActualNameWithTS(kind, timeStamp))); } public void iShouldDeleteTheRecordsForICreatedEarlier() { @@ -118,13 +118,13 @@ public class CleanupIndiciesSteps extends TestsBase { public void iShouldDeleteTheSchemaForICreatedEarlier(String kind) { ClientResponse response = httpClient.send(HttpMethod.DELETE, - String.format("%sschemas%s", getStorageBaseURL(), "/" + generateActualName(kind, timeStamp)),null, + String.format("%sschemas%s", getStorageBaseURL(), "/" + generateActualNameWithTS(kind, timeStamp)),null, headers, httpClient.getAccessToken()); assertEquals(HttpStatus.SC_NO_CONTENT, response.getStatus()); } public void iShouldCheckThetTheIndexforHasNotBeenDeleted(String kind) throws IOException, InterruptedException { - assertTrue(isNewIndexExist(generateActualName(kind, timeStamp))); + assertTrue(isNewIndexExist(generateActualNameWithTS(kind, timeStamp))); } public void iShouldToRunCleanupOfIndexesForAnd(String kind, String message) { @@ -137,11 +137,11 @@ public class CleanupIndiciesSteps extends TestsBase { } public void iShouldCheckThatTheIndexForHasBeenDeleted(String kind) throws IOException, InterruptedException { - assertFalse(isNewIndexExist(generateActualName(kind, timeStamp))); + assertFalse(isNewIndexExist(generateActualNameWithTS(kind, timeStamp))); } private String convertMessageIntoJson(String kind, String message) { - String actualKind = generateActualName(kind, timeStamp); + String actualKind = generateActualNameWithTS(kind, timeStamp); RecordChangedMessages recordChangedMessages = (new Gson()).fromJson(String.format(message, actualKind, actualKind, timeStamp), RecordChangedMessages.class); return new Gson().toJson(recordChangedMessages); 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..88858df839299d2ffacfebe4bd0c84dd4eb6cbfa 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"); } } @@ -66,43 +73,39 @@ public class RecordSteps extends TestsBase { for (Setup input : inputList) { TestIndex testIndex = getTextIndex(); testIndex.setHttpClient(httpClient); - testIndex.setIndex(generateActualName(input.getIndex(), timeStamp)); - testIndex.setKind(generateActualName(input.getKind(), timeStamp)); + testIndex.setIndex(generateActualNameWithTS(input.getIndex(), timeStamp)); + testIndex.setKind(generateActualNameWithTS(input.getKind(), timeStamp)); testIndex.setSchemaFile(input.getSchemaFile()); inputIndexMap.put(testIndex.getKind(), testIndex); } /******************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) { - String actualKind = generateActualName(kind, timeStamp); + String actualKind = generateActualNameWithTS(kind, timeStamp); try { String fileContent = FileHandler.readFile(String.format("%s.%s", record, "json")); 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()}; + String[] x_acl = {generateActualNameWithTS(dataGroup,timeStamp)+"."+getEntitlementsDomain()}; Acl acl = Acl.builder().viewers(x_acl).owners(x_acl).build(); 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,14 +113,18 @@ public class RecordSteps extends TestsBase { } } + protected String generateRecordId(Map<String, Object> testRecord) { + return generateActualNameWithTS(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); + index = generateActualNameWithTS(index, timeStamp); long numOfIndexedDocuments = createIndex(index); assertEquals(expectedCount, numOfIndexedDocuments); } public void i_should_get_the_elastic_for_the_tenant_testindex_timestamp_well_in_the_Elastic_Search(String expectedMapping, String type, String index) throws Throwable { - index = generateActualName(index, timeStamp); + index = generateActualNameWithTS(index, timeStamp); ImmutableOpenMap<String, MappingMetaData> elasticMapping = elasticUtils.getMapping(index); assertNotNull(elasticMapping); @@ -128,7 +135,7 @@ public class RecordSteps extends TestsBase { } public void iShouldGetTheNumberDocumentsForTheIndexInTheElasticSearchWithOutSkippedAttribute(int expectedCount, String index, String skippedAttributes) throws Throwable { - index = generateActualName(index, timeStamp); + index = generateActualNameWithTS(index, timeStamp); long numOfIndexedDocuments = createIndex(index); long documentCountByQuery = elasticUtils.fetchRecordsByExistQuery(index, skippedAttributes); assertEquals(expectedCount, documentCountByQuery); @@ -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..8e8f0267cfc5b278fd40c6f2d67dc69599484f51 --- /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(generateActualName(s.getIndex()))); + super.addShutDownHook(); + } + + private void createSchema(Setup input) { + PersistentSchemaTestIndex testIndex = new PersistentSchemaTestIndex(super.elasticUtils, super.httpClient, this); + testIndex.setIndex(generateActualNameWithTS(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 generateActualName(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..190007df607312ed783317dcb8cbf6f66e4d0430 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 @@ -54,19 +54,19 @@ public abstract class TestsBase { for (Setup input : inputList) { TestIndex testIndex = getTextIndex(); testIndex.setHttpClient(httpClient); - testIndex.setIndex(generateActualName(input.getIndex(), timeStamp)); - testIndex.setKind(generateActualName(input.getKind(), timeStamp)); + testIndex.setIndex(generateActualNameWithTS(input.getIndex(), timeStamp)); + testIndex.setKind(generateActualNameWithTS(input.getKind(), timeStamp)); testIndex.setMappingFile(input.getMappingFile()); testIndex.setRecordFile(input.getRecordFile()); List<String> dataGroup = new ArrayList<>(); String[] viewerGroup = input.getViewerGroup().split(","); for (int i = 0; i < viewerGroup.length; i++) { - viewerGroup[i] = generateActualName(viewerGroup[i], timeStamp) + "." + getEntitlementsDomain(); + viewerGroup[i] = generateActualNameWithTS(viewerGroup[i], timeStamp) + "." + getEntitlementsDomain(); dataGroup.add(viewerGroup[i]); } String[] ownerGroup = input.getOwnerGroup().split(","); for (int i = 0; i < ownerGroup.length; i ++) { - ownerGroup[i] = generateActualName(ownerGroup[i], timeStamp) + "." + getEntitlementsDomain(); + ownerGroup[i] = generateActualNameWithTS(ownerGroup[i], timeStamp) + "." + getEntitlementsDomain(); if (dataGroup.indexOf(ownerGroup[i]) > 0) { dataGroup.add(ownerGroup[i]); } @@ -123,16 +123,16 @@ 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); + public String generateActualName(String rawName) { + for (Map.Entry<String, String> tenant : tenantMap.entrySet()) { + rawName = rawName.replaceAll(tenant.getKey(), tenant.getValue()); } - return null; + return rawName.replaceAll("<timestamp>", ""); } - protected String generateActualName(String rawName, String timeStamp) { - for (String tenant : tenantMap.keySet()) { - rawName = rawName.replaceAll(tenant, getTenantMapping(tenant)); + protected String generateActualNameWithTS(String rawName, String timeStamp) { + for (Map.Entry<String, String> tenant : tenantMap.entrySet()) { + rawName = rawName.replaceAll(tenant.getKey(), tenant.getValue()); } return rawName.replaceAll("<timestamp>", timeStamp); } 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..7596a20db14c773aabe4bbf0494f517a334cbd26 --- /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.generateActualName(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..41b5ecdff97631c89ccc24f2c9bf15f6e6bf542c 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_SCHEMA_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 = ""; @@ -79,6 +80,10 @@ public class Config { return getEnvironmentVariableOrDefaultValue("STORAGE_HOST", DEFAULT_STORAGE_HOST); } + public static String getSchemaBaseURL() { + return getEnvironmentVariableOrDefaultValue("SCHEMA_HOST", DEFAULT_SCHEMA_HOST); + } + 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/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..5303867c142a05151cc6658343ec9a722c336bce --- /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("/v1/schema/{schema-id}") + .buildAndExpand(id).toUriString(); + } + + private String buildSchemaUri() { + return UriComponentsBuilder.fromHttpUrl(schemaBaseUrl) + .path("/v1/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..5c019df9ac8db7b05e0fa35ec03a53f4fd405178 --- /dev/null +++ b/testing/indexer-test-core/src/main/resources/testData/index_records_1.schema.json @@ -0,0 +1,83 @@ +{ + "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", + "x-slb-aliasProperties": [ + "witsml:GeographicLocationWGS84" + ] + }, + "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..1de2bade1a6862e737a7e2b42338644da9ee5c16 --- /dev/null +++ b/testing/indexer-test-core/src/main/resources/testData/index_records_2.schema.json @@ -0,0 +1,78 @@ +{ + "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", + "x-slb-aliasProperties": [ + "witsml:GeographicLocationWGS84" + ] + }, + "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..dc93c34a63ec6cbf09cbf7ad9a1c0fea041e03cb --- /dev/null +++ b/testing/indexer-test-core/src/main/resources/testData/index_records_3.schema.json @@ -0,0 +1,39 @@ +{ + "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", + "x-slb-aliasProperties": [ + "witsml:GeographicLocationWGS84" + ] + }, + "WellName": { + "type": "string" + } + } + } + ] + } + } + } +} \ No newline at end of file