Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package fr.birdia.tile19.exception;

public class BlankImageException extends RuntimeException {
public BlankImageException(String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import fr.birdia.tile19.concurrency.Workers;
import fr.birdia.tile19.model.airbus.AirbusProperties;
import fr.birdia.tile19.service.airbus.AirbusPNEOService;
import fr.birdia.tile19.validator.ImageValidator;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
Expand Down Expand Up @@ -40,18 +41,21 @@ public class ImageExtenderService {
private ImageDegraderService imageDegraderService;
private AirbusPNEOService airbusPNEOService;
private AirbusProperties airbusProperties;
private ImageValidator imageValidator;

public ImageExtenderService(
TilesDownloaderService downloader,
TilesMergerService merger,
Workers workers,
ImageDegraderService imageDegraderService,
AirbusPNEOService airbusPNEOService) {
AirbusPNEOService airbusPNEOService,
ImageValidator imageValidator) {
this.tileDownloader = downloader;
this.tileMerger = merger;
this.workers = workers;
this.imageDegraderService = imageDegraderService;
this.airbusPNEOService = airbusPNEOService;
this.imageValidator = imageValidator;
}

public String getLastUpdatedAtAirbus() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import fr.birdia.tile19.model.airbus.AirbusProperties;
import fr.birdia.tile19.service.airbus.AirbusPNEOService;
import fr.birdia.tile19.validator.ImageValidator;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
Expand Down Expand Up @@ -35,6 +36,7 @@ public class TilesDownloaderService {
private final XYZToBBOXService xyzToBBoxService;
private final AirbusPNEOService airbusPNEOService;
private RestTemplate restTemplate;
private ImageValidator imageValidator;

static double[] tileToLatLon(int x, int y, int zoom) {
int n = (int) Math.pow(2, zoom);
Expand Down Expand Up @@ -141,7 +143,10 @@ public BufferedImage download(int xTile, int yTile, int zoom, String server, Str
String contentType = response.headers().firstValue("Content-Type").orElse("");
if (contentType.startsWith("image")) {
try (InputStream is = response.body()) {
return ImageIO.read(is);
BufferedImage img = ImageIO.read(is);
log.info("Process image validator");
imageValidator.accept(img);
return img;
}
} else {
String error = new String(response.body().readAllBytes(), StandardCharsets.UTF_8);
Expand Down
68 changes: 68 additions & 0 deletions src/main/java/fr/birdia/tile19/validator/ImageValidator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package fr.birdia.tile19.validator;

import static org.springframework.http.MediaType.APPLICATION_JSON;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import fr.birdia.tile19.exception.BlankImageException;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;
import javax.imageio.ImageIO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.*;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

@Component
@Slf4j
public class ImageValidator implements Consumer<BufferedImage> {
private static final String IMAGE_VALIDATOR_API_URL = System.getenv("IMAGE_VALIDATOR_API_URL");
private final RestTemplate restTemplate;
private final ObjectMapper objectMapper;

public ImageValidator(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
this.objectMapper = new ObjectMapper();
}

@Override
public void accept(BufferedImage image) {
if (image == null) {
throw new BlankImageException("Image is null.");
}

try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(image, "jpeg", baos);
byte[] imageBytes = baos.toByteArray();
String base64 = Base64.getEncoder().encodeToString(imageBytes);
Map<String, String> body = new HashMap<>();
body.put("base64image", base64);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(APPLICATION_JSON);
HttpEntity<Map<String, String>> request = new HttpEntity<>(body, headers);
ResponseEntity<String> response =
restTemplate.postForEntity(IMAGE_VALIDATOR_API_URL, request, String.class);

if (!response.getStatusCode().is2xxSuccessful()) {
throw new RuntimeException("Validator API error: " + response.getStatusCode());
}

JsonNode jsonNode = objectMapper.readTree(response.getBody());
log.info("Validator response raw: {}", response.getBody());
boolean isCorrupted = jsonNode.get("isCorrupted").asBoolean();

if (isCorrupted) {
throw new BlankImageException("Image is corrupted.");
}

} catch (IOException e) {
throw new RuntimeException("Error processing image", e);
}
}
}
24 changes: 24 additions & 0 deletions src/test/java/fr/birdia/tile19/ImageExtenderIT.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import static fr.birdia.tile19.model.TileExtenderRequestBody.ShiftDirection.UP_DOWN_SIDE;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;

import fr.birdia.tile19.conf.FacadeIT;
import fr.birdia.tile19.endpoint.rest.controller.TileExtenderController;
Expand Down Expand Up @@ -175,6 +176,28 @@ public TileExtenderRequestBody airbusBody() {
.build();
}

public TileExtenderRequestBody throwBlankExceptionBody() {
return TileExtenderRequestBody.builder()
.x(521906)
.y(368610)
.z(20)
.server("geoserver")
.layer("PCRS")
.shiftNb(0)
.isCropped(false)
.latitude(47.047005283518075)
.longitude(-0.8176651895582759)
.isOpaque(false)
.build();
}

@Test
void test_throw_blank_exception() throws Exception {
assertThrows(
RuntimeException.class,
() -> tileExtenderController.extendImage(throwBlankExceptionBody()));
}

@Test
void test_ign_tile19() throws Exception {
ResponseEntity<String> response = tileExtenderController.extendImage(ignBody());
Expand All @@ -183,6 +206,7 @@ void test_ign_tile19() throws Exception {

@ParameterizedTest(name = "Download image for {0}")
@MethodSource("cityTileProvider")
@Disabled
public void extend_dijon(CityTileTestCase city) throws Exception {
log.info("Processing city={}", city.city());
TileExtenderRequestBody body = createTileExtenderRequestBodyFrom(city);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import fr.birdia.tile19.service.TilesMergerService;
import fr.birdia.tile19.service.XYZToBBOXService;
import fr.birdia.tile19.service.airbus.AirbusPNEOService;
import fr.birdia.tile19.validator.ImageValidator;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
Expand All @@ -26,19 +27,21 @@
public class ImageExtenderServiceTest {
XYZToBBOXService xyzToBBOXService = new XYZToBBOXService();
RestTemplate restTemplate = new RestTemplate();
ImageValidator imageValidator = new ImageValidator(restTemplate);
AirbusPNEOService airbusPNEOService =
new AirbusPNEOService(
restTemplate,
System.getenv("AIRBUS_AUTHENTICATION_BASEURL"),
System.getenv("AIRBUS_API_KEY"),
System.getenv("AIRBUS_SEARCHAPI_BASEURL"));
TilesDownloaderService downloader =
new TilesDownloaderService(xyzToBBOXService, airbusPNEOService, restTemplate);
new TilesDownloaderService(xyzToBBOXService, airbusPNEOService, restTemplate, imageValidator);
TilesMergerService merger = new TilesMergerService();
Workers workers = new Workers();
ImageDegraderService imageDegrader = new ImageDegraderService();
ImageExtenderService extender =
new ImageExtenderService(downloader, merger, workers, imageDegrader, airbusPNEOService);
new ImageExtenderService(
downloader, merger, workers, imageDegrader, airbusPNEOService, imageValidator);

@Test
public void full_herault_image_extension_ok() throws Exception {
Expand Down
6 changes: 4 additions & 2 deletions src/test/java/fr/birdia/tile19/unit/TilesDownloaderTest.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package fr.birdia.tile19.unit;

import static org.junit.Assert.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNotNull;

import fr.birdia.tile19.service.TilesDownloaderService;
import fr.birdia.tile19.service.XYZToBBOXService;
import fr.birdia.tile19.service.airbus.AirbusPNEOService;
import fr.birdia.tile19.validator.ImageValidator;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
Expand All @@ -23,8 +24,9 @@ public class TilesDownloaderTest {
System.getenv("AIRBUS_AUTHENTICATION_BASEURL"),
System.getenv("AIRBUS_API_KEY"),
System.getenv("AIRBUS_SEARCHAPI_BASEURL"));
ImageValidator imageValidator = new ImageValidator(restTemplate);
TilesDownloaderService tilesDownloaderService =
new TilesDownloaderService(xyzToBBOXService, airbusPNEOService, restTemplate);
new TilesDownloaderService(xyzToBBOXService, airbusPNEOService, restTemplate, imageValidator);

@Test
public void tiles_downloader_geoserver_ok() throws IOException, InterruptedException {
Expand Down