/*
* 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.ws.embedded;
// J2SE dependencies
import java.awt.image.BufferedImage;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.PostConstruct;
import javax.imageio.ImageIO;
import javax.imageio.spi.ImageReaderSpi;
import javax.imageio.spi.ImageWriterSpi;
import javax.inject.Inject;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.namespace.QName;
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.provider.DataProviders;
import org.constellation.provider.ProviderFactory;
import static org.constellation.provider.coveragesql.CoverageSQLProviderService.NAMESPACE_DESCRIPTOR;
import org.constellation.test.ImageTesting;
import org.constellation.test.utils.Order;
import org.constellation.test.utils.SpringTestRunner;
import org.geotoolkit.util.NamesExt;
import org.geotoolkit.image.io.plugin.WorldFileImageReader;
import org.geotoolkit.image.jai.Registry;
import org.geotoolkit.ogc.xml.exception.ServiceExceptionReport;
import org.geotoolkit.ows.xml.v110.ExceptionReport;
import static org.geotoolkit.utility.parameter.ParametersExt.getOrCreateGroup;
import static org.geotoolkit.utility.parameter.ParametersExt.getOrCreateValue;
import org.geotoolkit.wcs.xml.WCSMarshallerPool;
import org.geotoolkit.wcs.xml.v100.CoverageDescription;
import org.geotoolkit.wcs.xml.v100.CoverageOfferingBriefType;
import org.geotoolkit.wcs.xml.v100.CoverageOfferingType;
import org.geotoolkit.wcs.xml.v100.DCPTypeType.HTTP.Get;
import org.geotoolkit.wcs.xml.v100.LonLatEnvelopeType;
import org.geotoolkit.wcs.xml.v100.WCSCapabilitiesType;
import org.junit.AfterClass;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeNoException;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.opengis.parameter.ParameterValueGroup;
import org.opengis.util.GenericName;
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;
// JUnit dependencies
/**
* A set of methods that request a Grizzly server which embeds a WCS service.
*
* @version $Id$
*
* @author Cédric Briançon (Geomatys)
* @since 0.3
*/
@RunWith(SpringTestRunner.class)
@ContextConfiguration("classpath:/cstl/spring/test-context.xml")
@ActiveProfiles({"standard"})
public class WCSRequestsTest extends AbstractGrizzlyServer implements ApplicationContextAware {
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;
/**
* The layer to test.
*/
private static final GenericName LAYER_TEST = NamesExt.create("SSTMDE200305");
/**
* URLs which will be tested on the server.
*/
private static final String WCS_FALSE_REQUEST ="request=SomethingElse";
private static final String WCS_FALSE_REQUEST_100 ="request=GetCoverage&service=WCS&version=1.0.0&" +
"format=image/png&width=1024&height=512&" +
"crs=EPSG:4326&bbox=-180,-90,180,90&" +
"coverage=wrongLayer";
private static final String WCS_FALSE_REQUEST_111 ="request=GetCoverage&service=WCS&version=1.1.1&" +
"format=image/png&width=1024&height=512&" +
"crs=EPSG:4326&boundingbox=-180,-90,180,90,EPSG4326&" +
"identifier=wrongLayer";
private static final String WCS_GETCOVERAGE ="request=GetCoverage&service=WCS&version=1.0.0&" +
"format=image/png&width=1024&height=512&" +
"crs=EPSG:4326&bbox=-180,-90,180,90&" +
"coverage="+ LAYER_TEST;
private static final String WCS_GETCOVERAGE_MATRIX ="request=GetCoverage&service=WCS&version=1.0.0&" +
"format=matrix&width=1024&height=512&" +
"crs=EPSG:4326&bbox=-180,-90,180,90&" +
"coverage="+ LAYER_TEST;
private static final String WCS_GETCAPABILITIES ="request=GetCapabilities&service=WCS&version=1.0.0";
private static final String WCS_GETCAPABILITIES2 ="request=GetCapabilities&service=WCS&version=1.0.0";
private static final String WCS_DESCRIBECOVERAGE ="request=DescribeCoverage&coverage=SSTMDE200305&service=wcs&version=1.0.0";
private static boolean initialized = false;
@BeforeClass
public static void initTestDir() {
ConfigDirectory.setupTestEnvironement("WCSRequestsTest");
}
/**
* Initialize the list of layers from the defined providers in Constellation's configuration.
*/
@PostConstruct
public void initLayerList() {
SpringHelper.setApplicationContext(applicationContext);
if (!initialized) {
try {
layerBusiness.removeAll();
serviceBusiness.deleteAll();
dataBusiness.deleteAll();
providerBusiness.removeAll();
final File outputDir = 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:" + outputDir.getAbsolutePath() + "/org/constellation/data/SSTMDE200305.png"));
getOrCreateValue(srcCFConfig, "type").setValue("AUTO");
getOrCreateValue(srcCFConfig, NAMESPACE_DESCRIPTOR.getName().getCode()).setValue("no namespace");
providerBusiness.storeProvider("coverageTestSrc", null, ProviderType.LAYER, "coverage-store", sourceCF);
dataBusiness.create(new QName("SSTMDE200305"), "coverageTestSrc", "COVERAGE", false, true, null, null);
final LayerContext config = new LayerContext();
config.getCustomParameters().put("shiroAccessible", "false");
serviceBusiness.create("wcs", "default", config, null);
layerBusiness.add("SSTMDE200305", null, "coverageTestSrc", null, "default", "wcs", null);
serviceBusiness.create("wcs", "test", config, null);
layerBusiness.add("SSTMDE200305", null, "coverageTestSrc", null, "test", "wcs", null);
initServer(null, null);
pool = WCSMarshallerPool.getInstance();
WorldFileImageReader.Spi.registerDefaults(null);
//reset values, only allow pure java readers
for(String jn : ImageIO.getReaderFormatNames()){
Registry.setNativeCodecAllowed(jn, ImageReaderSpi.class, false);
}
//reset values, only allow pure java writers
for(String jn : ImageIO.getWriterFormatNames()){
Registry.setNativeCodecAllowed(jn, ImageWriterSpi.class, false);
}
initialized = true;
DataProviders.getInstance().reload();
} catch (Exception ex) {
LOGGER.log(Level.SEVERE, null, ex);
}
}
}
@AfterClass
public static void shutDown() throws JAXBException {
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());
}
ConfigDirectory.shutdownTestEnvironement("WCSRequestsTest");
finish();
}
/**
* Ensure that a wrong value given in the request parameter for the WCS server
* returned an error report for the user.
*/
@Test
@Order(order=1)
public void testWCSWrongRequest() throws Exception {
waitForStart();
// Creates an intentional wrong url, regarding the WCS version 1.0.0 standard
URL wrongUrl;
try {
wrongUrl = new URL("http://localhost:"+ grizzly.getCurrentPort() +"/wcs/default?SERVICE=WCS&" + WCS_FALSE_REQUEST);
} catch (MalformedURLException ex) {
assumeNoException(ex);
return;
}
// Try to marshall something from the response returned by the server.
// The response should be a ServiceExceptionReport.
Object obj = unmarshallResponse(wrongUrl);
assertTrue(obj instanceof ServiceExceptionReport);
try {
wrongUrl = new URL("http://localhost:"+ grizzly.getCurrentPort() +"/wcs/default?SERVICE=WCS&" + WCS_FALSE_REQUEST_100);
} catch (MalformedURLException ex) {
assumeNoException(ex);
return;
}
// Try to marshall something from the response returned by the server.
// The response should be a ServiceExceptionReport.
obj = unmarshallResponse(wrongUrl);
assertTrue(obj instanceof ServiceExceptionReport);
try {
wrongUrl = new URL("http://localhost:"+ grizzly.getCurrentPort() +"/wcs/default?SERVICE=WCS&" + WCS_FALSE_REQUEST_111);
} catch (MalformedURLException ex) {
assumeNoException(ex);
return;
}
// Try to marshall something from the response returned by the server.
// The response should be a OWS ExceptionReport.
obj = unmarshallResponse(wrongUrl);
assertTrue("exception type:" + obj.getClass().getName(), obj instanceof ExceptionReport);
}
/**
* Ensures that a valid GetCoverage request returns indeed a {@link BufferedImage}.
*/
@Test
@Order(order=2)
public void testWCSGetCoverage() throws Exception {
// Creates a valid GetCoverage url.
final URL getCoverageUrl;
try {
getCoverageUrl = new URL("http://localhost:"+ grizzly.getCurrentPort() +"/wcs/default?SERVICE=WCS&" + WCS_GETCOVERAGE);
} catch (MalformedURLException ex) {
assumeNoException(ex);
return;
}
// Try to get the coverage from the url.
final BufferedImage image = getImageFromURL(getCoverageUrl, "image/png");
// Test on the returned image.
assertFalse (ImageTesting.isImageEmpty(image));
assertEquals(1024, image.getWidth());
assertEquals(512, image.getHeight());
assertTrue (ImageTesting.getNumColors(image) > 8);
}
/**
* Ensures a GetCoverage request with the output format matrix works fine.
*
* For now, this format is not well handled by the current Geotools. There are some
* errors in the reading of this format, and they will be corrected in the next version
* of Geotools.
*
* @TODO: do this test when moving of Geotools' version
*/
@Ignore
@Order(order=3)
public void testWCSGetCoverageMatrixFormat() throws Exception {
// Creates a valid GetCoverage url.
final URL getCovMatrixUrl;
try {
getCovMatrixUrl = new URL("http://localhost:"+ grizzly.getCurrentPort() +"/wcs/default?SERVICE=WCS&" + WCS_GETCOVERAGE_MATRIX);
} catch (MalformedURLException ex) {
assumeNoException(ex);
return;
}
final BufferedImage image = getImageFromURL(getCovMatrixUrl, "application/matrix");
//assertEquals(Commons.checksum(image), ...);
}
/**
* Ensures that a valid GetCapabilities request returns indeed a valid GetCapabilities
* document representing the server capabilities in the WCS version 1.0.0 standard.
*/
@Test
@Order(order=4)
public void testWCSGetCapabilities() throws Exception {
// Creates a valid GetCapabilities url.
URL getCapsUrl;
try {
getCapsUrl = new URL("http://localhost:"+ grizzly.getCurrentPort() +"/wcs/default?SERVICE=WCS&" + WCS_GETCAPABILITIES);
} catch (MalformedURLException ex) {
assumeNoException(ex);
return;
}
// Try to marshall something from the response returned by the server.
// The response should be a WCSCapabilitiesType.
Object obj = unmarshallResponse(getCapsUrl);
assertTrue(obj.toString(), obj instanceof WCSCapabilitiesType);
WCSCapabilitiesType responseCaps = (WCSCapabilitiesType)obj;
final List<CoverageOfferingBriefType> coverages = responseCaps.getContentMetadata().getCoverageOfferingBrief();
assertNotNull(coverages);
assertFalse(coverages.isEmpty());
boolean layerTestFound = false;
for (CoverageOfferingBriefType coverage : coverages) {
for (JAXBElement<String> elem : coverage.getRest()) {
if (elem.getValue().equals(LAYER_TEST.tip().toString())) {
layerTestFound = true;
final LonLatEnvelopeType env = coverage.getLonLatEnvelope();
assertTrue(env.getPos().get(0).getValue().get(0) == -180d);
assertTrue(env.getPos().get(0).getValue().get(1) == -90d);
assertTrue(env.getPos().get(1).getValue().get(0) == 180d);
assertTrue(env.getPos().get(1).getValue().get(1) == 90d);
}
}
}
if (layerTestFound == false) {
throw new AssertionError("The layer \""+ LAYER_TEST +"\" was not found in the returned GetCapabilities.");
}
Get get = (Get) responseCaps.getCapability().getRequest().getGetCapabilities().getDCP().get(0).getHTTP().getRealGetOrPost().get(0);
assertEquals("http://localhost:"+ grizzly.getCurrentPort() +"/wcs/default?", get.getOnlineResource().getHref());
try {
getCapsUrl = new URL("http://localhost:"+ grizzly.getCurrentPort() +"/wcs/test?SERVICE=WCS&" + WCS_GETCAPABILITIES2);
} catch (MalformedURLException ex) {
assumeNoException(ex);
return;
}
// Try to marshall something from the response returned by the server.
// The response should be a WCSCapabilitiesType.
obj = unmarshallResponse(getCapsUrl);
assertTrue(obj instanceof WCSCapabilitiesType);
responseCaps = (WCSCapabilitiesType)obj;
get = (Get) responseCaps.getCapability().getRequest().getGetCapabilities().getDCP().get(0).getHTTP().getRealGetOrPost().get(0);
assertEquals("http://localhost:"+ grizzly.getCurrentPort() +"/wcs/test?", get.getOnlineResource().getHref());
try {
getCapsUrl = new URL("http://localhost:"+ grizzly.getCurrentPort() +"/wcs/default?SERVICE=WCS&" + WCS_GETCAPABILITIES);
} catch (MalformedURLException ex) {
assumeNoException(ex);
return;
}
// Try to marshall something from the response returned by the server.
// The response should be a WCSCapabilitiesType.
obj = unmarshallResponse(getCapsUrl);
assertTrue(obj instanceof WCSCapabilitiesType);
responseCaps = (WCSCapabilitiesType)obj;
get = (Get) responseCaps.getCapability().getRequest().getGetCapabilities().getDCP().get(0).getHTTP().getRealGetOrPost().get(0);
assertEquals("http://localhost:"+ grizzly.getCurrentPort() +"/wcs/default?", get.getOnlineResource().getHref());
}
/**
* Ensures that a valid DescribeCoverage request returns indeed a valid document.
*/
@Test
@Order(order=5)
public void testWCSDescribeCoverage() throws Exception {
// Creates a valid DescribeCoverage url.
final URL getCapsUrl;
try {
getCapsUrl = new URL("http://localhost:"+ grizzly.getCurrentPort() +"/wcs/default?SERVICE=WCS&" + WCS_DESCRIBECOVERAGE);
} catch (MalformedURLException ex) {
assumeNoException(ex);
return;
}
// Try to marshall something from the response returned by the server.
// The response should be a WCSCapabilitiesType.
final Object obj = unmarshallResponse(getCapsUrl);
assertTrue(obj instanceof CoverageDescription);
final CoverageDescription responseDesc = (CoverageDescription)obj;
assertNotNull(responseDesc);
final List<CoverageOfferingType> coverageOffs = responseDesc.getCoverageOffering();
assertFalse (coverageOffs.isEmpty());
assertEquals(LAYER_TEST.tip().toString(), coverageOffs.get(0).getRest().get(1).getValue());
// TODO: add more tests on returned XML doc
}
}