/*
* #%~
* org.overture.ide.debug
* %%
* Copyright (C) 2008 - 2014 Overture
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #~%
*/
package org.overture.ide.debug.core.launching;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.debug.core.model.IDebugTarget;
import org.overture.ide.debug.core.IDebugConstants;
import org.overture.ide.debug.core.VdmDebugPlugin;
import org.overture.ide.debug.core.dbgp.IDbgpSession;
import org.overture.ide.debug.core.dbgp.IDbgpThreadAcceptor;
import org.overture.ide.debug.core.dbgp.internal.utils.Util;
import org.overture.ide.debug.core.model.IVdmDebugTargetListener;
import org.overture.ide.debug.core.model.internal.VdmDebugTarget;
public class DebugSessionAcceptor implements IDbgpThreadAcceptor,
IVdmDebugTargetListener
{
private static class NopLaunchStatusHandler implements
ILaunchStatusHandler, ILaunchStatusHandlerExtension
{
public void initialize(IDebugTarget target, IProgressMonitor monitor)
{
// empty
}
public void updateElapsedTime(long elapsedTime)
{
// empty
}
public void dispose()
{
// empty
}
public boolean isCanceled()
{
return true;
}
}
private final VdmDebugTarget target;
private IProgressMonitor parentMonitor;
private boolean initialized = false;
private boolean connected = false;
private ILaunchStatusHandler statusHandler = null;
public DebugSessionAcceptor(VdmDebugTarget target, IProgressMonitor monitor)
{
this.target = target;
this.parentMonitor = monitor;
target.addListener(this);
target.getDbgpService().registerAcceptor(target.getSessionId(), this);
}
/*
* @see IVdmDebugTargetListener#targetInitialized()
*/
public void targetInitialized()
{
synchronized (this)
{
initialized = true;
notify();
}
}
public void targetTerminating()
{
target.getDbgpService().unregisterAcceptor(target.getSessionId());
disposeStatusHandler();
}
public void disposeStatusHandler()
{
if (statusHandler != null)
{
statusHandler.dispose();
statusHandler = null;
}
}
private static final int WAIT_CHUNK = 1000;
public boolean waitConnection(final int timeout) throws CoreException
{
final SubProgressMonitor sub = new SubProgressMonitor(parentMonitor, 1);
sub.beginTask(Util.EMPTY_STRING, timeout / WAIT_CHUNK);
try
{
sub.setTaskName("Waiting for Connection");
final long start = System.currentTimeMillis();
try
{
long waitStart = start;
for (;;)
{
synchronized (this)
{
if (connected)
{
return true;
}
}
if (target.isTerminated() || sub.isCanceled())
{
break;
}
abortIfProcessTerminated();
synchronized (this)
{
wait(WAIT_CHUNK);
}
final long now = System.currentTimeMillis();
if (timeout != 0 && now - start > timeout)
{
if (statusHandler == null)
{
statusHandler = createStatusHandler();
}
if (statusHandler instanceof ILaunchStatusHandlerExtension
&& ((ILaunchStatusHandlerExtension) statusHandler).isCanceled())
{
return false;
}
statusHandler.updateElapsedTime(now - start);
}
sub.worked((int) ((now - waitStart) / WAIT_CHUNK));
waitStart = now;
}
} catch (InterruptedException e)
{
Thread.currentThread().interrupt();
}
return false;
} finally
{
sub.done();
}
}
private void abortIfProcessTerminated() throws CoreException
{
if (target.getLaunch().getLaunchConfiguration().getAttribute(IDebugConstants.VDM_LAUNCH_CONFIG_REMOTE_DEBUG, false))
{
return;
}
if (target.getProcess() != null && target.getProcess().isTerminated())
{
throw new CoreException(new Status(IStatus.ERROR, VdmDebugPlugin.PLUGIN_ID, IDebugConstants.ERR_DEBUGGER_PROCESS_TERMINATED, "DebuggerUnexpectedlyTerminated", null));
}
}
/**
* @return
*/
private ILaunchStatusHandler createStatusHandler()
{
final String extensionPointId = VdmDebugPlugin.PLUGIN_ID
+ ".launchStatusHandler"; //$NON-NLS-1$
final IConfigurationElement[] elements = Platform.getExtensionRegistry().getConfigurationElementsFor(extensionPointId);
for (int i = 0; i < elements.length; ++i)
{
try
{
final ILaunchStatusHandler handler = (ILaunchStatusHandler) elements[i].createExecutableExtension("class"); //$NON-NLS-1$
handler.initialize(target, parentMonitor);
return handler;
} catch (Exception e)
{
VdmDebugPlugin.logWarning(e);
}
}
final ILaunchStatusHandler handler = new NopLaunchStatusHandler();
handler.initialize(target, parentMonitor);
return handler;
}
public void acceptDbgpThread(IDbgpSession session, IProgressMonitor monitor)
{
final boolean isFirst;
synchronized (this)
{
isFirst = !connected;
if (!connected)
{
connected = true;
notify();
}
}
if (isFirst)
{
IProgressMonitor sub = getInitializeMonitor();
try
{
target.getDbgpThreadAcceptor().acceptDbgpThread(session, sub);
} finally
{
sub.done();
}
} else
{
target.getDbgpThreadAcceptor().acceptDbgpThread(session, new NullProgressMonitor());
}
}
private IProgressMonitor initializeMonitor = null;
private synchronized IProgressMonitor getInitializeMonitor()
{
if (initializeMonitor == null)
{
initializeMonitor = new SubProgressMonitor(parentMonitor, 1);
initializeMonitor.beginTask(Util.EMPTY_STRING, 100);
initializeMonitor.setTaskName("waitInitialization");
}
return initializeMonitor;
}
public boolean waitInitialized(final int timeout) throws CoreException
{
final IProgressMonitor sub = getInitializeMonitor();
try
{
final long start = System.currentTimeMillis();
try
{
for (;;)
{
synchronized (this)
{
if (initialized)
{
return true;
}
}
if (target.isTerminated() || sub.isCanceled())
{
break;
}
abortIfProcessTerminated();
synchronized (this)
{
wait(WAIT_CHUNK);
}
final long now = System.currentTimeMillis();
if (timeout != 0 && now - start > timeout)
{
break;
}
}
} catch (InterruptedException e)
{
Thread.interrupted();
}
return false;
} finally
{
sub.done();
}
}
}