/*
* Constellation - An open source and standard compliant SDI
* http://www.constellation-sdi.org
*
* Copyright 2014 Geomatys.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.constellation.map.ws.rs;
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.TimeZone;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.PostConstruct;
import javax.inject.Inject;
import javax.ws.rs.core.MultivaluedMap;
import javax.xml.namespace.QName;
import org.apache.sis.util.logging.Logging;
import org.constellation.admin.SpringHelper;
import org.constellation.api.ProviderType;
import org.constellation.business.IDataBusiness;
import org.constellation.business.ILayerBusiness;
import org.constellation.business.IProviderBusiness;
import org.constellation.business.IServiceBusiness;
import org.constellation.configuration.ConfigDirectory;
import org.constellation.configuration.ConfigurationException;
import org.constellation.configuration.LayerContext;
import org.constellation.map.ws.QueryContext;
import org.constellation.provider.DataProviders;
import org.constellation.provider.ProviderFactory;
import org.constellation.test.utils.BasicMultiValueMap;
import org.constellation.test.utils.BasicUriInfo;
import org.constellation.test.utils.SpringTestRunner;
import org.constellation.ws.WSEngine;
import org.constellation.ws.Worker;
import org.constellation.ws.embedded.AbstractGrizzlyServer;
import org.constellation.ws.rs.AbstractWebService;
import org.geotoolkit.internal.referencing.CRSUtilities;
import static org.geotoolkit.utility.parameter.ParametersExt.createGroup;
import static org.geotoolkit.utility.parameter.ParametersExt.getOrCreateGroup;
import static org.geotoolkit.utility.parameter.ParametersExt.getOrCreateValue;
import org.geotoolkit.referencing.CRS;
import org.geotoolkit.referencing.ReferencingUtilities;
import org.geotoolkit.wms.xml.GetFeatureInfo;
import org.geotoolkit.wms.xml.GetMap;
import org.junit.AfterClass;
import static org.junit.Assert.assertEquals;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.opengis.geometry.Envelope;
import org.opengis.parameter.ParameterValueGroup;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
/**
* Testing wms service value parsing.
*
* @author Johann Sorel (Geomatys)
*/
@RunWith(SpringTestRunner.class)
@ContextConfiguration("classpath:/cstl/spring/test-context.xml")
@ActiveProfiles({"standard"})
public class WMSServiceTest implements ApplicationContextAware {
private static final Logger LOGGER = Logging.getLogger("org.constellation.map.ws.rs");
protected ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
@Inject
private IServiceBusiness serviceBusiness;
@Inject
protected ILayerBusiness layerBusiness;
@Inject
protected IProviderBusiness providerBusiness;
@Inject
protected IDataBusiness dataBusiness;
private static final double DELTA = 0.00000001;
private static WMSService service;
private final BasicUriInfo info = new BasicUriInfo(null, null);
private final MultivaluedMap<String,String> queryParameters = new BasicMultiValueMap<>();
private final MultivaluedMap<String,String> pathParameters = new BasicMultiValueMap<>();
private static boolean initialized = false;
@BeforeClass
public static void start() {
ConfigDirectory.setupTestEnvironement("WMSServiceTest");
}
@PostConstruct
public void init() {
SpringHelper.setApplicationContext(applicationContext);
if (!initialized) {
try {
layerBusiness.removeAll();
serviceBusiness.deleteAll();
dataBusiness.deleteAll();
providerBusiness.removeAll();
// coverage-file datastore
final File rootDir = AbstractGrizzlyServer.initDataDirectory();
final ProviderFactory covFilefactory = DataProviders.getInstance().getFactory("coverage-store");
final ParameterValueGroup sourceCF = covFilefactory.getProviderDescriptor().createValue();
getOrCreateValue(sourceCF, "id").setValue("coverageTestSrc");
getOrCreateValue(sourceCF, "load_all").setValue(true);
final ParameterValueGroup choice3 = getOrCreateGroup(sourceCF, "choice");
final ParameterValueGroup srcCFConfig = getOrCreateGroup(choice3, "FileCoverageStoreParameters");
getOrCreateValue(srcCFConfig, "path").setValue(new URL("file:" + rootDir.getAbsolutePath() + "/org/constellation/data/SSTMDE200305.png"));
getOrCreateValue(srcCFConfig, "type").setValue("AUTO");
getOrCreateValue(srcCFConfig, "namespace").setValue("no namespace");
providerBusiness.storeProvider("coverageTestSrc", null, ProviderType.LAYER, "coverage-store", sourceCF);
dataBusiness.create(new QName("SSTMDE200305"), "coverageTestSrc", "COVERAGE", false, true, null, null);
final ProviderFactory ffactory = DataProviders.getInstance().getFactory("feature-store");
final File outputDir = AbstractGrizzlyServer.initDataDirectory();
final ParameterValueGroup sourcef = ffactory.getProviderDescriptor().createValue();
getOrCreateValue(sourcef, "id").setValue("shapeSrc");
getOrCreateValue(sourcef, "load_all").setValue(true);
final ParameterValueGroup choice = getOrCreateGroup(sourcef, "choice");
final ParameterValueGroup shpconfig = createGroup(choice, "ShapefileParametersFolder");
getOrCreateValue(shpconfig, "url").setValue(new URL("file:"+outputDir.getAbsolutePath() + "/org/constellation/ws/embedded/wms111/shapefiles"));
getOrCreateValue(shpconfig, "namespace").setValue("http://www.opengis.net/gml");
final ParameterValueGroup layer = getOrCreateGroup(sourcef, "Layer");
getOrCreateValue(layer, "name").setValue("NamedPlaces");
getOrCreateValue(layer, "style").setValue("cite_style_NamedPlaces");
providerBusiness.storeProvider("shapeSrc", null, ProviderType.LAYER, "feature-store", sourcef);
dataBusiness.create(new QName("http://www.opengis.net/gml", "BuildingCenters"), "shapeSrc", "VECTOR", false, true, null, null);
dataBusiness.create(new QName("http://www.opengis.net/gml", "BasicPolygons"), "shapeSrc", "VECTOR", false, true, null, null);
dataBusiness.create(new QName("http://www.opengis.net/gml", "Bridges"), "shapeSrc", "VECTOR", false, true, null, null);
dataBusiness.create(new QName("http://www.opengis.net/gml", "Streams"), "shapeSrc", "VECTOR", false, true, null, null);
dataBusiness.create(new QName("http://www.opengis.net/gml", "Lakes"), "shapeSrc", "VECTOR", false, true, null, null);
dataBusiness.create(new QName("http://www.opengis.net/gml", "NamedPlaces"), "shapeSrc", "VECTOR", false, true, null, null);
dataBusiness.create(new QName("http://www.opengis.net/gml", "Buildings"), "shapeSrc", "VECTOR", false, true, null, null);
dataBusiness.create(new QName("http://www.opengis.net/gml", "RoadSegments"), "shapeSrc", "VECTOR", false, true, null, null);
dataBusiness.create(new QName("http://www.opengis.net/gml", "DividedRoutes"), "shapeSrc", "VECTOR", false, true, null, null);
dataBusiness.create(new QName("http://www.opengis.net/gml", "Forests"), "shapeSrc", "VECTOR", false, true, null, null);
dataBusiness.create(new QName("http://www.opengis.net/gml", "MapNeatline"), "shapeSrc", "VECTOR", false, true, null, null);
dataBusiness.create(new QName("http://www.opengis.net/gml", "Ponds"), "shapeSrc", "VECTOR", false, true, null, null);
final LayerContext config = new LayerContext();
config.getCustomParameters().put("shiroAccessible", "false");
serviceBusiness.create("wms", "default", config, null);
layerBusiness.add("SSTMDE200305", null, "coverageTestSrc", null, "default", "wms", null);
layerBusiness.add("BuildingCenters", "http://www.opengis.net/gml", "shapeSrc", null, "default", "wms", null);
layerBusiness.add("BasicPolygons", "http://www.opengis.net/gml", "shapeSrc", null, "default", "wms", null);
layerBusiness.add("Bridges", "http://www.opengis.net/gml", "shapeSrc", null, "default", "wms", null);
layerBusiness.add("Streams", "http://www.opengis.net/gml", "shapeSrc", null, "default", "wms", null);
layerBusiness.add("Lakes", "http://www.opengis.net/gml", "shapeSrc", null, "default", "wms", null);
layerBusiness.add("NamedPlaces", "http://www.opengis.net/gml", "shapeSrc", null, "default", "wms", null);
layerBusiness.add("Buildings", "http://www.opengis.net/gml", "shapeSrc", null, "default", "wms", null);
layerBusiness.add("RoadSegments", "http://www.opengis.net/gml", "shapeSrc", null, "default", "wms", null);
layerBusiness.add("DividedRoutes", "http://www.opengis.net/gml", "shapeSrc", null, "default", "wms", null);
layerBusiness.add("Forests", "http://www.opengis.net/gml", "shapeSrc", null, "default", "wms", null);
layerBusiness.add("MapNeatline", "http://www.opengis.net/gml", "shapeSrc", null, "default", "wms", null);
layerBusiness.add("Ponds", "http://www.opengis.net/gml", "shapeSrc", null, "default", "wms", null);
service = new WMSService();
initialized = true;
} catch (Exception ex) {
LOGGER.log(Level.SEVERE, null, ex);
}
}
}
@AfterClass
public static void finish() {
service.destroy();
ConfigDirectory.shutdownTestEnvironement("WMSServiceTest");
try {
final ILayerBusiness layerBean = SpringHelper.getBean(ILayerBusiness.class);
if (layerBean != null) {
layerBean.removeAll();
}
final IServiceBusiness service = SpringHelper.getBean(IServiceBusiness.class);
if (service != null) {
service.deleteAll();
}
final IDataBusiness dataBean = SpringHelper.getBean(IDataBusiness.class);
if (dataBean != null) {
dataBean.deleteAll();
}
final IProviderBusiness provider = SpringHelper.getBean(IProviderBusiness.class);
if (provider != null) {
provider.removeAll();
}
} catch (ConfigurationException ex) {
Logger.getAnonymousLogger().log(Level.WARNING, ex.getMessage());
}
}
public void setFields() throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException {
//do not use this in real code, just for testing
Field privateStringField = AbstractWebService.class.getDeclaredField("uriContext");
privateStringField.setAccessible(true);
privateStringField.set(service, info);
info.setPathParameters(pathParameters);
info.setQueryParameters(queryParameters);
}
private GetMap callGetMap() throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException, NoSuchMethodException{
//do not use this in real code, just for testing
final Worker worker = WSEngine.getInstance("WMS", "default");
final Method adaptGetMapMethod = WMSService.class.getDeclaredMethod(
"adaptGetMap", boolean.class, QueryContext.class, Worker.class);
adaptGetMapMethod.setAccessible(true);
final GetMap getMap = (GetMap)adaptGetMapMethod.invoke(service, true, new QueryContext(), worker);
return getMap;
}
private GetFeatureInfo callGetFeatureInfo() throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException, NoSuchMethodException{
//do not use this in real code, just for testing
final Worker worker = WSEngine.getInstance("WMS", "default");
final Method adaptGetMapMethod = WMSService.class.getDeclaredMethod(
"adaptGetFeatureInfo", QueryContext.class, Worker.class);
adaptGetMapMethod.setAccessible(true);
final GetFeatureInfo getFI = (GetFeatureInfo)adaptGetMapMethod.invoke(service, new QueryContext(), worker);
return getFI;
}
/**
* TODO must test :
* - Errors returned when missing parameters
* - Version 1.1 and 1.3
* - Dim_Range value
*/
@Test
public void testAdaptGetMap() throws Exception {
queryParameters.clear();
pathParameters.clear();
queryParameters.putSingle("AZIMUTH", "49");
queryParameters.putSingle("BBOX", "-4000,-150,3200,560");
queryParameters.putSingle("CRS", "EPSG:3395");
queryParameters.putSingle("ELEVATION", "156.789");
queryParameters.putSingle("FORMAT", "image/png");
queryParameters.putSingle("HEIGHT", "600");
queryParameters.putSingle("LAYERS", "BlueMarble");
queryParameters.putSingle("STYLES", "");
queryParameters.putSingle("TIME", "2007-06-23T14:31:56");
queryParameters.putSingle("WIDTH", "800");
queryParameters.putSingle("VERSION", "1.3.0");
setFields();
final GetMap parsedQuery = callGetMap();
//azimuth
assertEquals(49, parsedQuery.getAzimuth(), DELTA);
//elevation
assertEquals(156.789d, parsedQuery.getElevation().doubleValue(), DELTA);
//time
Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("GMT+0"));
cal.set(Calendar.YEAR, 2007);
cal.set(Calendar.MONTH, 05);
cal.set(Calendar.DAY_OF_MONTH, 23);
cal.set(Calendar.HOUR_OF_DAY, 14);
cal.set(Calendar.MINUTE, 31);
cal.set(Calendar.SECOND, 56);
cal.set(Calendar.MILLISECOND, 0);
Date time = cal.getTime();
assertEquals(time, parsedQuery.getTime().get(0));
//envelope 2D
Envelope env2D = parsedQuery.getEnvelope2D();
assertEquals(CRS.decode("EPSG:3395"), env2D.getCoordinateReferenceSystem());
assertEquals(-4000d, env2D.getMinimum(0),DELTA);
assertEquals(-150d, env2D.getMinimum(1),DELTA);
assertEquals(3200d, env2D.getMaximum(0),DELTA);
assertEquals(560d, env2D.getMaximum(1),DELTA);
//envelope 4D
final List<Date> times = parsedQuery.getTime();
final Date[] dates = new Date[2];
if (times != null && !times.isEmpty()) {
dates[0] = times.get(0);
dates[1] = times.get(times.size()-1);
}
Envelope env4D = ReferencingUtilities.combine(parsedQuery.getEnvelope2D(), dates, new Double[]{parsedQuery.getElevation(), parsedQuery.getElevation()});
CoordinateReferenceSystem crs = env4D.getCoordinateReferenceSystem();
assertEquals(4, crs.getCoordinateSystem().getDimension());
CoordinateReferenceSystem crs2D = CRSUtilities.getCRS2D(crs);
assertEquals(CRS.decode("EPSG:3395"), crs2D);
assertEquals(-4000d, env4D.getMinimum(0),DELTA);
assertEquals(-150d, env4D.getMinimum(1),DELTA);
assertEquals(3200d, env4D.getMaximum(0),DELTA);
assertEquals(560d, env4D.getMaximum(1),DELTA);
assertEquals(156.789d, env4D.getMinimum(2), DELTA);
assertEquals(156.789d, env4D.getMaximum(2), DELTA);
assertEquals(time.getTime(), env4D.getMinimum(3), DELTA);
assertEquals(time.getTime(), env4D.getMaximum(3), DELTA);
// TODO
// getMap.getBackground();
// getMap.getExceptionFormat();
// getMap.getFormat();
// getMap.getLayers();
// getMap.getRequest();
// getMap.getService();
// getMap.getSize();
// getMap.getSld();
// getMap.getStyles();
// getMap.getTime();
// getMap.getTransparent();
// getMap.getVersion();
}
@Test
public void testAdaptGetFeatureInfo() throws Exception{
queryParameters.clear();
pathParameters.clear();
queryParameters.putSingle("AZIMUTH", "49");
queryParameters.putSingle("BBOX", "-4000,-150,3200,560");
queryParameters.putSingle("CRS", "EPSG:3395");
queryParameters.putSingle("ELEVATION", "156.789");
queryParameters.putSingle("FORMAT", "image/png");
queryParameters.putSingle("HEIGHT", "600");
queryParameters.putSingle("I", "230");
queryParameters.putSingle("J", "315");
queryParameters.putSingle("LAYERS", "BlueMarble");
queryParameters.putSingle("QUERY_LAYERS", "BlueMarble");
queryParameters.putSingle("STYLES", "");
queryParameters.putSingle("TIME", "2007-06-23T14:31:56");
queryParameters.putSingle("WIDTH", "800");
queryParameters.putSingle("VERSION", "1.3.0");
setFields();
final GetFeatureInfo parsedQuery = callGetFeatureInfo();
//azimuth
assertEquals(49, parsedQuery.getAzimuth(), DELTA);
//elevation
assertEquals(156.789d, parsedQuery.getElevation().doubleValue(), DELTA);
//time
Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("GMT+0"));
cal.set(Calendar.YEAR, 2007);
cal.set(Calendar.MONTH, 05);
cal.set(Calendar.DAY_OF_MONTH, 23);
cal.set(Calendar.HOUR_OF_DAY, 14);
cal.set(Calendar.MINUTE, 31);
cal.set(Calendar.SECOND, 56);
cal.set(Calendar.MILLISECOND, 0);
Date time = cal.getTime();
assertEquals(time, parsedQuery.getTime().get(0));
//envelope 2D
Envelope env2D = parsedQuery.getEnvelope2D();
assertEquals(CRS.decode("EPSG:3395"), env2D.getCoordinateReferenceSystem());
assertEquals(-4000d, env2D.getMinimum(0),DELTA);
assertEquals(-150d, env2D.getMinimum(1),DELTA);
assertEquals(3200d, env2D.getMaximum(0),DELTA);
assertEquals(560d, env2D.getMaximum(1),DELTA);
//envelope 4D
final List<Date> times = parsedQuery.getTime();
final Date[] dates = new Date[2];
if (times != null && !times.isEmpty()) {
dates[0] = times.get(0);
dates[1] = times.get(times.size()-1);
}
Envelope env4D = ReferencingUtilities.combine(parsedQuery.getEnvelope2D(), dates, new Double[]{parsedQuery.getElevation(), parsedQuery.getElevation()});
CoordinateReferenceSystem crs = env4D.getCoordinateReferenceSystem();
assertEquals(4, crs.getCoordinateSystem().getDimension());
CoordinateReferenceSystem crs2D = CRSUtilities.getCRS2D(crs);
assertEquals(CRS.decode("EPSG:3395"), crs2D);
assertEquals(-4000d, env4D.getMinimum(0),DELTA);
assertEquals(-150d, env4D.getMinimum(1),DELTA);
assertEquals(3200d, env4D.getMaximum(0),DELTA);
assertEquals(560d, env4D.getMaximum(1),DELTA);
assertEquals(156.789d, env4D.getMinimum(2), DELTA);
assertEquals(156.789d, env4D.getMaximum(2), DELTA);
assertEquals(time.getTime(), env4D.getMinimum(3), DELTA);
assertEquals(time.getTime(), env4D.getMaximum(3), DELTA);
//mouse coordinate
assertEquals(230, parsedQuery.getX());
assertEquals(315, parsedQuery.getY());
// TODO
// getMap.getBackground();
// getMap.getExceptionFormat();
// getMap.getFormat();
// getMap.getLayers();
// getMap.getRequest();
// getMap.getService();
// getMap.getSize();
// getMap.getSld();
// getMap.getStyles();
// getMap.getTime();
// getMap.getTransparent();
// getMap.getVersion();
}
}