Package org.eclipse.jdi.internal.connect

Source Code of org.eclipse.jdi.internal.connect.PacketReceiveManager

/*******************************************************************************
* Copyright (c) 2000, 2012 IBM Corporation 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:
*     IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdi.internal.connect;

import java.io.IOException;
import java.io.InterruptedIOException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.ListIterator;

import org.eclipse.jdi.TimeoutException;
import org.eclipse.jdi.internal.VirtualMachineImpl;
import org.eclipse.jdi.internal.jdwp.JdwpCommandPacket;
import org.eclipse.jdi.internal.jdwp.JdwpPacket;
import org.eclipse.jdi.internal.jdwp.JdwpReplyPacket;
import org.eclipse.osgi.util.NLS;

import com.sun.jdi.VMDisconnectedException;
import com.sun.jdi.connect.spi.Connection;

/**
* This class implements a thread that receives packets from the Virtual
* Machine.
*
*/
public class PacketReceiveManager extends PacketManager {

  /** Generic timeout value for not blocking. */
  public static final int TIMEOUT_NOT_BLOCKING = 0;

  /** Generic timeout value for infinite timeout. */
  public static final int TIMEOUT_INFINITE = -1;

  /** List of Command packets received from Virtual Machine. */
  private LinkedList<JdwpCommandPacket> fCommandPackets;

  /** List of Reply packets received from Virtual Machine. */
  private LinkedList<JdwpReplyPacket> fReplyPackets;

  /**
   * List of Packets that have timed out already. Maintained so that responses
   * can be discarded if/when they are received.
   */
  private ArrayList<Integer> fTimedOutPackets;

  private VirtualMachineImpl fVM;

  /**
   * Create a new thread that receives packets from the Virtual Machine.
   */
  public PacketReceiveManager(Connection connection, VirtualMachineImpl vmImpl) {
    super(connection);
    fVM = vmImpl;
    fCommandPackets = new LinkedList<JdwpCommandPacket>();
    fReplyPackets = new LinkedList<JdwpReplyPacket>();
    fTimedOutPackets = new ArrayList<Integer>();
  }

  @Override
  public void disconnectVM() {
    super.disconnectVM();
    synchronized (fCommandPackets) {
      fCommandPackets.notifyAll();
    }
    synchronized (fReplyPackets) {
      fReplyPackets.notifyAll();
    }
  }

  /**
   * Thread's run method.
   */
  public void run() {
    try {
      while (!VMIsDisconnected()) {
        // Read a packet from the input stream.
        readAvailablePacket();
      }
    }
    // if the remote VM is interrupted, drop the connection and clean up,
    // don't wait for it to happen on its own
    catch (InterruptedIOException e) {
      disconnectVM(e);
    } catch (IOException e) {
      disconnectVM(e);
    }
  }

  /**
   * @return Returns a specified Command Packet from the Virtual Machine.
   */
  public JdwpCommandPacket getCommand(int command, long timeToWait)
      throws InterruptedException {
    JdwpCommandPacket packet = null;
    synchronized (fCommandPackets) {
      long remainingTime = timeToWait;
      long timeBeforeWait;
      long waitedTime;

      // Wait until command is available.
      while (!VMIsDisconnected()
          && (packet = removeCommandPacket(command)) == null
          && (timeToWait < 0 || remainingTime > 0)) {
        timeBeforeWait = System.currentTimeMillis();
        waitForPacketAvailable(remainingTime, fCommandPackets);
        waitedTime = System.currentTimeMillis() - timeBeforeWait;
        remainingTime -= waitedTime;
      }
    }
    // Check for an IO Exception.
    if (VMIsDisconnected()) {
      String message;
      if (getDisconnectException() == null) {
        message = ConnectMessages.PacketReceiveManager_Got_IOException_from_Virtual_Machine_1;
      } else {
        String exMessage = getDisconnectException().getMessage();
        if (exMessage == null) {
          message = NLS.bind(ConnectMessages.PacketReceiveManager_Got__0__from_Virtual_Machine_1,
                  new String[] { getDisconnectException()
                      .getClass().getName() });
        } else {
          message = NLS.bind(ConnectMessages.PacketReceiveManager_Got__0__from_Virtual_Machine___1__1,
                  new String[] {
                      getDisconnectException().getClass()
                          .getName(), exMessage });
        }
      }
      throw new VMDisconnectedException(message);
    }
    // Check for a timeout.
    if (packet == null) {
      throw new TimeoutException();
    }
    return packet;
  }

  /**
   * @return Returns a specified Reply Packet from the Virtual Machine.
   */
  public JdwpReplyPacket getReply(int id, long timeToWait) {
    JdwpReplyPacket packet = null;
    long remainingTime = timeToWait;
    synchronized (fReplyPackets) {
      final long timeBeforeWait = System.currentTimeMillis();
      // Wait until reply is available.
      while (!VMIsDisconnected() && remainingTime > 0) {
        packet = removeReplyPacket(id);
        if (packet != null) {
          break;
        }
        try {
          waitForPacketAvailable(remainingTime, fReplyPackets);
        }
        // if the remote VM is interrupted DO NOT drop the connection -
        // see bug 171075
        // just stop waiting for the reply and treat it as a timeout
        catch (InterruptedException e) {
          break;
        }
        long waitedTime = System.currentTimeMillis() - timeBeforeWait;
        remainingTime = timeToWait - waitedTime;
      }
    }
    if (packet == null) {
      synchronized (fReplyPackets) {
        packet = removeReplyPacket(id);
      }
    }
    // Check for an IO Exception.
    if (VMIsDisconnected())
      throw new VMDisconnectedException(
          ConnectMessages.PacketReceiveManager_Got_IOException_from_Virtual_Machine_2);
    // Check for a timeout.
    if (packet == null) {
      synchronized (fTimedOutPackets) {
        fTimedOutPackets.add(new Integer(id));
      }
      throw new TimeoutException(NLS.bind(
          ConnectMessages.PacketReceiveManager_0, new String[] { id
              + "" })); //$NON-NLS-1$
    }
    return packet;
  }

  /**
   * @return Returns a specified Reply Packet from the Virtual Machine.
   */
  public JdwpReplyPacket getReply(JdwpCommandPacket commandPacket) {
    return getReply(commandPacket.getId(), fVM.getRequestTimeout());
  }

  /**
   * Wait for an available packet from the Virtual Machine.
   */
  private void waitForPacketAvailable(long timeToWait, Object lock)
      throws InterruptedException {
    if (timeToWait == 0)
      return;
    else if (timeToWait < 0)
      lock.wait();
    else
      lock.wait(timeToWait);
  }

  /**
   * @return Returns and removes a specified command packet from the command
   *         packet list.
   */
  private JdwpCommandPacket removeCommandPacket(int command) {
    ListIterator<JdwpCommandPacket> iter = fCommandPackets.listIterator();
    while (iter.hasNext()) {
      JdwpCommandPacket packet = iter.next();
      if (packet.getCommand() == command) {
        iter.remove();
        return packet;
      }
    }
    return null;
  }

  /**
   * @return Returns a specified reply packet from the reply packet list.
   */
  private JdwpReplyPacket removeReplyPacket(int id) {
    ListIterator<JdwpReplyPacket> iter = fReplyPackets.listIterator();
    while (iter.hasNext()) {
      JdwpReplyPacket packet = iter.next();
      if (packet.getId() == id) {
        iter.remove();
        return packet;
      }
    }
    return null;
  }

  /**
   * Add a command packet to the command packet list.
   */
  private void addCommandPacket(JdwpCommandPacket packet) {
    if (isTimedOut(packet)) {
      return; // already timed out. No need to keep this one
    }
    synchronized (fCommandPackets) {
      fCommandPackets.add(packet);
      fCommandPackets.notifyAll();
    }
  }

  /**
   * Returns whether the request for the given packet has already timed out.
   *
   * @param packet
   *            response packet
   * @return whether the request for the given packet has already timed out
   */
  private boolean isTimedOut(JdwpPacket packet) {
    synchronized (fTimedOutPackets) {
      if (fTimedOutPackets.isEmpty()) {
        return false;
      }
      Integer id = new Integer(packet.getId());
      return fTimedOutPackets.remove(id);
    }
  }

  /**
   * Add a reply packet to the reply packet list.
   */
  private void addReplyPacket(JdwpReplyPacket packet) {
    if (isTimedOut(packet)) {
      return; // already timed out. No need to keep this one
    }
    synchronized (fReplyPackets) {
      fReplyPackets.add(packet);
      fReplyPackets.notifyAll();
    }
  }

  /**
   * Read a packet from the input stream and add it to the appropriate packet
   * list.
   */
  private void readAvailablePacket() throws IOException {
    // Read a packet from the Input Stream.
    byte[] bytes = getConnection().readPacket();
    JdwpPacket packet = JdwpPacket.build(bytes);
    // Add packet to command or reply queue.
    if (packet instanceof JdwpCommandPacket)
      addCommandPacket((JdwpCommandPacket) packet);
    else
      addReplyPacket((JdwpReplyPacket) packet);
  }
}
TOP

Related Classes of org.eclipse.jdi.internal.connect.PacketReceiveManager

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.