From 9e2a99d93383fd4b08b48c6cd8415dc4391d0aad Mon Sep 17 00:00:00 2001 From: Yurii Kondakov <ykondakov@slb.com> Date: Tue, 20 Jun 2023 15:18:46 +0300 Subject: [PATCH] add request timeout to crs conversion service requests --- .../conversion/CrsConversionService.java | 104 +++++++++++++----- .../osdu/storage/di/CrsConversionConfig.java | 34 ++++++ .../conversion/CrsConversionServiceTest.java | 13 ++- 3 files changed, 122 insertions(+), 29 deletions(-) create mode 100644 storage-core/src/main/java/org/opengroup/osdu/storage/di/CrsConversionConfig.java diff --git a/storage-core/src/main/java/org/opengroup/osdu/storage/conversion/CrsConversionService.java b/storage-core/src/main/java/org/opengroup/osdu/storage/conversion/CrsConversionService.java index ba79800e6..3647fe320 100644 --- a/storage-core/src/main/java/org/opengroup/osdu/storage/conversion/CrsConversionService.java +++ b/storage-core/src/main/java/org/opengroup/osdu/storage/conversion/CrsConversionService.java @@ -1,4 +1,4 @@ -// Copyright 2017-2019, Schlumberger +// Copyright 2017-2023, Schlumberger // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -14,28 +14,60 @@ package org.opengroup.osdu.storage.conversion; -import java.util.*; -import com.google.gson.*; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.base.Strings; +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonNull; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.JsonSyntaxException; import org.apache.http.HttpStatus; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.core.JsonProcessingException; +import org.apache.http.client.config.RequestConfig; import org.opengroup.osdu.core.common.Constants; -import org.opengroup.osdu.core.common.model.crs.*; -import org.opengroup.osdu.core.common.logging.JaxRsDpsLog; -import org.opengroup.osdu.core.common.model.crs.GeoJson.*; -import org.opengroup.osdu.core.common.model.http.AppException; +import org.opengroup.osdu.core.common.crs.CrsConversionServiceErrorMessages; import org.opengroup.osdu.core.common.crs.ICrsConverterFactory; import org.opengroup.osdu.core.common.crs.ICrsConverterService; -import org.opengroup.osdu.core.common.crs.CrsConversionServiceErrorMessages; +import org.opengroup.osdu.core.common.logging.JaxRsDpsLog; +import org.opengroup.osdu.core.common.model.crs.ConvertGeoJsonRequest; +import org.opengroup.osdu.core.common.model.crs.ConvertGeoJsonResponse; +import org.opengroup.osdu.core.common.model.crs.ConvertPointsRequest; +import org.opengroup.osdu.core.common.model.crs.ConvertPointsResponse; +import org.opengroup.osdu.core.common.model.crs.ConvertStatus; +import org.opengroup.osdu.core.common.model.crs.CrsConverterException; +import org.opengroup.osdu.core.common.model.crs.CrsPropertySet; +import org.opengroup.osdu.core.common.model.crs.GeoJson.GeoJsonBase; +import org.opengroup.osdu.core.common.model.crs.GeoJson.GeoJsonFeature; +import org.opengroup.osdu.core.common.model.crs.GeoJson.GeoJsonFeatureCollection; +import org.opengroup.osdu.core.common.model.crs.GeoJson.GeoJsonGeometryCollection; +import org.opengroup.osdu.core.common.model.crs.GeoJson.GeoJsonLineString; +import org.opengroup.osdu.core.common.model.crs.GeoJson.GeoJsonMultiLineString; +import org.opengroup.osdu.core.common.model.crs.GeoJson.GeoJsonMultiPoint; +import org.opengroup.osdu.core.common.model.crs.GeoJson.GeoJsonMultiPolygon; +import org.opengroup.osdu.core.common.model.crs.GeoJson.GeoJsonPoint; +import org.opengroup.osdu.core.common.model.crs.GeoJson.GeoJsonPolygon; +import org.opengroup.osdu.core.common.model.crs.Point; +import org.opengroup.osdu.core.common.model.crs.PointConversionInfo; +import org.opengroup.osdu.core.common.model.crs.RecordsAndStatuses; +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.http.RequestStatus; +import org.opengroup.osdu.core.common.model.storage.ConversionStatus; import org.opengroup.osdu.core.common.util.IServiceAccountJwtClient; +import org.opengroup.osdu.storage.di.CrsConversionConfig; +import org.opengroup.osdu.storage.di.SpringConfig; import org.opengroup.osdu.storage.util.ConversionJsonUtils; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; -import org.springframework.beans.factory.annotation.Autowired; -import org.opengroup.osdu.core.common.model.http.DpsHeaders; -import org.opengroup.osdu.core.common.model.storage.ConversionStatus; -import org.opengroup.osdu.storage.di.SpringConfig; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; import static org.opengroup.osdu.core.common.Constants.*; import static org.opengroup.osdu.core.common.crs.CrsConversionServiceErrorMessages.MISSING_GEOMETRIES; @@ -72,9 +104,13 @@ public class CrsConversionService { @Autowired private SpringConfig springConfig; + @Autowired private ConversionJsonUtils conversionJsonUtils; + @Autowired + private CrsConversionConfig crsConversionConfig; + public RecordsAndStatuses doCrsConversion(List<JsonObject> originalRecords, List<ConversionStatus.ConversionStatusBuilder> conversionStatuses) { RecordsAndStatuses crsConversionResult = new RecordsAndStatuses(); Map<String, List<PointConversionInfo>> pointConversionInfoList = this.gatherCrsConversionData(originalRecords, conversionStatuses); @@ -141,8 +177,7 @@ public class CrsConversionService { } private void gatherCrsGeoJsonConversionData(List<JsonObject> originalRecords, List<ConversionStatus.ConversionStatusBuilder> conversionStatuses) { - for (int i = 0; i < originalRecords.size(); i++) { - JsonObject recordJsonObject = originalRecords.get(i); + for (JsonObject recordJsonObject : originalRecords) { String recordId = this.getRecordId(recordJsonObject); ConversionStatus.ConversionStatusBuilder statusBuilder = this.getConversionStatusBuilderFromList(recordId, conversionStatuses); if(statusBuilder == null){ @@ -150,9 +185,7 @@ public class CrsConversionService { } List<String> validationErrors = new ArrayList<>(); JsonObject filteredObjects = this.dpsConversionService.filterDataFields(recordJsonObject, validationErrors); - Iterator<String> keys = filteredObjects.keySet().iterator(); - while(keys.hasNext()) { - String attributeName = keys.next(); + for (String attributeName : filteredObjects.keySet()) { JsonObject asIngestedCoordinates = filteredObjects.getAsJsonObject(attributeName).getAsJsonObject(AS_INGESTED_COORDINATES); if (asIngestedCoordinates != null) { GeoJsonFeatureCollection fc = new GeoJsonFeatureCollection(); @@ -176,7 +209,7 @@ public class CrsConversionService { } fc.setFeatures(featureArray); - ICrsConverterService crsConverterService = this.crsConverterFactory.create(this.customizeHeaderBeforeCallingCrsConversion(this.dpsHeaders)); + ICrsConverterService crsConverterService = this.crsConverterFactory.create(this.customizeHeaderBeforeCallingCrsConversion(this.dpsHeaders), getRequestConfig()); ConvertGeoJsonRequest request = new ConvertGeoJsonRequest(fc, TO_CRS_GEO_JSON, TO_UNIT_Z); try { if (statusBuilder.getErrors().isEmpty()) { @@ -192,6 +225,10 @@ public class CrsConversionService { } else { this.logger.error(String.format(CrsConversionServiceErrorMessages.CRS_OTHER_ERROR, crsEx.getHttpResponse().toString())); } + } catch (AppException ex) { + if (ex.getError().getCode() == RequestStatus.SOCKET_TIMEOUT) { + statusBuilder.addError(String.format(CrsConversionServiceErrorMessages.CRS_OTHER_ERROR, ex.getError().getMessage())); + } } } else { statusBuilder.addError(CrsConversionServiceErrorMessages.MISSING_AS_INGESTED_COORDINATES); @@ -382,7 +419,7 @@ public class CrsConversionService { originalPoints.add(point); } - ICrsConverterService crsConverterService = this.crsConverterFactory.create(this.customizeHeaderBeforeCallingCrsConversion(this.dpsHeaders)); + ICrsConverterService crsConverterService = this.crsConverterFactory.create(this.customizeHeaderBeforeCallingCrsConversion(this.dpsHeaders), getRequestConfig()); ConvertPointsRequest request = new ConvertPointsRequest(persistableReference, TO_CRS, originalPoints); ConvertPointsResponse response = crsConverterService.convertPoints(request); @@ -424,10 +461,12 @@ public class CrsConversionService { this.logger.error(String.format(CrsConversionServiceErrorMessages.CRS_OTHER_ERROR, cvEx.getHttpResponse().toString())); throw new AppException(HttpStatus.SC_INTERNAL_SERVER_ERROR, UNKNOWN_ERROR, "crs conversion service error."); } - } catch (ClassCastException ccEx) { + } catch (ClassCastException | IllegalStateException ccEx) { statusBuilder.addError(String.format(CrsConversionServiceErrorMessages.ILLEGAL_DATA_IN_NESTED_PROPERTY, nestedFieldName, ccEx.getMessage())); - } catch (IllegalStateException isEx) { - statusBuilder.addError(String.format(CrsConversionServiceErrorMessages.ILLEGAL_DATA_IN_NESTED_PROPERTY, nestedFieldName, isEx.getMessage())); + } catch (AppException ex) { + if (ex.getError().getCode() == RequestStatus.SOCKET_TIMEOUT) { + statusBuilder.addError(String.format(CrsConversionServiceErrorMessages.CRS_OTHER_ERROR, ex.getError().getMessage())); + } } catch (Exception e) { statusBuilder.addError(e.getMessage()); } @@ -449,8 +488,8 @@ public class CrsConversionService { } List<PointConversionInfo> callClientLibraryDoConversion(Map<String, List<PointConversionInfo>> originalPointsMap, List<ConversionStatus.ConversionStatusBuilder> conversionStatuses) { - ICrsConverterService crsConverterService = this.crsConverterFactory.create(this.customizeHeaderBeforeCallingCrsConversion(this.dpsHeaders)); - List<PointConversionInfo> convertedPointInfo = new ArrayList<>(); + ICrsConverterService crsConverterService = this.crsConverterFactory.create(this.customizeHeaderBeforeCallingCrsConversion(this.dpsHeaders), getRequestConfig()); + List<PointConversionInfo> convertedPointInfo = new ArrayList<>(); for (Map.Entry<String, List<PointConversionInfo>> entry : originalPointsMap.entrySet()) { List<Point> pointsToBeConverted = new ArrayList<>(); @@ -470,11 +509,14 @@ public class CrsConversionService { } catch (CrsConverterException e) { if (e.getHttpResponse().IsBadRequestCode()) { convertedPointInfo.addAll(this.putDataErrorFromCrsIntoPointsInfo(pointsList, e.getMessage())); - continue; } else { this.logger.error(String.format(CrsConversionServiceErrorMessages.CRS_OTHER_ERROR, e.getHttpResponse().toString())); throw new AppException(HttpStatus.SC_INTERNAL_SERVER_ERROR, UNKNOWN_ERROR, "crs conversion service error."); } + } catch (AppException ex) { + if (ex.getError().getCode() == RequestStatus.SOCKET_TIMEOUT) { + convertedPointInfo.addAll(this.putDataErrorFromCrsIntoPointsInfo(pointsList, ex.getMessage())); + } } } return convertedPointInfo; @@ -760,4 +802,12 @@ public class CrsConversionService { } return bbox; } + + private RequestConfig getRequestConfig(){ + return RequestConfig.custom() + .setSocketTimeout(crsConversionConfig.getSocketTimeout()) + .setConnectTimeout(crsConversionConfig.getConnectTimeout()) + .setConnectionRequestTimeout(crsConversionConfig.getConnectionRequestTimeout()) + .build(); + } } diff --git a/storage-core/src/main/java/org/opengroup/osdu/storage/di/CrsConversionConfig.java b/storage-core/src/main/java/org/opengroup/osdu/storage/di/CrsConversionConfig.java new file mode 100644 index 000000000..6fd28cd09 --- /dev/null +++ b/storage-core/src/main/java/org/opengroup/osdu/storage/di/CrsConversionConfig.java @@ -0,0 +1,34 @@ +// Copyright 2017-2023, 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.storage.di; + +import lombok.Getter; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; + +@Getter +@Configuration +public class CrsConversionConfig { + + @Value("${crs.conversion.connect.timeout:5000}") + private int connectTimeout; + + @Value("${crs.conversion.socket.timeout:60000}") + private int socketTimeout; + + @Value("${crs.conversion.connection.request.timeout:60000}") + private int connectionRequestTimeout; + +} diff --git a/storage-core/src/test/java/org/opengroup/osdu/storage/conversion/CrsConversionServiceTest.java b/storage-core/src/test/java/org/opengroup/osdu/storage/conversion/CrsConversionServiceTest.java index 242c531d1..4b81e2b6f 100644 --- a/storage-core/src/test/java/org/opengroup/osdu/storage/conversion/CrsConversionServiceTest.java +++ b/storage-core/src/test/java/org/opengroup/osdu/storage/conversion/CrsConversionServiceTest.java @@ -1,4 +1,4 @@ -// Copyright 2017-2019, Schlumberger +// Copyright 2017-2023, Schlumberger // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ package org.opengroup.osdu.storage.conversion; import com.google.gson.JsonObject; import com.google.gson.JsonParser; +import org.apache.http.client.config.RequestConfig; import org.opengroup.osdu.core.common.crs.CrsConversionServiceErrorMessages; import org.opengroup.osdu.core.common.model.crs.*; import org.opengroup.osdu.core.common.model.storage.ConversionStatus; @@ -23,6 +24,7 @@ import org.opengroup.osdu.core.common.model.crs.CrsPropertySet; import org.opengroup.osdu.core.common.model.crs.RecordsAndStatuses; import org.opengroup.osdu.core.common.logging.JaxRsDpsLog; import org.opengroup.osdu.core.common.util.IServiceAccountJwtClient; +import org.opengroup.osdu.storage.di.CrsConversionConfig; import org.opengroup.osdu.storage.di.SpringConfig; import org.apache.http.HttpStatus; import org.junit.Assert; @@ -69,6 +71,9 @@ public class CrsConversionServiceTest { @Mock private SpringConfig springConfig; + @Mock + private CrsConversionConfig crsConversionConfig; + private List<JsonObject> originalRecords = new ArrayList<>(); private List<ConversionStatus.ConversionStatusBuilder> conversionStatuses = new ArrayList<>(); private List<Point> convertedPoints = new ArrayList<>(); @@ -110,6 +115,7 @@ public class CrsConversionServiceTest { private static final String CONVERTED_RECORD_7 = "{\"id\":\"unit-test-6\",\"kind\":\"unit:test:1.0.0\",\"acl\":{\"viewers\":[\"viewers@unittest.com\"],\"owners\":[\"owners@unittest.com\"]},\"legal\":{\"legaltags\":[\"unit-test-legal\"],\"otherRelevantDataCountries\":[\"AA\"]},\"data\":{\"msg\":\"testing record 1\",\"X\":15788.036,\"Y\":9567.4,\"Z\":0.0},\"meta\":[{\"path\":\"\",\"kind\":\"CRS\",\"propertyNames\":[\"X\",\"Y\",\"Z\",\"T\"],\"name\":\"GCS_WGS_1984\",\"persistableReference\":\"%s\"}]}"; private static final String CONVERTED_RECORD_8 = "{\"id\":\"unit-test-20\",\"kind\":\"unit:test:1.0.0\",\"acl\":{\"viewers\":[\"viewers@unittest.com\"],\"owners\":[\"owners@unittest.com\"]},\"legal\":{\"legaltags\":[\"unit-test-legal\"],\"otherRelevantDataCountries\":[\"AA\"]},\"data\":{\"msg\":\"testing record 1\",\"Nested\":{\"X\":15788.036,\"Y\":9567.4},\"Z\":0.0},\"meta\":[{\"path\":\"\",\"kind\":\"CRS\",\"propertyNames\":[\"Nested.X\",\"Nested.Y\"],\"name\":\"GCS_WGS_1984\",\"persistableReference\":\"%s\"}]}"; private static final String CONVERTED_RECORD_9 = "{\"id\":\"unit-test-21\",\"kind\":\"unit:test:1.0.0\",\"acl\":{\"viewers\":[\"viewers@unittest.com\"],\"owners\":[\"owners@unittest.com\"]},\"legal\":{\"legaltags\":[\"unit-test-legal\"],\"otherRelevantDataCountries\":[\"AA\"]},\"data\":{\"msg\":\"testing record 1\",\"Nested\":{\"X\":15788.036,\"Y\":9567.4},\"Z\":0.0},\"meta\":[{\"path\":\"\",\"kind\":\"CRS\",\"propertyNames\":[\"Nested.X\",\"Nested.Y\"],\"name\":\"GCS_WGS_1984\",\"persistableReference\":\"%s\"}]}"; + private static final int TIMEOUT = 60000; @Before public void setup() throws Exception{ @@ -132,7 +138,10 @@ public class CrsConversionServiceTest { when(this.crsPropertySet.getPropertyPairing()).thenReturn(this.pairProperty); when(this.crsPropertySet.getNestedPropertyNames()).thenReturn(this.nestedPropertyNames); - when(this.crsConverterFactory.create(any())).thenReturn(this.crsConverterService); + when(this.crsConversionConfig.getSocketTimeout()).thenReturn(TIMEOUT); + when(this.crsConversionConfig.getConnectTimeout()).thenReturn(TIMEOUT); + when(this.crsConversionConfig.getConnectionRequestTimeout()).thenReturn(TIMEOUT); + when(this.crsConverterFactory.create(any(), any(RequestConfig.class))).thenReturn(this.crsConverterService); when(this.crsConverterService.convertPoints(any())).thenReturn(this.convertPointsResponse); when(this.jwtClient.getIdToken(any())).thenReturn("auth-token-unit-test"); -- GitLab