package org.geoserver.wms;
import static org.custommonkey.xmlunit.XMLAssert.assertXpathExists;
import static org.junit.Assert.assertEquals;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.geoserver.catalog.DimensionPresentation;
import org.geoserver.catalog.FeatureTypeInfo;
import org.geoserver.catalog.ResourceInfo;
import org.geoserver.data.test.MockData;
import org.geoserver.platform.ServiceException;
import org.geoserver.wms.map.GIFMapResponse;
import org.geotools.data.FeatureSource;
import org.geotools.map.FeatureLayer;
import org.geotools.map.Layer;
import org.geotools.styling.Style;
import org.junit.Before;
import org.junit.Test;
import org.opengis.feature.Feature;
import org.opengis.feature.type.FeatureType;
import org.w3c.dom.Document;
import org.springframework.mock.web.MockHttpServletResponse;
public class GetMapCallbackTest extends WMSDimensionsTestSupport {
private GetMap getMap;
@Before
public void cleanupCallbacks() {
getMap = applicationContext.getBean(GetMap.class);
getMap.setGetMapCallbacks((List<GetMapCallback>) Collections.EMPTY_LIST);
}
@Test
public void testStandardWorkflow() throws Exception {
TestCallback callback = new TestCallback();
getMap.setGetMapCallbacks(Arrays.asList((GetMapCallback) callback));
// request a layer group with two layers
Document dom = getAsDOM("wms?request=reflect&layers=nature&format=rss");
assertXpathExists("rss/channel/title[text() = 'cite:Lakes,cite:Forests']", dom);
assertEquals(1, callback.requests.size());
assertEquals(1, callback.mapContentsInited.size());
assertEquals(2, callback.layers.size());
assertEquals(1, callback.mapContents.size());
assertEquals(1, callback.maps.size());
assertEquals(0, callback.exceptions.size());
}
@Test
public void testBreakRequest() throws Exception {
final String message = "This layer is not allowed";
TestCallback callback = new TestCallback() {
@Override
public Layer beforeLayer(WMSMapContent content, Layer layer) {
throw new RuntimeException(message);
}
};
getMap.setGetMapCallbacks(Arrays.asList((GetMapCallback) callback));
// request a layer group with two layers
Document dom = getAsDOM("wms?request=reflect&layers=nature&format=rss&version=1.1.0");
// print(dom);
assertXpathExists("/ServiceExceptionReport", dom);
assertEquals(1, callback.requests.size());
assertEquals(1, callback.mapContentsInited.size());
assertEquals(0, callback.layers.size());
assertEquals(0, callback.mapContents.size());
assertEquals(0, callback.maps.size());
assertEquals(1, callback.exceptions.size());
assertEquals(message, callback.exceptions.get(0).getMessage());
}
@Test
public void testAddLayer() throws Exception {
FeatureTypeInfo ft = getCatalog().getFeatureTypeByName(getLayerId(MockData.BRIDGES));
FeatureSource<? extends FeatureType, ? extends Feature> fs = ft.getFeatureSource(null, null);
Style style = getCatalog().getStyleByName("point").getStyle();
final FeatureLayer layer = new FeatureLayer(fs, style);
layer.setTitle("extra");
TestCallback callback = new TestCallback() {
@Override
public WMSMapContent beforeRender(WMSMapContent mapContent) {
mapContent.addLayer(layer);
return super.beforeRender(mapContent);
}
};
getMap.setGetMapCallbacks(Arrays.asList((GetMapCallback) callback));
// request a layer group with two layers
Document dom = getAsDOM("wms?request=reflect&layers=nature&format=rss&version=1.1.0");
// print(dom);
assertXpathExists("rss/channel/title[text() = 'cite:Lakes,cite:Forests,extra']", dom);
assertEquals(1, callback.requests.size());
assertEquals(1, callback.mapContentsInited.size());
assertEquals(3, callback.layers.size());
assertEquals(1, callback.mapContents.size());
assertEquals(1, callback.maps.size());
assertEquals(0, callback.exceptions.size());
assertEquals(layer, callback.layers.get(2));
}
@Test
public void testRemoveLayer() throws Exception {
TestCallback callback = new TestCallback() {
@Override
public Layer beforeLayer(WMSMapContent content, Layer layer) {
if("cite:Lakes".equals(layer.getTitle())) {
return null;
} else {
return super.beforeLayer(content, layer);
}
}
};
getMap.setGetMapCallbacks(Arrays.asList((GetMapCallback) callback));
// request a layer group with two layers
Document dom = getAsDOM("wms?request=reflect&layers=nature&format=rss&version=1.1.0");
// print(dom);
assertXpathExists("rss/channel/title[text() = 'cite:Forests']", dom);
assertEquals(1, callback.requests.size());
assertEquals(1, callback.mapContentsInited.size());
assertEquals(1, callback.layers.size());
assertEquals(1, callback.mapContents.size());
assertEquals(1, callback.maps.size());
assertEquals(0, callback.exceptions.size());
assertEquals("cite:Forests", callback.layers.get(0).getTitle());
}
@Test
public void testAnimator() throws Exception {
TestCallback callback = new TestCallback();
getMap.setGetMapCallbacks(Arrays.asList((GetMapCallback) callback));
String requestURL = "wms/animate?layers=" + getLayerId(MockData.BASIC_POLYGONS) + "&aparam=fake_param&avalues=val0,val1,val2";
MockHttpServletResponse resp = getAsServletResponse(requestURL);
assertEquals("image/gif", resp.getContentType());
// the three frames, plus the fake request the animator does to get the mime type and
// map content for the output
assertEquals(4, callback.requests.size());
assertEquals(4, callback.mapContentsInited.size());
assertEquals(4, callback.layers.size());
assertEquals(4, callback.mapContents.size());
assertEquals(4, callback.maps.size());
assertEquals(0, callback.exceptions.size());
}
@Test
public void testAnimatedGifDimensions() throws Exception {
TestCallback callback = new TestCallback();
getMap.setGetMapCallbacks(Arrays.asList((GetMapCallback) callback));
setupVectorDimension(ResourceInfo.TIME, "time", DimensionPresentation.LIST, null, null, null);
MockHttpServletResponse response = getAsServletResponse("wms?service=WMS&version=1.1.1&request=GetMap"
+ "&bbox=-180,-90,180,90&styles=&Format=image/png&width=80&height=40&srs=EPSG:4326"
+ "&layers=" + getLayerId(V_TIME_ELEVATION)
+ "&time=2011-05-02,2011-05-04,2011-05-10&format=" + GIFMapResponse.IMAGE_GIF_SUBTYPE_ANIMATED);
assertEquals("image/gif", response.getContentType());
// the three frames in a single request
assertEquals(1, callback.requests.size());
assertEquals(3, callback.mapContentsInited.size());
assertEquals(3, callback.layers.size());
assertEquals(3, callback.mapContents.size());
assertEquals(1, callback.maps.size());
assertEquals(0, callback.exceptions.size());
}
private class TestCallback implements GetMapCallback {
private List<GetMapRequest> requests = new ArrayList<GetMapRequest>();
private List<WMSMapContent> mapContentsInited = new ArrayList<WMSMapContent>();
private List<Layer> layers = new ArrayList<Layer>();
private List<WMSMapContent> mapContents = new ArrayList<WMSMapContent>();
private List<WebMap> maps = new ArrayList<WebMap>();
private List<Throwable> exceptions = new ArrayList<Throwable>();
@Override
public synchronized GetMapRequest initRequest(GetMapRequest request) {
requests.add(request);
return request;
}
@Override
public synchronized void initMapContent(WMSMapContent mapContent) {
mapContentsInited.add(mapContent);
}
@Override
public synchronized Layer beforeLayer(WMSMapContent content, Layer layer) {
layers.add(layer);
return layer;
}
@Override
public synchronized WMSMapContent beforeRender(WMSMapContent mapContent) {
mapContents.add(mapContent);
return mapContent;
}
@Override
public synchronized WebMap finished(WebMap map) {
maps.add(map);
return map;
}
@Override
public synchronized void failed(Throwable t) {
exceptions.add(t);
}
}
}