/* * Copyright 2017 Nokia Solutions and Networks * Licensed under the Apache License, Version 2.0, * see license.txt file for details. */ package org.robotframework.ide.eclipse.main.plugin.launch; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collection; import java.util.Deque; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.function.Consumer; import java.util.function.Supplier; import org.eclipse.ui.services.IDisposable; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableList; /** * This service should be obtained by calling RedPlugin.getTestExecutionService() */ public class RobotTestExecutionService { @VisibleForTesting static final int LAUNCHES_HISTORY_LIMIT = 100; private final Deque<RobotTestsLaunch> launches = new ArrayDeque<>(); private final List<RobotTestExecutionListener> executionListeners = new ArrayList<>(); @VisibleForTesting Collection<RobotTestsLaunch> getLaunches() { return ImmutableList.copyOf(launches); } public void addExecutionListener(final RobotTestExecutionListener listener) { executionListeners.add(listener); } public void removeExecutionListener(final RobotTestExecutionListener listener) { executionListeners.remove(listener); } public synchronized void forEachLaunch(final Consumer<? super RobotTestsLaunch> action) { launches.forEach(action); } public synchronized Optional<RobotTestsLaunch> getLastLaunch() { return launches.stream().findFirst(); } public synchronized RobotTestsLaunch testExecutionStarting() { final RobotTestsLaunch newLaunch = new RobotTestsLaunch(); launches.addFirst(newLaunch); if (launches.size() > LAUNCHES_HISTORY_LIMIT) { final RobotTestsLaunch launch = launches.getLast(); if (launch.isTerminated()) { launches.remove(launch); launch.dispose(); } } executionListeners.forEach(listener -> listener.executionStarting(newLaunch)); return newLaunch; } public synchronized void testExecutionEnded(final RobotTestsLaunch launch) { launch.setTerminated(); executionListeners.forEach(listener -> listener.executionEnded(launch)); } public static interface RobotTestExecutionListener { void executionStarting(RobotTestsLaunch launch); void executionEnded(RobotTestsLaunch launch); } public static class RobotTestsLaunch { private final Map<Class<?>, Object> executionData = new HashMap<>(); private boolean isTerminated; public synchronized <T extends IDisposable> T getExecutionData(final Class<? extends T> clazz, final Supplier<T> supplyWhenAbsent) { final Object data = executionData.computeIfAbsent(clazz, c -> supplyWhenAbsent.get()); return clazz.cast(data); } public synchronized <T extends IDisposable> Optional<T> getExecutionData(final Class<? extends T> clazz) { return Optional.ofNullable(clazz.cast(executionData.get(clazz))); } public synchronized <T extends IDisposable> void performOnExecutionData(final Class<? extends T> clazz, final Consumer<T> consumer) { Optional.ofNullable(clazz.cast(executionData.get(clazz))).ifPresent(consumer); } private synchronized void dispose() { for (final Object data : executionData.values()) { IDisposable.class.cast(data).dispose(); } executionData.clear(); } public synchronized boolean isTerminated() { return isTerminated; } private synchronized void setTerminated() { isTerminated = true; } } }