package org.dresdenocl.debug.model; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.ConnectException; import java.net.Socket; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.List; import org.dresdenocl.debug.OclDebugPlugin; import org.dresdenocl.debug.events.IOclDebugEventListener; import org.eclipse.core.resources.IMarkerDelta; 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.jobs.Job; import org.eclipse.debug.core.DebugException; import org.eclipse.debug.core.ILaunch; import org.eclipse.debug.core.model.IBreakpoint; import org.eclipse.debug.core.model.IDebugTarget; import org.eclipse.debug.core.model.IMemoryBlock; import org.eclipse.debug.core.model.IProcess; import org.eclipse.debug.core.model.IThread; public class OclDebugTarget extends OclDebugElement implements IDebugTarget, IOclDebugEventListener { private OclDebugProcess m_process; private ILaunch m_launch; private Socket m_eventSocket; private BufferedReader m_eventReader; private boolean m_terminated = false; private OclDebugThread m_thread; private IThread[] m_threads; private OclDebugProxy m_debugProxy; private EventDispatchJob m_eventDispatch; private List<IOclDebugEventListener> m_eventListener; private class EventDispatchJob extends Job { private OclDebugCommunicationHelper m_communicationHelper = new OclDebugCommunicationHelper(); public EventDispatchJob() { super("Ocl Event Dispatch"); setSystem(true); } @Override protected IStatus run(IProgressMonitor monitor) { while (!isTerminated()) { OclDebugMessage message = m_communicationHelper.receive(m_eventReader); if (message != null) { notifyListeners(message); } else { terminated(); break; } } return Status.OK_STATUS; } private void notifyListeners(OclDebugMessage message) { // System.out.println("EventDispatch notifyListeners ( " + message + " )"); Object[] listeners = m_eventListener.toArray(); for (Object obj : listeners) { ((IOclDebugEventListener) obj).handleMessage(message); } } } public OclDebugTarget(ILaunch launch, OclDebugProcess process, int requestPort, int eventPort) throws CoreException { super(null); m_debugTarget = this; m_launch = launch; m_process = process; m_thread = new OclDebugThread(this); m_threads = new IThread[] { m_thread }; try { m_debugProxy = new OclDebugProxy(this, requestPort); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } m_eventListener = new ArrayList<IOclDebugEventListener>(); this.addEventListener(this); this.addEventListener(m_thread); this.addEventListener(m_process); try { m_eventSocket = new Socket("localhost", eventPort); m_eventReader = new BufferedReader(new InputStreamReader( m_eventSocket.getInputStream())); } catch (UnknownHostException e) { e.printStackTrace(); } catch (ConnectException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } m_eventDispatch = new EventDispatchJob(); m_eventDispatch.schedule(); this.getBreakpointManager().addBreakpointListener(this); } private void addEventListener(IOclDebugEventListener listener) { if (!m_eventListener.contains(listener)) { m_eventListener.add(listener); } } private void removeEventListener(IOclDebugEventListener listener) { m_eventListener.remove(listener); } private void started() { fireCreationEvent(); installDeferredBreakPoints(); try { resume(); } catch (DebugException e) { e.printStackTrace(); } } private void installDeferredBreakPoints() { IBreakpoint[] breakpoints = getBreakpointManager().getBreakpoints(OclDebugPlugin.DEBUG_MODEL_ID); for (IBreakpoint breakpoint : breakpoints) { breakpointAdded(breakpoint); } } private synchronized void terminated() { System.out.println("OclDebugTarget terminated()"); m_terminated = true; m_threads = new IThread[0]; fireTerminateEvent(); removeEventListener(this); removeEventListener(m_thread); removeEventListener(m_process); try { getBreakpointManager().removeBreakpointListener(this); } catch (NullPointerException e) { // do nothing } m_debugProxy.terminate(); } @Override public boolean canTerminate() { return m_process.canTerminate(); } @Override public boolean isTerminated() { return m_terminated || m_process.isTerminated(); } @Override public boolean canResume() { return m_thread.canResume(); } @Override public boolean canSuspend() { return m_thread.canSuspend(); } @Override public boolean isSuspended() { return m_thread.isSuspended(); } @Override public void resume() throws DebugException { System.out.println("OclDebugTarget resume()"); m_thread.resume(); } @Override public void suspend() throws DebugException { m_thread.suspend(); } @Override public void terminate() throws DebugException { m_thread.terminate(); } @Override public void breakpointAdded(IBreakpoint breakpoint) { if (supportsBreakpoint(breakpoint)) { try { if ((breakpoint.isEnabled() && getBreakpointManager().isEnabled()) || !breakpoint.isRegistered()) { OclLineBreakpoint lineBreakpoint = (OclLineBreakpoint) breakpoint; lineBreakpoint.install(this); } // no else } catch (CoreException e) { e.printStackTrace(); } } } @Override public void breakpointRemoved(IBreakpoint breakpoint, IMarkerDelta delta) { if (supportsBreakpoint(breakpoint)) { try { if ((breakpoint.isEnabled() && getBreakpointManager().isEnabled()) || !breakpoint.isRegistered()) { OclLineBreakpoint lineBreakpoint = (OclLineBreakpoint) breakpoint; lineBreakpoint.remove(this); } // no else } catch (DebugException e) { e.printStackTrace(); } catch (CoreException e) { e.printStackTrace(); } } } @Override public void breakpointChanged(IBreakpoint breakpoint, IMarkerDelta delta) { // empty } @Override public boolean canDisconnect() { return false; } @Override public void disconnect() throws DebugException { // empty } @Override public boolean isDisconnected() { return false; } @Override public boolean supportsStorageRetrieval() { return false; } @Override public IMemoryBlock getMemoryBlock(long startAddress, long length) throws DebugException { return null; } @Override public IProcess getProcess() { return m_process; } @Override public IThread[] getThreads() throws DebugException { return m_threads; } @Override public boolean hasThreads() throws DebugException { return true; } @Override public String getName() throws DebugException { return "OCL model"; } @Override public boolean supportsBreakpoint(IBreakpoint breakpoint) { return breakpoint.getModelIdentifier() .equals(OclDebugPlugin.DEBUG_MODEL_ID); } @Override public void handleMessage(OclDebugMessage message) { System.out.println("OclDebugTarget handleMessage( " + message + " )"); try { if (message.hasType(EOclDebugMessageType.STARTED)) { started(); } else if (message.hasType(EOclDebugMessageType.SUSPENDED)) { suspend(); } else if (message.hasType(EOclDebugMessageType.TERMINATED)) { terminated(); } else if (message.hasType(EOclDebugMessageType.RESUMED)) { // this event is handled by the debug thread } else if (message.hasType(EOclDebugMessageType.CONSTRAINT_INTERPRETED)) { // this event is handled in test code only } else { System.out.println("ERROR in " + this.getClass().getName() + ".handleMessage(): unknown event: " + message); } } catch (DebugException e) { e.printStackTrace(); } } public OclDebugProxy getDebugProxy() { return m_debugProxy; } public IThread getThread() { return m_thread; } public ILaunch getLaunch() { return m_launch; } @Override public boolean equals(Object that) { if (that == null) { return false; } if (that instanceof OclDebugTarget) { OclDebugTarget thatTarget = (OclDebugTarget) that; return m_process.equals(thatTarget.getProcess()) && m_launch.equals(thatTarget.getLaunch()) && m_thread.equals(thatTarget.getThread()); } return false; } @Override public IDebugTarget getDebugTarget() { return m_debugTarget; } }