diff --git a/pdb-ui/src/main/java/org/lucares/pdbui/PdbController.java b/pdb-ui/src/main/java/org/lucares/pdbui/PdbController.java index a4f3cb1..57422e1 100644 --- a/pdb-ui/src/main/java/org/lucares/pdbui/PdbController.java +++ b/pdb-ui/src/main/java/org/lucares/pdbui/PdbController.java @@ -1,6 +1,7 @@ package org.lucares.pdbui; import java.io.FileInputStream; +import java.io.IOException; import java.io.OutputStream; import java.text.Collator; import java.util.ArrayList; @@ -36,7 +37,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.http.CacheControl; import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.util.StreamUtils; import org.springframework.web.bind.annotation.GetMapping; @@ -49,9 +52,13 @@ import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody; +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; + @Controller @EnableAutoConfiguration -public class PdbController implements HardcodedValues { +public class PdbController implements HardcodedValues, PropertyKeys { private static final Logger LOGGER = LoggerFactory.getLogger(PdbController.class); @@ -60,9 +67,12 @@ public class PdbController implements HardcodedValues { private final ReentrantLock plotterLock = new ReentrantLock(); - @Value("${mode.production:true}") + @Value("${" + PRODUCTION_MODE + ":true}") private boolean modeProduction; + @Value("${" + CACHE_IMAGES_DURATION_SECONDS + ":" + CACHE_IMAGES_DURATION_SECONDS_DEFAULT + "}") + private int cacheDurationInSeconds; + public PdbController(final PerformanceDb db, final Plotter plotter) { this.db = db; this.plotter = plotter; @@ -79,13 +89,29 @@ public class PdbController implements HardcodedValues { return new ModelAndView(view, model); } + @RequestMapping(path = "/plots", // + method = RequestMethod.GET, // + consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, // + produces = MediaType.APPLICATION_JSON_UTF8_VALUE // + ) + @ResponseBody + ResponseEntity createPlotGet(@RequestParam(name = "request") final String request) + throws InternalPlottingException, InterruptedException, JsonParseException, JsonMappingException, + IOException { + + final ObjectMapper objectMapper = new ObjectMapper(); + final PlotRequest plotRequest = objectMapper.readValue(request, PlotRequest.class); + + return createPlot(plotRequest); + } + @RequestMapping(path = "/plots", // method = RequestMethod.POST, // consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, // produces = MediaType.APPLICATION_JSON_UTF8_VALUE // ) @ResponseBody - PlotResponse createPlot(@RequestBody final PlotRequest request) + ResponseEntity createPlot(@RequestBody final PlotRequest request) throws InternalPlottingException, InterruptedException { final PlotSettings plotSettings = PlotSettingsTransformer.toSettings(request); @@ -107,7 +133,11 @@ public class PdbController implements HardcodedValues { : imageUrl; final PlotResponseStats stats = PlotResponseStats.fromDataSeries(result.getDataSeries()); - return new PlotResponse(stats, imageUrl, thumbnailUrl); + final PlotResponse plotResponse = new PlotResponse(stats, imageUrl, thumbnailUrl); + + final CacheControl cacheControl = CacheControl.maxAge(cacheDurationInSeconds, TimeUnit.SECONDS); + + return ResponseEntity.ok().cacheControl(cacheControl).body(plotResponse); } catch (final NoDataPointsException e) { throw new NotFoundException(e); } finally { diff --git a/pdb-ui/src/main/java/org/lucares/pdbui/PropertyKeys.java b/pdb-ui/src/main/java/org/lucares/pdbui/PropertyKeys.java index 2995cb9..0cfdfc6 100644 --- a/pdb-ui/src/main/java/org/lucares/pdbui/PropertyKeys.java +++ b/pdb-ui/src/main/java/org/lucares/pdbui/PropertyKeys.java @@ -11,4 +11,20 @@ public interface PropertyKeys { * Path for temporary files */ String TMP_DIR = "path.tmp"; + + /** + * The number of seconds generated images shall be cached. + */ + String CACHE_IMAGES_DURATION_SECONDS = "cache.images.duration.seconds"; + + /** + * Default value for {@link PropertyKeys#CACHE_IMAGES_DURATION_SECONDS} + */ + String CACHE_IMAGES_DURATION_SECONDS_DEFAULT = "3600"; + + /** + * Indicates whether or not this instance is running in production. This + * property is used to switch Vue.js into production or development mode. + */ + String PRODUCTION_MODE = "mode.production"; } diff --git a/pdb-ui/src/main/java/org/lucares/pdbui/WebConfiguration.java b/pdb-ui/src/main/java/org/lucares/pdbui/WebConfiguration.java index 538e68f..7bc7568 100644 --- a/pdb-ui/src/main/java/org/lucares/pdbui/WebConfiguration.java +++ b/pdb-ui/src/main/java/org/lucares/pdbui/WebConfiguration.java @@ -1,19 +1,25 @@ package org.lucares.pdbui; import java.nio.file.Paths; +import java.util.concurrent.TimeUnit; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; +import org.springframework.http.CacheControl; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration -public class WebConfiguration extends WebMvcConfigurerAdapter implements HardcodedValues, PropertyKeys { +public class WebConfiguration implements WebMvcConfigurer, HardcodedValues, PropertyKeys { private final String outputDir; + private final int cacheDurationInSeconds; - public WebConfiguration(@Value("${" + PATH_GENERATED_IMAGES + "}") final String outputDir) { + public WebConfiguration(@Value("${" + PATH_GENERATED_IMAGES + "}") final String outputDir, + @Value("${" + CACHE_IMAGES_DURATION_SECONDS + ":" + CACHE_IMAGES_DURATION_SECONDS_DEFAULT + + "}") final int cacheDurationInSeconds) { this.outputDir = outputDir; + this.cacheDurationInSeconds = cacheDurationInSeconds; } @Override @@ -22,6 +28,7 @@ public class WebConfiguration extends WebMvcConfigurerAdapter implements Hardcod final String pathPattern = "/" + WEB_IMAGE_OUTPUT_PATH + "/**"; final String resourceLocation = "file:" + Paths.get(outputDir).toAbsolutePath() + "/"; - registry.addResourceHandler(pathPattern).addResourceLocations(resourceLocation); + final CacheControl cacheControl = CacheControl.maxAge(cacheDurationInSeconds, TimeUnit.SECONDS); + registry.addResourceHandler(pathPattern).addResourceLocations(resourceLocation).setCacheControl(cacheControl); } } diff --git a/pdb-ui/src/main/resources/application.properties b/pdb-ui/src/main/resources/application.properties index 4328d87..ac2c504 100644 --- a/pdb-ui/src/main/resources/application.properties +++ b/pdb-ui/src/main/resources/application.properties @@ -4,4 +4,6 @@ db.base=${base.dir}/db path.tmp=${base.dir}/tmp path.output=${base.dir}/out +cache.images.duration.seconds=3600 + logging.config=classpath:log4j2.xml diff --git a/pdb-ui/src/main/resources/resources/js/ui.js b/pdb-ui/src/main/resources/resources/js/ui.js index 5ffe810..03ebae5 100644 --- a/pdb-ui/src/main/resources/resources/js/ui.js +++ b/pdb-ui/src/main/resources/resources/js/ui.js @@ -908,7 +908,10 @@ function sendPlotRequest(query){ }; data.searchBar.imagelink = ''; - postJson("plots", request, success, error); + const requestParam = { + 'request': JSON.stringify(request) + }; + getJson("plots", requestParam, success, error) } function updateImageLink(query) { @@ -1002,7 +1005,10 @@ function createDashboardItem(originalQuery, field, imageHeight, imageWidth) data.dashboard.progress.value++; createDashboardItem(originalQuery, field, imageHeight, imageWidth); }; - postJson("plots", request, success, error); + var requestParam = { + request: JSON.stringify(request) + }; + getJson("plots", requestParam, success, error) } } @@ -1045,7 +1051,8 @@ function getJson(url, requestData, successCallback, errorCallback) { type: "GET", url: url, data: requestData, - contentType: 'application/json' + contentType: 'application/json', + cache:true }) .done(successCallback) .fail(errorCallback);