All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.ats.executor.drivers.engines.webservices.ApiExecutor Maven / Gradle / Ivy

The newest version!
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you 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 com.ats.executor.drivers.engines.webservices;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.StringWriter;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
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;

import com.ats.element.AtsBaseElement;
import com.ats.element.FoundElement;
import com.ats.element.api.AtsApiElement;
import com.ats.element.api.AtsJsonElement;
import com.ats.element.api.AtsXmlElement;
import com.ats.element.test.TestElement;
import com.ats.executor.ActionStatus;
import com.ats.executor.channels.Channel;
import com.ats.generator.variables.CalculatedProperty;
import com.ats.script.actions.ActionApi;
import com.ats.tools.logger.MessageCode;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonIOException;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonSyntaxException;

import okhttp3.Headers;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

public abstract class ApiExecutor implements IApiDriverExecutor {

	private final static String TRUNCATED_DATA = "TRUNCATED_DATA";
	private final static Pattern xmlPropertyPattern = Pattern.compile(".*:");

	private final static short TEXT_TYPE = 0;
	private final static short JSON_TYPE = 1;
	private final static short XML_TYPE = 2;

	private final static String ELEMENT = "ELEMENT";
	private final static String NODE = "NODE";
	private final static String OBJECT = "OBJECT";
	private final static String ARRAY = "ARRAY";
	public final static String RESPONSE = "RESPONSE";
	public final static String DATA = "DATA";
	public final static String ROOT = "root";
	public final static String HEADERS = "headers";

	private URI uri;
	private String source;
	private short type;

	private ActionApi lastAction;

	private ArrayList atsElements;

	protected Map headerProperties;

	protected String authentication;
	protected String authenticationValue;

	protected int timeout;
	protected int maxTry;

	protected Channel channel;

	protected OkHttpClient client;
	private Response response;
	private String responseCode = "200";

	private PrintStream logStream;

	public ApiExecutor(PrintStream logStream, AtsCookieJar cookieJar, OkHttpClient client, int timeout, int maxTry, Channel channel) {
		this.logStream = logStream;
		this.client = client;
		this.timeout = timeout;
		this.maxTry = maxTry;
		this.channel = channel;
		this.authentication = channel.getAuthentication();
		this.authenticationValue = channel.getAuthenticationValue();
	}

	protected void setUri(String value) {
		if(value != null) {
			try {
				this.uri = new URI(value);
			} catch (URISyntaxException e) {}
		}
	}

	protected URI getUri() {
		if(lastAction.getPort() > -1) {
			try {
				final URL originalURL = uri.toURL();
				return new URI(originalURL.getProtocol() + "://" + originalURL.getHost() + ":" + lastAction.getPort() + "/" + originalURL.getFile());
			} catch (MalformedURLException | URISyntaxException e) {}
		}
		return uri;
	}

	protected URI getMethodUri() {
		return getUri().resolve(lastAction.getMethod().getCalculated());
	}

	public String getCurrentUrl() {
		return getMethodUri().toString();
	}

	@Override
	public void execute(ActionStatus status, ActionApi action) {
		source = "";
		type = TEXT_TYPE;
		lastAction = action;

		status.setMessage("authentication");

		headerProperties = new HashMap<>();

		if(!Strings.isNullOrEmpty(authentication) && !Strings.isNullOrEmpty(authenticationValue)) {
			headerProperties.put("Authorization", authentication + " " + authenticationValue);
			status.setData(authentication);
		}else {
			status.setData("");
		}

		if(action.getHeaders() != null) {
			for (CalculatedProperty property : action.getHeaders()) {
				headerProperties.put(property.getName(), property.getValue().getCalculated());
			}
		}
	}

	protected void addHeader(String key, String value) {
		if(!headerProperties.containsKey(key)) {
			headerProperties.put(key, value);
		}
	}

	private void refresh(Channel channel) {
		if(lastAction != null && !lastAction.isUseCache()) {
			execute(channel.newActionStatus(), lastAction);
		} else {
			atsElements = new ArrayList<>(atsElementsCache);
		}
	}

	//------------------------------------------------------------------------------------------------------------
	//------------------------------------------------------------------------------------------------------------

	protected void loadLocalFile(String type, String fileUri) {

		try {
			URI uri = new URI(fileUri);
			File f = new File(uri);
			if(f.exists()) {
				responseCode = "200";
				source = parseResponse(type, f, new JsonArray());
			}else {
				responseCode = "404";
				source = "file not found";
			}

		} catch (IOException | URISyntaxException e) {
			source = e.getMessage();
		}
	}

	protected void executeRequest(ActionStatus status, final Request request) {
		logStream.println("==========  CURL REQUEST  =========== \n" + toCurl(request) + "\n");

		int max = maxTry;
		while(!clientCall(status, request) && max > 0) {
			channel.sendLog(MessageCode.PROPERTY_TRY_ASSERT, "Call webservice failed", max);
			channel.sleep(500);
			max--;
		}

		if(max == 0) {
			logStream.println("call request failed -> " + status.getFailMessage());
		}
	}

	private boolean clientCall(ActionStatus status, Request request) {

		String type = "";

		try {

			response = client.newCall(request).execute();
			final List contentTypes = response.headers("Content-Type");

			final JsonArray headers = new JsonArray();
			for (String key:response.headers().names()) {
				for (String value:response.headers(key)) {
					JsonObject headerObject = new JsonObject();
					headerObject.addProperty("name", key);
					headerObject.addProperty("value", value);
					headers.add(headerObject);
				}
			}

			if(contentTypes != null && contentTypes.size() > 0) {
				type = contentTypes.get(0);
			}

			File tempFile = Files.createTempFile("ats-", ".tmp").toFile();
			try (OutputStream output = new FileOutputStream(tempFile)) {
				response.body().byteStream().transferTo(output);
			} catch (IOException ignored) { }

			responseCode = String.valueOf(response.code());
			if(Strings.isNullOrEmpty(responseCode)) {
				responseCode = "500";
			}

			source = parseResponse(type, tempFile, headers);
			tempFile.delete();
			atsElementsCache = new ArrayList<>(atsElements);

			response.close();

			return true;

		} catch (IOException e) {
			status.setError(ActionStatus.WEB_DRIVER_ERROR, "call Webservice error -> " + e.getMessage());
		}

		return false;
	}

	private ArrayList atsElementsCache;

	//------------------------------------------------------------------------------------------------------------
	//------------------------------------------------------------------------------------------------------------

	private String parseResponse(String type, File bodyFile, JsonArray headers) throws FileNotFoundException {

		InputStreamReader isr = new InputStreamReader(new FileInputStream(bodyFile), StandardCharsets.UTF_8);
		initAtsElements();

		if (type.contains("/xml")) {
			try {
				final Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new InputSource(isr));

				this.type = XML_TYPE;

				final NodeList streams = doc.getElementsByTagName("Stream");
				if (streams != null && streams.getLength() > 0) {

					for (int i = 0; i < streams.getLength(); i++) {

						final Element stream = (Element) streams.item(i);
						final int len = stream.getTextContent().length();

						if (len > 100000) {
							final Node streamParent = stream.getParentNode();
							streamParent.removeChild(stream);

							final Element newStream = doc.createElement("Stream");
							newStream.setTextContent("[" + TRUNCATED_DATA + ", size:" + len + "]");
							streamParent.appendChild(newStream);
						}
					}
					doc.normalize();
				}

				loadElementsList(doc.getElementsByTagName("*"));

				final Transformer transform = TransformerFactory.newInstance().newTransformer();
				transform.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");

				final StringWriter writer = new StringWriter();
				transform.transform(new DOMSource(doc), new StreamResult(writer));

				isr.close();

				return "" + writer.getBuffer().toString() + "";

			} catch (SAXException | IOException | TransformerException | ParserConfigurationException ignored) {
			}

		} else {
			try {
				loadElementsList(headers, HEADERS);

				final JsonElement root = JsonParser.parseReader(isr);
				loadElementsList(root, ROOT);

				if (!root.isJsonPrimitive()) {
					this.type = JSON_TYPE;

					isr.close();

					return "{\"response\":{\"name\":\"response\",\"code\":" + responseCode + ",\"" + ROOT + "\":" + root + ",\"" + HEADERS + "\":" + headers + "}}";
				}
			} catch (JsonIOException | JsonSyntaxException | IOException ignored) {
			}
		}

		this.type = TEXT_TYPE;

		isr = new InputStreamReader(new FileInputStream(bodyFile), StandardCharsets.UTF_8);
		final BufferedReader reader = new BufferedReader(isr);
		final String content = reader.lines().collect(Collectors.joining("\n"));
		atsElements.add(new AtsApiElement(DATA, ImmutableMap.of("value", content)));

		try {
			reader.close();
			isr.close();
		} catch (IOException e) {}

		return "" + responseCode + "";
	}

	private void initAtsElements() {
		this.atsElements = new ArrayList<>();
		atsElements.add(new AtsApiElement(RESPONSE, ImmutableMap.of("name", "response", "code", responseCode)));
	}

	public String getSource() {
		return source;
	}

	public ArrayList findElements(Channel channel, TestElement testObject, String tagName, Predicate predicate) {

		final String searchedTag = tagName.toUpperCase();
		final ArrayList result = new ArrayList<>();

		if (testObject.getParent() == null) {
			refresh(channel);
		} else {
			final Optional parentElement = atsElements.stream().filter(e -> e.getId().equals(testObject.getParent().getFoundElement().getId())).findFirst();
			if (parentElement.isPresent()) {
				if (!parentElement.get().isResponse()) {
					if (type == XML_TYPE) {
						final Element elem = ((AtsXmlElement) parentElement.get()).getElement();
						if (elem != null) {
							initAtsElements();
							loadElementsList(elem.getElementsByTagName("*"));
						}
					} else if (type == JSON_TYPE) {
						final AtsJsonElement elem = (AtsJsonElement) parentElement.get();
						initAtsElements();
						loadElementsList(elem.getElement(), elem.getAttribute("name"));
					}
				}
			}
		}

		if ("*".equals(tagName)) {
			atsElements.stream().filter(predicate).forEach(e -> result.add(new FoundElement(e)));
		} else {
			atsElements.stream().filter(e -> e.getTag().equals(searchedTag)).filter(predicate).forEach(e -> result.add(new FoundElement(e)));
		}

		return result;
	}


	//-------------------------------------------------------------------------------------------------------------------------------------------------------
	// Json
	//-------------------------------------------------------------------------------------------------------------------------------------------------------

	private void loadElementsList(JsonElement json, String name) {

		final HashMap attributes;

		if (json.isJsonArray()) {
			attributes = new HashMap<>(Map.of("name", name));
			final JsonArray array = json.getAsJsonArray();
			attributes.put("size", array.size() + "");

			atsElements.add(new AtsJsonElement(json, ARRAY, attributes));

			int index = 0;
			for (JsonElement el : array) {
				if (el.isJsonPrimitive()) {
					loadArrayList(el, "index" + index, el.getAsString());
				} else {
					loadElementsList(el, "index" + index);
				}

				index++;
			}

		} else if (json.isJsonObject()) {

			if (json.getAsJsonObject().has("name")) {
				attributes = new HashMap<>(Map.of("key", name));
			} else {
				attributes = new HashMap<>(Map.of("name", name));
			}

			for (Entry entry : json.getAsJsonObject().entrySet()) {
				final String attributeName = entry.getKey();
				final JsonElement attributeValue = entry.getValue();

				if (attributeValue.isJsonPrimitive()) {
					if (attributes.containsKey(attributeName)) {
						attributes.replace(attributeName, attributeValue.getAsJsonPrimitive().getAsString());
					} else {
						attributes.put(attributeName, attributeValue.getAsJsonPrimitive().getAsString());
					}
				} else {
					loadElementsList(attributeValue, attributeName);
				}
			}

			atsElements.add(new AtsJsonElement(json, OBJECT, attributes));
		}
	}

	private void loadArrayList(JsonElement el, String item, String value) {
		atsElements.add(new AtsJsonElement(el, ELEMENT, ImmutableMap.of("name", item, "value", value)));
	}

	//-------------------------------------------------------------------------------------------------------------------------------------------------------
	// Xml
	//-------------------------------------------------------------------------------------------------------------------------------------------------------

	private void loadElementsList(NodeList nodeList) {

		for (int i = 0; i < nodeList.getLength(); i++) {

			final Node node = nodeList.item(i);
			final String nodeName = node.getNodeName();

			final Map foundAttributes = new HashMap<>();
			final NamedNodeMap nodeAttributes = node.getAttributes();

			foundAttributes.put("name", xmlPropertyPattern.matcher(nodeName).replaceFirst(""));

			for(int j=0; j 0) {
							if(nodeChildElement.getNodeType() == Node.TEXT_NODE) {
								foundAttributes.put("text", nodeChildValue);
							}else if(nodeChildElement.getNodeType() == Node.COMMENT_NODE) {
								foundAttributes.put("comment", nodeChildValue);
							}
						}
					}
				}
			}

			if(hasChild) {//Node
				atsElements.add(new AtsXmlElement(node, NODE, foundAttributes));
			}else{//Element
				final NodeList properties = node.getChildNodes();
				for(int j=0; j 0) {
							String propertyName = property.getNodeName();
							if("#text".equals(propertyName)) {
								propertyName = "value";
							}else {
								xmlPropertyPattern.matcher(propertyName).replaceFirst("");
							}
							addAttribute(foundAttributes, propertyName, propertyValue);
						}
					}
				}
				atsElements.add(new AtsXmlElement(node, ELEMENT, foundAttributes));
			}
		}
	}

	private void addAttribute(Map map, String propertyName, String propertyValue) {
		if(!"xsd".equals(propertyName) && !"xsi".equals(propertyName)) {
			map.put(propertyName, propertyValue);
		}
	}

	public String getElementAttribute(String id, String attributeName) {
		final Optional elem = atsElements.stream().filter(e -> e.getId().equals(id)).findFirst();
		if(elem.isPresent()) {
			return elem.get().getAttribute(attributeName);
		}
		return null;
	}

	public CalculatedProperty[] getElementAttributes(String id) {
		final Optional elem = atsElements.stream().filter(e -> e.getId().equals(id)).findFirst();
		if(elem.isPresent()) {
			return elem.get().getAttributesMap().entrySet().stream().parallel().map(e -> new CalculatedProperty(e.getKey(), e.getValue())).toArray(c -> new CalculatedProperty[c]);
		}
		return null;
	}
	
	private static String toCurl(Request request) {
		StringBuilder curlCmd = new StringBuilder("curl \\\n");

		// Add method
		curlCmd.append("  -X ").append(request.method()).append(" \\\n");

		// Add headers
		Headers headers = request.headers();
		for (int i = 0; i < headers.size(); i++) {
			curlCmd.append("  -H \"").append(headers.name(i)).append(": ").append(headers.value(i)).append("\" \\\n");
		}

		// Add URL
		curlCmd.append("  \"").append(request.url()).append("\"");

		// Add body (if POST or PUT)
		if (request.body() != null && (request.method().equalsIgnoreCase("POST") || request.method().equalsIgnoreCase("PUT"))) {
			if (request.body() instanceof MultipartBody) {
				MultipartBody multipartBody = (MultipartBody) request.body();
				for (MultipartBody.Part part : multipartBody.parts()) {
					try {
						okio.Buffer buffer = new okio.Buffer();
						part.body().writeTo(buffer);
						curlCmd.append(" \\\n  -F \"").append(part.headers().get("Content-Disposition").replace("form-data; ", "").replace("\"", "\\\"")).append("=").append(buffer.readUtf8()).append("\"");
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			} else {
				okio.Buffer buffer = new okio.Buffer();
				try {
					request.body().writeTo(buffer);
					String body = buffer.readUtf8();
					curlCmd.append(" \\\n  --data '").append(body).append("'");
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}

		return curlCmd.toString();
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy