package org.jactr.eclipse.execution.internal;
/*
* default logging
*/
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.Executor;
import org.eclipse.core.resources.IProject;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.jactr.eclipse.execution.IExecutionControl;
import org.jactr.eclipse.execution.IExecutionService;
import org.jactr.eclipse.execution.IExecutionServiceListener;
import org.jactr.eclipse.execution.IExecutionSession;
import org.jactr.eclipse.execution.IExecutionSessionListener;
public abstract class AbstractExecutionService implements IExecutionService
{
static private enum EventType {
CREATED, CHANGED, DESTROYED
};
private final GeneralEventManager<IExecutionServiceListener, SessionEvent> _eventManager;
/**
* relays session changes to the service listeners
*/
private final IExecutionSessionListener _changeRelayListener;
private final Collection<IExecutionSession> _activeSessions;
private final LinkedList<IExecutionSession> _queue;
public AbstractExecutionService()
{
_queue = new LinkedList<IExecutionSession>();
_activeSessions = new ArrayList<IExecutionSession>();
_eventManager = new GeneralEventManager<IExecutionServiceListener, SessionEvent>(
new GeneralEventManager.INotifier<IExecutionServiceListener, SessionEvent>() {
public void notify(IExecutionServiceListener listener,
SessionEvent event)
{
switch (event._type)
{
case CREATED:
listener.sessionCreated(event._session);
break;
case CHANGED:
listener.sessionStateChanged(event._session);
break;
case DESTROYED:
listener.sessionDestroyed(event._session);
break;
}
}
});
_changeRelayListener = new IExecutionSessionListener() {
public void detailsHaveChanged(IExecutionSession session)
{
}
public void stateHasChanged(IExecutionSession session)
{
signalStateChanged(session);
if (session.getState() == IExecutionSession.State.COMPLETED)
checkQueue();
}
public void notificationReceived(IExecutionSession session, Object message)
{
}
};
}
public void addListener(IExecutionServiceListener listener, Executor executor)
{
_eventManager.addListener(listener, executor);
}
public void getSessions(Collection<IExecutionSession> container)
{
synchronized (_activeSessions)
{
container.addAll(_activeSessions);
}
}
public void removeListener(IExecutionServiceListener listener)
{
_eventManager.removeListener(listener);
}
public boolean hasListeners()
{
return _eventManager.hasListeners();
}
/**
* create the actual session object
*
* @param parameters
* @return
*/
abstract protected IExecutionSession createSession(IProject project,
ILaunchConfiguration configuration, Object... parameters);
/**
* start the processing of the session - either by executing or queuing for
* later
*
* @param session
*/
abstract protected void startSessionProcessing(IExecutionSession session)
throws Exception;
/**
* destroy session resources
*
* @param session
*/
abstract protected void destroySession(IExecutionSession session);
abstract protected void validate(IProject project,
ILaunchConfiguration launchConfiguration) throws Exception;
abstract protected boolean shouldQueue(IExecutionSession session,
List<IExecutionSession> queue);
protected void checkQueue()
{
IExecutionSession session = null;
synchronized (_queue)
{
if (_queue.size() != 0) session = _queue.remove(0);
}
if (session != null) try
{
startSession(session, true);
}
catch (Exception e)
{
// ?? should log it..
}
}
protected void queueSession(IExecutionSession session)
{
synchronized (_queue)
{
_queue.addLast(session);
}
((AbstractExecutionSession) session).queued();
}
protected void startSession(IExecutionSession session,
boolean callStartProcessing) throws Exception
{
try
{
if (callStartProcessing) startSessionProcessing(session);
// should probably lock
synchronized (_activeSessions)
{
_activeSessions.add(session);
}
}
catch (Exception e)
{
destroy(session);
throw e;
}
}
/**
* submit the execution request
*/
public IExecutionSession submit(IProject project,
ILaunchConfiguration launchConfiguration, Object... parameters)
throws Exception
{
validate(project, launchConfiguration);
IExecutionSession session = createSession(project, launchConfiguration,
parameters);
session.addListener(_changeRelayListener, null);
_eventManager.notify(new SessionEvent(session, EventType.CREATED));
boolean delayProcessing = false;
synchronized (_queue)
{
delayProcessing = shouldQueue(session, _queue);
}
if (!delayProcessing)
startSession(session, true);
else
queueSession(session);
return session;
}
public IExecutionSession adopt(IProject project,
ILaunchConfiguration launchConfiguration, Object... parameters)
throws Exception
{
validate(project, launchConfiguration);
IExecutionSession session = createSession(project, launchConfiguration,
parameters);
session.addListener(_changeRelayListener, null);
_eventManager.notify(new SessionEvent(session, EventType.CREATED));
startSession(session, false);
return session;
}
protected void destroy(IExecutionSession session) throws DebugException
{
try
{
/*
* make sure it isn't running
*/
IExecutionControl control = session.getControl();
if (control != null && control.isRunning() && control.canTerminate())
control.terminate();
}
finally
{
synchronized (_activeSessions)
{
_activeSessions.remove(session);
}
_eventManager.notify(new SessionEvent(session, EventType.DESTROYED));
destroySession(session);
}
}
protected void signalStateChanged(IExecutionSession session)
{
_eventManager.notify(new SessionEvent(session, EventType.CHANGED));
}
private class SessionEvent
{
final IExecutionSession _session;
final EventType _type;
public SessionEvent(IExecutionSession session, EventType type)
{
_type = type;
_session = session;
}
}
}