diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/indexproperty/PropertyConfiguration.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/indexproperty/PropertyConfiguration.java index de4e53f7a8dd1056d3f36cee3aecf659dd24010c..289fd6252c682538bb49371b645ae24f868345d0 100644 --- a/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/indexproperty/PropertyConfiguration.java +++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/indexproperty/PropertyConfiguration.java @@ -19,6 +19,7 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import lombok.ToString; +import org.opengroup.osdu.indexer.util.PropertyUtil; import java.util.List; @@ -41,6 +42,10 @@ public class PropertyConfiguration { @JsonProperty("Paths") private List<PropertyPath> paths; + public String getExtendedPropertyName() { + return PropertyUtil.removeDataPrefix(this.name); + } + public boolean isExtractFirstMatch() { return EXTRACT_FIRST_MATCH_POLICY.equalsIgnoreCase(policy); } @@ -54,7 +59,12 @@ public class PropertyConfiguration { return hasValidPath && (isExtractFirstMatch() || isExtractAllMatches()); } - public String getRelatedObjectKind() { + /** + * Though one extended property can be mapped to a property from different kinds of source objects, we assume + * that all those source properties should have the same schema. + * @return + */ + public String getFirstRelatedObjectKind() { if(paths != null) { for (PropertyPath path : paths) { if (path.isValid() && path.hasValidRelatedObjectsSpec()) { diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/indexproperty/PropertyConfigurations.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/indexproperty/PropertyConfigurations.java index 6fbb00c7727610df9912cdfca75ae315bb409a95..3c0318dc99c530d2e1efae995e440864b7ec5480 100644 --- a/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/indexproperty/PropertyConfigurations.java +++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/indexproperty/PropertyConfigurations.java @@ -53,7 +53,9 @@ public class PropertyConfigurations { Set<String> relatedObjectKinds = new HashSet<>(); for(PropertyConfiguration configuration : configurations) { - String relatedObjectKind = configuration.getRelatedObjectKind(); + // In the same configuration, we can use any related object kind to + // resolve the schema of the extended property in this configuration + String relatedObjectKind = configuration.getFirstRelatedObjectKind(); if(!Strings.isNullOrEmpty(relatedObjectKind)) { relatedObjectKinds.add(relatedObjectKind); } diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/indexproperty/RelatedCondition.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/indexproperty/RelatedCondition.java index ba9683e26dfb1c73e52cf03d77200155c7ed2727..5c087d5b4a64377dcf0d99fa3b123da61514f20d 100644 --- a/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/indexproperty/RelatedCondition.java +++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/indexproperty/RelatedCondition.java @@ -19,6 +19,7 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.google.api.client.util.Strings; import lombok.Data; import lombok.ToString; +import org.opengroup.osdu.indexer.util.PropertyUtil; import java.util.List; @@ -32,27 +33,44 @@ public class RelatedCondition { protected List<String> relatedConditionMatches; + protected boolean hasCondition() { + return !Strings.isNullOrEmpty(relatedConditionProperty) && + relatedConditionMatches != null && + !relatedConditionMatches.isEmpty(); + } + protected boolean hasValidCondition(String property) { - if(Strings.isNullOrEmpty(property) || - Strings.isNullOrEmpty(relatedConditionProperty) || - relatedConditionMatches == null || - relatedConditionMatches.isEmpty()) + if(Strings.isNullOrEmpty(property) || !this.hasCondition()) return false; - if(property.indexOf(ARRAY_SYMBOL + "." ) <= 0 || property.endsWith(ARRAY_SYMBOL) || - relatedConditionProperty.indexOf(ARRAY_SYMBOL + "." ) <= 0 || relatedConditionProperty.endsWith(ARRAY_SYMBOL)) + if((property.endsWith(ARRAY_SYMBOL) || relatedConditionProperty.endsWith(ARRAY_SYMBOL)) || + (property.contains(ARRAY_SYMBOL) && !relatedConditionProperty.contains(ARRAY_SYMBOL)) || + (!property.contains(ARRAY_SYMBOL) && relatedConditionProperty.contains(ARRAY_SYMBOL))) return false; - String delimiter = "\\[\\]\\."; + // If it is not nested object, it is valid in terms of syntax. + if(!property.contains(ARRAY_SYMBOL) && !relatedConditionProperty.contains(ARRAY_SYMBOL)) + return true; + + property = this.getSubstringWithLastArrayField( + PropertyUtil.removeDataPrefix(property)); + String conditionProperty = this.getSubstringWithLastArrayField( + PropertyUtil.removeDataPrefix(relatedConditionProperty)); + + String delimiter = "\\."; String[] propertyParts = property.split(delimiter); - String[] relatedConditionPropertyParts = relatedConditionProperty.split(delimiter); - if(propertyParts.length != relatedConditionPropertyParts.length || propertyParts.length < 2) + String[] relatedConditionPropertyParts = conditionProperty.split(delimiter); + if(propertyParts.length != relatedConditionPropertyParts.length) return false; - for(int i = 0; i < propertyParts.length -1; i++) { + for(int i = 0; i < propertyParts.length; i++) { if(!propertyParts[i].equals(relatedConditionPropertyParts[i])) return false; } return true; } + + private String getSubstringWithLastArrayField(String property) { + return property.substring(0, property.lastIndexOf(ARRAY_SYMBOL)); + } } diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/indexproperty/RelatedObjectsSpec.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/indexproperty/RelatedObjectsSpec.java index 8ff9b57f55e75af1ebaeace577c8475426a0a2c5..bb9c8e076ecedace85be459b8b3f73ce892f5aa7 100644 --- a/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/indexproperty/RelatedObjectsSpec.java +++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/indexproperty/RelatedObjectsSpec.java @@ -38,8 +38,10 @@ public class RelatedObjectsSpec extends RelatedCondition { public boolean isParentToChildren() { return PARENT_TO_CHILDREN.equalsIgnoreCase(relationshipDirection); } public boolean isValid() { - return !Strings.isNullOrEmpty(relatedObjectID) && !Strings.isNullOrEmpty(relatedObjectKind) && - (isChildToParent() || isParentToChildren()); + return !Strings.isNullOrEmpty(relatedObjectID) && + !Strings.isNullOrEmpty(relatedObjectKind) && + (isChildToParent() || isParentToChildren()) && + (!this.hasCondition() || this.hasValidCondition()); } /** @@ -48,6 +50,6 @@ public class RelatedObjectsSpec extends RelatedCondition { * @return */ public boolean hasValidCondition() { - return isValid() && super.hasValidCondition(relatedObjectID); + return super.hasValidCondition(relatedObjectID); } } diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/indexproperty/ValueExtraction.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/indexproperty/ValueExtraction.java index 1ae141d2b31595747afb9dfc1e8a806824a00c33..82eca51d855184199e3a93745cc1fd78621ffedc 100644 --- a/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/indexproperty/ValueExtraction.java +++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/model/indexproperty/ValueExtraction.java @@ -29,7 +29,7 @@ public class ValueExtraction extends RelatedCondition { private String valuePath; public boolean isValid() { - return !Strings.isNullOrEmpty(valuePath); + return !Strings.isNullOrEmpty(valuePath) && (!this.hasCondition() || this.hasValidCondition()); } /** @@ -38,6 +38,6 @@ public class ValueExtraction extends RelatedCondition { * @return */ public boolean hasValidCondition() { - return isValid() && super.hasValidCondition(valuePath); + return super.hasValidCondition(valuePath); } } diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/service/PropertyConfigurationsServiceImpl.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/service/PropertyConfigurationsServiceImpl.java index 91b58d88e6482ccd0273c49c47c15d3b75ce9141..b97465eb4d83c696a320eb8baba6b8f8ebadd361 100644 --- a/indexer-core/src/main/java/org/opengroup/osdu/indexer/service/PropertyConfigurationsServiceImpl.java +++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/service/PropertyConfigurationsServiceImpl.java @@ -19,6 +19,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.base.Strings; import com.google.gson.Gson; +import org.apache.commons.collections.CollectionUtils; import org.opengroup.osdu.core.common.logging.JaxRsDpsLog; import org.opengroup.osdu.core.common.model.http.DpsHeaders; import org.opengroup.osdu.core.common.model.indexer.OperationType; @@ -39,10 +40,8 @@ import org.opengroup.osdu.indexer.util.PropertyUtil; import org.springframework.stereotype.Component; import javax.inject.Inject; -import java.io.UnsupportedEncodingException; import java.net.URISyntaxException; import java.util.*; -import java.util.stream.Collectors; @Component @@ -64,9 +63,15 @@ public class PropertyConfigurationsServiceImpl implements PropertyConfigurations private static final String ARRAY_SYMBOL = "[]"; private static final String SCHEMA_NESTED_KIND = "nested"; + private static final String STRING_KIND = "string"; + + private static final String STRING_ARRAY_KIND = "[]string"; + + private static final PropertyConfigurations EMPTY_CONFIGURATIONS = new PropertyConfigurations(); + private static final String SEARCH_GENERAL_ERROR = "Failed to call search service."; + private final Gson gson = new Gson(); private final ObjectMapper objectMapper = new ObjectMapper(); - private final PropertyConfigurations EMPTY_CONFIGURATIONS = new PropertyConfigurations(); @Inject private IndexerConfigurationProperties configurationProperties; @@ -170,12 +175,13 @@ public class PropertyConfigurationsServiceImpl implements PropertyConfigurations @Override public Map<String, Object> getExtendedProperties(String objectId, Map<String, Object> originalDataMap, PropertyConfigurations propertyConfigurations) { + // Get all data maps of the related objects in one query in order to improve the performance. + Map<String, Map<String, Object>> idObjectDataMap = getRelatedObjectsData(originalDataMap, propertyConfigurations); + Set<String> associatedIdentities = new HashSet<>(); Map<String, Object> extendedDataMap = new HashMap<>(); - - Map<String, Map<String, Object>> idObjectDataMap = getRelatedObjectsData(originalDataMap, propertyConfigurations); - for (PropertyConfiguration configuration : propertyConfigurations.getConfigurations().stream().filter(c -> c.isValid()).collect(Collectors.toList())) { - String extendedPropertyName = configuration.getName(); + for (PropertyConfiguration configuration : propertyConfigurations.getConfigurations().stream().filter(c -> c.isValid()).toList()) { + String extendedPropertyName = configuration.getExtendedPropertyName(); if (originalDataMap.containsKey(extendedPropertyName) && originalDataMap.get(extendedPropertyName) != null) { // If the original record already has the property, then we should not override. // For example, if the trajectory record already SpatialLocation value, then it should not be overridden by the SpatialLocation of the well bore. @@ -183,7 +189,7 @@ public class PropertyConfigurationsServiceImpl implements PropertyConfigurations } Map<String, Object> allPropertyValues = new HashMap<>(); - for (PropertyPath path : configuration.getPaths().stream().filter(p -> p.hasValidValueExtraction()).collect(Collectors.toList())) { + for (PropertyPath path : configuration.getPaths().stream().filter(p -> p.hasValidValueExtraction()).toList()) { if (path.hasValidRelatedObjectsSpec()) { RelatedObjectsSpec relatedObjectsSpec = path.getRelatedObjectsSpec(); if (relatedObjectsSpec.isChildToParent()) { @@ -206,11 +212,11 @@ public class PropertyConfigurationsServiceImpl implements PropertyConfigurations } } else { List<SearchRecord> childrenRecords = searchChildrenRecords(relatedObjectsSpec.getRelatedObjectKind(), relatedObjectsSpec.getRelatedObjectID(), objectId); - for (SearchRecord record : childrenRecords) { - // If the child record is in the cache, that means the record was updated very recently. - // In this case, use the cache's record instead of the record from search result - RecordData cachedRecordData = this.relatedObjectCache.get(record.getId()); - Map<String, Object> childDataMap = (cachedRecordData != null)? cachedRecordData.getData() : record.getData(); + for (SearchRecord searchRecord : childrenRecords) { + // If the child record is in the cache, that means the searchRecord was updated very recently. + // In this case, use the cache's record instead of the searchRecord from search result + RecordData cachedRecordData = this.relatedObjectCache.get(searchRecord.getId()); + Map<String, Object> childDataMap = (cachedRecordData != null)? cachedRecordData.getData() : searchRecord.getData(); Map<String, Object> propertyValues = getExtendedPropertyValues(extendedPropertyName, childDataMap, path.getValueExtraction(), configuration.isExtractFirstMatch()); if (allPropertyValues.isEmpty() && configuration.isExtractFirstMatch()) { allPropertyValues = propertyValues; @@ -246,10 +252,10 @@ public class PropertyConfigurationsServiceImpl implements PropertyConfigurations public List<SchemaItem> getExtendedSchemaItems(Schema originalSchema, Map<String, Schema> relatedObjectKindSchemas, PropertyConfigurations propertyConfigurations) { List<SchemaItem> extendedSchemaItems = new ArrayList<>(); boolean hasChildToParentRelationship = false; - for (PropertyConfiguration configuration : propertyConfigurations.getConfigurations().stream().filter(c -> c.isValid()).collect(Collectors.toList())) { + for (PropertyConfiguration configuration : propertyConfigurations.getConfigurations().stream().filter(c -> c.isValid()).toList()) { Schema schema = null; PropertyPath propertyPath = null; - for (PropertyPath path : configuration.getPaths().stream().filter(p -> p.hasValidRelatedObjectsSpec()).collect(Collectors.toList())) { + for (PropertyPath path : configuration.getPaths().stream().filter(p -> p.hasValidRelatedObjectsSpec()).toList()) { RelatedObjectsSpec relatedObjectsSpec = path.getRelatedObjectsSpec(); if (relatedObjectsSpec.isChildToParent()) { hasChildToParentRelationship = true; @@ -370,6 +376,10 @@ public class PropertyConfigurationsServiceImpl implements PropertyConfigurations return extendedSchemaItem; } + private String createIdsQuery(List<String> ids) { + return String.format("id: (%s)", createIdsFilter(ids)); + } + private String createIdsFilter(List<String> ids) { StringBuilder idsBuilder = new StringBuilder(); for (String id : ids) { @@ -420,8 +430,8 @@ public class PropertyConfigurationsServiceImpl implements PropertyConfigurations private Map<String, Map<String, Object>> getRelatedObjectsData(Map<String, Object> originalDataMap, PropertyConfigurations propertyConfigurations) { Map<String, Map<String, Object>> idData = new HashMap<>(); Map<String, Set<String>> kindIds = new HashMap<>(); - for (PropertyConfiguration configuration : propertyConfigurations.getConfigurations().stream().filter(c -> c.isValid()).collect(Collectors.toList())) { - for (PropertyPath path : configuration.getPaths().stream().filter(p -> p.hasValidValueExtraction()).collect(Collectors.toList())) { + for (PropertyConfiguration configuration : propertyConfigurations.getConfigurations().stream().filter(c -> c.isValid()).toList()) { + for (PropertyPath path : configuration.getPaths().stream().filter(p -> p.hasValidValueExtraction()).toList()) { if (path.hasValidRelatedObjectsSpec()) { RelatedObjectsSpec relatedObjectsSpec = path.getRelatedObjectsSpec(); List<String> relatedObjectIds = getRelatedObjectIds(originalDataMap, relatedObjectsSpec); @@ -441,7 +451,7 @@ public class PropertyConfigurationsServiceImpl implements PropertyConfigurations for (String recordId : entry.getValue()) { String id = PropertyUtil.removeIdPostfix(recordId); RecordData recordData = relatedObjectCache.get(id); - Map<String, Object> data = (recordData != null)? recordData.getData() : null;; + Map<String, Object> data = (recordData != null)? recordData.getData() : null; if (data != null) { idData.put(id, data); } else { @@ -450,7 +460,7 @@ public class PropertyConfigurationsServiceImpl implements PropertyConfigurations } } } - if (kindsToSearch.size() > 0) { + if (!kindsToSearch.isEmpty()) { List<SearchRecord> records = searchRelatedRecords(kindsToSearch, idsToSearch); for (SearchRecord searchRecord : records) { Map<String, Object> data = searchRecord.getData(); @@ -511,34 +521,35 @@ public class PropertyConfigurationsServiceImpl implements PropertyConfigurations private List<SchemaItem> getExtendedSchemaItems(Schema schema, PropertyConfiguration configuration, PropertyPath propertyPath) { String relatedPropertyPath = PropertyUtil.removeDataPrefix(propertyPath.getValueExtraction().getValuePath()); + List<SchemaItem> extendedSchemaItems; if (relatedPropertyPath.contains(ARRAY_SYMBOL)) { // Nested - List<SchemaItem> extendedSchemaItems = new ArrayList<>(); extendedSchemaItems = cloneExtendedSchemaItemsFromNestedSchema(Arrays.asList(schema.getSchema()), configuration, relatedPropertyPath); - if (extendedSchemaItems.isEmpty()) { - // It is possible that the format of the source property is not defined - // In this case, we assume that the format of property is string in order to make its value(s) searchable - SchemaItem extendedSchemaItem = new SchemaItem(); - extendedSchemaItem.setPath(configuration.getName()); - if (configuration.isExtractFirstMatch()) { - extendedSchemaItem.setKind("string"); - } else { - extendedSchemaItem.setKind("[]string"); - } - extendedSchemaItems.add(extendedSchemaItem); - } - return extendedSchemaItems; } else {// Flatten - List<SchemaItem> schemaItems = Arrays.asList(schema.getSchema()); - return cloneExtendedSchemaItems(schemaItems, configuration, relatedPropertyPath); + extendedSchemaItems = cloneExtendedSchemaItems(Arrays.asList(schema.getSchema()), configuration, relatedPropertyPath); + } + + if (extendedSchemaItems.isEmpty()) { + // It is possible that the format (or schema) of the source property is not defined. + // In this case, we assume that the format of property is string in order to make its value(s) searchable + SchemaItem extendedSchemaItem = new SchemaItem(); + extendedSchemaItem.setPath(configuration.getExtendedPropertyName()); + if (configuration.isExtractFirstMatch()) { + extendedSchemaItem.setKind(STRING_KIND); + } else { + extendedSchemaItem.setKind(STRING_ARRAY_KIND); + } + extendedSchemaItems.add(extendedSchemaItem); } + return extendedSchemaItems; } private List<SchemaItem> cloneExtendedSchemaItems(List<SchemaItem> schemaItems, PropertyConfiguration configuration, String relatedPropertyPath) { List<SchemaItem> extendedSchemaItems = new ArrayList<>(); + String extendedPropertyName = configuration.getExtendedPropertyName(); for (SchemaItem schemaItem : schemaItems) { if (PropertyUtil.isPropertyPathMatched(schemaItem.getPath(), relatedPropertyPath)) { String path = schemaItem.getPath(); - path = path.replace(relatedPropertyPath, configuration.getName()); + path = path.replace(relatedPropertyPath, extendedPropertyName); SchemaItem extendedSchemaItem = new SchemaItem(); extendedSchemaItem.setPath(path); if (configuration.isExtractFirstMatch()) { @@ -580,8 +591,8 @@ public class PropertyConfigurationsServiceImpl implements PropertyConfigurations Map<String, Object> propertyValues = getPropertyValues(dataMap, relatedObjectsSpec.getRelatedObjectID(), relatedObjectsSpec, relatedObjectsSpec.hasValidCondition(), false); List<String> relatedObjectIds = new ArrayList<>(); for (Object value : propertyValues.values()) { - if (value instanceof List) { - for (Object obj : (List) value) { + if (value instanceof List<? extends Object> values) { + for (Object obj : values) { relatedObjectIds.add(obj.toString()); } } else { @@ -605,78 +616,113 @@ public class PropertyConfigurationsServiceImpl implements PropertyConfigurations String conditionProperty = null; List<String> conditionMatches = null; if (hasValidCondition) { - int idx = relatedCondition.getRelatedConditionProperty().lastIndexOf(NESTED_OBJECT_DELIMITER); - conditionProperty = relatedCondition.getRelatedConditionProperty().substring(idx + NESTED_OBJECT_DELIMITER.length()); + conditionProperty = relatedCondition.getRelatedConditionProperty(); conditionMatches = relatedCondition.getRelatedConditionMatches(); } - List<Object> valueList = getPropertyValuesFromNestedObjects(dataMap, valuePath, conditionProperty, conditionMatches, hasValidCondition, isExtractFirstMatch); - if (!valueList.isEmpty()) { - if (isExtractFirstMatch) { - propertyValues.put(valuePath, valueList.get(0)); - } else { - propertyValues.put(valuePath, valueList); - } - } + propertyValues = getPropertyValuesFromNestedObjects(dataMap, valuePath, conditionProperty, conditionMatches, hasValidCondition, isExtractFirstMatch); } else { // Flatten - for (Map.Entry<String, Object> entry : dataMap.entrySet()) { - String key = entry.getKey(); - if ((key.equals(valuePath) || key.startsWith(valuePath + PROPERTY_DELIMITER)) && entry.getValue() != null) { - if (isExtractFirstMatch) { - propertyValues.put(key, entry.getValue()); - } else { + String conditionProperty = null; + List<String> conditionMatches = null; + if (hasValidCondition) { + conditionProperty = relatedCondition.getRelatedConditionProperty(); + conditionMatches = relatedCondition.getRelatedConditionMatches(); + } + propertyValues = getPropertyValueOfNoneNestedProperty(dataMap, valuePath, conditionProperty, conditionMatches, hasValidCondition); + if(!isExtractFirstMatch) { + Map<String, Object> tmpValues = new HashMap<>(); + for(Map.Entry<String, Object> entry : propertyValues.entrySet()) { + if (entry.getValue() instanceof List<? extends Object>) { + tmpValues.put(entry.getKey(), entry.getValue()); + } + else { List<Object> values = new ArrayList<>(); values.add(entry.getValue()); - propertyValues.put(key, values); + tmpValues.put(entry.getKey(), values); } } + propertyValues = tmpValues; } } return propertyValues; } - private List<Object> getPropertyValuesFromNestedObjects(Map<String, Object> dataMap, String valuePath, String conditionProperty, List<String> conditionMatches, boolean hasCondition, boolean isExtractFirstMatch) { - Set<Object> propertyValues = new HashSet<>(); + private Map<String, Object> getPropertyValuesFromNestedObjects(Map<String, Object> dataMap, String valuePath, String conditionProperty, List<String> conditionMatches, boolean hasCondition, boolean isExtractFirstMatch) { + Map<String, Object> propertyValues = new HashMap<>(); if (valuePath.contains(ARRAY_SYMBOL)) { int idx = valuePath.indexOf(NESTED_OBJECT_DELIMITER); String prePath = valuePath.substring(0, idx); String postPath = valuePath.substring(idx + NESTED_OBJECT_DELIMITER.length()); + if(conditionProperty != null) { + idx = conditionProperty.indexOf(NESTED_OBJECT_DELIMITER); + if(idx > 0) { + conditionProperty = conditionProperty.substring(idx + NESTED_OBJECT_DELIMITER.length()); + } + else { + // Should not reach here + conditionProperty = null; + } + } try { if (dataMap.containsKey(prePath) && dataMap.get(prePath) != null) { List<Map<String, Object>> nestedObjects = (List<Map<String, Object>>) dataMap.get(prePath); for (Map<String, Object> nestedObject : nestedObjects) { - List<Object> valueList = getPropertyValuesFromNestedObjects(nestedObject, postPath, conditionProperty, conditionMatches, hasCondition, isExtractFirstMatch); - if (valueList != null && !valueList.isEmpty()) { - propertyValues.addAll(valueList); - if (isExtractFirstMatch) - break; + Map<String, Object> subPropertyValues = getPropertyValuesFromNestedObjects(nestedObject, postPath, conditionProperty, conditionMatches, hasCondition, isExtractFirstMatch); + for (Map.Entry<String, Object> entry: subPropertyValues.entrySet()) { + String key = prePath + ARRAY_SYMBOL + PROPERTY_DELIMITER + entry.getKey(); + if(isExtractFirstMatch) { + propertyValues.put(key, entry.getValue()); + } + else { + List<Object> values = propertyValues.containsKey(key) + ? (List<Object>)propertyValues.get(key) + : new ArrayList<>(); + if(entry.getValue() instanceof List<? extends Object> valueList) { + values.addAll(valueList); + } + else { + values.add(entry.getValue()); + } + propertyValues.put(key, values); + } } + if (isExtractFirstMatch) + break; } } } catch (Exception ex) { //Ignore cast exception } - } else if (dataMap.containsKey(valuePath) && dataMap.get(valuePath) != null) { - Object extractPropertyValue = dataMap.get(valuePath); - if (hasCondition) { - if (dataMap.containsKey(conditionProperty) && dataMap.get(conditionProperty) != null) { - String conditionPropertyValue = dataMap.get(conditionProperty).toString(); - if (conditionMatches.contains(conditionPropertyValue) && extractPropertyValue != null) { - propertyValues.add(extractPropertyValue); + } else { + propertyValues = getPropertyValueOfNoneNestedProperty(dataMap, valuePath, conditionProperty, conditionMatches, hasCondition); + } + return propertyValues; + } + + private Map<String, Object> getPropertyValueOfNoneNestedProperty(Map<String, Object> dataMap, String valuePath, String conditionProperty, List<String> conditionMatches, boolean hasCondition) { + Map<String, Object> propertyValue = PropertyUtil.getValueOfNoneNestedProperty(valuePath, dataMap); + if(!propertyValue.isEmpty() && hasCondition) { + boolean matched = false; + Map<String, Object> conditionPropertyValue = PropertyUtil.getValueOfNoneNestedProperty(conditionProperty, dataMap); + if (conditionPropertyValue.containsKey(conditionProperty)) { + for(String condition: conditionMatches) { + if(PropertyUtil.isMatch(conditionPropertyValue.get(conditionProperty).toString(), condition)) { + matched = true; + break; } } - } else { - propertyValues.add(extractPropertyValue); + } + if(!matched) { + // Reset the propertyValue if there is no match + propertyValue = new HashMap<>(); } } - - List<Object> propertyValueList = new ArrayList<>(propertyValues); - Collections.sort(propertyValueList, Comparator.comparing(Object::toString)); - return propertyValueList; + return propertyValue; } + private List<String> getChildrenKinds(String parentKind) { final String parentKindWithMajor = PropertyUtil.getKindWithMajor(parentKind); ChildrenKinds childrenKinds = childrenKindsCache.get(parentKindWithMajor); @@ -709,7 +755,7 @@ public class PropertyConfigurationsServiceImpl implements PropertyConfigurations p.hasValidRelatedObjectsSpec() && p.getRelatedObjectsSpec().isParentToChildren() && p.getRelatedObjectsSpec().getRelatedObjectKind().contains(childKindWithMajor)) - .collect(Collectors.toList()); + .toList(); for(PropertyPath propertyPath: matchedPropertyPaths) { ParentChildRelationshipSpec spec = toParentChildRelationshipSpec(propertyPath, configurations.getCode(), childKindWithMajor); boolean merged = false; @@ -748,13 +794,14 @@ public class PropertyConfigurationsServiceImpl implements PropertyConfigurations private void updateAssociatedParentRecords(String ancestors, String childKind, List<RecordChangeInfo> childRecordChangeInfos) { ParentChildRelationshipSpecs specs = getParentChildRelatedObjectsSpecs(childKind); - Set ancestorSet = new HashSet<>(Arrays.asList(ancestors.split(ANCESTRY_KINDS_DELIMITER))); + Set<String> ancestorSet = new HashSet<>(Arrays.asList(ancestors.split(ANCESTRY_KINDS_DELIMITER))); for (ParentChildRelationshipSpec spec : specs.getSpecList()) { - List childRecordIds = getChildRecordIdsWithExtendedPropertiesChanged(spec, childRecordChangeInfos); - if (childRecordIds.isEmpty()) - continue; + List<String> childRecordIds = getChildRecordIdsWithExtendedPropertiesChanged(spec, childRecordChangeInfos); - List<String> parentIds = searchUniqueParentIds(childKind, childRecordIds, spec.getParentObjectIdPath()); + List<String> parentIds = new ArrayList<>(); + if (!childRecordIds.isEmpty()) { + parentIds = searchUniqueParentIds(childKind, childRecordIds, spec.getParentObjectIdPath()); + } if (parentIds.isEmpty()) continue; @@ -820,7 +867,7 @@ public class PropertyConfigurationsServiceImpl implements PropertyConfigurations if(propertyConfigurations != null) { for (PropertyConfiguration propertyConfiguration : propertyConfigurations.getConfigurations()) { for (PropertyPath propertyPath : propertyConfiguration.getPaths().stream().filter( - p -> p.hasValidValueExtraction() && p.hasValidRelatedObjectsSpec()).collect(Collectors.toList())) { + p -> p.hasValidValueExtraction() && p.hasValidRelatedObjectsSpec()).toList()) { String relatedObjectKind = propertyPath.getRelatedObjectsSpec().getRelatedObjectKind(); String valuePath = PropertyUtil.removeDataPrefix(propertyPath.getValueExtraction().getValuePath()); @@ -828,7 +875,7 @@ public class PropertyConfigurationsServiceImpl implements PropertyConfigurations RecordChangeInfo parentRecordChangeInfo = parentRecordChangeInfos.stream().filter(info -> { if (PropertyUtil.hasSameMajorKind(info.getRecordInfo().getKind(), relatedObjectKind)) { List<String> matchedProperties = info.getUpdatedProperties().stream().filter( - p -> PropertyUtil.isPropertyPathMatched(p, valuePath) || PropertyUtil.isPropertyPathMatched(valuePath, p)).collect(Collectors.toList()); + p -> PropertyUtil.isPropertyPathMatched(p, valuePath) || PropertyUtil.isPropertyPathMatched(valuePath, p)).toList(); return !matchedProperties.isEmpty(); } return false; @@ -844,13 +891,13 @@ public class PropertyConfigurationsServiceImpl implements PropertyConfigurations } private void updateAssociatedChildrenRecords(String ancestors, String parentKind, List<RecordChangeInfo> recordChangeInfos) { - List<String> processedIds = recordChangeInfos.stream().map(recordChangeInfo -> recordChangeInfo.getRecordInfo().getId()).collect(Collectors.toList()); + List<String> processedIds = recordChangeInfos.stream().map(recordChangeInfo -> recordChangeInfo.getRecordInfo().getId()).toList(); String query = String.format("data.%s:(%s)", ASSOCIATED_IDENTITIES_PROPERTY, createIdsFilter(processedIds)); List<String> childrenKinds = getChildrenKinds(parentKind); for (String ancestryKind : ancestors.split(ANCESTRY_KINDS_DELIMITER)) { // Exclude the kinds in the ancestryKinds to prevent circular chasing - childrenKinds.removeIf(k -> ancestryKind.contains(k)); + childrenKinds.removeIf(ancestryKind::contains); } if(childrenKinds.isEmpty()) { return; @@ -866,18 +913,18 @@ public class PropertyConfigurationsServiceImpl implements PropertyConfigurations searchRequest.setQuery(query); searchRequest.setReturnedFields(Arrays.asList("kind", "id", "data." + ASSOCIATED_IDENTITIES_PROPERTY)); List<RecordInfo> recordInfos = new ArrayList<>(); - for (SearchRecord record : searchRecordsWithCursor(searchRequest)) { - Map<String, Object> data = record.getData(); + for (SearchRecord searchRecord : searchRecordsWithCursor(searchRequest)) { + Map<String, Object> data = searchRecord.getData(); if (!data.containsKey(ASSOCIATED_IDENTITIES_PROPERTY) || data.get(ASSOCIATED_IDENTITIES_PROPERTY) == null) continue; List<String> associatedParentIds = (List<String>) data.get(ASSOCIATED_IDENTITIES_PROPERTY); List<RecordChangeInfo> associatedParentRecordChangeInfos = recordChangeInfos.stream().filter( - info -> associatedParentIds.contains(info.getRecordInfo().getId())).collect(Collectors.toList()); - if (areExtendedPropertiesChanged(record.getKind(), associatedParentRecordChangeInfos)) { + info -> associatedParentIds.contains(info.getRecordInfo().getId())).toList(); + if (areExtendedPropertiesChanged(searchRecord.getKind(), associatedParentRecordChangeInfos)) { RecordInfo recordInfo = new RecordInfo(); - recordInfo.setKind(record.getKind()); - recordInfo.setId(record.getId()); + recordInfo.setKind(searchRecord.getKind()); + recordInfo.setId(searchRecord.getId()); recordInfo.setOp(OperationType.update.getValue()); recordInfos.add(recordInfo); @@ -900,7 +947,7 @@ public class PropertyConfigurationsServiceImpl implements PropertyConfigurations String latestKind = null; try { SchemaInfoResponse response = schemaService.getSchemaInfos(kind.getAuthority(), kind.getSource(), kind.getType(), majorVersion, null, null, true); - if (response != null && response.getSchemaInfos() != null && response.getSchemaInfos().size() > 0) { + if (response != null && !CollectionUtils.isEmpty(response.getSchemaInfos())) { SchemaInfo schemaInfo = response.getSchemaInfos().get(0); SchemaIdentity schemaIdentity = schemaInfo.getSchemaIdentity(); latestKind = schemaIdentity.getAuthority() + ":" + @@ -910,9 +957,7 @@ public class PropertyConfigurationsServiceImpl implements PropertyConfigurations schemaIdentity.getSchemaVersionMinor() + "." + schemaIdentity.getSchemaVersionPatch(); } - } catch (URISyntaxException e) { - jaxRsDpsLog.error("failed to get schema info", e); - } catch (UnsupportedEncodingException e) { + } catch (Exception e) { jaxRsDpsLog.error("failed to get schema info", e); } @@ -984,7 +1029,7 @@ public class PropertyConfigurationsServiceImpl implements PropertyConfigurations kinds.add(kind); } searchRequest.setKind(kinds); - String query = String.format("id: (%s)", createIdsFilter(relatedObjectIds)); + String query = createIdsQuery(relatedObjectIds); searchRequest.setQuery(query); return searchRecords(searchRequest); } @@ -994,16 +1039,16 @@ public class PropertyConfigurationsServiceImpl implements PropertyConfigurations SearchRequest searchRequest = new SearchRequest(); String kind = PropertyUtil.isConcreteKind(majorKind) ? majorKind : majorKind + "*"; searchRequest.setKind(kind); - String query = String.format("id: (%s)", createIdsFilter(ids)); + String query = createIdsQuery(ids); searchRequest.setReturnedFields(Arrays.asList("kind", "id")); searchRequest.setQuery(query); - for (SearchRecord record : searchRecords(searchRequest)) { - if (kindIds.containsKey(record.getKind())) { - kindIds.get(record.getKind()).add(record.getId()); + for (SearchRecord searchRecord : searchRecords(searchRequest)) { + if (kindIds.containsKey(searchRecord.getKind())) { + kindIds.get(searchRecord.getKind()).add(searchRecord.getId()); } else { List<String> idList = new ArrayList<>(); - idList.add(record.getId()); - kindIds.put(record.getKind(), idList); + idList.add(searchRecord.getId()); + kindIds.put(searchRecord.getKind(), idList); } } return kindIds; @@ -1013,13 +1058,13 @@ public class PropertyConfigurationsServiceImpl implements PropertyConfigurations Set<String> parentIds = new HashSet<>(); SearchRequest searchRequest = new SearchRequest(); searchRequest.setKind(childKind); - String query = String.format("id: (%s)", createIdsFilter(childRecordIds)); + String query = createIdsQuery(childRecordIds); searchRequest.setReturnedFields(Arrays.asList(parentObjectIdPath)); searchRequest.setQuery(query); parentObjectIdPath = PropertyUtil.removeDataPrefix(parentObjectIdPath); - for (SearchRecord record : searchRecords(searchRequest)) { - if (record.getData().containsKey(parentObjectIdPath)) { - Object id = record.getData().get(parentObjectIdPath); + for (SearchRecord searchRecord : searchRecords(searchRequest)) { + if (searchRecord.getData().containsKey(parentObjectIdPath)) { + Object id = searchRecord.getData().get(parentObjectIdPath); if (id != null && !parentIds.contains(id)) { parentIds.add(id.toString()); } @@ -1045,7 +1090,7 @@ public class PropertyConfigurationsServiceImpl implements PropertyConfigurations do { SearchResponse searchResponse = searchService.queryWithCursor(searchRequest); results = searchResponse.getResults(); - if (results != null && results.size() > 0) { + if (!CollectionUtils.isEmpty(results)) { allRecords.addAll(results); if (!Strings.isNullOrEmpty(searchResponse.getCursor()) && results.size() == MAX_SEARCH_LIMIT) { searchRequest.setCursor(searchResponse.getCursor()); @@ -1053,7 +1098,7 @@ public class PropertyConfigurationsServiceImpl implements PropertyConfigurations } } while(results != null && results.size() == MAX_SEARCH_LIMIT); } catch (URISyntaxException e) { - jaxRsDpsLog.error("Failed to call search service.", e); + jaxRsDpsLog.error(SEARCH_GENERAL_ERROR, e); } return allRecords; } @@ -1068,14 +1113,14 @@ public class PropertyConfigurationsServiceImpl implements PropertyConfigurations do { SearchResponse searchResponse = searchService.query(searchRequest); results = searchResponse.getResults(); - if (results != null && results.size() > 0) { + if (!CollectionUtils.isEmpty(results)) { allRecords.addAll(results); offset += results.size(); searchRequest.setOffset(offset); } } while(results != null && results.size() == MAX_SEARCH_LIMIT); } catch (URISyntaxException e) { - jaxRsDpsLog.error("Failed to call search service.", e); + jaxRsDpsLog.error(SEARCH_GENERAL_ERROR, e); } return allRecords; } @@ -1089,7 +1134,7 @@ public class PropertyConfigurationsServiceImpl implements PropertyConfigurations return results.get(0); } } catch (URISyntaxException e) { - jaxRsDpsLog.error("Failed to call search service.", e); + jaxRsDpsLog.error(SEARCH_GENERAL_ERROR, e); } return null; } diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/service/SearchServiceImpl.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/service/SearchServiceImpl.java index 51f39344987c7b6ff700bc59b3ae10ed8aa5335f..5f7ca991920c174f0248b470aa1e018ff577b048 100644 --- a/indexer-core/src/main/java/org/opengroup/osdu/indexer/service/SearchServiceImpl.java +++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/service/SearchServiceImpl.java @@ -33,6 +33,7 @@ import java.net.URISyntaxException; @Component public class SearchServiceImpl implements SearchService { + private static final String ERROR_MESSAGE = "Search service: failed to call the search service."; private static final String QUERY_PATH = "query"; private static final String QUERY_WITH_CURSOR_PATH = "query_with_cursor"; private final Gson gson = new Gson(); @@ -78,9 +79,9 @@ public class SearchServiceImpl implements SearchService { return gson.fromJson(response.getBody(), SearchResponse.class); } else { if (response != null) - jaxRsDpsLog.error(String.format("Search service: failed to call the search service: %d", response.getResponseCode())); + jaxRsDpsLog.error(ERROR_MESSAGE + String.format(" responseCode = %d", response.getResponseCode())); else - jaxRsDpsLog.error(String.format("Search service: failed to call the search service. The response is null.")); + jaxRsDpsLog.error(String.format(ERROR_MESSAGE + " The response is null.")); return new SearchResponse(); } } @@ -88,7 +89,7 @@ public class SearchServiceImpl implements SearchService { throw ex; } catch(Exception ex) { - jaxRsDpsLog.error(String.format("Search service: failed to call the search service", ex)); + jaxRsDpsLog.error(ERROR_MESSAGE, ex); throw new URISyntaxException(ex.getMessage(), "Unexpected exception type: " + ex.getClass().getName()); } } diff --git a/indexer-core/src/main/java/org/opengroup/osdu/indexer/util/PropertyUtil.java b/indexer-core/src/main/java/org/opengroup/osdu/indexer/util/PropertyUtil.java index 49a7175ee43287395f3bfc28fe1a3f2d2acba903..86771914ae0e8c54d7bb3e3cfe7fdb81d172748b 100644 --- a/indexer-core/src/main/java/org/opengroup/osdu/indexer/util/PropertyUtil.java +++ b/indexer-core/src/main/java/org/opengroup/osdu/indexer/util/PropertyUtil.java @@ -21,6 +21,8 @@ import com.google.common.collect.Maps; import org.opengroup.osdu.indexer.model.Kind; import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; public class PropertyUtil { public static final String DATA_VIRTUAL_DEFAULT_LOCATION = "data.VirtualProperties.DefaultLocation"; @@ -42,6 +44,33 @@ public class PropertyUtil { return !Strings.isNullOrEmpty(propertyPath) && (propertyPath.startsWith(parentPropertyPath + PROPERTY_DELIMITER) || propertyPath.equals(parentPropertyPath)); } + public static Map<String, Object> getValueOfNoneNestedProperty(String propertyPath, Map<String, Object> data) { + if(Strings.isNullOrEmpty(propertyPath) || propertyPath.contains(ARRAY_SYMBOL) || data == null || data.isEmpty()) + return new HashMap<>(); + + Map<String, Object> values = new HashMap<>(); + if(data.containsKey(propertyPath)) { + values.put(propertyPath, data.get(propertyPath)); + } + else { + for (String key : data.keySet()) { + if (propertyPath.startsWith(key + PROPERTY_DELIMITER)) { + Object v = data.get(key); + if (v instanceof Map) { + propertyPath = propertyPath.substring((key + PROPERTY_DELIMITER).length()); + Map<String, Object> subPropertyValues = getValueOfNoneNestedProperty(propertyPath, (Map<String, Object>) v); + for (Map.Entry<String, Object> entry: subPropertyValues.entrySet()) { + values.put(key + PROPERTY_DELIMITER + entry.getKey(), entry.getValue()); + } + } + } else if (key.startsWith(propertyPath + PROPERTY_DELIMITER)) { + values.put(key, data.get(key)); + } + } + } + return values; + } + public static boolean hasSameMajorKind(String left, String right) { try { Kind leftKind = new Kind(left); @@ -258,4 +287,22 @@ public class PropertyUtil { return new ArrayList<>(changedProperties); } + + /* + * matchCondition can be either non-empty string or regular expression + */ + public static boolean isMatch(String propertyValue, String matchCondition) { + if(Strings.isNullOrEmpty(propertyValue) || Strings.isNullOrEmpty(matchCondition)) + return false; + + try { + Pattern pattern = Pattern.compile(matchCondition); + Matcher matcher = pattern.matcher(propertyValue); + return matcher.find(); + } + catch(Exception ex) { + // If matchCondition is not regex, do string compare + return propertyValue.equals(matchCondition); + } + } } diff --git a/indexer-core/src/test/java/org/opengroup/osdu/indexer/model/indexproperty/RelatedObjectsSpecTest.java b/indexer-core/src/test/java/org/opengroup/osdu/indexer/model/indexproperty/RelatedObjectsSpecTest.java index 63a53c37d41db25c2ae8284fe6947016ad40906c..52945410cdf23e67e8017346ffb4caa72a87ac77 100644 --- a/indexer-core/src/test/java/org/opengroup/osdu/indexer/model/indexproperty/RelatedObjectsSpecTest.java +++ b/indexer-core/src/test/java/org/opengroup/osdu/indexer/model/indexproperty/RelatedObjectsSpecTest.java @@ -108,14 +108,14 @@ public class RelatedObjectsSpecTest { } @Test - public void hasValidCondition_return_false_for_none_nested_property() { + public void hasValidCondition_return_true_for_none_nested_property() { RelatedObjectsSpec spec = new RelatedObjectsSpec(); spec.setRelatedObjectKind("osdu:wks:master-data--GeoPoliticalEntity:1."); spec.setRelatedObjectID("data.GeoContexts.GeoPoliticalEntityID"); spec.setRelatedConditionProperty("data.GeoContexts.GeoTypeID"); List<String> matches = Arrays.asList("opendes:reference-data--GeoPoliticalEntityType:Country:"); spec.setRelatedConditionMatches(matches); - Assert.assertFalse(spec.hasValidCondition()); + Assert.assertTrue(spec.hasValidCondition()); } } diff --git a/indexer-core/src/test/java/org/opengroup/osdu/indexer/model/indexproperty/ValueExtractionTest.java b/indexer-core/src/test/java/org/opengroup/osdu/indexer/model/indexproperty/ValueExtractionTest.java index 4c578c9a400250d5c69cb5259d8cd0ee53031281..c1db28ecf18ea6feba6ae561510ae68ac08f155e 100644 --- a/indexer-core/src/test/java/org/opengroup/osdu/indexer/model/indexproperty/ValueExtractionTest.java +++ b/indexer-core/src/test/java/org/opengroup/osdu/indexer/model/indexproperty/ValueExtractionTest.java @@ -98,12 +98,22 @@ public class ValueExtractionTest { } @Test - public void hasValidCondition_return_false_for_none_nested_property() { + public void hasValidCondition_return_true_for_property_under_same_none_nested_property() { ValueExtraction valueExtraction = new ValueExtraction(); valueExtraction.setValuePath("data.NameAliases.AliasName"); valueExtraction.setRelatedConditionProperty("data.NameAliases.AliasNameTypeID"); List<String> matches = Arrays.asList("opendes:reference-data--AliasNameType:UniqueIdentifier:","reference-data--AliasNameType:RegulatoryName:"); valueExtraction.setRelatedConditionMatches(matches); - Assert.assertFalse(valueExtraction.hasValidCondition()); + Assert.assertTrue(valueExtraction.hasValidCondition()); + } + + @Test + public void hasValidCondition_return_true_for_property_under_different_none_nested_property() { + ValueExtraction valueExtraction = new ValueExtraction(); + valueExtraction.setValuePath("data.NameAliases.AliasName"); + valueExtraction.setRelatedConditionProperty("data.AliasNameTypeID"); + List<String> matches = Arrays.asList("opendes:reference-data--AliasNameType:UniqueIdentifier:","reference-data--AliasNameType:RegulatoryName:"); + valueExtraction.setRelatedConditionMatches(matches); + Assert.assertTrue(valueExtraction.hasValidCondition()); } } diff --git a/indexer-core/src/test/java/org/opengroup/osdu/indexer/service/PropertyConfigurationsServiceImplTest.java b/indexer-core/src/test/java/org/opengroup/osdu/indexer/service/PropertyConfigurationsServiceImplTest.java index e68ca9dbf6870b80157bc25115fb679d2ba9abfd..4c5be0ea97eb23ba1d257c6e56bff84a7c5724d8 100644 --- a/indexer-core/src/test/java/org/opengroup/osdu/indexer/service/PropertyConfigurationsServiceImplTest.java +++ b/indexer-core/src/test/java/org/opengroup/osdu/indexer/service/PropertyConfigurationsServiceImplTest.java @@ -267,8 +267,8 @@ public class PropertyConfigurationsServiceImplTest { Assert.assertEquals(value, extendedProperties.get(name)); } else if(value instanceof List) { - List<String> expectedValues = (List<String>)value; - List<String> values = (List<String>)extendedProperties.get(name); + List<String> expectedValues = ((List<String>)value).stream().sorted().toList(); + List<String> values = ((List<String>)extendedProperties.get(name)).stream().sorted().toList(); Assert.assertEquals(expectedValues.size(), values.size()); for(int i = 0; i < expectedValues.size(); i++) { Assert.assertEquals(expectedValues.get(i), values.get(i)); diff --git a/indexer-core/src/test/java/org/opengroup/osdu/indexer/util/PropertyUtilTest.java b/indexer-core/src/test/java/org/opengroup/osdu/indexer/util/PropertyUtilTest.java index 683953925ea222178228f6ed4b4b348148b9b476..b041ae6550d83fa9d4cab2c85a96acea0817278e 100644 --- a/indexer-core/src/test/java/org/opengroup/osdu/indexer/util/PropertyUtilTest.java +++ b/indexer-core/src/test/java/org/opengroup/osdu/indexer/util/PropertyUtilTest.java @@ -44,6 +44,41 @@ public class PropertyUtilTest { Assert.assertFalse(PropertyUtil.isPropertyPathMatched(null, "data.ProjectedBottomHole")); } + @Test + public void getValueOfNoneNestedProperty() { + Map<String, Object> data = this.getDataMap("wellLog.json"); + + Map<String, Object> value = PropertyUtil.getValueOfNoneNestedProperty("SpatialLocation.SpatialGeometryTypeID", data); + Assert.assertTrue(value.containsKey("SpatialLocation.SpatialGeometryTypeID")); + Assert.assertEquals("opendes:reference-data--SpatialGeometryType:Point:", value.get("SpatialLocation.SpatialGeometryTypeID").toString()); + + value = PropertyUtil.getValueOfNoneNestedProperty("SpatialLocation.Wgs84Coordinates.type", data); + Assert.assertTrue(value.containsKey("SpatialLocation.Wgs84Coordinates.type")); + Assert.assertEquals("geometrycollection", value.get("SpatialLocation.Wgs84Coordinates.type").toString()); + + List<String> propertyNamesWithValues = Arrays.asList( + "SpatialLocation.SpatialGeometryTypeID", + "SpatialLocation.Wgs84Coordinates", + "SpatialLocation.IsDecimated"); + List<String> propertyNamesWithNullValues = Arrays.asList( + "SpatialLocation.SpatialParameterTypeID", + "SpatialLocation.CoordinateQualityCheckPerformedBy", + "SpatialLocation.QualitativeSpatialAccuracyTypeID", + "SpatialLocation.QuantitativeAccuracyBandID"); + value = PropertyUtil.getValueOfNoneNestedProperty("SpatialLocation", data); + for(String propertyName : propertyNamesWithValues) { + Assert.assertTrue(value.containsKey(propertyName)); + Assert.assertNotNull(value.get(propertyName)); + } + for(String propertyName : propertyNamesWithNullValues) { + Assert.assertTrue(value.containsKey(propertyName)); + Assert.assertNull(value.get(propertyName)); + } + + value = PropertyUtil.getValueOfNoneNestedProperty("Curves[].CurveID", data); + Assert.assertTrue(value.isEmpty()); + } + @Test public void hasSameMajorVersion() { Assert.assertTrue(PropertyUtil.hasSameMajorKind("osdu:wks:master-data--Well:1.0.0", "osdu:wks:master-data--Well:1.0.0")); @@ -272,6 +307,20 @@ public class PropertyUtilTest { changedProperties.forEach(p -> Assert.assertTrue(expectedChangedWellLogProperties.contains(p))); } + @Test + public void isMatch_for_String() { + Assert.assertTrue(PropertyUtil.isMatch("opendes:reference-data--AliasNameType:UniqueIdentifier:", "opendes:reference-data--AliasNameType:UniqueIdentifier:")); + Assert.assertFalse(PropertyUtil.isMatch("OPENDES:reference-data--AliasNameType:UniqueIdentifier:", "opendes:reference-data--AliasNameType:UniqueIdentifier:")); + } + + @Test + public void isMatch_for_Regex() { + Assert.assertTrue(PropertyUtil.isMatch("opendes:master-data--Wellbore:F03B95515F91--2B886EAF-83A9-4811-9068", "^[\\w\\-\\.]+:master-data\\-\\-Wellbore:[\\w\\-\\.\\:\\%]+$")); + Assert.assertTrue(PropertyUtil.isMatch("opendes:work-product-component--WellLog:8CAFB37C-A674-42F8-ABCD-34BA8E6C1480", "^[\\w\\-\\.]+:work-product-component\\-\\-WellLog:[\\w\\-\\.\\:\\%]+$")); + Assert.assertTrue(PropertyUtil.isMatch("opendes:work-product-component--Document:wks-0f2546ca6b45960fa32db", "^[\\w\\-\\.]+:work-product-component\\-\\-Document:[\\w\\-\\.\\:\\%]+$")); + } + + private Map<String, Object> getDataMap(String file) { String jsonText = getJsonFromFile(file); Type type = new TypeToken<Map<String, Object>>() {}.getType(); diff --git a/indexer-core/src/test/resources/indexproperty/well_configuration_record.json b/indexer-core/src/test/resources/indexproperty/well_configuration_record.json index 0cf4995d3cdd40b537d685b2fd7af394605df845..a4fae666ff9c9d51214a293bc6c5da7cabd9b926 100644 --- a/indexer-core/src/test/resources/indexproperty/well_configuration_record.json +++ b/indexer-core/src/test/resources/indexproperty/well_configuration_record.json @@ -21,7 +21,7 @@ "Paths": [{ "RelatedObjectsSpec.RelatedObjectID": "data.GeoContexts[].GeoPoliticalEntityID", "RelatedObjectsSpec.RelatedConditionMatches": [ - "opendes:reference-data--GeoPoliticalEntityType:Country:" + "^[\\w\\-\\.]+:reference-data\\-\\-GeoPoliticalEntityType:Country:$" ], "ValueExtraction.ValuePath": "data.GeoPoliticalEntityName", "RelatedObjectsSpec.RelatedObjectKind": "osdu:wks:master-data--GeoPoliticalEntity:1.", @@ -41,11 +41,11 @@ "RelatedObjectsSpec.RelatedConditionProperty": null, "RelatedObjectsSpec.RelationshipDirection": null, "ValueExtraction.RelatedConditionMatches": [ - "opendes:reference-data--AliasNameType:UniqueIdentifier:", - "opendes:reference-data--AliasNameType:RegulatoryName:", - "opendes:reference-data--AliasNameType:PreferredName:", - "opendes:reference-data--AliasNameType:CommonName:", - "opendes:reference-data--AliasNameType:ShortName:" + "^[\\w\\-\\.]+:reference-data--AliasNameType:UniqueIdentifier:$", + "^[\\w\\-\\.]+:reference-data--AliasNameType:RegulatoryName:$", + "^[\\w\\-\\.]+:reference-data--AliasNameType:PreferredName:$", + "^[\\w\\-\\.]+:reference-data--AliasNameType:CommonName:$", + "^[\\w\\-\\.]+:reference-data--AliasNameType:ShortName:$" ], "ValueExtraction.RelatedConditionProperty": "data.NameAliases[].AliasNameTypeID" } diff --git a/testing/indexer-test-core/src/main/resources/testData/osdu_wks_IndexPropertyPathConfiguration_v1.json b/testing/indexer-test-core/src/main/resources/testData/osdu_wks_IndexPropertyPathConfiguration_v1.json index f8ba28eb63ab5e68676610c029c12defbd962e2e..075c70f17e80ba2680fcb6f00538990bec20d43c 100644 --- a/testing/indexer-test-core/src/main/resources/testData/osdu_wks_IndexPropertyPathConfiguration_v1.json +++ b/testing/indexer-test-core/src/main/resources/testData/osdu_wks_IndexPropertyPathConfiguration_v1.json @@ -51,11 +51,11 @@ "Paths": [{ "ValueExtraction": { "RelatedConditionMatches": [ - "tenant1:reference-data--AliasNameType:UniqueIdentifier:", - "tenant1:reference-data--AliasNameType:RegulatoryName:", - "tenant1:reference-data--AliasNameType:PreferredName:", - "tenant1:reference-data--AliasNameType:CommonName:", - "tenant1:reference-data--AliasNameType:ShortName:" + "^[\\w\\-\\.]+:reference-data\\-\\-AliasNameType:UniqueIdentifier:$", + "^[\\w\\-\\.]+:reference-data\\-\\-AliasNameType:RegulatoryName:$", + "^[\\w\\-\\.]+:reference-data\\-\\-AliasNameType:PreferredName:$", + "^[\\w\\-\\.]+:reference-data\\-\\-AliasNameType:CommonName:$", + "^[\\w\\-\\.]+:reference-data\\-\\-AliasNameType:ShortName:$" ], "RelatedConditionProperty": "data.NameAliases[].AliasNameTypeID", "ValuePath": "data.NameAliases[].AliasName"