
step.core.deployment.ControllerServices Maven / Gradle / Ivy
/*******************************************************************************
* Copyright (C) 2020, exense GmbH
*
* This file is part of STEP
*
* STEP is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* STEP 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with STEP. If not, see .
******************************************************************************/
package step.core.deployment;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.PostConstruct;
import jakarta.inject.Singleton;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import org.bson.types.ObjectId;
import step.artefacts.CallPlan;
import step.artefacts.handlers.PlanLocator;
import step.artefacts.handlers.SelectorHelper;
import step.core.Controller;
import step.core.GlobalContext;
import step.core.Version;
import step.core.artefacts.AbstractArtefact;
import step.core.artefacts.reports.ReportNode;
import step.core.dynamicbeans.DynamicJsonObjectResolver;
import step.core.dynamicbeans.DynamicJsonValueResolver;
import step.core.execution.model.Execution;
import step.core.execution.model.ExecutionAccessor;
import step.core.objectenricher.ObjectHookRegistry;
import step.core.objectenricher.ObjectPredicate;
import step.core.objectenricher.ObjectPredicateFactory;
import step.core.plans.Plan;
import step.core.plans.PlanAccessor;
import step.core.repositories.ArtefactInfo;
import step.core.repositories.RepositoryObjectReference;
import step.core.repositories.TestSetStatusOverview;
import step.framework.server.security.Secured;
import java.io.File;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static step.core.Controller.USER_ACTIVITY_MAP_KEY;
@Singleton
@Path("controller")
@Tag(name = "Controller")
public class ControllerServices extends AbstractStepServices {
private Version currentVersion;
private PlanLocator planLocator;
private Controller controller;
private ExecutionAccessor executionAccessor;
private Map userActivityMap;
private long initializationTime;
private ObjectHookRegistry objectHooks;
private ObjectPredicateFactory objectPredicateFactory;
@PostConstruct
public void init() throws Exception {
super.init();
GlobalContext context = getContext();
currentVersion = context.getCurrentVersion();
controller = context.require(Controller.class);
DynamicJsonObjectResolver dynamicJsonObjectResolver = new DynamicJsonObjectResolver(new DynamicJsonValueResolver(getContext().getExpressionHandler()));
SelectorHelper selectorHelper = new SelectorHelper(dynamicJsonObjectResolver);
planLocator = new PlanLocator(getContext().getPlanAccessor(), selectorHelper);
objectHooks = context.get(ObjectHookRegistry.class);
objectPredicateFactory = context.get(ObjectPredicateFactory.class);
executionAccessor = context.getExecutionAccessor();
userActivityMap = (Map) context.get(USER_ACTIVITY_MAP_KEY);
initializationTime = System.currentTimeMillis();
}
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Path("/shutdown")
@Secured(right="controller-manage")
public void shutdown() {
new Thread(() -> controller.destroy()).start();
}
@GET
@Path("/reportnode/{id}")
@Produces(MediaType.APPLICATION_JSON)
@Secured(right="execution-read")
public ReportNode getReportNode(@PathParam("id") String reportNodeId) {
return getContext().getReportAccessor().get(new ObjectId(reportNodeId));
}
@GET
@Path("/reportnode/{id}/path")
@Produces(MediaType.APPLICATION_JSON)
@Secured(right="execution-read")
public List getReportNodePath(@PathParam("id") String reportNodeId) {
// Forced to convert result to ArrayList to avoid error in Jackson
List result = new ArrayList<>();
List path = getContext().getReportAccessor().getReportNodePath(new ObjectId(reportNodeId));
path.forEach((node) -> result.add(node));
return result;
}
@GET
@Path("/reportnode/{id}/plan")
@Produces(MediaType.APPLICATION_JSON)
@Secured(right="execution-read")
public Plan getReportNodeRootPlan(@PathParam("id") String reportNodeId) {
ObjectPredicate objectPredicate = objectHooks.getObjectPredicate(getSession());
PlanAccessor planAccessor = getContext().getPlanAccessor();
ReportNode reportNode = getContext().getReportAccessor().get(reportNodeId);
Plan plan = planAccessor.get(getContext().getExecutionAccessor().get(reportNode.getExecutionID()).getPlanId());
if (reportNode.getParentID() != null) {
CallPlan callPlan = getParentCallPlan(reportNode.getParentID().toString());
if (callPlan != null) {
Plan locatedPlan = planLocator.selectPlan(callPlan, objectPredicate, null);
plan = (locatedPlan != null) ? locatedPlan : plan;
}
}
return plan;
}
private CallPlan getParentCallPlan(String nodeId) {
ReportNode reportNode = (nodeId != null) ? getContext().getReportAccessor().get(nodeId): null;
if (reportNode != null) {
AbstractArtefact resolvedArtefact = reportNode.getResolvedArtefact();
if (resolvedArtefact instanceof CallPlan) {
//get related plan
return (CallPlan) resolvedArtefact;
} else if (reportNode.getParentID() != null) {
return getParentCallPlan(reportNode.getParentID().toString());
}
}
return null;
}
@GET
@Path("/reportnode/{id}/children")
@Produces(MediaType.APPLICATION_JSON)
@Secured(right="execution-read")
public List getReportNodeChildren(@PathParam("id") String reportNodeId, @QueryParam("skip") Integer skip, @QueryParam("limit") Integer limit) {
skip = skip!=null?skip:0;
limit = limit!=null?limit:1000;
List result = new ArrayList<>();
Iterator it = getContext().getReportAccessor().getChildren(new ObjectId(reportNodeId), skip, limit);
while(it.hasNext()) {
result.add(it.next());
}
return result;
}
@POST
@Path("/repository/artefact/info")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@Secured(right="execution-read")
public ArtefactInfo getArtefactInfo(RepositoryObjectReference ref) {
try {
return getContext().getRepositoryObjectManager().getArtefactInfo(ref);
} catch (Exception e) {
throw new WebApplicationException(Response.status(500).entity("Unable to retrieve artefact."+e.getMessage()).type("text/plain").build());
}
}
@POST
@Path("/repository/report")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@Secured(right="execution-read")
public TestSetStatusOverview getReport(RepositoryObjectReference report) throws Exception {
ObjectPredicate objectPredicate = objectPredicateFactory.getObjectPredicate(getSession());
return getContext().getRepositoryObjectManager().getReport(report, objectPredicate);
}
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("/version")
public Version getVersion() {
return this.currentVersion;
}
private static final Pattern JAR_FILENAME_PATTERN = Pattern.compile("([^\\\\/]+)-(\\d+\\.\\d+\\.?[^.]+).jar");
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("/lib/versions")
public Map getLibVersions() {
HashMap result = new HashMap<>();
Arrays.asList(System.getProperty("java.class.path").split(File.pathSeparator)).forEach(e -> {
Matcher matcher = JAR_FILENAME_PATTERN.matcher(e);
if (matcher.find()) {
String lib = matcher.group(1);
String version = matcher.group(2);
result.put(lib, version);
}
});
return result;
}
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("/status")
public Status getControllerStatus() {
Status status = new Status();
List activeTests = executionAccessor.getActiveTests();
status.activeTests = activeTests.size();
status.lastExecutionEndTime = -1;
Iterator iterator = executionAccessor.findLastEnded(1).iterator();
status.lastExecutionEndTime = (iterator.hasNext()) ?
Objects.requireNonNullElse(iterator.next().getEndTime(),-1L) : -1;
status.lastUserActivityTime = userActivityMap.values().stream().mapToLong(v -> v).max().orElse(initializationTime);
//If test are currently running idle time is 0
if (status.activeTests > 0) {
status.idleTimeMs = 0;
} else {
//idle time is either latest end time of executions or last logged-in user activity
long lastActivity = (status.lastUserActivityTime > status.lastExecutionEndTime) ?
status.lastUserActivityTime : status.lastExecutionEndTime;
status.idleTimeMs = System.currentTimeMillis() - lastActivity;
}
return status;
}
private class Status {
public long idleTimeMs;
public long activeTests;
public long lastExecutionEndTime;
public long lastUserActivityTime;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy