content: /**
   * ﻿Copyright (C) 2007 - 2019 52°North Initiative for Geospatial Open Source
   * Software GmbH
   *
   * This program is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License version 2 as published
   * by the Free Software Foundation.
   *
   * If the program is linked with libraries which are licensed under one of
   * the following licenses, the combination of the program with the linked
   * library is not considered a "derivative work" of the program:
   *
   *       • Apache License, version 2.0
   *       • Apache Software License, version 1.0
   *       • GNU Lesser General Public License, version 3
   *       • Mozilla Public License, versions 1.0, 1.1 and 2.0
   *       • Common Development and Distribution License (CDDL), version 1.0
   *
   * Therefore the distribution of the program linked with libraries licensed
   * under the aforementioned licenses, is permitted by the copyright holders
   * if the distribution is compliant with both the GNU General Public
   * License version 2 and the aforementioned licenses.
   *
   * This program is distributed in the hope that it will be useful, but
   * WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
   * Public License for more details.
   */
  package org.n52.wps.test;
  
  import static org.hamcrest.MatcherAssert.assertThat;
  import static org.hamcrest.Matchers.anyOf;
  import static org.hamcrest.Matchers.containsString;
  import static org.hamcrest.Matchers.equalTo;
  import static org.hamcrest.Matchers.greaterThan;
  import static org.hamcrest.Matchers.is;
  import static org.hamcrest.Matchers.not;
  import static org.hamcrest.Matchers.nullValue;
  import static org.junit.Assert.assertTrue;
  
  import java.io.IOException;
  import java.io.InputStream;
  import java.io.StringReader;
  import java.net.URL;
  import java.net.URLConnection;
  import java.util.List;
  
  import javax.xml.parsers.DocumentBuilder;
  import javax.xml.parsers.DocumentBuilderFactory;
  import javax.xml.parsers.ParserConfigurationException;
  
  import net.opengis.wps.x100.ComplexDataType;
  import net.opengis.wps.x100.DataType;
  import net.opengis.wps.x100.ExecuteResponseDocument;
  import net.opengis.wps.x100.ExecuteResponseDocument.ExecuteResponse.ProcessOutputs;
  import net.opengis.wps.x100.OutputDataType;
  import net.opengis.wps.x100.OutputReferenceType;
  
  import org.apache.commons.codec.binary.Base64;
  import org.geotools.coverage.grid.GridCoverage2D;
  import org.n52.wps.io.data.IData;
  import org.n52.wps.io.datahandler.parser.GeotiffParser;
  import org.w3c.dom.Document;
  import org.w3c.dom.NamedNodeMap;
  import org.w3c.dom.Node;
  import org.w3c.dom.NodeList;
  import org.xml.sax.InputSource;
  import org.xml.sax.SAXException;
  
  public class AllTestsIT {
  
      public static int getPort() {
          return Integer.parseInt(System.getProperty("test.port", "8080"));
      }
  
      public static String getHost() {
          return System.getProperty("test.host", "127.0.0.1");
      }
  
      public static String getContext() {
          return System.getProperty("test.context", "/wps/WebProcessingService");
      }
  
      public static String getURL() {
          return "http://" + getHost() + ":" + getPort() + getContext();
      }
  
      public static Document parseXML(String xmlString) throws ParserConfigurationException, SAXException, IOException {
          DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
          StringReader inStream = new StringReader(xmlString);
          InputSource inSource = new InputSource(inStream);
          return documentBuilder.parse(inSource);
      }
  
      public static void validateBinaryBase64Async(String response) throws IOException,
              ParserConfigurationException,
              SAXException {
          String referencedDocument = getAsyncDoc(response);
          assertThat(referencedDocument, referencedDocument, not(containsString("ExceptionReport")));
          assertThat(referencedDocument, referencedDocument, containsString("ExecuteResponse"));
          assertThat(referencedDocument,
                     referencedDocument,
                     anyOf(containsString("AAEGAAMAAAABAAEAAAEVAAMAAAABA"),
                           containsString("Tk9SVEg6IDIyOD"),
                           containsString("SUkqAAgAAAASAAABAwABAAAAIwAA")));
      }
  
      public static String getRefAsString(String response) throws ParserConfigurationException, SAXException, IOException {
          assertThat(response, response, not(containsString("ExceptionReport")));
          assertThat(response, response, containsString("ProcessSucceeded"));
          assertThat(response, response, containsString("Reference"));
  
          Document doc = AllTestsIT.parseXML(response);
          NodeList executeResponse = doc.getElementsByTagName("wps:Reference");
  
          assertThat(executeResponse.getLength(), greaterThan(0));
  
          NamedNodeMap attributes = executeResponse.item(0).getAttributes();
          String statusLocation = attributes.getNamedItem("href").getNodeValue();
          String[] splittedURL = statusLocation.split("RetrieveResultServlet?");
  
          assertThat(splittedURL.length, equalTo(2));
  
          String referencedDocument = GetClient.sendRequest(splittedURL[0] + "RetrieveResultServlet", splittedURL[1]);
  
          return referencedDocument;
      }
  
      public static InputStream getRefAsStream(String response) throws ParserConfigurationException,
              SAXException,
              IOException {
          assertThat(response, response, not(containsString("ExceptionReport")));
          assertThat(response, response, containsString("ProcessSucceeded"));
          assertThat(response, response, containsString("Reference"));
  
          Document doc = AllTestsIT.parseXML(response);
          NodeList executeResponse = doc.getElementsByTagName("wps:Reference");
  
          assertThat(executeResponse.getLength(), greaterThan(0));
  
          NamedNodeMap attributes = executeResponse.item(0).getAttributes();
          String statusLocation = attributes.getNamedItem("href").getNodeValue();
          String[] splittedURL = statusLocation.split("RetrieveResultServlet?");
  
          assertThat(splittedURL.length, equalTo(2));
  
          return GetClient.sendRequestForInputStream(splittedURL[0] + "RetrieveResultServlet", splittedURL[1]);
      }
  
      public static String getAsyncDoc(String response) throws IOException, ParserConfigurationException, SAXException {
          assertThat(response, response, not(containsString("ExceptionReport")));
          assertThat(response, response, containsString("statusLocation"));
  
          Document doc;
          doc = AllTestsIT.parseXML(response);
  
          NodeList executeResponse = doc.getElementsByTagName("wps:ExecuteResponse");
  
          assertThat(executeResponse.getLength(), greaterThan(0));
  
          NamedNodeMap attributes = executeResponse.item(0).getAttributes();
          String statusLocation = attributes.getNamedItem("statusLocation").getNodeValue();
          String[] splittedURL = statusLocation.split("RetrieveResultServlet?");
  
          assertThat(splittedURL.length, equalTo(2));
  
          String referencedDocument = GetClient.sendRequest(splittedURL[0] + "RetrieveResultServlet", splittedURL[1]);
  
          assertThat(referencedDocument, referencedDocument, not(containsString("ExceptionReport")));
          assertThat(referencedDocument, referencedDocument, containsString("Status"));
  
          for (int i = 0; i < 4; i++) {
              if ( !referencedDocument.contains("ProcessSucceeded") && !referencedDocument.contains("ProcessFailed")) {
                  try {
                      System.out.println("WPS process still processing. Waiting...");
                      Thread.sleep(1000 * 3);
                      referencedDocument = GetClient.sendRequest(splittedURL[0] + "RetrieveResultServlet", splittedURL[1]);
                  }
                  catch (InterruptedException ignore) {
                      // do nothing
                  }
              }
              else {
                  return referencedDocument;
              }
          }
          throw new IOException("Test did not complete in allotted time");
      }
  	
  	public static void checkContentDispositionOfRetrieveResultServlet(String response, String filename, String suffix)
  			throws IOException, ParserConfigurationException, SAXException {
  
  		String refResult = AllTestsIT.getAsyncDoc(response);
  		
      	ExecuteResponseDocument document = null;
      	
      	try {    		
      		document = ExecuteResponseDocument.Factory.parse(refResult);	    		
  		} catch (Exception e) {
  			System.err.println("Could not parse execute response document.");
  		}   	
      	
      	assertThat(document, not(nullValue()));    	
      	
      	ProcessOutputs outputs = document.getExecuteResponse().getProcessOutputs();
      	
      	assertThat(outputs, not(nullValue()));    	
      	assertThat(outputs.sizeOfOutputArray(), not(0)); 
      	
      	OutputDataType outputDataType = document.getExecuteResponse().getProcessOutputs().getOutputArray(0);
      	
      	assertThat(outputDataType, not(nullValue()));       	
      	
      	OutputReferenceType data = outputDataType.getReference();  
      	
      	assertThat(data, not(nullValue()));
      	
      	String url = data.getHref();
      	
      	if(filename != null){
      		//concat filename to URL
      		url = url.concat("&filename=" + filename);
      	}
      	
      	URLConnection urlConnection = new URL(url).openConnection();
      	
      	List<String> headerFields = urlConnection.getHeaderFields().get("Content-Disposition");
      	
      	boolean oneHeaderFieldContainsFilename = false;
      	
  		for (String field : headerFields) {
  			if(field.contains("filename")){
  				oneHeaderFieldContainsFilename = true;
  				if(suffix != null && !suffix.equals("")){
  					assertTrue(field.endsWith(suffix + "\""));
  				}
  				if(filename != null && !filename.equals("")){
  					assertTrue(field.contains(filename));
  				}
  			}
  		}
  		assertTrue(oneHeaderFieldContainsFilename);
  	}
  
      public static void checkReferenceXMLResult(String response, String stringThatShouldBeContained) throws ParserConfigurationException,
              SAXException,
              IOException {
          String referencedDocument = getRefAsString(response);
          assertThat(referencedDocument, referencedDocument, not(containsString("ExceptionReport")));
          assertThat(referencedDocument, referencedDocument, containsString(stringThatShouldBeContained));
          assertThat(AllTestsIT.parseXML(response), is(not(nullValue())));
      }
  
      public static void checkReferenceBinaryResultBase64(String response) throws ParserConfigurationException,
              SAXException,
              IOException {
          assertThat(response, response, not(containsString("ExceptionReport")));
          assertThat(response, response, containsString("ProcessSucceeded"));
          assertThat(response, response, containsString("Reference"));
  
          InputStream stream = getRefAsStream(response);
          GeotiffParser parser = new GeotiffParser();
          IData data = parser.parseBase64(stream, "image/tiff", null);
          assertThat(data.getPayload() instanceof GridCoverage2D, is(true));
          stream.close();
      }
  
      public static void checkReferenceBinaryResultDefault(String response) throws ParserConfigurationException,
              SAXException,
              IOException {
          assertThat(response, response, not(containsString("ExceptionReport")));
          assertThat(response, response, containsString("ProcessSucceeded"));
          assertThat(response, response, containsString("Reference"));
  
          InputStream stream = getRefAsStream(response);
          GeotiffParser parser = new GeotiffParser();
          IData data = parser.parse(stream, "image/tiff", null);
          assertThat(data.getPayload() instanceof GridCoverage2D, is(true));
          stream.close();
      }
      
      public static void checkInlineResultBase64(String response){
      	
      	ExecuteResponseDocument document = null;
      	
      	try {    		
      		document = ExecuteResponseDocument.Factory.parse(response);	    		
  		} catch (Exception e) {
  			System.err.println("Could not parse execute response document.");
  		}   	
      	
      	assertThat(document, not(nullValue()));    	
      	
      	ProcessOutputs outputs = document.getExecuteResponse().getProcessOutputs();
      	
      	assertThat(outputs, not(nullValue()));    	
      	assertThat(outputs.sizeOfOutputArray(), not(0)); 
      	
      	OutputDataType outputDataType = document.getExecuteResponse().getProcessOutputs().getOutputArray(0);
      	
      	assertThat(outputDataType, not(nullValue()));       	
      	
      	DataType data = outputDataType.getData();
      	
      	assertTrue(data.isSetComplexData());    	
      	
      	ComplexDataType complexData = outputDataType.getData().getComplexData();
      	
      	assertThat(complexData, not(nullValue())); 
      	
      	Node domNode = complexData.getDomNode();
      	
      	assertThat(domNode, not(nullValue()));       
      	
      	Node firstChild = domNode.getFirstChild();
      	
      	assertThat(firstChild, not(nullValue()));       
      	
      	String nodeValue = firstChild.getNodeValue();
      	
      	assertThat(nodeValue, not(nullValue()));   
  		
  		assertTrue(Base64.isBase64(nodeValue));
      	
      }
  }