/* (c) 2014 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.sextante;
import static org.geoserver.wps.sextante.SextanteProcessFactory.*;
import java.util.HashMap;
import java.util.Map;
import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.data.DataUtilities;
import org.geotools.data.FeatureSource;
import org.geotools.data.Query;
import org.geotools.feature.FeatureCollection;
import org.geotools.process.Process;
import org.opengis.util.ProgressListener;
import com.vividsolutions.jts.geom.Envelope;
import es.unex.sextante.core.GeoAlgorithm;
import es.unex.sextante.core.ITaskMonitor;
import es.unex.sextante.core.OutputObjectsSet;
import es.unex.sextante.core.ParametersSet;
import es.unex.sextante.dataObjects.IDataObject;
import es.unex.sextante.exceptions.GeoAlgorithmExecutionException;
import es.unex.sextante.exceptions.WrongParameterIDException;
import es.unex.sextante.outputs.Output;
import es.unex.sextante.outputs.OutputRasterLayer;
import es.unex.sextante.parameters.Parameter;
import es.unex.sextante.core.AnalysisExtent;
import org.geoserver.wps.sextante.GTOutputFactory;
import org.geoserver.wps.sextante.GTRasterLayer;
import org.geoserver.wps.sextante.GTVectorLayer;
public class SextanteProcess implements Process{
private GeoAlgorithm m_Algorithm;
/**
* Constructs a new process based on a SEXTANTE geoalgorithm
* @param algorithm the SEXTANTE geoalgorithm
*/
public SextanteProcess(GeoAlgorithm algorithm) {
m_Algorithm = algorithm;
}
public Map<String, Object> execute(Map<String, Object> input,
ProgressListener monitor) {
ITaskMonitor taskMonitor = new ProgressListenerTaskMonitor(monitor);
try {
setAlgorithmInputs(input);
/*
* Execute the algorithm
* The output factory tells the algorithm how to create
* new data objects (layers and tables)
* Since we are working with GeoTools , we use the
* GTOutputFactory, which creates objects based on geotools
* data objects (DataStore and GridCoverage)
*/
if (m_Algorithm.execute(taskMonitor, new GTOutputFactory())){
return createReturnMapFromOutputObjects();
}
else{
//if the execution was canceled, we return null
return null;
}
} catch (GeoAlgorithmExecutionException e) {
e.printStackTrace();
return null;
}
}
/**
* Creates a suitable return map for this process
* from the outputs generated by the SEXTANTE algorithm
* @return a map with algorithm results
*/
private Map<String, Object> createReturnMapFromOutputObjects() {
try {
Map<String, Object> results = new HashMap<String, Object>();
OutputObjectsSet outputs = m_Algorithm.getOutputObjects();
for (int i = 0; i < outputs.getOutputObjectsCount(); i++) {
Output output = outputs.getOutput(i);
Object outputObject = output.getOutputObject();
// if the output object is a layer or a table, we return
// the inner GeoTools object
if (outputObject instanceof IDataObject){
IDataObject dataObject = (IDataObject) outputObject;
Object wrapped = dataObject.getBaseDataObject();
if(wrapped instanceof FeatureSource) {
results.put(output.getName(), ((FeatureSource) wrapped).getFeatures());
} else if(wrapped instanceof GridCoverage2D) {
results.put(output.getName(), wrapped);
} else {
results.put(output.getName(), wrapped);
}
}
else{
results.put(output.getName(), outputObject);
}
}
return results;
} catch(Throwable t) {
throw new RuntimeException(t);
}
}
/**
* Sets the input of the SEXTANTE algorithm from the input map
* of this process
* @param input the input map of this process
* @throws WrongParameterIDException
*/
private void setAlgorithmInputs(Map<String, Object> input)
throws GeoAlgorithmExecutionException {
// set the normal parameters
ParametersSet paramSet = (ParametersSet) m_Algorithm.getParameters();
boolean gridExtendRequired = false;
for(String sKey : input.keySet()) {
if(SEXTANTE_GRID_CELL_SIZE.equals(sKey) || SEXTANTE_GRID_ENVELOPE.equals(sKey)) {
// these two parameters we made up to expose the GridExtent, we'll deal with them later
continue;
}
Object paramValue = input.get(sKey);
Parameter param = paramSet.getParameter(sKey);
if(paramValue instanceof FeatureCollection) {
GTVectorLayer layer = new GTVectorLayer();
layer.create(DataUtilities.source((FeatureCollection) paramValue));
param.setParameterValue(layer);
} else if(paramValue instanceof GridCoverage2D) {
GTRasterLayer layer = new GTRasterLayer();
gridExtendRequired = true;
layer.create(paramValue);
param.setParameterValue(layer);
} else {
param.setParameterValue(paramValue);
}
}
// check the outputs as well for raster data
OutputObjectsSet outputs = m_Algorithm.getOutputObjects();
for (int i = 0; i < outputs.getOutputObjectsCount(); i++) {
Output output = outputs.getOutput(i);
if(output instanceof OutputRasterLayer) {
gridExtendRequired = true;
}
}
// handle the grid extent if necessary
if(gridExtendRequired) {
// get the cell size
double cellSize = Double.NaN;
if(input.get(SEXTANTE_GRID_CELL_SIZE) != null) {
cellSize = (Double) input.get(SEXTANTE_GRID_CELL_SIZE);
} else {
for(String sKey : input.keySet()) {
Object value = paramSet.getParameter(sKey).getParameterValueAsObject();
if(value instanceof GTRasterLayer) {
cellSize = ((GTRasterLayer) value).getLayerCellSize();
return;
}
}
}
if(Double.isNaN(cellSize)) {
throw new GeoAlgorithmExecutionException(SEXTANTE_GRID_CELL_SIZE
+ " parameter could not be derived from inputs, and is not available among ");
}
// get the extents
Envelope envelope = null;
if(input.get(SEXTANTE_GRID_ENVELOPE) != null) {
envelope = (Envelope) input.get(SEXTANTE_GRID_ENVELOPE);
} else {
for(String sKey : input.keySet()) {
Object value = paramSet.getParameter(sKey).getParameterValueAsObject();
if(value instanceof GTRasterLayer) {
AnalysisExtent ge = ((GTRasterLayer) value).getLayerGridExtent();
Envelope genv = new Envelope(ge.getXMin(), ge.getXMax(), ge.getYMin(), ge.getYMax());
if(envelope == null) {
envelope = genv;
} else {
envelope.expandToInclude(genv);
}
return;
}
}
}
if(envelope == null) {
if(Double.isNaN(cellSize)) {
throw new GeoAlgorithmExecutionException(SEXTANTE_GRID_ENVELOPE
+ " parameter could not be derived from inputs, and is not available among ");
}
}
// build and set the grid extends
AnalysisExtent extent = new AnalysisExtent();
extent.setXRange(envelope.getMinX(), envelope.getMaxX(), false);
extent.setYRange(envelope.getMinY(), envelope.getMaxY(), false);
extent.setCellSize(cellSize);
m_Algorithm.setAnalysisExtent(extent);
}
}
}