Unverified Commit b0c20ecc authored by Andrea Aime's avatar Andrea Aime Committed by GitHub

Merge pull request #3435 from aaime/sldservice_env_215x

Backporting SLD service env variable support to 2.15.x
parents f218e6c8 70434230
......@@ -209,6 +209,11 @@ The parameters usable to customize the ColorMap are:
- limits the data the classifier is working on to a range of "stddevs" standard deviations around the mean value.
- a positive floating point number (e.g., '1', '2.5', '3').
-
* - env
- a list of environment variables that the underlying layer may be using to select features/rasters to be
classified (e.g., by using the ``filter`` in vector and mosaic layer definitions)
- a semicolon separate list of name to value assignments, e.g. ``name1:value1;name2:value2;name3:value3;...``
-
Examples
~~~~~~~~~~
......
......@@ -14,5 +14,7 @@
<!-- <mvc:annotation-driven/> -->
<context:component-scan base-package="org.geoserver.sldservice.rest"/>
<bean id="restEnvCallback" class="org.geoserver.sldservice.rest.RestEnvVariableCallback"/>
</beans>
\ No newline at end of file
......@@ -168,6 +168,7 @@ public class ClassifierController extends BaseSLDServiceController {
boolean continuous,
@RequestParam(value = "bbox", required = false) ReferencedEnvelope bbox,
@RequestParam(value = "stddevs", required = false) Double stddevs,
@RequestParam(value = "env", required = false) String env,
final HttpServletResponse response)
throws Exception {
LayerInfo layerInfo = catalog.getLayerByName(layerName);
......@@ -193,7 +194,11 @@ public class ClassifierController extends BaseSLDServiceController {
this.getColorRamp(
customClasses, customColors, startColor, endColor, midColor, colors);
final List<Rule> rules;
if (env != null) {
RestEnvVariableCallback.setOptions(env);
}
try {
ResourceInfo obj = layerInfo.getResource();
/* Check if it's feature type or coverage */
if (obj instanceof FeatureTypeInfo) {
......@@ -246,6 +251,12 @@ public class ClassifierController extends BaseSLDServiceController {
throw new RestException(e.getMessage(), HttpStatus.BAD_REQUEST, e);
}
if (rules == null || rules.isEmpty()) {
throw new RestException(
"Could not generate any rule, there is likely no data matching the request (layer is empty, of filtered down to no matching features/pixels)",
HttpStatus.NOT_FOUND);
}
if (fullSLD) {
StyledLayerDescriptor sld = SF.createStyledLayerDescriptor();
NamedLayer namedLayer = SF.createNamedLayer();
......
......@@ -10,14 +10,23 @@ import java.awt.image.RenderedImage;
import java.awt.image.SampleModel;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.geoserver.catalog.CoverageInfo;
import org.geoserver.data.util.CoverageUtils;
import org.geoserver.rest.RestException;
import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.coverage.grid.GridEnvelope2D;
import org.geotools.coverage.grid.GridGeometry2D;
import org.geotools.coverage.grid.io.AbstractGridFormat;
import org.geotools.coverage.grid.io.GranuleSource;
import org.geotools.coverage.grid.io.GridCoverage2DReader;
import org.geotools.coverage.grid.io.StructuredGridCoverage2DReader;
import org.geotools.coverage.processing.CoverageProcessor;
import org.geotools.data.Query;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.filter.visitor.SimplifyingFilterVisitor;
import org.geotools.gce.imagemosaic.ImageMosaicFormat;
import org.geotools.geometry.Envelope2D;
import org.geotools.geometry.GeneralEnvelope;
import org.geotools.geometry.jts.JTS;
......@@ -28,6 +37,9 @@ import org.geotools.referencing.operation.transform.AffineTransform2D;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.Polygon;
import org.opengis.coverage.grid.GridEnvelope;
import org.opengis.coverage.grid.GridGeometry;
import org.opengis.filter.Filter;
import org.opengis.parameter.GeneralParameterDescriptor;
import org.opengis.parameter.GeneralParameterValue;
import org.opengis.parameter.ParameterValue;
import org.opengis.parameter.ParameterValueGroup;
......@@ -45,7 +57,7 @@ import org.springframework.http.HttpStatus;
class ImageReader {
private static final CoverageProcessor PROCESSOR = CoverageProcessor.getInstance();
private ArrayList<GeneralParameterValue> readParameters;
private GeneralParameterValue[] readParameters;
private final ReferencedEnvelope envelope;
private CoverageInfo coverageInfo;
private int selectedBand;
......@@ -66,22 +78,32 @@ class ImageReader {
}
public ImageReader invoke() throws IOException, TransformException, FactoryException {
// grab the raster, for the time being, read fully trying to force deferred loading where
// possible
readParameters = new ArrayList<>();
GridCoverage2DReader reader =
(GridCoverage2DReader) coverageInfo.getGridCoverageReader(null, null);
ParameterValue<Boolean> useImageRead = AbstractGridFormat.USE_JAI_IMAGEREAD.createValue();
useImageRead.setValue(true);
readParameters.add(useImageRead);
// use the configured reading parameters
final ParameterValueGroup readParametersDescriptor = reader.getFormat().getReadParameters();
final List<GeneralParameterDescriptor> parameterDescriptors =
new ArrayList<>(readParametersDescriptor.getDescriptor().descriptors());
this.readParameters =
CoverageUtils.getParameters(
readParametersDescriptor, coverageInfo.getParameters(), false);
// grab the raster, for the time being, read fully trying to force deferred loading where
// possible
readParameters =
CoverageUtils.mergeParameter(
parameterDescriptors,
readParameters,
true,
AbstractGridFormat.USE_JAI_IMAGEREAD.getName().getCode());
// grab the original grid geometry
GridEnvelope originalGridrange = reader.getOriginalGridRange();
GeneralEnvelope originalEnvelope = reader.getOriginalEnvelope();
MathTransform g2w = reader.getOriginalGridToWorld(PixelInCell.CELL_CORNER);
Filter readFilter = getReadFilter(readParameters);
GridGeometry originalGeometry = getOriginalGridGeometry(reader, readFilter);
Envelope2D originalEnvelope = ((GridGeometry2D) originalGeometry).getEnvelope2D();
CoordinateReferenceSystem crs = originalEnvelope.getCoordinateReferenceSystem();
GridGeometry2D originalGeometry =
new GridGeometry2D(originalGridrange, PixelInCell.CELL_CORNER, g2w, crs, null);
MathTransform g2w = reader.getOriginalGridToWorld(PixelInCell.CELL_CORNER);
GridGeometry2D readGeometry = new GridGeometry2D(originalGeometry);
// do we need to restrict to a specific bounding box?
......@@ -121,11 +143,24 @@ class ImageReader {
readGeometry = new GridGeometry2D(reducedRange, readGeometry.getEnvelope());
}
// if there is a filter, set it back as it might have been simplified (e.g., env var
// expansion)
if (readFilter != null) {
readParameters =
CoverageUtils.mergeParameter(
parameterDescriptors,
readParameters,
readFilter,
ImageMosaicFormat.FILTER.getName().getCode());
}
if (!readGeometry.equals(originalGeometry)) {
ParameterValue<GridGeometry2D> ggParam =
AbstractGridFormat.READ_GRIDGEOMETRY2D.createValue();
ggParam.setValue(readGeometry);
readParameters.add(ggParam);
readParameters =
CoverageUtils.mergeParameter(
parameterDescriptors,
readParameters,
readGeometry,
AbstractGridFormat.READ_GRIDGEOMETRY2D.getName().getCode());
}
// can we delegate band selection to the reader? if so, it can help a lot, especially
......@@ -140,19 +175,25 @@ class ImageReader {
if (sampleModel != null) {
verifyBandSelection(selectedBand, sampleModel);
if (sampleModel.getNumBands() > 1) {
ParameterValue<int[]> value = AbstractGridFormat.BANDS.createValue();
// this param is zero based, the service is like SLD, 1-based
value.setValue(new int[] {selectedBand - 1});
readParameters.add(value);
readParameters =
CoverageUtils.mergeParameter(
parameterDescriptors,
readParameters,
new int[] {selectedBand - 1},
AbstractGridFormat.BANDS.getName().getCode());
bandSelected = true;
}
}
}
// finally perform the read
coverage =
reader.read(
readParameters.toArray(new GeneralParameterValue[readParameters.size()]));
coverage = reader.read(readParameters);
if (coverage == null) {
throw new RestException(
"Could not generate any rule, there is likely no data matching the request (layer is empty, of filtered down to no matching features/pixels)",
HttpStatus.NOT_FOUND);
}
// the reader can do a best-effort on grid geometry, might not have cut it
if (readEnvelope != null && isUncut(coverage, readGeometry)) {
......@@ -186,6 +227,46 @@ class ImageReader {
return this;
}
private GridGeometry2D getOriginalGridGeometry(GridCoverage2DReader reader, Filter readFilter)
throws IOException {
MathTransform g2w = reader.getOriginalGridToWorld(PixelInCell.CELL_CORNER);
CoordinateReferenceSystem crs = reader.getCoordinateReferenceSystem();
if (readFilter != null && reader instanceof StructuredGridCoverage2DReader) {
StructuredGridCoverage2DReader sr = (StructuredGridCoverage2DReader) reader;
String coverageName = reader.getGridCoverageNames()[0];
GranuleSource granules = sr.getGranules(coverageName, true);
SimpleFeatureCollection filteredGranules =
granules.getGranules(new Query(null, readFilter));
ReferencedEnvelope bounds = filteredGranules.getBounds();
if (bounds == null || bounds.isEmpty()) {
throw new RestException(
"Could not generate any rule, there is likely no data matching the request (layer is empty, of filtered down to no matching features/pixels)",
HttpStatus.NOT_FOUND);
}
return new GridGeometry2D(PixelInCell.CELL_CORNER, g2w, bounds, null);
} else {
GridEnvelope originalGridRange = reader.getOriginalGridRange();
return new GridGeometry2D(originalGridRange, PixelInCell.CELL_CORNER, g2w, crs, null);
}
}
private Filter getReadFilter(GeneralParameterValue[] readParameters) {
for (GeneralParameterValue readParameter : readParameters) {
if (readParameter instanceof ParameterValue
&& ImageMosaicFormat.FILTER
.getName()
.equals(readParameter.getDescriptor().getName())) {
ParameterValue pv = (ParameterValue) readParameter;
Filter filter = (Filter) pv.getValue();
return (Filter) filter.accept(new SimplifyingFilterVisitor(), null);
}
}
return null;
}
private boolean isUncut(GridCoverage2D coverage, GridGeometry2D targetGridGeometry) {
Envelope2D actual = coverage.getEnvelope2D();
Envelope2D expected = targetGridGeometry.getEnvelope2D();
......@@ -214,8 +295,8 @@ class ImageReader {
return image;
}
ArrayList<GeneralParameterValue> getReadParameters() {
return readParameters;
List<GeneralParameterValue> getReadParameters() {
return Arrays.asList(readParameters);
}
GridCoverage2D getCoverage() {
......
/* (c) 2019 Open Source Geospatial Foundation - all rights reserved
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.sldservice.rest;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.geoserver.ows.kvp.FormatOptionsKvpParser;
import org.geoserver.rest.DispatcherCallbackAdapter;
import org.geoserver.rest.RestException;
import org.geotools.filter.function.EnvFunction;
import org.springframework.http.HttpStatus;
/** Parses and sets the environment variables, clears them at the end of the request */
public class RestEnvVariableCallback extends DispatcherCallbackAdapter {
static final FormatOptionsKvpParser PARSER = new FormatOptionsKvpParser("env");
/**
* Parses and sets the environment variables from their "var1:value1;v2:value;..." syntax, that
* a {@link org.springframework.stereotype.Controller} retrieved from the request some way
* (ideally via a "env" KVP parameter, but we don't want to be prescriptive about it, in REST
* "env" could be used for something else
*
* @param unparsedOptions
*/
public static void setOptions(String unparsedOptions) {
try {
Map<String, Object> localEnvVars = (Map<String, Object>) PARSER.parse(unparsedOptions);
EnvFunction.setLocalValues(localEnvVars);
} catch (Exception e) {
throw new RestException(
"Invalid syntax for environment variables", HttpStatus.BAD_REQUEST, e);
}
}
@Override
public void finished(HttpServletRequest request, HttpServletResponse response) {
EnvFunction.clearLocalValues();
}
}
......@@ -9,10 +9,13 @@ package org.geoserver.sldservice.rest;
import static org.geoserver.sldservice.utils.classifier.RasterSymbolizerBuilder.DEFAULT_MAX_PIXELS;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
......@@ -26,6 +29,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.TreeSet;
import java.util.stream.Collectors;
import javax.media.jai.PlanarImage;
......@@ -38,6 +42,7 @@ import org.geoserver.catalog.CoverageView;
import org.geoserver.catalog.CoverageView.CompositionType;
import org.geoserver.catalog.CoverageView.CoverageBand;
import org.geoserver.catalog.CoverageView.InputCoverageBand;
import org.geoserver.catalog.FeatureTypeInfo;
import org.geoserver.catalog.LayerInfo;
import org.geoserver.data.test.SystemTestData;
import org.geoserver.data.test.SystemTestData.LayerProperty;
......@@ -46,10 +51,12 @@ import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.coverage.grid.GridGeometry2D;
import org.geotools.coverage.grid.io.AbstractGridFormat;
import org.geotools.factory.CommonFactoryFinder;
import org.geotools.filter.function.EnvFunction;
import org.geotools.filter.function.FilterFunction_parseDouble;
import org.geotools.filter.text.cql2.CQL;
import org.geotools.filter.text.cql2.CQLException;
import org.geotools.filter.text.ecql.ECQL;
import org.geotools.gce.imagemosaic.ImageMosaicFormat;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.image.util.ImageUtilities;
import org.geotools.referencing.CRS;
......@@ -70,6 +77,7 @@ import org.geotools.xml.styling.SLDParser;
import org.hamcrest.Matchers;
import org.junit.Test;
import org.opengis.filter.Filter;
import org.opengis.filter.PropertyIsEqualTo;
import org.opengis.filter.PropertyIsLessThan;
import org.opengis.geometry.Envelope;
import org.opengis.parameter.GeneralParameterDescriptor;
......@@ -89,6 +97,9 @@ public class ClassifierTest extends SLDServiceBaseTest {
new QName(
SystemTestData.CITE_URI, "ClassificationPolygons", SystemTestData.CITE_PREFIX);
static final QName FILTERED_POINTS =
new QName(SystemTestData.CITE_URI, "FilteredPoints", SystemTestData.CITE_PREFIX);
static final QName MILANOGEO =
new QName(SystemTestData.CITE_URI, "milanogeo", SystemTestData.CITE_PREFIX);
......@@ -101,6 +112,9 @@ public class ClassifierTest extends SLDServiceBaseTest {
static final QName SRTM =
new QName(SystemTestData.CITE_URI, "srtm", SystemTestData.CITE_PREFIX);
static final QName SFDEM_MOSAIC =
new QName(SystemTestData.CITE_URI, "sfdem_mosaic", SystemTestData.CITE_PREFIX);
private static final String sldPrefix =
"<StyledLayerDescriptor><NamedLayer><Name>feature</Name><UserStyle><FeatureTypeStyle>";
private static final String sldPostfix =
......@@ -186,6 +200,24 @@ public class ClassifierTest extends SLDServiceBaseTest {
catalog.add(coverageInfo);
final LayerInfo layerInfoView = builder.buildLayer(coverageInfo);
catalog.add(layerInfoView);
// add a filtered view with env vars for vector env parameter testing
testData.addVectorLayer(
FILTERED_POINTS,
props,
"ClassificationPoints.properties",
this.getClass(),
catalog);
FeatureTypeInfo ft = catalog.getFeatureTypeByName(FILTERED_POINTS.getLocalPart());
ft.setCqlFilter("group = env('group', 'Group0')");
catalog.save(ft);
// add a filtered mosaic with a "direction" column
testData.addRasterLayer(
SFDEM_MOSAIC, "sfdem-tiles.zip", null, null, ClassifierTest.class, catalog);
CoverageInfo sfdem = catalog.getCoverageByName(getLayerId(SFDEM_MOSAIC));
sfdem.getParameters().put("Filter", "direction = env('direction','NE')");
catalog.save(sfdem);
}
@Test
......@@ -665,9 +697,9 @@ public class ClassifierTest extends SLDServiceBaseTest {
Rule[] rules =
checkRules(
resultXml.replace("<Rules>", sldPrefix).replace("</Rules>", sldPostfix), 3);
checkRule(rules[0], "#690000", org.opengis.filter.PropertyIsEqualTo.class);
checkRule(rules[1], "#B40000", org.opengis.filter.PropertyIsEqualTo.class);
checkRule(rules[2], "#FF0000", org.opengis.filter.PropertyIsEqualTo.class);
checkRule(rules[0], "#690000", PropertyIsEqualTo.class);
checkRule(rules[1], "#B40000", PropertyIsEqualTo.class);
checkRule(rules[2], "#FF0000", PropertyIsEqualTo.class);
TreeSet<String> orderedRules = new TreeSet<String>();
orderedRules.add(rules[0].getTitle());
orderedRules.add(rules[1].getTitle());
......@@ -678,6 +710,69 @@ public class ClassifierTest extends SLDServiceBaseTest {
assertEquals("foobar", iter.next());
}
@Test
public void testEnvVectorGroup2() throws Exception {
final String restPath =
RestBaseController.ROOT_PATH
+ "/sldservice/cite:FilteredPoints/"
+ getServiceUrl()
+ ".xml?"
+ "attribute=name&method=uniqueInterval&fullSLD=true&env=group:Group2";
Document dom = getAsDOM(restPath, 200);
List<Rule> rules = getRules(dom);
assertEquals(2, rules.size());
checkRule(rules.get(0), "#8E0000", PropertyIsEqualTo.class);
checkRule(rules.get(1), "#FF0000", PropertyIsEqualTo.class);
List<String> sortedRules =
rules.stream()
.map(r -> r.getDescription().getTitle().toString())
.sorted()
.collect(Collectors.toList());
assertThat(sortedRules, contains("bar", "foo"));
// also make sure the env vars have been cleared, this thread is the same that run the
// request
assertNull(CQL.toExpression("env('group')").evaluate(null));
}
@Test
public void testEnvVectorGroup0() throws Exception {
final String restPath =
RestBaseController.ROOT_PATH
+ "/sldservice/cite:FilteredPoints/"
+ getServiceUrl()
+ ".xml?"
+ "attribute=name&method=uniqueInterval&fullSLD=true&env=group:Group0";
Document dom = getAsDOM(restPath, 200);
List<Rule> rules = getRules(dom);
assertEquals(2, rules.size());
checkRule(rules.get(0), "#8E0000", PropertyIsEqualTo.class);
checkRule(rules.get(1), "#FF0000", PropertyIsEqualTo.class);
List<String> sortedRules =
rules.stream()
.map(r -> r.getDescription().getTitle().toString())
.sorted()
.collect(Collectors.toList());
assertThat(sortedRules, contains("foo", "foobar"));
// also make sure the env vars have been cleared, this thread is the same that run the
// request
assertNull(CQL.toExpression("env('group')").evaluate(null));
}
@Test
public void testEnvVectorNotThere() throws Exception {
final String restPath =
RestBaseController.ROOT_PATH
+ "/sldservice/cite:FilteredPoints/"
+ getServiceUrl()
+ ".xml?"
+ "attribute=name&method=uniqueInterval&fullSLD=true&env=group:NotAGroup";
MockHttpServletResponse response = getAsServletResponse(restPath);
assertEquals(404, response.getStatus());
assertNull(CQL.toExpression("env('group')").evaluate(null));
}
@Test
public void testBlueRamp() throws Exception {
final String restPath =
......@@ -696,9 +791,9 @@ public class ClassifierTest extends SLDServiceBaseTest {
checkRules(
resultXml.replace("<Rules>", sldPrefix).replace("</Rules>", sldPostfix), 3);
checkRule(rules[0], "#000069", org.opengis.filter.PropertyIsEqualTo.class);
checkRule(rules[1], "#0000B4", org.opengis.filter.PropertyIsEqualTo.class);
checkRule(rules[2], "#0000FF", org.opengis.filter.PropertyIsEqualTo.class);
checkRule(rules[0], "#000069", PropertyIsEqualTo.class);
checkRule(rules[1], "#0000B4", PropertyIsEqualTo.class);
checkRule(rules[2], "#0000FF", PropertyIsEqualTo.class);
}
@Test
......@@ -719,9 +814,9 @@ public class ClassifierTest extends SLDServiceBaseTest {
checkRules(
resultXml.replace("<Rules>", sldPrefix).replace("</Rules>", sldPostfix), 3);
checkRule(rules[0], "#0000FF", org.opengis.filter.PropertyIsEqualTo.class);
checkRule(rules[1], "#0000B4", org.opengis.filter.PropertyIsEqualTo.class);
checkRule(rules[2], "#000069", org.opengis.filter.PropertyIsEqualTo.class);
checkRule(rules[0], "#0000FF", PropertyIsEqualTo.class);
checkRule(rules[1], "#0000B4", PropertyIsEqualTo.class);
checkRule(rules[2], "#000069", PropertyIsEqualTo.class);
}
@Test
......@@ -765,9 +860,9 @@ public class ClassifierTest extends SLDServiceBaseTest {
checkRules(
resultXml.replace("<Rules>", sldPrefix).replace("</Rules>", sldPostfix), 3);
checkRule(rules[0], "#FF0000", org.opengis.filter.PropertyIsEqualTo.class);
checkRule(rules[1], "#7F007F", org.opengis.filter.PropertyIsEqualTo.class);
checkRule(rules[2], "#0000FF", org.opengis.filter.PropertyIsEqualTo.class);
checkRule(rules[0], "#FF0000", PropertyIsEqualTo.class);
checkRule(rules[1], "#7F007F", PropertyIsEqualTo.class);
checkRule(rules[2], "#0000FF", PropertyIsEqualTo.class);
}
private Rule[] checkRules(String resultXml, int classes) {
......@@ -1312,11 +1407,8 @@ public class ClassifierTest extends SLDServiceBaseTest {
Map<GeneralParameterDescriptor, Object> parameters =
getParametersMap(reader.getReadParameters());
// expect the bands selection and deferred loading
assertThat(
parameters.keySet(),
Matchers.containsInAnyOrder(
AbstractGridFormat.BANDS, AbstractGridFormat.USE_JAI_IMAGEREAD));
// expect the bands selection
assertThat(parameters.keySet(), Matchers.hasItem(AbstractGridFormat.BANDS));
int[] bands = (int[]) parameters.get(AbstractGridFormat.BANDS);
assertArrayEquals(new int[] {0}, bands);
......@@ -1327,6 +1419,27 @@ public class ClassifierTest extends SLDServiceBaseTest {
}
}
@Test
public void testDeferredLoadMosaic() throws Exception {
// the backing reader supports deferred loading
CoverageInfo coverage = getCatalog().getCoverageByName(getLayerId(SFDEM_MOSAIC));
ImageReader reader = new ImageReader(coverage, 1, DEFAULT_MAX_PIXELS, null).invoke();
Map<GeneralParameterDescriptor, Object> parameters =
getParametersMap(reader.getReadParameters());
// expect the bands selection
assertThat(parameters.keySet(), Matchers.hasItem(AbstractGridFormat.USE_JAI_IMAGEREAD));
Boolean imageRead = (Boolean) parameters.get(AbstractGridFormat.USE_JAI_IMAGEREAD);
assertTrue(imageRead);
RenderedImage image = reader.getImage();
assertEquals(1, image.getSampleModel().getNumBands());
if (image instanceof PlanarImage) {
ImageUtilities.disposePlanarImageChain((PlanarImage) image);
}
}
@Test
public void testJAIBandSelection() throws Exception {
// the backing reader does not support native selection
......@@ -1338,7 +1451,7 @@ public class ClassifierTest extends SLDServiceBaseTest {
getParametersMap(reader.getReadParameters());
// expect only deferred loading
assertThat(parameters.keySet(), Matchers.contains(AbstractGridFormat.USE_JAI_IMAGEREAD));
assertThat(parameters.keySet(), not(contains(AbstractGridFormat.BANDS)));
// yet the image just has one band
RenderedImage image = reader.getImage();
......@@ -1359,11 +1472,7 @@ public class ClassifierTest extends SLDServiceBaseTest {
getParametersMap(reader.getReadParameters());
// expect deferred loading and restricted grid geometry
assertThat(
parameters.keySet(),
Matchers.containsInAnyOrder(
AbstractGridFormat.USE_JAI_IMAGEREAD,
AbstractGridFormat.READ_GRIDGEOMETRY2D));
assertThat(parameters.keySet(), Matchers.hasItem(AbstractGridFormat.READ_GRIDGEOMETRY2D));
// reduced pixels
GridGeometry2D gg = (GridGeometry2D) parameters.get(AbstractGridFormat.READ_GRIDGEOMETRY2D);
assertEquals(35, gg.getGridRange2D().width);
......@@ -1391,11 +1500,7 @@ public class ClassifierTest extends SLDServiceBaseTest {
// expect deferred loading and restricted grid geometry
Map<GeneralParameterDescriptor, Object> parameters =
getParametersMap(reader.getReadParameters());
assertThat(
parameters.keySet(),
Matchers.containsInAnyOrder(
AbstractGridFormat.USE_JAI_IMAGEREAD,