/* * #%~ * 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.dbgp.internal; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.IOException; import java.net.Socket; import org.eclipse.core.runtime.ListenerList; import org.overture.ide.debug.core.ExtendedDebugEventDetails; import org.overture.ide.debug.core.VdmDebugPlugin; import org.overture.ide.debug.core.dbgp.DbgpRequest; import org.overture.ide.debug.core.dbgp.IDbgpRawListener; import org.overture.ide.debug.core.dbgp.IDbgpRawPacket; import org.overture.ide.debug.core.dbgp.internal.packets.DbgpNotifyPacket; import org.overture.ide.debug.core.dbgp.internal.packets.DbgpPacketReceiver; import org.overture.ide.debug.core.dbgp.internal.packets.DbgpPacketSender; import org.overture.ide.debug.core.dbgp.internal.packets.DbgpResponsePacket; import org.overture.ide.debug.core.dbgp.internal.packets.DbgpStreamPacket; import org.overture.ide.debug.core.dbgp.internal.packets.IDbgpRawLogger; import org.overture.ide.debug.core.model.DebugEventHelper; public class DbgpDebugingEngine extends DbgpTermination implements IDbgpDebugingEngine, IDbgpTerminationListener { private final Socket socket; private final DbgpPacketReceiver receiver; private final DbgpPacketSender sender; private final Object terminatedLock = new Object(); private boolean terminated = false; private final int id; private static int lastId = 0; private static final Object idLock = new Object(); // FIXME [OutOfMemory] private static boolean outOfMemory = false; public DbgpDebugingEngine(Socket socket) throws IOException { this.socket = socket; synchronized (idLock) { id = ++lastId; } receiver = new DbgpPacketReceiver(new BufferedInputStream(socket.getInputStream())); receiver.setLogger(new IDbgpRawLogger() { public void log(IDbgpRawPacket output) { firePacketReceived(output); } }); receiver.addTerminationListener(this); // FIXME [OutOfMemory] The start is skipped if a out of memory exception have occurred. The memory here is the // native memory used for threads. See http://blogs.msdn.com/b/oldnewthing/archive/2005/07/29/444912.aspx try { if (!outOfMemory) { receiver.start(); } } catch (OutOfMemoryError e) { outOfMemory = true; throw e; } sender = new DbgpPacketSender(new BufferedOutputStream(socket.getOutputStream())); sender.setLogger(new IDbgpRawLogger() { public void log(IDbgpRawPacket output) { firePacketSent(output); } }); /* * FIXME this event is delivered on the separate thread, so sometimes logging misses a few initial packets. */ DebugEventHelper.fireExtendedEvent(this, ExtendedDebugEventDetails.DGBP_NEW_CONNECTION); } public DbgpStreamPacket getStreamPacket() throws IOException, InterruptedException { return receiver.getStreamPacket(); } public DbgpNotifyPacket getNotifyPacket() throws IOException, InterruptedException { return receiver.getNotifyPacket(); } public DbgpResponsePacket getResponsePacket(int transactionId, int timeout) throws IOException, InterruptedException { return receiver.getResponsePacket(transactionId, timeout); } public void sendCommand(DbgpRequest command) throws IOException { sender.sendCommand(command); } // IDbgpTerminataion public void requestTermination() { // always just close the socket try { socket.close(); } catch (IOException e) { if (VdmDebugPlugin.DEBUG) { e.printStackTrace(); } } } public void waitTerminated() throws InterruptedException { synchronized (terminatedLock) { if (terminated) { return; } receiver.waitTerminated(); } } public void objectTerminated(Object object, Exception e) { synchronized (terminatedLock) { if (terminated) { return; } receiver.removeTerminationListener(this); try { receiver.waitTerminated(); } catch (InterruptedException e1) { // OK, interrupted } terminated = true; } fireObjectTerminated(e); } private final ListenerList listeners = new ListenerList(); protected void firePacketReceived(IDbgpRawPacket content) { Object[] list = listeners.getListeners(); for (int i = 0; i < list.length; ++i) { ((IDbgpRawListener) list[i]).dbgpPacketReceived(id, content); } } protected void firePacketSent(IDbgpRawPacket content) { Object[] list = listeners.getListeners(); for (int i = 0; i < list.length; ++i) { ((IDbgpRawListener) list[i]).dbgpPacketSent(id, content); } } public void addRawListener(IDbgpRawListener listener) { listeners.add(listener); } public void removeRawListenr(IDbgpRawListener listener) { listeners.remove(listener); } }