Skip to content

Commit cac3b45

Browse files
New forceFailOnError configuration parameter to set once failOnError for all layers (#3623)
* Add forceFailOnError configuration parameter to set failOnError on all layers
1 parent 1d5656e commit cac3b45

8 files changed

Lines changed: 432 additions & 0 deletions

File tree

core/src/main/java/org/mapfish/print/attribute/map/GenericMapAttribute.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import org.mapfish.print.config.Configuration;
1919
import org.mapfish.print.config.ConfigurationException;
2020
import org.mapfish.print.config.Template;
21+
import org.mapfish.print.map.AbstractLayerParams;
2122
import org.mapfish.print.map.MapLayerFactoryPlugin;
2223
import org.mapfish.print.parser.HasDefaultValue;
2324
import org.mapfish.print.parser.MapfishParser;
@@ -462,6 +463,11 @@ private void parseSingleLayer(final List<MapLayer> layerList, final PObject laye
462463
layerParser.getTypeNames().contains(layer.getString(TYPE).toLowerCase());
463464
if (layerApplies) {
464465
Object param = layerParser.createParameter();
466+
// We force fail on error parameter if requested in the template configuration
467+
if (param instanceof AbstractLayerParams abstractLayerParams
468+
&& this.template.getConfiguration().isForceFailOnError()) {
469+
abstractLayerParams.failOnError = true;
470+
}
465471

466472
MapfishParser.parse(
467473
this.template.getConfiguration().isThrowErrorOnExtraParameters(), layer, param, TYPE);

core/src/main/java/org/mapfish/print/config/Configuration.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@ public class Configuration implements ConfigurationObject {
107107
private Set<String> jdbcDrivers = new HashSet<>();
108108
private Map<String, Style> namedStyles = new HashMap<>();
109109
private UriMatchers allowedReferers = null;
110+
private boolean forceFailOnError = false;
111+
110112
private SmtpConfig smtp = null;
111113

112114
/** The color used to draw the WMS tiles error default: transparent pink. */
@@ -728,4 +730,19 @@ public SmtpConfig getSmtp() {
728730
public void setSmtp(final SmtpConfig smtp) {
729731
this.smtp = smtp;
730732
}
733+
734+
/** Get the forceFailOnError parameter value. */
735+
public boolean isForceFailOnError() {
736+
return forceFailOnError;
737+
}
738+
739+
/**
740+
* Set the param forceFailOnError.
741+
*
742+
* @param forceFailOnError if true all the rendered layers will have the parameter {@link
743+
* org.mapfish.print.map.AbstractLayerParams#failOnError} set to true.
744+
*/
745+
public void setForceFailOnError(final boolean forceFailOnError) {
746+
this.forceFailOnError = forceFailOnError;
747+
}
731748
}

core/src/test/java/org/mapfish/print/TestHttpClientFactory.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ public void registerHandler(Predicate<URI> matcher, Handler handler) {
3636
handlers.put(matcher, handler);
3737
}
3838

39+
public void resetHandlers() {
40+
handlers.clear();
41+
}
42+
3943
@Nonnull
4044
@Override
4145
public ConfigurableRequest createRequest(@Nonnull URI uri, @Nonnull final HttpMethod httpMethod) {
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
package org.mapfish.print.processor.map;
2+
3+
import java.io.IOException;
4+
import java.net.URI;
5+
import java.util.HashMap;
6+
import java.util.Map;
7+
import java.util.concurrent.CancellationException;
8+
import java.util.concurrent.TimeUnit;
9+
import java.util.concurrent.atomic.AtomicBoolean;
10+
import java.util.function.Function;
11+
import org.junit.Assert;
12+
import org.junit.Test;
13+
import org.junit.jupiter.api.Timeout;
14+
import org.mapfish.print.AbstractMapfishSpringTest;
15+
import org.mapfish.print.PrintException;
16+
import org.mapfish.print.TestHttpClientFactory;
17+
import org.mapfish.print.config.Configuration;
18+
import org.mapfish.print.config.ConfigurationFactory;
19+
import org.mapfish.print.output.AbstractJasperReportOutputFormat;
20+
import org.mapfish.print.output.OutputFormat;
21+
import org.mapfish.print.wrapper.json.PJsonObject;
22+
import org.springframework.beans.factory.annotation.Autowired;
23+
import org.springframework.http.HttpMethod;
24+
import org.springframework.http.HttpStatus;
25+
import org.springframework.mock.http.client.MockClientHttpRequest;
26+
import org.springframework.mock.http.client.MockClientHttpResponse;
27+
import org.springframework.test.annotation.DirtiesContext;
28+
29+
/**
30+
* Test that verify that forceFailOnError apply the failOnError parameter on all requested layers
31+
*/
32+
public class CreateMapPagesForceFailOnErrorProcessorTest extends AbstractMapfishSpringTest {
33+
public static final String BASE_DIR = "paging_processor_force_fail_on_error_test/";
34+
@Autowired private ConfigurationFactory configurationFactory;
35+
@Autowired private TestHttpClientFactory requestFactory;
36+
@Autowired private Map<String, OutputFormat> outputFormat;
37+
38+
private static PJsonObject loadJsonRequestData() throws IOException {
39+
return parseJSONObjectFromFile(
40+
CreateMapPagesForceFailOnErrorProcessorTest.class, BASE_DIR + "requestData.json");
41+
}
42+
43+
private static final AtomicBoolean hasFailOnce = new AtomicBoolean(false);
44+
45+
/** File handler that will fail on the first request. */
46+
protected TestHttpClientFactory.Handler createFailingFileHandler(Function<URI, String> filename) {
47+
return new TestHttpClientFactory.Handler() {
48+
@Override
49+
public MockClientHttpRequest handleRequest(URI uri, HttpMethod httpMethod) throws Exception {
50+
if (hasFailOnce.compareAndSet(false, true)) {
51+
MockClientHttpRequest request = new MockClientHttpRequest(httpMethod, uri);
52+
MockClientHttpResponse response =
53+
new MockClientHttpResponse(new byte[0], HttpStatus.REQUEST_TIMEOUT);
54+
request.setResponse(response);
55+
return request;
56+
}
57+
byte[] bytes = getFileBytes(filename.apply(uri));
58+
return ok(uri, bytes, httpMethod);
59+
}
60+
};
61+
}
62+
63+
@Test
64+
@DirtiesContext
65+
@Timeout(value = 1, unit = TimeUnit.MINUTES)
66+
public void testExecute() throws Exception {
67+
final String host = "paging_processor_force_fail_on_error_test";
68+
Configuration config = configurationFactory.getConfig(getFile(BASE_DIR + "config.yaml"));
69+
PJsonObject requestData = loadJsonRequestData();
70+
final AbstractJasperReportOutputFormat format =
71+
(AbstractJasperReportOutputFormat) this.outputFormat.get("pngOutputFormat");
72+
73+
// .wms will fail once
74+
requestFactory.registerHandler(
75+
input -> (input.getAuthority() != null && input.getAuthority().contains(host + ".wms")),
76+
createFailingFileHandler(uri -> "/map-data/tiger-ny.png"));
77+
requestFactory.registerHandler(
78+
input -> (input.getAuthority() != null && input.getAuthority().contains(host + ".wmts")),
79+
createFileHandler(uri -> "/map-data/tiger-ny.png"));
80+
testPrint(config, requestData, format, true);
81+
config.setForceFailOnError(false);
82+
testPrint(config, requestData, format, false);
83+
84+
// .wmts will fail once and create a PrintException error
85+
config.setForceFailOnError(true);
86+
requestFactory.resetHandlers();
87+
hasFailOnce.set(false);
88+
requestFactory.registerHandler(
89+
input -> (input.getAuthority() != null && input.getAuthority().contains(host + ".wms")),
90+
createFileHandler(uri -> "/map-data/tiger-ny.png"));
91+
requestFactory.registerHandler(
92+
input -> (input.getAuthority() != null && input.getAuthority().contains(host + ".wmts")),
93+
createFailingFileHandler(uri -> "/map-data/tiger-ny.png"));
94+
testPrint(config, requestData, format, true);
95+
config.setForceFailOnError(false);
96+
testPrint(config, requestData, format, false);
97+
}
98+
99+
private void testPrint(
100+
Configuration config,
101+
PJsonObject requestData,
102+
AbstractJasperReportOutputFormat format,
103+
boolean shouldFail) {
104+
try {
105+
format.getJasperPrint(
106+
new HashMap<>(), requestData, config, config.getDirectory(), getTaskDirectory());
107+
if (shouldFail) {
108+
Assert.fail("Generation was not canceled");
109+
}
110+
} catch (Exception e) {
111+
if (!shouldFail) {
112+
Assert.fail("Generation was canceled");
113+
}
114+
// WMS interrupt cause is CancellationException or RuntimeException
115+
// WMTS interrupt cause is PrintException
116+
Assert.assertTrue(
117+
String.format(
118+
"Exception cause should be CancellationException or PrintException with message that"
119+
+ " contains 'Failed to compute Coverage Task' or RuntimeException with message"
120+
+ " that contains 'Request Timeout' but was %s, exception : %s",
121+
e.getCause(), e),
122+
e.getCause() instanceof CancellationException
123+
|| (e.getCause() instanceof PrintException
124+
&& e.getMessage().contains("Failed to compute Coverage Task"))
125+
|| (e.getCause() instanceof RuntimeException
126+
&& e.getMessage().contains("Request Timeout")));
127+
}
128+
}
129+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
forceFailOnError: true
2+
templates:
3+
#===========================================================================
4+
main: !template
5+
#===========================================================================
6+
reportTemplate: simpleReport.jrxml
7+
attributes:
8+
map: !map
9+
maxDpi: 400
10+
width: 780
11+
height: 330
12+
zoomSnapTolerance: 0.025
13+
zoomLevelSnapStrategy: CLOSEST_LOWER_SCALE_ON_TIE
14+
zoomLevels: !zoomLevels
15+
scales: [5000, 10000, 50000, 110000, 500000, 1000000]
16+
paging: !paging
17+
default:
18+
scale: 5000
19+
overlap: 0
20+
processors:
21+
- !reportBuilder # compile all reports in current directory
22+
directory: '.'
23+
- !createMapPages {} # creates the iterable<Values> consumed by dataSource
24+
- !createMap {}
25+
- !createDataSource
26+
processors:
27+
- !createMap {}
28+
tableData: jrDataSource
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
{
2+
"forceFailOnError": true,
3+
"layout": "main",
4+
"attributes": {
5+
"map": {
6+
"areaOfInterest": {
7+
"area": {
8+
"type": "Polygon",
9+
"coordinates": [
10+
[
11+
[-8234842.163180278, 4980450.801914547],
12+
[-8234404.899063832, 4979475.366574329],
13+
[-8232980.987710278, 4979172.645261847],
14+
[-8234147.025354133, 4978668.109741045],
15+
[-8233765.820739795, 4977255.410282798],
16+
[-8234875.798881543, 4977771.157704063],
17+
[-8235907.2937203385, 4977289.045984185],
18+
[-8235234.579695038, 4978623.262139196],
19+
[-8236434.253040158, 4979307.188067394],
20+
[-8235133.672591242, 4979441.730872942],
21+
[-8234842.163180278, 4980450.801914547]
22+
]
23+
]
24+
}
25+
},
26+
"projection": "EPSG:3857",
27+
"dpi": 72,
28+
"layers": [
29+
{
30+
"type": "wms",
31+
"baseURL": "http://paging_processor_force_fail_on_error_test.wms:1234/wms",
32+
"opacity": 1.0,
33+
"layers": ["tiger-ny"],
34+
"styles": ["line"],
35+
"version": "1.0.0",
36+
"imageFormat": "image/png"
37+
},
38+
{
39+
"type": "WMTS",
40+
"baseURL": "http://paging_processor_force_fail_on_error_test.wmts:1234/wmts",
41+
"opacity": 1.0,
42+
"layer": "tiger-ny",
43+
"version": "1.0.0",
44+
"requestEncoding": "KVP",
45+
"dimensions": null,
46+
"dimensionParams": {},
47+
"matrixSet": "EPSG:900913",
48+
"matrices": [
49+
{
50+
"identifier": "EPSG:900913:12",
51+
"matrixSize": [4096, 4096],
52+
"scaleDenominator": 136494.69334738597,
53+
"tileSize": [256, 256],
54+
"topLeftCorner": [-2.003750834e7, 2.0037508e7]
55+
},
56+
{
57+
"identifier": "EPSG:900913:13",
58+
"matrixSize": [8192, 8192],
59+
"scaleDenominator": 68247.34667369298,
60+
"tileSize": [256, 256],
61+
"topLeftCorner": [-2.003750834e7, 2.0037508e7]
62+
},
63+
{
64+
"identifier": "EPSG:900913:14",
65+
"matrixSize": [16384, 16384],
66+
"scaleDenominator": 34123.67333684649,
67+
"tileSize": [256, 256],
68+
"topLeftCorner": [-2.003750834e7, 2.0037508e7]
69+
},
70+
{
71+
"identifier": "EPSG:900913:15",
72+
"matrixSize": [32768, 32768],
73+
"scaleDenominator": 17061.836668423246,
74+
"tileSize": [256, 256],
75+
"topLeftCorner": [-2.003750834e7, 2.0037508e7]
76+
},
77+
{
78+
"identifier": "EPSG:900913:16",
79+
"matrixSize": [65536, 65536],
80+
"scaleDenominator": 8530.9183342116231,
81+
"tileSize": [256, 256],
82+
"topLeftCorner": [-2.003750834e7, 2.0037508e7]
83+
},
84+
{
85+
"identifier": "EPSG:900913:17",
86+
"matrixSize": [131072, 131072],
87+
"scaleDenominator": 4265.4591671058115,
88+
"tileSize": [256, 256],
89+
"topLeftCorner": [-2.003750834e7, 2.0037508e7]
90+
}
91+
],
92+
"imageFormat": "image/png"
93+
}
94+
]
95+
}
96+
}
97+
}

0 commit comments

Comments
 (0)