/******************************************************************************* * Copyright (c) 2009, 2016 xored software, Inc. 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: * xored software, Inc. - initial API and Implementation (Alex Panchenko) *******************************************************************************/ package org.eclipse.dltk.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.eclipse.dltk.compiler.util.Util; import org.eclipse.dltk.dbgp.IDbgpSession; import org.eclipse.dltk.dbgp.IDbgpThreadAcceptor; import org.eclipse.dltk.debug.core.model.IScriptDebugTargetListener; import org.eclipse.dltk.internal.debug.core.model.ScriptDebugTarget; import org.eclipse.dltk.internal.launching.DLTKLaunchingPlugin; public class DebugSessionAcceptor implements IDbgpThreadAcceptor, IScriptDebugTargetListener { private static class NopLaunchStatusHandler implements ILaunchStatusHandlerExtension { @Override public void initialize(IDebugTarget target, IProgressMonitor monitor) { // empty } @Override public void updateElapsedTime(long elapsedTime) { // empty } @Override public void dispose() { // empty } @Override public boolean isCanceled() { return true; } } private final ScriptDebugTarget target; private IProgressMonitor parentMonitor; private boolean initialized = false; private boolean connected = false; private ILaunchStatusHandler statusHandler = null; public DebugSessionAcceptor(ScriptDebugTarget target, IProgressMonitor monitor) { this.target = target; this.parentMonitor = monitor; target.addListener(this); target.getDbgpService().registerAcceptor(target.getSessionId(), this); } /* * @see IScriptDebugTargetListener#targetInitialized() */ @Override public void targetInitialized() { synchronized (this) { initialized = true; notify(); } } @Override 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(Messages.DebugSessionAcceptor_waitConnection); 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.getProcess() != null && target.getProcess().isTerminated()) { throw new CoreException(new Status(IStatus.ERROR, DLTKLaunchingPlugin.PLUGIN_ID, ScriptLaunchConfigurationConstants.ERR_DEBUGGER_PROCESS_TERMINATED, LaunchingMessages.DebugSessionAcceptor_DebuggerUnexpectedlyTerminated, null)); } } /** * @return */ private ILaunchStatusHandler createStatusHandler() { final String extensionPointId = DLTKLaunchingPlugin.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) { DLTKLaunchingPlugin.logWarning(e); } } final ILaunchStatusHandler handler = new NopLaunchStatusHandler(); handler.initialize(target, parentMonitor); return handler; } @Override 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( Messages.DebugSessionAcceptor_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(); } } }