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

com.infotel.seleniumrobot.grid.servlets.server.NodeStatusServlet Maven / Gradle / Ivy

The newest version!
package com.infotel.seleniumrobot.grid.servlets.server;

import java.awt.Dimension;
import java.awt.HeadlessException;
import java.awt.Rectangle;
import java.io.IOException;
import java.io.StringWriter;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Collectors;

import javax.management.InstanceNotFoundException;
import javax.management.IntrospectionException;
import javax.management.MalformedObjectNameException;
import javax.management.ReflectionException;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.openqa.selenium.MutableCapabilities;
import org.openqa.selenium.json.Json;
import org.openqa.selenium.remote.CapabilityType;

import com.google.common.net.MediaType;
import com.infotel.seleniumrobot.grid.config.LaunchConfig;
import com.infotel.seleniumrobot.grid.exceptions.SeleniumGridException;
import com.infotel.seleniumrobot.grid.tasks.ScreenshotTask;
import com.infotel.seleniumrobot.grid.utils.GridStatus;
import com.infotel.seleniumrobot.grid.utils.MemoryInfo;
import com.infotel.seleniumrobot.grid.utils.SystemInfos;
import com.infotel.seleniumrobot.grid.utils.Utils;
import com.seleniumtests.util.PackageUtility;

public class NodeStatusServlet extends GridServlet {
	
	private final Json json = new Json();
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private static final String RESOURCE_LOADER_PATH = "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader";
	private static final Logger logger = LogManager.getLogger(NodeStatusServlet.class);

	private static final String driverVersion = PackageUtility.getDriverVersion();

	protected VelocityEngine initVelocityEngine() throws Exception {
		VelocityEngine ve = new VelocityEngine();
		ve.setProperty("resource.loader", "class");
		ve.setProperty("class.resource.loader.class", RESOURCE_LOADER_PATH);
		ve.init();
		return ve;
	}
	
	/**
	 * GET `/extra/NodeStatusServlet`: returns a partial GUI which is used by hub GuiServlet
	 * GET `/extra/NodeStatusServlet&format=json`: returns the node information in json format
	 * {
	 * "memory": {
	 *   "totalMemory": 17054,
	 *   "class": "com.infotel.seleniumrobot.grid.utils.MemoryInfo",
	 *   "freeMemory": 4629
	 * },
	 * "maxSessions": 1,
	 * "port": 5554,
	 * "ip": "node_machine",
	 * "cpu": 25.2,
	 * "version": "3.14.0-SNAPSHOT",
	 * "status": "ACTIVE"
	 * }
	 */
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		ServletResponse response = getStatus(req.getParameter("format"));
		response.send(resp);
	}

	public ServletResponse getStatus(String format) {

		if ("json".equalsIgnoreCase(format)) {
			return getJsonStatus();
		} else {
			return getHtmlStatus();
		}
	}

	/**
	 * POST `/extra/NodeStatusServlet?status=INACTIVE`: disable this node. 
	 * It won't accept any new session, but current test session will continue. Allowed values are 'ACTIVE' and 'INACTIVE'
	 */
	@Override
	protected void doPost(HttpServletRequest request, HttpServletResponse resp) {
		ServletResponse response = setStatus(request.getParameter("status"));
		response.send(resp);
	}

	public ServletResponse setStatus(String statusString) {

		String msg = "OK";
		
		try {
			GridStatus status = GridStatus.fromString(statusString);
	
			if (GridStatus.ACTIVE.equals(status)) {
				LaunchConfig.getCurrentNodeConfig().setStatus(GridStatus.ACTIVE);
			} else if (GridStatus.INACTIVE.equals(status)) {
				LaunchConfig.getCurrentNodeConfig().setStatus(GridStatus.INACTIVE);
			}
		} catch (IllegalArgumentException e) {
			msg = "you must provide a 'status' parameter (either 'active' or 'inactive')";
			return new ServletResponse(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, msg);
		}

		return new ServletResponse(HttpServletResponse.SC_OK, msg);
	}
	
	/**
	 * Send JSON status of the node
	 */
	private ServletResponse getJsonStatus() {
		try {
			Object res = buildNodeStatus();
			return new ServletResponse(HttpServletResponse.SC_OK, json.toJson(res), MediaType.JSON_UTF_8);
		} catch (Throwable e) {
			return new ServletResponse(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
		}	
	}
	

	private Map buildNodeStatus() {

		Map nodeInfos = new HashMap<>();
		nodeInfos.put("version", Utils.getCurrentversion());
		nodeInfos.put("driverVersion", driverVersion);
		try {
			nodeInfos.put("memory", SystemInfos.getMemory());
			nodeInfos.put("cpu", SystemInfos.getCpuLoad());
		} catch (MalformedObjectNameException | InstanceNotFoundException | ReflectionException | IntrospectionException e) {
			nodeInfos.put("cpu", 11.11);
			nodeInfos.put("memory", new MemoryInfo(0, 0));
		}
		Dimension screenDimension;
		try {
			screenDimension = SystemInfos.getMainScreenResolution().getSize();
		} catch (HeadlessException e) {
			screenDimension = new Rectangle(0, 0).getSize();
		}
		Map dims = new HashMap<>();
		dims.put("width", screenDimension.width);
		dims.put("height", screenDimension.height);
		nodeInfos.put("screen", dims);
		nodeInfos.put("maxSessions", LaunchConfig.getCurrentLaunchConfig().getMaxSessions());
		String ip = LaunchConfig.getCurrentNodeConfig().getServerOptions().getHostname().orElse("localhost");
		nodeInfos.put("ip", ip);
		nodeInfos.put("hub", LaunchConfig.getCurrentNodeConfig().getNodeOptions().getPublicGridUri().get().getHost());
		nodeInfos.put("port", LaunchConfig.getCurrentNodeConfig().getNodeOptions().getPublicGridUri().get().getPort());
		nodeInfos.put("nodeTags", LaunchConfig.getCurrentLaunchConfig().getNodeTags());
		nodeInfos.put("capabilities", LaunchConfig.getCurrentNodeConfig()
													.getCapabilities()
													.stream()
													.map(c -> filterCapabilities(c)).collect(Collectors.toList())
													);
		
		nodeInfos.put("status", LaunchConfig.getCurrentNodeConfig().getStatus());
		

		return nodeInfos;
	}
	
	/**
	 * Filter capabilities that we will display
	 * @param nodeCapabilities
	 * @return
	 */
	private MutableCapabilities filterCapabilities(MutableCapabilities nodeCapabilities) {

		List capsToKeep = Arrays.asList(CapabilityType.BROWSER_NAME, CapabilityType.BROWSER_VERSION, CapabilityType.PLATFORM_NAME);
		
		return new MutableCapabilities(nodeCapabilities.asMap()
					.entrySet()
					.stream()
					.filter(cap -> capsToKeep.contains(cap.getKey()))
					.collect(Collectors.toMap(Entry::getKey, Entry::getValue)));
	}
	
	/**
	 * send HTML status of the node
	 */
	private ServletResponse getHtmlStatus() {
		Map status = buildNodeStatus();
		try {

			VelocityEngine ve = initVelocityEngine();
			Template t = ve.getTemplate( "templates/nodeStatus.vm");
			StringWriter writer = new StringWriter();
			VelocityContext context = new VelocityContext();
			context.put("version", status.get("version"));
			context.put("driverVersion", status.get("driverVersion"));
			context.put("memory", status.get("memory"));
			context.put("cpu", status.get("cpu"));
			context.put("ip", status.get("ip"));
			context.put("port", status.get("port"));
			ScreenshotTask screenshotTask = new ScreenshotTask();
			screenshotTask.execute();
			if (screenshotTask.getScreenshot() != null) {
				context.put("image", screenshotTask.getScreenshot());
			}

			t.merge( context, writer );

			return new ServletResponse(HttpServletResponse.SC_OK, writer.toString(), MediaType.HTML_UTF_8);
        } catch (Exception e) {
			return new ServletResponse(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Error sending reply: " + e.getMessage());
        }
	}
	
	
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy