/* * Copyright 2016 Nokia Solutions and Networks * Licensed under the Apache License, Version 2.0, * see license.txt file for details. */ package org.rf.ide.core.jvmutils.process; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Optional; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.function.Consumer; import org.rf.ide.core.executor.RobotRuntimeEnvironment; import org.rf.ide.core.jvmutils.process.IProcessTreeHandler.ProcessKillException; import com.google.common.annotations.VisibleForTesting; public class OSProcessHelper { public static final int SUCCESS = 0; private final List<IProcessTreeHandler> osPidCheckers; @VisibleForTesting public OSProcessHelper(final List<IProcessTreeHandler> osPidCheckers) { this.osPidCheckers = osPidCheckers; } public OSProcessHelper() { this.osPidCheckers = new ArrayList<IProcessTreeHandler>( Arrays.asList(new WindowsProcessTreeHandler(this), new UnixProcessTreeHandler(this))); } public IProcessTreeHandler getInstanceByOS() { IProcessTreeHandler proc = null; for (final IProcessTreeHandler handler : osPidCheckers) { if (handler.isSupportedOS()) { proc = handler; break; } } return proc; } public int execCommandAndCollectOutput(final List<String> command, final Collection<String> output) throws IOException { final MyLineHandler handler = new MyLineHandler(); final int exitCode = RobotRuntimeEnvironment.runExternalProcess(command, handler); output.addAll(handler.getCollectedOutput()); return exitCode; } private class MyLineHandler implements Consumer<String> { private final Queue<String> lines = new ConcurrentLinkedQueue<>(); @Override public void accept(final String line) { lines.add(line); } public Queue<String> getCollectedOutput() { return lines; } } public ProcessInformation getProcessTreeInformations(final Process process) { ProcessInformation processInfo = new ProcessInformation(ProcessInformation.PROCESS_NOT_FOUND); final Optional<IProcessTreeHandler> processTreeProv = findProcessTreeProviderFor(process); if (processTreeProv.isPresent()) { final IProcessTreeHandler provider = processTreeProv.get(); processInfo = fillProcessTree(provider, provider.getProcessPid(process)); } return processInfo; } public void destroyProcessTree(final Process process) throws ProcessHelperException { final ProcessInformation procInfo = getProcessTreeInformations(process); if (procInfo.wasFound()) { this.destroyProcessTree(procInfo); } else { throw new ProcessHelperException("Couldn't find PID!"); } } public void destroyProcessTree(final ProcessInformation procInfo) throws ProcessHelperException { final Optional<IProcessTreeHandler> osHandler = procInfo.findHandler(); if (osHandler.isPresent()) { try { osHandler.get().killProcessTree(procInfo); } catch (final ProcessKillException e) { throw new ProcessHelperException(e); } } else { throw new ProcessHelperException("Couldn't find suiteable handler!"); } } @VisibleForTesting protected ProcessInformation fillProcessTree(final IProcessTreeHandler provider, final long pid) { final ProcessInformation process = new ProcessInformation(pid); process.setHandler(provider); final List<Long> childPids = provider.getChildPids(pid); for (final Long childPid : childPids) { process.addChildProcess(fillProcessTree(provider, childPid)); } return process; } @VisibleForTesting protected Optional<IProcessTreeHandler> findProcessTreeProviderFor(final Process process) { Optional<IProcessTreeHandler> provider = Optional.empty(); for (final IProcessTreeHandler prov : osPidCheckers) { if (prov.isSupported(process)) { provider = Optional.of(prov); break; } } return provider; } public static class ProcessHelperException extends Exception { private static final long serialVersionUID = 4817848076505721680L; public ProcessHelperException(final String errMsg) { super(errMsg); } public ProcessHelperException(final Exception e) { super(e); } } }