Skip to content

Commit

Permalink
[GEOS-8263] Allow in layer preview filtering (CQL, OGC and FeatureID)…
Browse files Browse the repository at this point in the history
… for rasters formats that support filtering
  • Loading branch information
Nuno Oliveira committed Aug 24, 2017
1 parent 4f89258 commit ab0e85e
Show file tree
Hide file tree
Showing 8 changed files with 327 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import org.geoserver.wms.WMS;
import org.geoserver.wms.WMSMapContent;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.map.GridReaderLayer;
import org.geotools.map.Layer;
import org.geotools.map.WMSLayer;
import org.geotools.referencing.CRS;
Expand All @@ -46,6 +47,7 @@
import org.geotools.util.logging.Logging;
import org.opengis.feature.type.FeatureType;
import org.opengis.geometry.MismatchedDimensionException;
import org.opengis.parameter.GeneralParameterValue;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.crs.ProjectedCRS;
Expand Down Expand Up @@ -163,7 +165,9 @@ public RawMap produceMap(WMSMapContent mapContent)
Template template = cfg.getTemplate(templateName);
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("context", mapContent);
map.put("pureCoverage", hasOnlyCoverages(mapContent));
boolean hasOnlyCoverages = hasOnlyCoverages(mapContent);
map.put("pureCoverage", hasOnlyCoverages);
map.put("supportsFiltering", supportsFiltering(mapContent, hasOnlyCoverages));
map.put("styles", styleNames(mapContent));
GetMapRequest request = mapContent.getRequest();
map.put("request", request);
Expand Down Expand Up @@ -287,6 +291,34 @@ private boolean hasOnlyCoverages(WMSMapContent mapContent) {
return true;
}

/**
* Helper method that checks if filtering support should be activated. If the map
* is not composed only by coverages then filtering should be activated. If the
* map is composed only of coverages but at least one of the coverages supports
* filtering, then filtering should be activated. Otherwise filtering capabilities
* will be deactivated.
*/
private boolean supportsFiltering(WMSMapContent mapContent, boolean hasOnlyCoverages) {
// if we non coverages layers exist filtering will be activated
// if only coverages layers are present filtering will eb activated
// if at least one coverage reader supports filtering
return !hasOnlyCoverages || mapContent.layers().stream().anyMatch(layer -> {
if (!(layer instanceof GridReaderLayer)) {
// unlikely situation, we cannot know if filtering is supported
return false;
}
GeneralParameterValue[] readParams = ((GridReaderLayer) layer).getParams();
for (GeneralParameterValue readParam : readParams) {
if (readParam.getDescriptor().getName().getCode().equalsIgnoreCase("FILTER")) {
// the reader of this layer supports filtering
return true;
}
}
// no coverage reader supports filtering, so filtering shoudl not be activated
return false;
});
}

private List<String> styleNames(WMSMapContent mapContent) {
if (mapContent.layers().size() != 1 || mapContent.getRequest() == null)
return Collections.emptyList();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@
var untiled;
var tiled;
var pureCoverage = ${pureCoverage?string};
var supportsFiltering = ${supportsFiltering?string};
// pink tile avoidance
OpenLayers.IMAGE_RELOAD_ATTEMPTS = 5;
// make OL compute scale according to WMS spec
Expand All @@ -120,13 +121,17 @@
// and default to jpeg format
format = 'image/png';
if(pureCoverage) {
document.getElementById('antialiasSelector').disabled = true;
document.getElementById('jpeg').selected = true;
format = "image/jpeg";
}
if (!supportsFiltering) {
document.getElementById('filterType').disabled = true;
document.getElementById('filter').disabled = true;
document.getElementById('antialiasSelector').disabled = true;
document.getElementById('updateFilterButton').disabled = true;
document.getElementById('resetFilterButton').disabled = true;
document.getElementById('jpeg').selected = true;
format = "image/jpeg";
}
var bounds = new OpenLayers.Bounds(
Expand Down Expand Up @@ -406,7 +411,7 @@
}
function updateFilter(){
if(pureCoverage)
if(!supportsFiltering)
return;
var filterType = document.getElementById('filterType').value;
Expand All @@ -431,7 +436,7 @@
}
function resetFilter() {
if(pureCoverage)
if(!supportsFiltering)
return;
document.getElementById('filter').value = "";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -234,13 +234,17 @@
var bounds = [${request.bbox.minX?c}, ${request.bbox.minY?c},
${request.bbox.maxX?c}, ${request.bbox.maxY?c}];
if (pureCoverage) {
document.getElementById('antialiasSelector').disabled = true;
document.getElementById('jpeg').selected = true;
format = "image/jpeg";
}
var supportsFiltering = ${supportsFiltering?string};
if (!supportsFiltering) {
document.getElementById('filterType').disabled = true;
document.getElementById('filter').disabled = true;
document.getElementById('antialiasSelector').disabled = true;
document.getElementById('updateFilterButton').disabled = true;
document.getElementById('resetFilterButton').disabled = true;
document.getElementById('jpeg').selected = true;
format = "image/jpeg";
}
var mousePositionControl = new ol.control.MousePosition({
Expand Down Expand Up @@ -397,7 +401,7 @@
}
function updateFilter(){
if (pureCoverage) {
if (!supportsFiltering) {
return;
}
var filterType = document.getElementById('filterType').value;
Expand Down Expand Up @@ -425,7 +429,7 @@
}
function resetFilter() {
if (pureCoverage) {
if (!supportsFiltering) {
return;
}
document.getElementById('filter').value = "";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
*/
package org.geoserver.wms.map;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;

import java.awt.Color;
Expand All @@ -14,8 +16,15 @@
import java.util.regex.Pattern;

import org.geoserver.catalog.Catalog;
import org.geoserver.catalog.CoverageStoreInfo;
import org.geoserver.catalog.NamespaceInfo;
import org.geoserver.catalog.StoreInfo;
import org.geoserver.catalog.StyleInfo;
import org.geoserver.catalog.WorkspaceInfo;
import org.geoserver.catalog.impl.CoverageInfoImpl;
import org.geoserver.catalog.impl.LayerInfoImpl;
import org.geoserver.data.test.MockData;
import org.geoserver.data.test.SystemTestData;
import org.geoserver.wms.GetMapRequest;
import org.geoserver.wms.WMSMapContent;
import org.geoserver.wms.WMSTestSupport;
Expand All @@ -28,6 +37,7 @@
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.mock.web.MockHttpServletResponse;

import com.vividsolutions.jts.geom.Envelope;

Expand All @@ -53,7 +63,18 @@ protected OpenLayersMapOutputFormat getProducerInstance() {
public void unsetMapProducer() throws Exception {
this.mapProducer = null;
}


@Override
protected void onSetUp(SystemTestData testData) throws Exception {
// get default workspace info
WorkspaceInfo workspaceInfo = getCatalog().getWorkspaceByName(MockData.DEFAULT_PREFIX);
// create static raster store
StoreInfo store = createStaticRasterStore(workspaceInfo);
// create static raster layer
NamespaceInfo nameSpace = getCatalog().getNamespaceByPrefix(MockData.DEFAULT_PREFIX);
createStaticRasterLayer(nameSpace, store, "staticRaster");
}

/**
* Test for GEOS-5318: xss vulnerability when a weird parameter is added to the
* request (something like: %3C%2Fscript%
Expand Down Expand Up @@ -105,4 +126,67 @@ public void testXssFix() throws Exception {
"\"</script\\><script\\>alert(\\'x-scripted\\');</script\\><script\\>\": 'foo'");
assertTrue(index > -1);
}

@Test
public void testRastersFilteringCapabilities() throws Exception {
// static raster layer supports filtering
MockHttpServletResponse response = getAsServletResponse(
"wms?service=WMS&version=1.1.0&request=GetMap&layers=gs:staticRaster" +
"&styles=&bbox=0.2372206885127698,40.562080748421806," +
"14.592757149389236,44.55808294568743&width=768&height=330" +
"&srs=EPSG:4326&format=application/openlayers");
String content = response.getContentAsString();
assertThat(content.contains("var supportsFiltering = true;"), is(true));
// world raster layer doesn't support filtering
response = getAsServletResponse(
"wms?service=WMS&version=1.1.0&request=GetMap&layers=wcs:World" +
"&styles=&bbox=0.2372206885127698,40.562080748421806," +
"14.592757149389236,44.55808294568743&width=768&height=330" +
"&srs=EPSG:4326&format=application/openlayers");
content = response.getContentAsString();
assertThat(content.contains("var supportsFiltering = false;"), is(true));
}

/**
* Helper method that creates a static raster store and adds it to the catalog.
*/
private StoreInfo createStaticRasterStore(WorkspaceInfo workspace) {
Catalog catalog = getCatalog();
CoverageStoreInfo store = catalog.getFactory().createCoverageStore();
store.setWorkspace(workspace);
store.setType("StaticRaster");
store.setEnabled(true);
store.setName("StaticRaster");
// some fictive URL
store.setURL("http://127.0.0.1:geoserver");
// add the store to the catalog
catalog.add(store);
return store;
}

/**
* Helper method that creates a static raster layer and adds it to the catalog.
*/
private void createStaticRasterLayer(NamespaceInfo namespace, StoreInfo store, String layerName) {
Catalog catalog = getCatalog();
// creating the coverage info
CoverageInfoImpl coverageInfo = new CoverageInfoImpl(catalog);
coverageInfo.setNamespace(namespace);
coverageInfo.setName(layerName);
coverageInfo.setNativeCoverageName(layerName);
coverageInfo.setStore(store);
// creating the layer
LayerInfoImpl layer = new LayerInfoImpl();
layer.setResource(coverageInfo);
layer.setEnabled(true);
layer.setName(layerName);
// set the layers styles
layer.setDefaultStyle(catalog.getStyleByName("raster"));
// set layer CRS and native CRS
coverageInfo.setNativeCRS(DefaultGeographicCRS.WGS84);
coverageInfo.setSRS("EPSG:4326");
// saving everything
catalog.add(coverageInfo);
catalog.add(layer);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/* (c) 2017 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.wms.staticRasterStore;

import org.geotools.coverage.grid.io.AbstractGridFormat;
import org.geotools.coverage.grid.io.imageio.GeoToolsWriteParams;
import org.geotools.factory.Hints;
import org.geotools.parameter.DefaultParameterDescriptor;
import org.geotools.parameter.DefaultParameterDescriptorGroup;
import org.geotools.parameter.ParameterGroup;
import org.opengis.coverage.grid.Format;
import org.opengis.coverage.grid.GridCoverageWriter;
import org.opengis.filter.Filter;
import org.opengis.parameter.GeneralParameterDescriptor;
import org.opengis.parameter.ParameterDescriptor;
import org.opengis.parameter.ParameterValueGroup;

import java.util.HashMap;

/**
* Format class for the static raster reader.
*/
final class StaticRasterFormat extends AbstractGridFormat implements Format {

// add filtering capabilities
public static final ParameterDescriptor<Filter> FILTER =
new DefaultParameterDescriptor<>("Filter", Filter.class, null, null);

StaticRasterFormat() {
setInfo();
// reader capabilities
readParameters = new ParameterGroup(new DefaultParameterDescriptorGroup(
mInfo, new GeneralParameterDescriptor[]{
AbstractGridFormat.READ_GRIDGEOMETRY2D,
FILTER}));
}

private void setInfo() {
HashMap<String, String> info = new HashMap<>();
info.put("name", "StaticRaster");
info.put("description", "Static raster store");
info.put("vendor", "Geotools");
info.put("docURL", "http://geotools.org/");
info.put("version", "1.0");
mInfo = info;
}

@Override
public StaticRasterReader getReader(Object source) {
// we just create the reader with no hints
return getReader(source, null);
}

@Override
public StaticRasterReader getReader(Object source, Hints hints) {
return new StaticRasterReader(source);
}

@Override
public boolean accepts(Object input, Hints hints) {
// we don't need anything here
return true;
}

@Override
public ParameterValueGroup getReadParameters() {
// this will return the read parameters we setup in the constructor
return super.getReadParameters();
}

@Override
public GeoToolsWriteParams getDefaultImageIOWriteParameters() {
throw new UnsupportedOperationException("Operation not supported.");
}

@Override
public GridCoverageWriter getWriter(Object destination, Hints hints) {
throw new UnsupportedOperationException("Operation not supported.");
}

@Override
public GridCoverageWriter getWriter(Object destination) {
throw new UnsupportedOperationException("Operation not supported.");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/* (c) 2017 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.wms.staticRasterStore;

import org.geotools.coverage.grid.io.GridFormatFactorySpi;

import java.awt.*;
import java.util.Collections;
import java.util.Map;

/**
* Simple factory for the static raster format.
*/
public final class StaticRasterFormatFactory implements GridFormatFactorySpi {

public boolean isAvailable() {
// we don't need anything specific
return true;
}

public StaticRasterFormat createFormat() {
return new StaticRasterFormat();
}

public Map<RenderingHints.Key, ?> getImplementationHints() {
return Collections.emptyMap();
}
}

0 comments on commit ab0e85e

Please sign in to comment.