/**
* Copyright (C) 2007 - 2016 52°North Initiative for Geospatial Open Source
* Software GmbH
*
* 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.n52.wps.client;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactoryConfigurationError;
import net.opengis.ows.x11.ExceptionReportDocument.ExceptionReport;
import net.opengis.wps.x100.DocumentOutputDefinitionType;
import net.opengis.wps.x100.ExecuteDocument;
import net.opengis.wps.x100.ExecuteResponseDocument;
import net.opengis.wps.x100.OutputDataType;
import net.opengis.wps.x100.OutputDescriptionType;
import net.opengis.wps.x100.ProcessDescriptionType;
import org.n52.wps.commons.XMLUtil;
import org.n52.wps.io.IParser;
import org.n52.wps.io.data.IData;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/*
*
* returns the processOutputs according to the encoding of the process.
* @author foerster
*
*/
public class ExecuteResponseAnalyser {
private static Logger LOGGER = LoggerFactory.getLogger(ExecuteResponseAnalyser.class);
ProcessDescriptionType processDesc;
ExecuteDocument exec;
Object response;
public ExecuteResponseAnalyser(ExecuteDocument exec, Object response, ProcessDescriptionType processDesc) throws WPSClientException {
this.processDesc = processDesc;
this.exec= exec;
if(response instanceof ExceptionReport){
throw new WPSClientException("Output is not ComplexData but an Exception Report");
}
this.response = response;
}
/**
* delivers the parsed ComplexData by name
* @param outputID id of the output element
* @param binding Class of the output binding, e.g. GenericFileDataBinding
* @return the parsed ComplexData in the requested format defined by the binding
* @throws WPSClientException
*/
public IData getComplexData(String outputID, Class<?> binding) throws WPSClientException {
return parseProcessOutput(outputID, binding);
}
/**
* delivers the parsed ComplexData by index
* @param index index of the output element starting with 0
* @param binding Class of the output binding, e.g. GenericFileDataBinding
* @return the parsed ComplexData in the requested format defined by the binding
* @throws WPSClientException
*/
public IData getComplexDataByIndex(int index, Class<?> binding) throws WPSClientException {
ExecuteResponseDocument doc = null;
if(response instanceof ExecuteResponseDocument){
doc = (ExecuteResponseDocument) response;
}else{
throw new WPSClientException("Output cannot be determined by index since it is either raw data or an exception report");
}
OutputDataType[] outputs = doc.getExecuteResponse().getProcessOutputs().getOutputArray();
int counter = 0;
for(OutputDataType output : outputs) {
if(output.getData().getComplexData() != null) {
if(counter == index) {
return this.parseProcessOutput(output.getIdentifier().getStringValue(), binding);
}
counter ++;
}
}
return null;
}
/**
* delivers just the URL of a referenced output identified by index
* @param index index of the output
* @return URL of the stored output
* @throws WPSClientException
*/
public String getComplexReferenceByIndex(int index) throws WPSClientException {
ExecuteResponseDocument doc = null;
if(response instanceof ExecuteResponseDocument){
doc = (ExecuteResponseDocument) response;
}else{
throw new WPSClientException("Output cannot be determined by index since it is either raw data or an exception report");
}
OutputDataType[] outputs = doc.getExecuteResponse().getProcessOutputs().getOutputArray();
int counter = 0;
for(OutputDataType output : outputs) {
if(output.getReference() != null) {
if(counter == index) {
return output.getReference().getHref();
}
counter ++;
}
}
RuntimeException rte = new RuntimeException("No reference found in response");
LOGGER.error(rte.getMessage());
throw rte;
}
/**
* parses a specific WPS output
*
* @param outputID id of the output
* @param outputDataBindingClass class of the desired output binding
* @return parsed WPS output as IData
* @throws WPSClientException
*/
private IData parseProcessOutput(String outputID, Class<?> outputDataBindingClass) throws WPSClientException {
OutputDescriptionType outputDesc = null;
String schema = null;
String mimeType = null;
String encoding = null;
if(exec.getExecute().isSetResponseForm() && exec.getExecute().getResponseForm().isSetRawDataOutput()){
// get data specification from request
schema = exec.getExecute().getResponseForm().getRawDataOutput().getSchema();
mimeType = exec.getExecute().getResponseForm().getRawDataOutput().getMimeType();
encoding = exec.getExecute().getResponseForm().getRawDataOutput().getEncoding();
}else if(exec.getExecute().isSetResponseForm() && exec.getExecute().getResponseForm().isSetResponseDocument()){
DocumentOutputDefinitionType[] outputs = exec.getExecute().getResponseForm().getResponseDocument().getOutputArray();
for(DocumentOutputDefinitionType output : outputs){
if(output.getIdentifier().getStringValue().equals(outputID)){
schema = output.getSchema();
mimeType = output.getMimeType();
encoding = output.getEncoding();
}
}
}
if(mimeType==null){
for(OutputDescriptionType tempDesc : processDesc.getProcessOutputs().getOutputArray()) {
if(outputID.equals(tempDesc.getIdentifier().getStringValue())) {
outputDesc = tempDesc;
break;
}
}
// get default data spec since mime type is not set
mimeType = outputDesc.getComplexOutput().getDefault().getFormat().getMimeType();
encoding = outputDesc.getComplexOutput().getDefault().getFormat().getEncoding();
schema = outputDesc.getComplexOutput().getDefault().getFormat().getSchema();
}
IParser parser = StaticDataHandlerRepository.getParserFactory().getParser(schema, mimeType, encoding, outputDataBindingClass);
InputStream is = null;
if(response instanceof InputStream){
is = (InputStream)response;
}else if (response instanceof ExecuteResponseDocument){
ExecuteResponseDocument responseDocument = (ExecuteResponseDocument) response;
OutputDataType[] processOutputs = responseDocument.getExecuteResponse().getProcessOutputs().getOutputArray();
for(OutputDataType processOutput : processOutputs){
if(processOutput.getIdentifier().getStringValue().equalsIgnoreCase(outputID)){
if(processOutput.isSetReference()){
//request the reference
String urlString = processOutput.getReference().getHref();
URL url;
try {
url = new URL(urlString);
is = url.openStream();
} catch (MalformedURLException e) {
throw new WPSClientException("Could not fetch response from referenced URL", e);
} catch (IOException e) {
throw new WPSClientException("Could not fetch response from referenced URL", e);
}
}else{
String complexDataContent;
try {
NodeList candidateNodes = processOutput.getData().getComplexData().getDomNode().getChildNodes();
Node complexDataNode = candidateNodes.getLength() > 1 ? candidateNodes.item(1) : candidateNodes.item(0);
complexDataContent = XMLUtil.nodeToString(complexDataNode);
is = new ByteArrayInputStream(complexDataContent.getBytes());
} catch (TransformerFactoryConfigurationError e) {
LOGGER.error(e.getMessage());
} catch (TransformerException e) {
LOGGER.error(e.getMessage());
}
}
}
}
}else{
throw new WPSClientException("Wrong output type");
}
if(parser != null) {
if(encoding != null && encoding.equalsIgnoreCase("base64")){
return parser.parseBase64(is, mimeType, schema);
}else{
return parser.parse(is, mimeType, schema);
}
}
RuntimeException rte = new RuntimeException("Could not find suitable parser");
LOGGER.error(rte.getMessage());
throw rte;
}
}