/*
* Created on Apr 12, 2007 Copyright (C) 2001-5, Anthony Harrison anh23@pitt.edu
* (jactr.org) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of the License,
* or (at your option) any later version. This library is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
* the GNU Lesser General Public License for more details. You should have
* received a copy of the GNU Lesser General Public License along with this
* library; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.jactr.eclipse.runtime.launching.iterative;
import java.net.InetSocketAddress;
import java.text.DateFormat;
import java.util.Collection;
import java.util.Date;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.commonreality.net.session.ISessionInfo;
import org.commonreality.netty.service.ServerService;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.swt.widgets.Display;
import org.jactr.eclipse.core.CorePlugin;
import org.jactr.eclipse.runtime.RuntimePlugin;
import org.jactr.eclipse.runtime.launching.session.AbstractSession;
import org.jactr.eclipse.runtime.launching.session.SessionTracker;
import org.jactr.eclipse.runtime.preferences.RuntimePreferences;
import org.jactr.tools.async.credentials.ICredentials;
import org.jactr.tools.async.iterative.tracker.IterativeRunTracker;
import org.jactr.tools.deadlock.IDeadLockListener;
public class IterativeSession extends AbstractSession
{
private final class IterativeTrackerJob extends Job
{
final private int TOTAL_WORK = 1000;
private IterativeTrackerJob(String name)
{
super(name);
}
protected int waitForConnection(long timeToWait, IProgressMonitor monitor)
{
long start = System.currentTimeMillis();
long delta = 0;
while (_tracker.getTotalIterations() == 0 && delta < timeToWait
&& !monitor.isCanceled())
{
if (LOGGER.isDebugEnabled())
LOGGER.debug(delta + " is less than " + timeToWait
+ " and no total iterations, snoozing");
try
{
Thread.sleep(500);
}
catch (Exception e)
{
}
delta = System.currentTimeMillis() - start;
}
if (LOGGER.isDebugEnabled())
LOGGER.debug("Got " + _tracker.getTotalIterations() + " iterations");
return _tracker.getTotalIterations();
}
protected String generateLabel()
{
StringBuilder sb = new StringBuilder("Running ");
sb.append(_tracker.getCurrentIteration()).append("/");
sb.append(_tracker.getTotalIterations()).append(" ETA : ");
DateFormat format = DateFormat.getDateTimeInstance(DateFormat.SHORT,
DateFormat.SHORT);
sb.append(format.format(new Date(_tracker.getETA()))).append(" (");
/*
* how much time is remaining
*/
long remaining = _eta = _tracker.getTimeToCompletion();
remaining /= 1000;
long[] scalors = { 86400, 3600, 60, 1 };
char[] tags = { 'd', 'h', 'm', 's' };
int len = scalors.length;
for (int i = 0; i < len; i++)
{
long unit = remaining / scalors[i];
if (unit > 0)
{
sb.append(unit).append(tags[i]).append(' ');
remaining -= unit * scalors[i];
// cut the seconds if anything else is displayed
if (tags[i] != 's') len = scalors.length - 1;
}
}
sb.append("remain)");
Collection<Integer> exceptions = _tracker.getExceptionCycles();
if (exceptions.size() != 0)
{
_cleanRun = false;
sb.append(" Errors on iterations:");
sb.append(exceptions);
}
int queued = getIterativeSessionTracker().getNumberOfDeferredLaunches();
if (queued != 0) sb.append(" (").append(queued).append(" runs queued)");
return sb.toString();
}
protected void processIterations(IProgressMonitor monitor)
{
int total = _tracker.getTotalIterations();
monitor = new SubProgressMonitor(monitor, TOTAL_WORK - 2);
monitor.beginTask(generateLabel(), TOTAL_WORK - 2);
try
{
double lastProgress = 0;
int currentIteration = 0;
ISessionInfo session = _tracker.getActiveSession();
while ((currentIteration = _tracker.getCurrentIteration()) <= total
&& !monitor.isCanceled() && session.isConnected())
{
double currentProgress = (double) (currentIteration - 1)
/ (double) total;
_percent = (float) currentProgress;
boolean shouldSleep = true;
if (currentProgress > lastProgress)
{
int increment = (int) ((currentProgress - lastProgress) * (TOTAL_WORK - 2));
if (increment >= 1)
{
monitor.worked(increment);
/*
* ratchet up the lastProgress by the same increment so that we
* don't drift when iterations > TOTAL_WORK
*/
lastProgress += (double) increment / (double) (TOTAL_WORK - 2);
shouldSleep = false;
}
// but always update the display
String label = generateLabel();
monitor.setTaskName(label);
}
if (shouldSleep) try
{
Thread.sleep(1000);
}
catch (InterruptedException e)
{
}
}
}
finally
{
monitor.done();
}
}
@Override
protected IStatus run(IProgressMonitor monitor)
{
try
{
monitor.beginTask("Waiting for connection", TOTAL_WORK);
/*
* wait for the connection..
*/
long waitTime = 1000 * RuntimePlugin.getDefault()
.getPluginPreferences()
.getInt(RuntimePreferences.ITERATIVE_START_WAIT_PREF);
int totalIterations = waitForConnection(waitTime, monitor);
monitor.setTaskName("Will run " + totalIterations + " iterations");
monitor.worked(1);
if (totalIterations == 0)
{
if (LOGGER.isDebugEnabled())
LOGGER.debug("Could not establish connection");
monitor.setTaskName("Could not establish connection");
}
else
/*
* we've got something to do..
*/
processIterations(monitor);
monitor.setTaskName("Cleaning up");
if (monitor.isCanceled() || totalIterations == 0)
if (!_launch.isTerminated()) try
{
_launch.terminate();
}
catch (DebugException de)
{
CorePlugin.error("Could not terminate iterative run ", de);
}
monitor.worked(1);
if (monitor.isCanceled()) return Status.CANCEL_STATUS;
/*
* beep to notify
*/
if (RuntimePlugin.getDefault().getPluginPreferences()
.getBoolean(RuntimePreferences.ITERATIVE_BEEP_PREF))
{
final Display display = Display.getDefault();
Runnable beep = new Runnable() {
public void run()
{
display.beep();
}
};
display.asyncExec(beep);
}
return Status.OK_STATUS;
}
finally
{
monitor.done();
}
}
}
static public final String LAUNCH_TYPE = "org.jactr.eclipse.runtime.launching.iterative";
static private SessionTracker<IterativeSession> _sessionTracker = new SessionTracker<IterativeSession>();
static public SessionTracker<IterativeSession> getIterativeSessionTracker()
{
return _sessionTracker;
}
/**
* Logger definition
*/
static private final transient Log LOGGER = LogFactory
.getLog(IterativeSession.class);
private final IterativeRunTracker _tracker;
private long _eta;
private float _percent;
private boolean _cleanRun = true;
public IterativeSession(ILaunch launch, ILaunchConfiguration configuration)
{
super(launch, configuration);
_tracker = new IterativeRunTracker();
_tracker.setService(new ServerService());
_tracker.setCredentialInformation("none:nopass");
_tracker.setAddressInfo("localhost:0");
_tracker.setDeadLockListener(new IDeadLockListener() {
public void deadlockDetected()
{
CorePlugin.error("Deadlock detected, terminating session");
try
{
stop();
}
catch (CoreException ce)
{
CorePlugin.error("Failed to terminate session ", ce);
}
}
});
}
public boolean wasCleanRun()
{
return _cleanRun;
}
public float getPercentCompleted()
{
return _percent;
}
public long getETA()
{
return _eta;
}
@Override
protected Job createSessionJob()
{
Job job = new IterativeTrackerJob(getConfiguration().getName());
job.setPriority(Job.LONG);
return job;
}
public IterativeRunTracker getIterativeRunTracker()
{
return _tracker;
}
@Override
protected void connect() throws CoreException
{
try
{
_tracker.start();
}
catch (Exception e)
{
LOGGER.error("Could not start iterative tracker ", e);
throw new CoreException(new Status(IStatus.ERROR,
RuntimePlugin.PLUGIN_ID, "Could not start iterative tracker", e));
}
}
@Override
protected void disconnect(boolean force) throws CoreException
{
try
{
_tracker.stop();
ISessionInfo session = _tracker.getActiveSession();
if (session != null) session.waitForDisconnect();
}
catch (Exception e)
{
LOGGER.error("Could not stop iterative tracker ", e);
throw new CoreException(new Status(IStatus.ERROR,
RuntimePlugin.PLUGIN_ID, "Could not stop iterative tracker", e));
}
}
@Override
public InetSocketAddress getConnectionAddress()
{
return (InetSocketAddress) _tracker.getActualAddress();
}
@Override
public ICredentials getCredentials()
{
return _tracker.getActualCredentials();
}
@Override
protected SessionTracker getSessionTracker()
{
return _sessionTracker;
}
}