blob: a336bebf5f57fa8f31d1af49fe0961bd1e770455 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2018 1C-Soft LLC.
*
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Vladimir Piskarev (1C) - initial API and implementation
*******************************************************************************/
package org.eclipse.handly.internal.examples.lsp;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.SubMonitor;
/**
* Utilities that integrate java.util.concurrent.Future
* with org.eclipse.core.runtime.
*/
class Futures
{
/**
* Waits if necessary for at most the given time for the computation
* to complete, and then retrieves its result, if available.
*
* @param future the computation's future
* @param timeout the maximum time to wait
* @param unit the time unit of the timeout argument
* @param monitor a progress monitor, or <code>null</code>
* if progress reporting is not desired. The caller must not rely on
* {@link IProgressMonitor#done()} having been called by this method
* @return the computed result
* @throws ExecutionException if the computation threw an exception
* @throws TimeoutException if the wait timed out
* @throws OperationCanceledException if the computation was cancelled
*/
static <T> T get(Future<T> future, long timeout, TimeUnit unit,
IProgressMonitor monitor) throws ExecutionException, TimeoutException
{
SubMonitor subMonitor = SubMonitor.convert(monitor);
long remainingNanos = unit.toNanos(timeout);
long end = System.nanoTime() + remainingNanos;
boolean interrupted = false;
try
{
while (true)
{
subMonitor.setWorkRemaining((int)(remainingNanos / 10000000));
try
{
// wait for at most 10 ms
return future.get(Math.min(remainingNanos, 10000000),
TimeUnit.NANOSECONDS);
}
catch (CancellationException e)
{
throw new OperationCanceledException();
}
catch (InterruptedException e)
{
interrupted = true;
remainingNanos = Math.max(0, end - System.nanoTime());
}
catch (TimeoutException e)
{
remainingNanos = end - System.nanoTime();
if (remainingNanos <= 0)
throw e;
subMonitor.split(1);
}
}
}
finally
{
if (interrupted)
Thread.currentThread().interrupt();
}
}
/**
* Converts the given ExecutionException to a CoreException.
*
* @param e the given exception (not <code>null</code>)
* @return the converted exception (never <code>null</code>)
*/
static CoreException toCoreException(ExecutionException e)
{
Throwable cause = e.getCause();
if (cause instanceof CoreException)
return (CoreException)cause;
if (cause == null)
cause = e;
return new CoreException(Activator.createErrorStatus(cause.getMessage(),
cause));
}
/**
* Converts the given TimeoutException to a CoreException.
*
* @param e the given exception (not <code>null</code>)
* @return the converted exception (never <code>null</code>)
*/
static CoreException toCoreException(TimeoutException e)
{
return new CoreException(Activator.createErrorStatus(e.getMessage(),
e));
}
private Futures()
{
}
}