/* (c) 2014 - 2016 Open Source Geospatial Foundation - all rights reserved * (c) 2001 - 2013 OpenPlans * This code is licensed under the GPL 2.0 license, available at the root * application directory. */ package org.geoserver.wms.featureinfo; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import net.opengis.wfs.FeatureCollectionType; import net.opengis.wfs.WfsFactory; import org.geoserver.catalog.FeatureTypeInfo; import org.geoserver.catalog.LayerInfo; import org.geoserver.catalog.NamespaceInfo; import org.geoserver.catalog.ResourceInfo; import org.geoserver.catalog.PublishedType; import org.geoserver.catalog.impl.FeatureTypeInfoImpl; import org.geoserver.catalog.impl.LayerInfoImpl; import org.geoserver.catalog.impl.NamespaceInfoImpl; import org.geoserver.data.test.MockData; import org.geoserver.ows.Dispatcher; import org.geoserver.ows.Request; import org.geoserver.template.GeoServerTemplateLoader; import org.geoserver.wms.GetFeatureInfoRequest; import org.geoserver.wms.MapLayerInfo; import org.geoserver.wms.WMSTestSupport; import org.junit.Before; import org.junit.Test; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.mock.web.MockServletContext; public class HTMLFeatureInfoOutputFormatTest extends WMSTestSupport { private HTMLFeatureInfoOutputFormat outputFormat; private FeatureCollectionType fcType; Map<String, Object> parameters; GetFeatureInfoRequest getFeatureInfoRequest; private static final String templateFolder = "/org/geoserver/wms/featureinfo/"; private String currentTemplate; @Before public void setUp() throws URISyntaxException, IOException { outputFormat = new HTMLFeatureInfoOutputFormat(getWMS()); currentTemplate = "test_content.ftl"; // configure template loader GeoServerTemplateLoader templateLoader = new GeoServerTemplateLoader( this.getClass(), getDataDirectory()) { @Override public Object findTemplateSource(String path) throws IOException { String templatePath; if (path.toLowerCase().contains("content")) { templatePath = currentTemplate; } else { templatePath = "empty.ftl"; } try { return new File(this.getClass() .getResource(templateFolder + templatePath).toURI()); } catch (URISyntaxException e) { return null; } } }; outputFormat.templateLoader = templateLoader; // test request with some parameters to use in templates Request request = new Request(); parameters = new HashMap<String, Object>(); parameters.put("LAYER", "testLayer"); Map<String, String> env = new HashMap<String, String>(); env.put("TEST1", "VALUE1"); env.put("TEST2", "VALUE2"); parameters.put("ENV", env); request.setKvp(parameters); Dispatcher.REQUEST.set(request); final FeatureTypeInfo featureType = getFeatureTypeInfo(MockData.PRIMITIVEGEOFEATURE); fcType = WfsFactory.eINSTANCE.createFeatureCollectionType(); fcType.getFeature().add(featureType.getFeatureSource(null, null).getFeatures()); // fake layer list List<MapLayerInfo> queryLayers = new ArrayList<MapLayerInfo>(); LayerInfo layerInfo = new LayerInfoImpl(); layerInfo.setType(PublishedType.VECTOR); ResourceInfo resourceInfo = new FeatureTypeInfoImpl(null); NamespaceInfo nameSpace = new NamespaceInfoImpl(); nameSpace.setPrefix("topp"); nameSpace.setURI("http://www.topp.org"); resourceInfo.setNamespace(nameSpace); layerInfo.setResource(resourceInfo); MapLayerInfo mapLayerInfo = new MapLayerInfo(layerInfo); queryLayers.add(mapLayerInfo); getFeatureInfoRequest = new GetFeatureInfoRequest(); getFeatureInfoRequest.setQueryLayers(queryLayers); } /** * Test request values are inserted in processed template * * @throws IOException * @throws URISyntaxException */ @Test public void testRequestParametersAreEvaluatedInTemplate() throws IOException { ByteArrayOutputStream outStream = new ByteArrayOutputStream(); outputFormat.write(fcType, getFeatureInfoRequest, outStream); String result = new String(outStream.toByteArray()); assertEquals("VALUE1,VALUE2,testLayer" , result); } @Test public void testEnvironmentVariablesAreEvaluatedInTemplate() throws IOException { currentTemplate = "test_env_content.ftl"; System.setProperty("TEST_PROPERTY", "MYVALUE"); MockServletContext servletContext = (MockServletContext)applicationContext.getServletContext(); servletContext.setInitParameter("TEST_INIT_PARAM", "MYPARAM"); try { ByteArrayOutputStream outStream = new ByteArrayOutputStream(); outputFormat.write(fcType, getFeatureInfoRequest, outStream); String result = new String(outStream.toByteArray()); assertEquals("MYVALUE,MYPARAM" , result); } finally { System.clearProperty("TEST_PROPERTY"); } } /** * Test that if template asks a request parameter that is not present in request * an exception is thrown. * */ @Test public void testErrorWhenRequestParametersAreNotDefined() { ByteArrayOutputStream outStream = new ByteArrayOutputStream(); boolean error = false; // remove one parameter required in template parameters.remove("LAYER"); try { outputFormat.write(fcType, getFeatureInfoRequest, outStream); } catch (IOException e) { error = true; } assertTrue(error); } @Test public void testHTMLGetFeatureInfoCharset() throws Exception { String layer = getLayerId(MockData.FORESTS); String request = "wms?version=1.1.1&bbox=-0.002,-0.002,0.002,0.002&styles=&format=jpeg" + "&request=GetFeatureInfo&layers=" + layer + "&query_layers=" + layer + "&width=20&height=20&x=10&y=10" + "&info_format=text/html"; MockHttpServletResponse response = getAsServletResponse(request,""); // MimeType assertEquals("text/html", response.getContentType()); // Check if the character encoding is the one expected assertTrue("UTF-8".equals(response.getCharacterEncoding())); } @SuppressWarnings("unchecked") @Test public void testConcurrentRequests() throws Exception { FeatureTypeInfo featureType1 = getFeatureTypeInfo(MockData.PRIMITIVEGEOFEATURE); List<MapLayerInfo> layers1 = Collections.singletonList(new MapLayerInfo( getCatalog().getLayerByName(featureType1.prefixedName()))); FeatureCollectionType type1 = WfsFactory.eINSTANCE.createFeatureCollectionType(); type1.getFeature().add(featureType1.getFeatureSource(null, null).getFeatures()); final FeatureTypeInfo featureType2 = getFeatureTypeInfo(MockData.BASIC_POLYGONS); List<MapLayerInfo> layers2 = Collections.singletonList(new MapLayerInfo( getCatalog().getLayerByName(featureType2.prefixedName()))); FeatureCollectionType type2 = WfsFactory.eINSTANCE.createFeatureCollectionType(); type2.getFeature().add(featureType2.getFeatureSource(null, null).getFeatures()); final HTMLFeatureInfoOutputFormat format = new HTMLFeatureInfoOutputFormat(getWMS()); format.templateLoader = new GeoServerTemplateLoader(getClass(), getDataDirectory()) { @Override public Object findTemplateSource(String path) throws IOException { String templatePath = "empty.ftl"; if (path.toLowerCase().contains("content") && (this.resource != null) && this.resource.prefixedName().equals(featureType2.prefixedName())) { templatePath = "test_content.ftl"; } try { return new File(this.getClass() .getResource(templateFolder + templatePath).toURI()); } catch (URISyntaxException e) { return null; } } }; int numRequests = 50; List<Callable<String>> tasks = new ArrayList<>(numRequests); for (int i = 0; i < numRequests; i++) { final GetFeatureInfoRequest request = new GetFeatureInfoRequest(); request.setQueryLayers(((i % 2) == 0) ? layers1 : layers2); final FeatureCollectionType type = (((i % 2) == 0) ? type1 : type2); tasks.add(new Callable<String>() { @Override public String call() throws Exception { ByteArrayOutputStream output = new ByteArrayOutputStream(); format.write(type, request, output); return new String(output.toByteArray()); } }); } ExecutorService executor = Executors.newFixedThreadPool(8); try { List<Future<String>> futures = executor.invokeAll(tasks); for (int i = 0; i < numRequests; i++) { String info = futures.get(i).get(); if ((i % 2) == 0) { assertEquals("", info); } else { assertNotEquals("", info); } } } finally { executor.shutdown(); } } }