/* (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.wps;
import static org.custommonkey.xmlunit.XMLAssert.assertXpathExists;
import static org.junit.Assert.fail;
import it.geosolutions.jaiext.JAIExt;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.Callable;
import javax.xml.namespace.QName;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.dom.DOMSource;
import org.custommonkey.xmlunit.SimpleNamespaceContext;
import org.custommonkey.xmlunit.XMLUnit;
import org.custommonkey.xmlunit.XpathEngine;
import org.geoserver.catalog.Catalog;
import org.geoserver.data.test.MockData;
import org.geoserver.data.test.SystemTestData;
import org.geoserver.data.test.SystemTestData.LayerProperty;
import org.geoserver.test.GeoServerSystemTestSupport;
import org.geoserver.wcs.CoverageCleanerCallback;
import org.geoserver.wps.xml.WPSConfiguration;
import org.geotools.process.Processors;
import org.geotools.xml.Configuration;
import org.geotools.xml.Parser;
import org.junit.After;
import org.opengis.coverage.grid.GridCoverage;
import org.w3c.dom.Document;
import org.xml.sax.SAXParseException;
import org.springframework.mock.web.MockHttpServletResponse;
public abstract class WPSTestSupport extends GeoServerSystemTestSupport {
protected static Catalog catalog;
protected static XpathEngine xp;
// WCS 1.1
public static String WCS_PREFIX = "wcs";
public static String WCS_URI = "http://www.opengis.net/wcs/1.1.1";
public static QName TASMANIA_DEM = new QName(WCS_URI, "DEM", WCS_PREFIX);
public static QName TASMANIA_BM = new QName(WCS_URI, "BlueMarble", WCS_PREFIX);
public static QName ROTATED_CAD = new QName(WCS_URI, "RotatedCad", WCS_PREFIX);
public static QName WORLD = new QName(WCS_URI, "World", WCS_PREFIX);
public static String TIFF = "tiff";
List<GridCoverage> coverages = new ArrayList<GridCoverage>();
static {
JAIExt.initJAIEXT(true, true);
Processors.addProcessFactory(MonkeyProcess.getFactory());
Processors.addProcessFactory(MultiRawProcess.getFactory());
Processors.addProcessFactory(MultiOutputEchoProcess.getFactory());
}
protected void scheduleForDisposal(GridCoverage coverage) {
this.coverages.add(coverage);
}
@After
public void disposeCoverages() {
for (GridCoverage coverage : coverages) {
CoverageCleanerCallback.disposeCoverage(coverage);
}
}
@Override
protected void onSetUp(SystemTestData testData) throws Exception {
super.onSetUp(testData);
//addUser("admin", "geoxserver", null, Arrays.asList("ROLE_ADMINISTRATOR"));
// addLayerAccessRule("*", "*", AccessMode.READ, "*");
// addLayerAccessRule("*", "*", AccessMode.WRITE, "*");
catalog = getCatalog();
// init xmlunit
Map<String, String> namespaces = new HashMap<String, String>();
namespaces.put("wps", "http://www.opengis.net/wps/1.0.0");
namespaces.put("ows", "http://www.opengis.net/ows/1.1");
namespaces.put("gml", "http://www.opengis.net/gml");
namespaces.put("wfs", "http://www.opengis.net/wfs");
namespaces.put("xlink", "http://www.w3.org/1999/xlink");
namespaces.put("xsi", "http://www.w3.org/2001/XMLSchema-instance");
namespaces.put("feature", "http://geoserver.sf.net");
testData.registerNamespaces(namespaces);
registerNamespaces(namespaces);
XMLUnit.setXpathNamespaceContext(new SimpleNamespaceContext(namespaces));
xp = XMLUnit.newXpathEngine();
}
/**
* Subclasses can override to register custom namespace mappings for xml unit
* @param namespaces
*/
protected void registerNamespaces(Map<String, String> namespaces) {
// TODO Auto-generated method stub
}
protected final void setUpUsers(Properties props) {
}
protected final void setUpLayerRoles(Properties properties) {
}
// @Before
// public void login() throws Exception {
// login("admin", "geoserver", "ROLE_ADMINISTRATOR");
// }
protected String root() {
return "wps?";
}
/**
* Validates a document based on the WPS schema
* @throws TransformerException
* @throws ParserConfigurationException
*/
protected void checkValidationErrors(Document dom) throws Exception {
checkValidationErrors(dom, new WPSConfiguration());
}
/**
* Validates a document against the
* @param dom
* @param configuration
*/
protected void checkValidationErrors(Document dom, Configuration configuration) throws Exception {
Parser p = new Parser(configuration);
p.setValidating( true );
p.parse( new DOMSource( dom ) );
if ( !p.getValidationErrors().isEmpty() ) {
for ( Iterator e = p.getValidationErrors().iterator(); e.hasNext(); ) {
SAXParseException ex = (SAXParseException) e.next();
System.out.println( ex.getLineNumber() + "," + ex.getColumnNumber() + " -" + ex.toString() );
}
fail("Document did not validate.");
}
}
protected String readFileIntoString(String filename) throws IOException {
InputStream stream = getClass().getResourceAsStream( filename );
BufferedReader in =
new BufferedReader( new InputStreamReader(stream ) );
StringBuffer sb = new StringBuffer();
String line = null;
while( (line = in.readLine() ) != null ) {
sb.append( line );
}
in.close();
return sb.toString();
}
/**
* Adds the wcs 1.1 coverages.
* @param testData
*/
public void addWcs11Coverages(SystemTestData testData) throws Exception {
String styleName = "raster";
testData.addStyle(styleName, "raster.sld", MockData.class, getCatalog());
Map<LayerProperty, Object> props = new HashMap<SystemTestData.LayerProperty, Object>();
props.put(LayerProperty.STYLE, styleName);
//wcs 1.1
testData.addRasterLayer(TASMANIA_DEM, "tazdem.tiff", TIFF, props, MockData.class, getCatalog());
testData.addRasterLayer(TASMANIA_BM, "tazbm.tiff", TIFF, props, MockData.class, getCatalog());
testData.addRasterLayer(ROTATED_CAD, "rotated.tiff", TIFF, props, MockData.class, getCatalog());
testData.addRasterLayer(WORLD, "world.tiff", TIFF, props, MockData.class, getCatalog());
}
/**
* Submits an asynch execute request and waits for the final result, which is then returned
*
* @param xml
* @param maxWaitSeconds
*
*/
protected Document submitAsynchronous(String xml, long maxWaitSeconds) throws Exception {
Document dom = postAsDOM("wps", xml);
assertXpathExists("//wps:ProcessAccepted", dom);
XpathEngine xpath = XMLUnit.newXpathEngine();
String fullStatusLocation = xpath.evaluate("//wps:ExecuteResponse/@statusLocation", dom);
String statusLocation = fullStatusLocation.substring(fullStatusLocation.indexOf('?') - 3);
return waitForProcessEnd(statusLocation, maxWaitSeconds);
}
protected Document waitForProcessEnd(String statusLocation, long maxWaitSeconds)
throws Exception {
XpathEngine xpath = XMLUnit.newXpathEngine();
Document dom = null;
long start = System.currentTimeMillis();
while ((((System.currentTimeMillis() - start) / 1000) < maxWaitSeconds)) {
MockHttpServletResponse response = getAsServletResponse(statusLocation);
String contents = response.getContentAsString();
// super weird... and I believe related to the testing harness... just ignoring it
// for the moment.
if ("".equals(contents)) {
continue;
}
dom = dom(new ByteArrayInputStream(contents.getBytes()));
// print(dom);
// are we still waiting for termination?
if (xpath.getMatchingNodes("//wps:Status/wps:ProcessAccepted", dom).getLength() > 0
|| xpath.getMatchingNodes("//wps:Status/wps:ProcessStarted", dom).getLength() > 0
|| xpath.getMatchingNodes("//wps:Status/wps:ProcessQueued", dom).getLength() > 0) {
Thread.sleep(100);
} else {
return dom;
}
}
throw new Exception("Waited for the process to complete more than " + maxWaitSeconds);
}
protected Document waitForProcessEnd(String statusLocation, int maxWaitSeconds)
throws Exception {
return waitForProcessEnd(statusLocation, maxWaitSeconds, new Callable<Void>() {
@Override
public Void call() throws Exception {
Thread.sleep(100);
return null;
}
});
}
protected Document waitForProcessEnd(String statusLocation, int maxWaitSeconds,
Callable<Void> waitAction) throws Exception {
XpathEngine xpath = XMLUnit.newXpathEngine();
Document dom = null;
long start = System.currentTimeMillis();
while ((((System.currentTimeMillis() - start) / 1000) < maxWaitSeconds)) {
MockHttpServletResponse response = getAsServletResponse(statusLocation);
String contents = response.getContentAsString();
// super weird... and I believe related to the testing harness... just ignoring it
// for the moment.
if ("".equals(contents)) {
continue;
}
dom = dom(new ByteArrayInputStream(contents.getBytes()));
// print(dom);
// are we still waiting for termination?
if (xpath.getMatchingNodes("//wps:Status/wps:ProcessAccepted", dom).getLength() > 0
|| xpath.getMatchingNodes("//wps:Status/wps:ProcessStarted", dom).getLength() > 0
|| xpath.getMatchingNodes("//wps:Status/wps:ProcessQueued", dom).getLength() > 0) {
waitAction.call();
} else {
return dom;
}
}
throw new Exception("Waited for the process to complete more than " + maxWaitSeconds);
}
protected Document waitForProcessStart(String statusLocation, long maxWaitSeconds)
throws Exception {
XpathEngine xpath = XMLUnit.newXpathEngine();
Document dom = null;
long start = System.currentTimeMillis();
while ((((System.currentTimeMillis() - start) / 1000) < maxWaitSeconds)) {
MockHttpServletResponse response = getAsServletResponse(statusLocation);
String contents = response.getContentAsString();
// super weird... and I believe related to the testing harness... just ignoring it
// for the moment.
if ("".equals(contents)) {
continue;
}
dom = dom(new ByteArrayInputStream(contents.getBytes()));
// print(dom);
// are we still waiting for termination?
if (xpath.getMatchingNodes("//wps:Status/wps:ProcessAccepted", dom).getLength() > 0
|| xpath.getMatchingNodes("//wps:Status/wps:ProcessQueued", dom).getLength() > 0) {
Thread.sleep(100);
} else {
return dom;
}
}
throw new Exception("Waited for the process to complete more than " + maxWaitSeconds);
}
}