/******************************************************************************* * Copyright (c) 2014 Bruno Medeiros and other Contributors. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Bruno Medeiros - initial API and implementation *******************************************************************************/ package melnorme.lang.ide.core.utils.process; import static melnorme.utilbox.core.Assert.AssertNamespace.assertNotNull; import melnorme.lang.ide.core.LangCore; import melnorme.lang.utils.ProcessUtils; import melnorme.utilbox.collections.ArrayList2; import melnorme.utilbox.concurrency.ICancelMonitor; import melnorme.utilbox.concurrency.OperationCancellation; import melnorme.utilbox.core.CommonException; import melnorme.utilbox.misc.StringUtil; import melnorme.utilbox.process.ExternalProcessHelper.ExternalProcessResult; import melnorme.utilbox.process.ExternalProcessNotifyingHelper; import melnorme.utilbox.process.ExternalProcessNotifyingHelper.IProcessOutputListener; /** * Helper class around {@link ExternalProcessNotifyingHelper} to start and await completion of an external process, * and providing listeners notification for those events. */ public abstract class AbstractRunProcessTask implements IRunProcessTask { protected final ProcessBuilder pb; protected final ICancelMonitor cancelMonitor; protected ArrayList2<IProcessOutputListener> processListeners = new ArrayList2<>(); public AbstractRunProcessTask(ProcessBuilder pb, ICancelMonitor cancelMonitor) { this.pb = assertNotNull(pb); this.cancelMonitor = assertNotNull(cancelMonitor); } public ExternalProcessNotifyingHelper startProcess() throws CommonException, OperationCancellation { ICancelMonitor.checkCancelation(cancelMonitor); Process process; try { process = ProcessUtils.startProcess(pb); } catch (CommonException ce) { handleProcessStartResult(new ProcessStartHelper() { @Override public void addProcessListener(IProcessOutputListener listener) throws CommonException { throw ce; } }); throw ce; } return readFromStartedProcess(process, cancelMonitor); } protected ExternalProcessNotifyingHelper readFromStartedProcess(Process process, ICancelMonitor pm) { handleProcessStartResult(new ProcessStartHelper() { @Override public void addProcessListener(IProcessOutputListener listener) throws CommonException { assertNotNull(processListeners); processListeners.add(listener); } }); try { return new ExternalProcessNotifyingHelper(process, true, pm, processListeners, LangCore.log()); } finally { processListeners = null; // Set to null to fail fast if anyone else tries to modify afterward. } } protected abstract void handleProcessStartResult(ProcessStartHelper psh); public static interface ProcessStartHelper { /** * Add given process listener to a process that is about to have its output read. * @throws CommonException if process was unable to be started. */ void addProcessListener(IProcessOutputListener listener) throws CommonException; } @Override public ExternalProcessResult call() throws CommonException, OperationCancellation { return runProcess(); } public ExternalProcessResult runProcess() throws CommonException, OperationCancellation { return runProcess(null); } public ExternalProcessResult runProcess(String input) throws CommonException, OperationCancellation { return doRunProcess(input); } public ExternalProcessResult doRunProcess(String input) throws CommonException, OperationCancellation { ExternalProcessNotifyingHelper processHelper = startProcess(); processHelper.writeInput_(input, StringUtil.UTF8); return processHelper.awaitTerminationAndResult_ce(true); } }