/*
* #%~
* 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.model.internal;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.overture.ide.debug.core.IDbgpService;
import org.overture.ide.debug.core.IDebugPreferenceConstants;
import org.overture.ide.debug.core.VdmDebugPlugin;
import org.overture.ide.debug.core.dbgp.DbgpServer;
import org.overture.ide.debug.core.dbgp.IDbgpServerListener;
import org.overture.ide.debug.core.dbgp.IDbgpSession;
import org.overture.ide.debug.core.dbgp.IDbgpSessionInfo;
import org.overture.ide.debug.core.dbgp.IDbgpThreadAcceptor;
import org.overture.ide.debug.core.dbgp.internal.IDbgpTerminationListener;
public class DbgpService implements IDbgpService, IDbgpTerminationListener,
IDbgpServerListener
{
private static final int FROM_PORT = 10000;
private static final int TO_PORT = 50000;
protected static final int SERVER_SOCKET_TIMEOUT = 500;
protected static final int CLIENT_SOCKET_TIMEOUT = 10000000;
private DbgpServer server;
private final Map<String, IDbgpThreadAcceptor> acceptors = Collections.synchronizedMap(new HashMap<String, IDbgpThreadAcceptor>());
private int serverPort;
private void stopServer()
{
if (server != null)
{
try
{
server.removeTerminationListener(this);
server.setListener(null);
server.requestTermination();
try
{
server.waitTerminated();
} catch (InterruptedException e)
{
VdmDebugPlugin.log(e);
}
} finally
{
server = null;
}
}
}
private void startServer(int port)
{
serverPort = port;
server = createServer(port);
server.addTerminationListener(this);
server.setListener(this);
server.start();
}
protected DbgpServer createServer(int port)
{
return new DbgpServer(port, CLIENT_SOCKET_TIMEOUT);
}
private void restartServer(int port)
{
stopServer();
startServer(port);
}
public DbgpService(int port)
{
startServer(autoSelectPost(port));
}
private int autoSelectPost(int port)
{
if (port == IDebugPreferenceConstants.DBGP_AVAILABLE_PORT)
{
port = DbgpServer.findAvailablePort(FROM_PORT, TO_PORT);
}
return port;
}
public void shutdown()
{
stopServer();
}
public int getPort()
{
return serverPort;
}
/**
* Waits until the socket is actually started using the default timeout.
*
* @return <code>true</code> if socket was successfully started and <code>false</code> otherwise.
*/
public boolean waitStarted()
{
return server != null && server.waitStarted();
}
/**
* Waits until the socket is actually started using specified timeout.
*
* @return <code>true</code> if socket was successfully started and <code>false</code> otherwise.
*/
public boolean waitStarted(long timeout)
{
return server != null && server.waitStarted(timeout);
}
// Acceptors
public void registerAcceptor(String id, IDbgpThreadAcceptor acceptor)
{
acceptors.put(id, acceptor);
}
public IDbgpThreadAcceptor unregisterAcceptor(String id)
{
return (IDbgpThreadAcceptor) acceptors.remove(id);
}
public void restart(int newPort)
{
if (serverPort != newPort)
{
// Only restart if concrete port specified
restartServer(autoSelectPost(newPort));
}
}
// IDbgpTerminationListener
public void objectTerminated(Object object, Exception e)
{
if (e != null)
{
VdmDebugPlugin.log(e);
final Job job = new Job("ServerRestart")
{
protected IStatus run(IProgressMonitor monitor)
{
restartServer(serverPort);
return Status.OK_STATUS;
}
};
job.schedule(2000);
}
}
public boolean available()
{
return true;
}
// INewDbgpServerListener
public void clientConnected(IDbgpSession session)
{
final IDbgpSessionInfo info = session.getInfo();
if (info != null)
{
final IDbgpThreadAcceptor acceptor = (IDbgpThreadAcceptor) acceptors.get(info.getIdeKey());
if (acceptor != null)
{
acceptor.acceptDbgpThread(session, new NullProgressMonitor());
} else
{
session.requestTermination();
}
}
}
}