/* Copyright (c) 2001 - 2013 OpenPlans - www.openplans.org. All rights reserved.
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.wps.response;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.sax.TransformerHandler;
import javax.xml.transform.stream.StreamResult;
import net.opengis.ows11.BoundingBoxType;
import net.opengis.wps10.ComplexDataType;
import net.opengis.wps10.ExecuteResponseType;
import net.opengis.wps10.ExecuteType;
import net.opengis.wps10.LiteralDataType;
import net.opengis.wps10.OutputDataType;
import org.geoserver.ows.Response;
import org.geoserver.ows.XmlObjectEncodingResponse;
import org.geoserver.platform.Operation;
import org.geoserver.platform.ServiceException;
import org.geoserver.wps.BinaryEncoderDelegate;
import org.geoserver.wps.CDataEncoderDelegate;
import org.geoserver.wps.Execute;
import org.geoserver.wps.RawDataEncoderDelegate;
import org.geoserver.wps.WPSException;
import org.geoserver.wps.XMLEncoderDelegate;
import org.geotools.ows.v1_1.OWS;
import org.geotools.ows.v1_1.OWSConfiguration;
import org.geotools.xml.Encoder;
/**
* Encodes the Execute response either in the normal XML format or in the raw format
* @author Andrea Aime
*
*/
public class ExecuteProcessResponse extends Response {
XmlObjectEncodingResponse standardResponse;
public ExecuteProcessResponse(Class binding, String elementName, Class xmlConfiguration) {
super(ExecuteResponseType.class);
this.standardResponse = new XmlObjectEncodingResponse(binding, elementName, xmlConfiguration);
}
@Override
public String getMimeType(Object value, Operation operation)
throws ServiceException {
if (isStandardDocumentResponse(operation)) {
// normal execute response encoding
return standardResponse.getMimeType(value, operation);
} else {
// raw response, let's see what the output is
ExecuteResponseType response = (ExecuteResponseType) value;
if(response.getProcessOutputs() == null) {
// just a status report or a failure report
return "text/xml";
}
OutputDataType result = (OutputDataType) response.getProcessOutputs().getOutput().get(0);
LiteralDataType literal = result.getData().getLiteralData();
ComplexDataType complex = result.getData().getComplexData();
if(literal != null) {
// literals are encoded as plain strings
return "text/plain";
} else if(complex != null) {
// Execute should have properly setup the mime type
return complex.getMimeType();
} else {
// bbox
return "text/xml";
}
}
}
private boolean isStandardDocumentResponse(Operation operation) {
if(operation.getParameters()[0] instanceof ExecuteType) {
ExecuteType execute = (ExecuteType) operation.getParameters()[0];
return execute.getResponseForm() != null && execute.getResponseForm().getRawDataOutput() == null;
}
return true;
}
@Override
public String getPreferredDisposition(Object value, Operation operation) {
String mimeType = getMimeType(value, operation);
String disposition = DISPOSITION_INLINE;
if (mimeType != null) {
// if there is a BinaryEncoder we could expose a method that allows
// expressing preferred type as opposed to this ugliness
if (mimeType.indexOf("image") == 0) {
// tiff for download
if (mimeType.indexOf("tiff") > 0) {
disposition = DISPOSITION_ATTACH;
}
} else if (mimeType.equals("application/zip")) {
disposition = DISPOSITION_ATTACH;
} else if (mimeType.equals("application/arcgrid")) {
disposition = DISPOSITION_ATTACH;
}
}
return disposition;
}
@Override
public String getAttachmentFileName(Object value, Operation operation) {
if(isStandardDocumentResponse(operation)) {
return "execute.xml";
} else {
ExecuteType execute = (ExecuteType) operation.getParameters()[0];
ExecuteResponseType response = (ExecuteResponseType) value;
if(response.getProcessOutputs() == null) {
// just a status report or a failure report
return "execute.xml";
}
OutputDataType result = (OutputDataType) response.getProcessOutputs().getOutput().get(0);
String fname = result.getIdentifier().getValue();
LiteralDataType literal = result.getData().getLiteralData();
ComplexDataType complex = result.getData().getComplexData();
String fext;
// this is not the most robust way to get mime type...
if (literal != null) {
fext = "txt";
} else if(complex != null) {
String mimeType = result.getData().getComplexData().getMimeType();
if (mimeType == null) {
fext = "txt";
} else {
fext = mimeType.split("/")[1].toLowerCase();
}
} else {
fext = "xml";
}
return fname + "." + fext;
}
}
@Override
public void write(Object value, OutputStream output, Operation operation)
throws IOException, ServiceException {
ExecuteResponseType response = (ExecuteResponseType) value;
// From the spec:
// In the most primitive case, when a response form of ―RawDataOutput‖ is requested,
// process execution is successful, and only one complex output is produced, then the
// Execute operation response will consist simply of that one complex output in its raw form
// returned directly to the client.
// In all other cases, the response to a valid Execute operation request is an
// ExecuteResponse XML document
if (isStandardDocumentResponse(operation) ||
response.getStatus().getProcessSucceeded() == null) {
// normal execute response encoding
standardResponse.write(value, output, operation);
} else {
// raw response, let's see what the output is
OutputDataType result = (OutputDataType) response
.getProcessOutputs().getOutput().get(0);
LiteralDataType literal = result.getData().getLiteralData();
BoundingBoxType bbox = result.getData().getBoundingBoxData();
if (literal != null) {
writeLiteral(output, literal);
} else if(bbox != null) {
writeBBox(output, bbox);
} else {
writeComplex(output, result);
}
}
}
private void writeBBox(OutputStream os, BoundingBoxType bbox) throws IOException {
Encoder encoder = new Encoder(new OWSConfiguration());
encoder.encode(bbox, OWS.BoundingBox, os);
}
/**
* Write out complex data assuming {@link Execute} has set up the proper
* encoder as the output
*
* @param output
* @param result
* @throws IOException
*/
void writeComplex(OutputStream output, OutputDataType result)
throws IOException {
Object rawResult = result.getData().getComplexData().getData().get(0);
if (rawResult instanceof RawDataEncoderDelegate) {
RawDataEncoderDelegate delegate = (RawDataEncoderDelegate) rawResult;
delegate.encode(output);
} else if (rawResult instanceof XMLEncoderDelegate) {
XMLEncoderDelegate delegate = (XMLEncoderDelegate) rawResult;
try {
TransformerHandler xmls =
((SAXTransformerFactory)SAXTransformerFactory.newInstance()).newTransformerHandler();
xmls.setResult(new StreamResult(output));
delegate.encode(xmls);
} catch (IOException e) {
throw e;
} catch (Exception e) {
throw new WPSException("An error occurred while encoding "
+ "the results of the process", e);
}
} else if(rawResult instanceof CDataEncoderDelegate) {
try {
((CDataEncoderDelegate) rawResult).encode(output);
} catch(Exception e) {
throw new WPSException("An error occurred while encoding "
+ "the results of the process", e);
}
} else if(rawResult instanceof BinaryEncoderDelegate) {
try {
((BinaryEncoderDelegate) rawResult).encode(output);
} catch(Exception e) {
throw new WPSException("An error occurred while encoding "
+ "the results of the process", e);
}
} else {
throw new WPSException("Cannot encode an object of class "
+ rawResult.getClass() + " in raw form");
}
}
/**
* Write out literal results by converting them to strings
* @param output
* @param literal
*/
void writeLiteral(OutputStream output, LiteralDataType literal) {
PrintWriter writer = new PrintWriter(output);
writer.write(literal.getValue());
writer.flush();
}
}