/* Copyright (c) 2001 - 2007 TOPP - www.openplans.org. All rights reserved.
* This code is licensed under the GPL 2.0 license, availible at the root
* application directory.
*/
package org.geoserver.wms.map;
import static org.geoserver.data.test.MockData.STREAMS;
import java.awt.Color;
import java.awt.geom.NoninvertibleTransformException;
import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import java.io.IOException;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.namespace.QName;
import junit.framework.Test;
import org.geoserver.catalog.Catalog;
import org.geoserver.catalog.FeatureTypeInfo;
import org.geoserver.catalog.LayerInfo;
import org.geoserver.catalog.StyleInfo;
import org.geoserver.data.test.MockData;
import org.geoserver.platform.ServiceException;
import org.geoserver.security.decorators.DecoratingFeatureSource;
import org.geoserver.wms.GetMapRequest;
import org.geoserver.wms.WMS;
import org.geoserver.wms.WMSMapContent;
import org.geoserver.wms.WMSTestSupport;
import org.geotools.data.FeatureSource;
import org.geotools.data.Query;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureSource;
import org.geotools.feature.IllegalAttributeException;
import org.geotools.filter.IllegalFilterException;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.map.FeatureLayer;
import org.geotools.map.FeatureSourceMapLayer;
import org.geotools.referencing.crs.DefaultGeographicCRS;
import org.geotools.styling.Style;
import org.geotools.util.logging.Logging;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.operation.TransformException;
import com.vividsolutions.jts.geom.Envelope;
public class RenderedImageMapOutputFormatTest extends WMSTestSupport {
private static final Logger LOGGER = org.geotools.util.logging.Logging
.getLogger(RenderedImageMapOutputFormatTest.class.getPackage().getName());
private RenderedImageMapOutputFormat rasterMapProducer;
private String mapFormat = "image/gif";
/**
* This is a READ ONLY TEST so we can use one time setup
*/
public static Test suite() {
return new OneTimeTestSetup(new RenderedImageMapOutputFormatTest());
}
public void setUpInternal() throws Exception {
Logging.getLogger("org.geotools.rendering").setLevel(Level.OFF);
super.setUpInternal();
this.rasterMapProducer = getProducerInstance();
}
protected RenderedImageMapOutputFormat getProducerInstance() {
return new DummyRasterMapProducer(getWMS());
}
public void tearDownInternal() throws Exception {
this.rasterMapProducer = null;
super.tearDownInternal();
}
public String getMapFormat() {
return this.mapFormat;
}
public void testSimpleGetMapQuery() throws Exception {
Catalog catalog = getCatalog();
final FeatureSource fs = catalog.getFeatureTypeByName(MockData.BASIC_POLYGONS.getPrefix(),
MockData.BASIC_POLYGONS.getLocalPart()).getFeatureSource(null, null);
final Envelope env = fs.getBounds();
LOGGER.info("about to create map ctx for BasicPolygons with bounds " + env);
GetMapRequest request = new GetMapRequest();
final WMSMapContent map = new WMSMapContent();
map.getViewport().setBounds(new ReferencedEnvelope(env, DefaultGeographicCRS.WGS84));
map.setMapWidth(300);
map.setMapHeight(300);
map.setBgColor(Color.red);
map.setTransparent(false);
map.setRequest(request);
StyleInfo styleByName = catalog.getStyleByName("Default");
Style basicStyle = styleByName.getStyle();
map.addLayer(new FeatureLayer(fs, basicStyle));
request.setFormat(getMapFormat());
RenderedImageMap imageMap = this.rasterMapProducer.produceMap(map);
BufferedImage image = (BufferedImage) imageMap.getImage();
imageMap.dispose();
assertNotBlank("testSimpleGetMapQuery", image);
}
public void testDefaultStyle() throws Exception {
List<org.geoserver.catalog.FeatureTypeInfo> typeInfos = getCatalog().getFeatureTypes();
for (org.geoserver.catalog.FeatureTypeInfo info : typeInfos) {
if (info.getQualifiedName().getNamespaceURI().equals(MockData.CITE_URI)
&& info.getFeatureType().getGeometryDescriptor() != null)
testDefaultStyle(info.getFeatureSource(null, null));
}
}
public void testBlueLake() throws IOException, IllegalFilterException, Exception {
final Catalog catalog = getCatalog();
org.geoserver.catalog.FeatureTypeInfo typeInfo = catalog.getFeatureTypeByName(
MockData.LAKES.getNamespaceURI(), MockData.LAKES.getLocalPart());
Envelope env = typeInfo.getFeatureSource(null, null).getBounds();
double shift = env.getWidth() / 6;
env = new Envelope(env.getMinX() - shift, env.getMaxX() + shift, env.getMinY() - shift,
env.getMaxY() + shift);
GetMapRequest request = new GetMapRequest();
final WMSMapContent map = new WMSMapContent();
int w = 400;
int h = (int) Math.round((env.getHeight() * w) / env.getWidth());
map.setMapWidth(w);
map.setMapHeight(h);
map.setBgColor(BG_COLOR);
map.setTransparent(true);
map.setRequest(request);
addToMap(map, MockData.FORESTS);
addToMap(map, MockData.LAKES);
addToMap(map, MockData.STREAMS);
addToMap(map, MockData.NAMED_PLACES);
addToMap(map, MockData.ROAD_SEGMENTS);
addToMap(map, MockData.PONDS);
addToMap(map, MockData.BUILDINGS);
addToMap(map, MockData.DIVIDED_ROUTES);
addToMap(map, MockData.BRIDGES);
addToMap(map, MockData.MAP_NEATLINE);
map.getViewport().setBounds(new ReferencedEnvelope(env, DefaultGeographicCRS.WGS84));
request.setFormat(getMapFormat());
RenderedImageMap imageMap = this.rasterMapProducer.produceMap(map);
BufferedImage image = (BufferedImage) imageMap.getImage();
imageMap.dispose();
assertNotBlank("testBlueLake", image);
}
private void addToMap(final WMSMapContent map, final QName typeName) throws IOException {
final FeatureTypeInfo ftInfo = getCatalog().getFeatureTypeByName(
typeName.getNamespaceURI(), typeName.getLocalPart());
List<LayerInfo> layers = getCatalog().getLayers(ftInfo);
StyleInfo defaultStyle = layers.get(0).getDefaultStyle();
Style style = defaultStyle.getStyle();
map.addLayer(new FeatureLayer(ftInfo.getFeatureSource(null, null), style));
}
private void testDefaultStyle(FeatureSource fSource) throws Exception {
Catalog catalog = getCatalog();
Style style = catalog.getStyleByName("Default").getStyle();
FeatureTypeInfo typeInfo = catalog.getFeatureTypeByName(MockData.LAKES.getNamespaceURI(),
MockData.LAKES.getLocalPart());
Envelope env = typeInfo.getFeatureSource(null, null).getBounds();
env.expandToInclude(fSource.getBounds());
int w = 400;
int h = (int) Math.round((env.getHeight() * w) / env.getWidth());
double shift = env.getWidth() / 6;
env = new Envelope(env.getMinX() - shift, env.getMaxX() + shift, env.getMinY() - shift,
env.getMaxY() + shift);
WMSMapContent map = new WMSMapContent();
GetMapRequest request = new GetMapRequest();
map.setRequest(request);
map.addLayer(new FeatureLayer(fSource, style));
map.getViewport().setBounds(new ReferencedEnvelope(env, DefaultGeographicCRS.WGS84));
map.setMapWidth(w);
map.setMapHeight(h);
map.setBgColor(BG_COLOR);
map.setTransparent(false);
// this.rasterMapProducer.setOutputFormat(getMapFormat());
// this.rasterMapProducer.setMapContext(map);
// this.rasterMapProducer.produceMap();
request.setFormat(getMapFormat());
RenderedImageMap imageMap = this.rasterMapProducer.produceMap(map);
RenderedImage image = imageMap.getImage();
imageMap.dispose();
assertNotNull(image);
String typeName = fSource.getSchema().getName().getLocalPart();
assertNotBlank("testDefaultStyle " + typeName, (BufferedImage) image);
}
/**
* Checks {@link RenderedImageMapOutputFormat} makes good use of {@link RenderExceptionStrategy}
*/
@SuppressWarnings("deprecation")
public void testRenderingErrorsHandling() throws Exception {
// the ones that are ignorable by the renderer
assertNotNull(forceRenderingError(new TransformException("fake transform exception")));
assertNotNull(forceRenderingError(new NoninvertibleTransformException(
"fake non invertible exception")));
assertNotNull(forceRenderingError(new IllegalAttributeException(
"non illegal attribute exception")));
assertNotNull(forceRenderingError(new FactoryException("fake factory exception")));
// any other one should make the map producer fail
try {
forceRenderingError(new RuntimeException("fake runtime exception"));
fail("Expected WMSException");
} catch (ServiceException e) {
assertTrue(true);
}
try {
forceRenderingError(new IOException("fake IO exception"));
fail("Expected WMSException");
} catch (ServiceException e) {
assertTrue(true);
}
try {
forceRenderingError(new IllegalArgumentException("fake IAE exception"));
fail("Expected WMSException");
} catch (ServiceException e) {
assertTrue(true);
}
}
/**
* Sets up a rendering loop and throws {@code renderExceptionToThrow} wrapped to a
* RuntimeException when the renderer tries to get a Feature to render.
* <p>
* If the rendering succeeded returns the image, which is going to be a blank one but means the
* renderer didn't complain about the exception caught. Otherwise throws back the exception
* thrown by {@link RenderedImageMapOutputFormat#produceMap()}
* </p>
*/
@SuppressWarnings("unchecked")
private RenderedImage forceRenderingError(final Exception renderExceptionToThrow)
throws Exception {
GetMapRequest request = new GetMapRequest();
final WMSMapContent map = new WMSMapContent();
map.setMapWidth(100);
map.setMapHeight(100);
map.setRequest(request);
final ReferencedEnvelope bounds = new ReferencedEnvelope(-180, 180, -90, 90,
DefaultGeographicCRS.WGS84);
map.getViewport().setBounds(bounds);
final FeatureTypeInfo ftInfo = getCatalog().getFeatureTypeByName(STREAMS.getNamespaceURI(),
STREAMS.getLocalPart());
final SimpleFeatureSource featureSource = (SimpleFeatureSource) ftInfo.getFeatureSource(
null, null);
DecoratingFeatureSource source;
// This source should make the renderer fail when asking for the features
source = new DecoratingFeatureSource(featureSource) {
@Override
public SimpleFeatureCollection getFeatures(Query query) throws IOException {
throw new RuntimeException(renderExceptionToThrow);
// return delegate.getFeatures(query);
}
};
StyleInfo someStyle = getCatalog().getStyles().get(0);
map.addLayer(new FeatureLayer(source, someStyle.getStyle()));
request.setFormat(getMapFormat());
RenderedImageMap imageMap = this.rasterMapProducer.produceMap(map);
BufferedImage image = (BufferedImage) imageMap.getImage();
imageMap.dispose();
return image;
}
/**
* This dummy producer adds no functionality to DefaultRasterMapOutputFormat, just implements a
* void formatImageOutputStream to have a concrete class over which test that
* DefaultRasterMapOutputFormat correctly generates the BufferedImage.
*
* @author Gabriel Roldan
* @version $Id: DefaultRasterMapOutputFormatTest.java 6797 2007-05-16 10:23:50Z aaime $
*/
private static class DummyRasterMapProducer extends RenderedImageMapOutputFormat {
public DummyRasterMapProducer(WMS wms) {
super("image/gif", new String[] { "image/gif" }, wms);
}
}
}