blob: 24d0748641dcc5d2f6e31a74c57e5ead19adf852 [file] [log] [blame]
/*
* Copyright (c) 2006 IBM Corporation and others.
* 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:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.emf.cdo.internal.efs;
import org.eclipse.emf.cdo.internal.efs.bundle.OM;
import org.eclipse.net4j.util.WrappedException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.ProgressMonitorWrapper;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import java.util.concurrent.Callable;
/**
* This class provides a simulation of progress. This is useful for situations where computing the amount of work to do
* in advance is too costly. The monitor will accept any number of calls to {@link #worked(int)}, and will scale the
* actual reported work appropriately so that the progress never quite completes.
*/
public class InfiniteProgress extends ProgressMonitorWrapper
{
private static final Object NO_RESULT = new Object();
/*
* Fields for progress monitoring algorithm. Initially, give progress for every 4 resources, double this value at
* halfway point, then reset halfway point to be half of remaining work. (this gives an infinite series that converges
* at total work after an infinite number of resources).
*/
private int totalWork;
private int currentIncrement = 4;
private int halfWay;
private int nextProgress = currentIncrement;
private int worked = 0;
protected InfiniteProgress(IProgressMonitor monitor)
{
super(monitor);
}
@Override
public void beginTask(String name, int work)
{
super.beginTask(name, work);
totalWork = work;
halfWay = totalWork / 2;
}
@Override
public void worked(int work)
{
if (--nextProgress <= 0)
{
// we have exhausted the current increment, so report progress
super.worked(1);
worked++;
if (worked >= halfWay)
{
// we have passed the current halfway point, so double the
// increment and reset the halfway point.
currentIncrement *= 2;
halfWay += (totalWork - halfWay) / 2;
}
// reset the progress counter to another full increment
nextProgress = currentIncrement;
}
}
@SuppressWarnings("unchecked")
public static <T> T call(final String label, final Callable<T> callable)
{
final Object[] result = { NO_RESULT };
final IProgressMonitor[] jobMonitor = { null };
Job job = new Job(label)
{
@Override
protected IStatus run(IProgressMonitor monitor)
{
jobMonitor[0] = new InfiniteProgress(monitor);
jobMonitor[0].beginTask(label, 10);
try
{
result[0] = callable.call();
synchronized (result)
{
result.notifyAll();
}
return Status.OK_STATUS;
}
catch (Throwable t)
{
result[0] = t;
if (jobMonitor[0].isCanceled())
{
return Status.OK_STATUS;
}
return new Status(IStatus.ERROR, OM.BUNDLE_ID, t.getLocalizedMessage(), t);
}
finally
{
monitor = jobMonitor[0];
jobMonitor[0] = null;
monitor.done();
}
}
};
job.schedule();
while (result[0] == NO_RESULT)
{
synchronized (result)
{
if (jobMonitor[0] != null)
{
if (jobMonitor[0].isCanceled())
{
job.cancel();
throw new OperationCanceledException();
}
jobMonitor[0].worked(1);
}
try
{
System.out.println("wait...");
result.wait(100L);
}
catch (InterruptedException ex)
{
job.cancel();
throw new OperationCanceledException();
}
}
}
if (result[0] instanceof Error)
{
throw (Error)result[0];
}
if (result[0] instanceof Exception)
{
throw WrappedException.wrap((Exception)result[0]);
}
return (T)result[0];
}
}