You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
wps/src/main/java/org/gcube/data/analysis/wps/ExecuteResponseBuilder.java

420 lines
17 KiB
Java

package org.gcube.data.analysis.wps;
import java.io.InputStream;
import java.net.Inet4Address;
import java.net.UnknownHostException;
import java.util.Calendar;
import javax.xml.XMLConstants;
import javax.xml.namespace.QName;
import net.opengis.ows.x11.DomainMetadataType;
import net.opengis.ows.x11.LanguageStringType;
import net.opengis.wps.x100.DataInputsType;
import net.opengis.wps.x100.DocumentOutputDefinitionType;
import net.opengis.wps.x100.ExecuteResponseDocument;
import net.opengis.wps.x100.ExecuteResponseDocument.ExecuteResponse;
import net.opengis.wps.x100.OutputDefinitionType;
import net.opengis.wps.x100.OutputDescriptionType;
import net.opengis.wps.x100.ProcessDescriptionType;
import net.opengis.wps.x100.StatusType;
import org.apache.xmlbeans.XmlCursor;
import org.n52.wps.ServerDocument.Server;
import org.n52.wps.commons.WPSConfig;
import org.n52.wps.io.data.IBBOXData;
import org.n52.wps.io.data.IData;
import org.n52.wps.server.ExceptionReport;
import org.n52.wps.server.RepositoryManager;
import org.n52.wps.server.WebProcessingService;
import org.n52.wps.server.request.Request;
import org.n52.wps.server.response.OutputDataItem;
import org.n52.wps.server.response.RawData;
import org.n52.wps.util.XMLBeansHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* WPS Execute operation response. By default, this XML document is delivered to
* the client in response to an Execute request. If "status" is "false" in the
* Execute operation request, this document is normally returned when process
* execution has been completed. If "status" in the Execute request is "true",
* this response shall be returned as soon as the Execute request has been
* accepted for processing. In this case, the same XML document is also made
* available as a web-accessible resource from the URL identified in the
* statusLocation, and the WPS server shall repopulate it once the process has
* completed. It may repopulate it on an ongoing basis while the process is
* executing. However, the response to an Execute request will not include this
* element in the special case where the output is a single complex value result
* and the Execute request indicates that "store" is "false". Instead, the
* server shall return the complex result (e.g., GIF image or GML) directly,
* without encoding it in the ExecuteResponse. If processing fails in this
* special case, the normal ExecuteResponse shall be sent, with the error
* condition indicated. This option is provided to simplify the programming
* required for simple clients and for service chaining.
*
* @author Timon ter Braak
*
*/
public class ExecuteResponseBuilder {
private String identifier;
private DataInputsType dataInputs;
// private DocumentOutputDefinitionType[] outputDefs;
private ExecuteRequest request;
private ExecuteResponseDocument doc;
private RawData rawDataHandler = null;
private ProcessDescriptionType description;
private static Logger LOGGER = LoggerFactory.getLogger(ExecuteResponseBuilder.class);
private Calendar creationTime;
String webPath;
String webStatus;
public ExecuteResponseBuilder(ExecuteRequest request) throws ExceptionReport {
LOGGER.debug("Building Doc");
this.request = request;
doc = ExecuteResponseDocument.Factory.newInstance();
doc.addNewExecuteResponse();
XmlCursor c = doc.newCursor();
c.toFirstChild();
c.toLastAttribute();
c.setAttributeText(new QName(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, "schemaLocation"),
"http://www.opengis.net/wps/1.0.0 http://schemas.opengis.net/wps/1.0.0/wpsExecute_response.xsd");
Server docServer = WPSConfig.getInstance().getWPSConfig().getServer();
String webapp = docServer.getWebappPath();
if (webapp == null)
webapp = "wps";
String host = docServer.getHostname();
if (host.toLowerCase().equals("localhost"))
try {
host = Inet4Address.getLocalHost().getHostAddress();
} catch (UnknownHostException e) {
LOGGER.error("error", e);
}
String port = docServer.getHostport();
String protocol = docServer.getProtocol();
if (protocol == null || protocol.isEmpty()) {
LOGGER.info("Protocol not found, use https in default mode.");
protocol = "https";
}
LOGGER.debug("Service Config: [Protocol: {}, Host: {} , Port: {}, Webapp: {} ]", protocol, host, port, webapp);
webPath = protocol + "://" + host + ":" + port + "/" + webapp + "/WebProcessingService";
webStatus = protocol + "://" + host + ":" + port + "/" + webapp + "/RetrieveResultServlet";
LOGGER.debug("WebPath: {}", webPath);
LOGGER.debug("WebStatus: {}", webStatus);
// statistical-manager-new.d4science.org:8080/wps/WebProcessingService?Request=GetCapabilities&Service=WPS
// doc.getExecuteResponse().setServiceInstance(webPath+"?REQUEST=GetCapabilities&SERVICE=WPS");
doc.getExecuteResponse().setServiceInstance(webPath);
doc.getExecuteResponse().setLang(WebProcessingService.DEFAULT_LANGUAGE);
doc.getExecuteResponse().setService("WPS");
doc.getExecuteResponse().setVersion(Request.SUPPORTED_VERSION);
LOGGER.debug("Doc attributes set");
this.identifier = request.getExecute().getIdentifier().getStringValue().trim();
LOGGER.debug("Identifier: " + identifier);
ExecuteResponse responseElem = doc.getExecuteResponse();
responseElem.addNewProcess().addNewIdentifier().setStringValue(identifier);
LOGGER.debug("Getting description for " + identifier);
description = RepositoryManager.getInstance().getProcessDescription(this.identifier);
LOGGER.debug("Description " + description);
if (description == null) {
// throw new RuntimeException("Error while accessing the process
// description for "+ identifier);
}
responseElem.getProcess().setTitle(description.getTitle());
responseElem.getProcess().setProcessVersion(description.getProcessVersion());
creationTime = Calendar.getInstance();
LOGGER.debug("Execute Response Created!");
}
public void update() throws ExceptionReport {
// copying the request parameters to the response
ExecuteResponse responseElem = doc.getExecuteResponse();
// if status succeeded, update reponse with result
if (responseElem.getStatus().isSetProcessSucceeded()) {
// the response only include dataInputs, if the property is set to
// true;
// if(Boolean.getBoolean(WPSConfiguration.getInstance().getProperty(WebProcessingService.PROPERTY_NAME_INCLUDE_DATAINPUTS_IN_RESPONSE)))
// {
if (new Boolean(WPSConfig.getInstance().getWPSConfig().getServer().getIncludeDataInputsInResponse())) {
dataInputs = request.getExecute().getDataInputs();
responseElem.setDataInputs(dataInputs);
}
responseElem.addNewProcessOutputs();
// has the client specified the outputs?
if (request.getExecute().isSetResponseForm()) {
// Get the outputdescriptions from the algorithm
OutputDescriptionType[] outputDescs = description.getProcessOutputs().getOutputArray();
if (request.isRawData()) {
OutputDefinitionType rawDataOutput = request.getExecute().getResponseForm().getRawDataOutput();
String id = rawDataOutput.getIdentifier().getStringValue();
OutputDescriptionType desc = XMLBeansHelper.findOutputByID(id, outputDescs);
if (desc.isSetComplexOutput()) {
String encoding = ExecuteResponseBuilder.getEncoding(desc, rawDataOutput);
String schema = ExecuteResponseBuilder.getSchema(desc, rawDataOutput);
String responseMimeType = getMimeType(rawDataOutput);
generateComplexDataOutput(id, false, true, schema, responseMimeType, encoding, null);
}
else if (desc.isSetLiteralOutput()) {
String mimeType = null;
String schema = null;
String encoding = null;
DomainMetadataType dataType = desc.getLiteralOutput().getDataType();
String reference = dataType != null ? dataType.getReference() : null;
generateLiteralDataOutput(id, doc, true, reference, schema, mimeType, encoding,
desc.getTitle());
} else if (desc.isSetBoundingBoxOutput()) {
generateBBOXOutput(id, doc, true, desc.getTitle());
}
return;
}
// Get the outputdefinitions from the clients request
// For each request of output
for (int i = 0; i < request.getExecute().getResponseForm().getResponseDocument()
.getOutputArray().length; i++) {
OutputDefinitionType definition = request.getExecute().getResponseForm().getResponseDocument()
.getOutputArray(i);
DocumentOutputDefinitionType documentDef = request.getExecute().getResponseForm()
.getResponseDocument().getOutputArray(i);
String responseID = definition.getIdentifier().getStringValue();
OutputDescriptionType desc = XMLBeansHelper.findOutputByID(responseID, outputDescs);
if (desc == null) {
throw new ExceptionReport("Could not find the output id " + responseID,
ExceptionReport.INVALID_PARAMETER_VALUE);
}
if (desc.isSetComplexOutput()) {
String mimeType = getMimeType(definition);
String schema = ExecuteResponseBuilder.getSchema(desc, definition);
String encoding = ExecuteResponseBuilder.getEncoding(desc, definition);
generateComplexDataOutput(responseID, documentDef.getAsReference(), false, schema, mimeType,
encoding, desc.getTitle());
} else if (desc.isSetLiteralOutput()) {
String mimeType = null;
String schema = null;
String encoding = null;
DomainMetadataType dataType = desc.getLiteralOutput().getDataType();
String reference = dataType != null ? dataType.getReference() : null;
generateLiteralDataOutput(responseID, doc, false, reference, schema, mimeType, encoding,
desc.getTitle());
} else if (desc.isSetBoundingBoxOutput()) {
generateBBOXOutput(responseID, doc, false, desc.getTitle());
} else {
throw new ExceptionReport("Requested type not supported: BBOX",
ExceptionReport.INVALID_PARAMETER_VALUE);
}
}
} else {
LOGGER.info("OutputDefinitions are not stated explicitly in request");
// THIS IS A WORKAROUND AND ACTUALLY NOT COMPLIANT TO THE SPEC.
ProcessDescriptionType description = RepositoryManager.getInstance()
.getProcessDescription(request.getExecute().getIdentifier().getStringValue());
if (description == null) {
throw new RuntimeException("Error while accessing the process description for "
+ request.getExecute().getIdentifier().getStringValue());
}
OutputDescriptionType[] d = description.getProcessOutputs().getOutputArray();
for (int i = 0; i < d.length; i++) {
if (d[i].isSetComplexOutput()) {
String schema = d[i].getComplexOutput().getDefault().getFormat().getSchema();
String encoding = d[i].getComplexOutput().getDefault().getFormat().getEncoding();
String mimeType = d[i].getComplexOutput().getDefault().getFormat().getMimeType();
generateComplexDataOutput(d[i].getIdentifier().getStringValue(), false, false, schema, mimeType,
encoding, d[i].getTitle());
} else if (d[i].isSetLiteralOutput()) {
generateLiteralDataOutput(d[i].getIdentifier().getStringValue(), doc, false,
d[i].getLiteralOutput().getDataType().getReference(), null, null, null,
d[i].getTitle());
}
}
}
} else if (request.isStoreResponse()) {
// statusLocation="http://localhost:8080/wps/RetrieveResultServlet?id=e4defcf6-d39f-48bf-8128-5591dca13dcb"
// responseElem.setStatusLocation(DatabaseFactory.getDatabase().generateRetrieveResultURL((request.getUniqueId()).toString()));
responseElem.setStatusLocation(webStatus + "?id=" + request.getUniqueId());
}
}
/**
* Returns the schema according to the given output description and type.
*/
private static String getSchema(OutputDescriptionType desc, OutputDefinitionType def) {
String schema = null;
if (def != null) {
schema = def.getSchema();
}
return schema;
}
private static String getEncoding(OutputDescriptionType desc, OutputDefinitionType def) {
String encoding = null;
if (def != null) {
encoding = def.getEncoding();
}
return encoding;
}
public String getMimeType() {
return getMimeType(null);
}
public String getMimeType(OutputDefinitionType def) {
String mimeType = "";
OutputDescriptionType[] outputDescs = description.getProcessOutputs().getOutputArray();
boolean isResponseForm = request.getExecute().isSetResponseForm();
String inputID = "";
if (def != null) {
inputID = def.getIdentifier().getStringValue();
} else if (isResponseForm) {
if (request.getExecute().getResponseForm().isSetRawDataOutput()) {
inputID = request.getExecute().getResponseForm().getRawDataOutput().getIdentifier().getStringValue();
} else if (request.getExecute().getResponseForm().isSetResponseDocument()) {
inputID = request.getExecute().getResponseForm().getResponseDocument().getOutputArray(0).getIdentifier()
.getStringValue();
}
}
OutputDescriptionType outputDes = null;
for (OutputDescriptionType tmpOutputDes : outputDescs) {
if (inputID.equalsIgnoreCase(tmpOutputDes.getIdentifier().getStringValue())) {
outputDes = tmpOutputDes;
break;
}
}
if (isResponseForm) {
// Get the outputdescriptions from the algorithm
if (request.isRawData()) {
mimeType = request.getExecute().getResponseForm().getRawDataOutput().getMimeType();
} else {
// mimeType = "text/xml";
// MSS 03/02/2009 defaulting to text/xml doesn't work when the
// data is a complex raster
if (outputDes.isSetLiteralOutput()) {
mimeType = "text/plain";
} else if (outputDes.isSetBoundingBoxOutput()) {
mimeType = "text/xml";
} else {
if (def != null) {
mimeType = def.getMimeType();
} else {
if (outputDes.isSetComplexOutput()) {
mimeType = outputDes.getComplexOutput().getDefault().getFormat().getMimeType();
LOGGER.warn("Using default mime type: " + mimeType + " for input: " + inputID);
}
}
}
}
}
if (mimeType == null) {
if (outputDes.isSetLiteralOutput()) {
mimeType = "text/plain";
} else if (outputDes.isSetBoundingBoxOutput()) {
mimeType = "text/xml";
} else if (outputDes.isSetComplexOutput()) {
mimeType = outputDes.getComplexOutput().getDefault().getFormat().getMimeType();
LOGGER.warn("Using default mime type: " + mimeType + " for input: " + inputID);
}
}
return mimeType;
}
private void generateComplexDataOutput(String responseID, boolean asReference, boolean rawData, String schema,
String mimeType, String encoding, LanguageStringType title) throws ExceptionReport {
IData obj = request.getAttachedResult().get(responseID);
if (rawData) {
rawDataHandler = new RawData(obj, responseID, schema, encoding, mimeType, this.identifier, description);
} else {
OutputDataItem handler = new OutputDataItem(obj, responseID, schema, encoding, mimeType, title,
this.identifier, description);
if (asReference) {
handler.updateResponseAsReference(doc, (request.getUniqueId()).toString(), mimeType);
} else {
handler.updateResponseForInlineComplexData(doc);
}
}
}
private void generateLiteralDataOutput(String responseID, ExecuteResponseDocument res, boolean rawData,
String dataTypeReference, String schema, String mimeType, String encoding, LanguageStringType title)
throws ExceptionReport {
IData obj = request.getAttachedResult().get(responseID);
if (rawData) {
rawDataHandler = new RawData(obj, responseID, schema, encoding, mimeType, this.identifier, description);
} else {
OutputDataItem handler = new OutputDataItem(obj, responseID, schema, encoding, mimeType, title,
this.identifier, description);
handler.updateResponseForLiteralData(res, dataTypeReference);
}
}
private void generateBBOXOutput(String responseID, ExecuteResponseDocument res, boolean rawData,
LanguageStringType title) throws ExceptionReport {
IBBOXData obj = (IBBOXData) request.getAttachedResult().get(responseID);
if (rawData) {
rawDataHandler = new RawData(obj, responseID, null, null, null, this.identifier, description);
} else {
OutputDataItem handler = new OutputDataItem(obj, responseID, null, null, null, title, this.identifier,
description);
handler.updateResponseForBBOXData(res, obj);
}
}
public InputStream getAsStream() throws ExceptionReport {
if (request.isRawData() && rawDataHandler != null) {
return rawDataHandler.getAsStream();
}
if (request.isStoreResponse()) {
String id = request.getUniqueId().toString();
// String statusLocation =
// DatabaseFactory.getDatabase().generateRetrieveResultURL(id);
String statusLocation = webStatus + "?id=" + id;
doc.getExecuteResponse().setStatusLocation(statusLocation);
}
try {
return doc.newInputStream(XMLBeansHelper.getXmlOptions());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public void setStatus(StatusType status) {
// workaround, should be generated either at the creation of the
// document or when the process has been finished.
status.setCreationTime(creationTime);
doc.getExecuteResponse().setStatus(status);
}
}