/******************************************************************************* * Copyright (c) 2005 - 2007 committers of openArchitectureWare 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: * committers of openArchitectureWare - initial API and implementation *******************************************************************************/ package org.eclipse.emf.mwe.internal.core.debug.communication; import java.io.IOException; import java.io.InterruptedIOException; import java.util.ArrayList; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.eclipse.emf.mwe.internal.core.debug.communication.packages.AbstractPackage; /** * This Runnable listens for incoming packages asynchroniously and keeps them, until they are required by * customers. */ public class PackageReceiver implements Runnable { private final ArrayList<AbstractPackage> receivedPackages; private static final Log logger = LogFactory.getLog(PackageReceiver.class); private final Connection connection; private boolean interrupt = false; private Exception exception; /** * create a new instance and starts the runnable in a new thread * * @param connection the <code>Connection</code> that controls this data receiver. * @return the instance */ public static PackageReceiver newPackageReceiver(final Connection connection) { PackageReceiver receiver = new PackageReceiver(connection); Thread thread = new Thread(receiver, "PackageReceiver"); thread.setDaemon(true); thread.start(); return receiver; } private PackageReceiver(final Connection connection) { this.connection = connection; receivedPackages = new ArrayList<AbstractPackage>(); } /** * Get a packet of the requested type, wait the specified time until it arrives, if time is negative, wait * until socket will be closed * * @param type the packet type * @param timeToWait until timeout * @return the received packet * @throws InterruptedIOException */ public AbstractPackage getPackage(final Class<? extends AbstractPackage> type, final long timeToWait) throws InterruptedIOException { return getPackage(type, 0, timeToWait); } /** * Get a packet of the requested type with a specific id, wait the specified time until it arrives, if time is * negative, wait until socket will be closed * * @param type the packet type * @param refId the id the receiving packet must have * @param timeToWait until timeout * @return the received packet * @throws InterruptedIOException * @throws InterruptedIOException */ public AbstractPackage getPackage(final Class<? extends AbstractPackage> type, final int refId, final long timeToWait) throws InterruptedIOException { AbstractPackage packet = null; //sync to be able to wait synchronized (receivedPackages) { long remainingTime = timeToWait; long timeBeforeWait; // Wait until type is available. while (((packet = popReceivedPackage(type, refId)) == null) && connection.isConnected() && !interrupt && ((timeToWait < 0) || (remainingTime > 0))) { timeBeforeWait = System.currentTimeMillis(); try { waitForPackageAvailable(remainingTime); } catch (InterruptedException e) { } if (timeToWait >= 0) { remainingTime -= System.currentTimeMillis() - timeBeforeWait; } } } checkForException(packet); return packet; } private void close() { interrupt = true; synchronized (receivedPackages) { receivedPackages.notifyAll(); } } private void waitForPackageAvailable(final long timeToWait) throws InterruptedException { if (timeToWait == 0) { return; } else if (timeToWait < 0) { receivedPackages.wait(); } else { receivedPackages.wait(timeToWait); } } /** * Returns the first packet of the specified type and removes from the packet list. */ private synchronized AbstractPackage popReceivedPackage(final Class<? extends AbstractPackage> type, final int refId) { for (AbstractPackage packet : receivedPackages) { if (!type.isInstance(packet) || ((refId != 0) && (packet.refId != refId))) { continue; } receivedPackages.remove(packet); return packet; } return null; } private void checkForException(final AbstractPackage packet) throws InterruptedIOException { if (packet != null) { return; } if ((exception != null) && !(exception instanceof IOException)) { // print stack trace if it is not an IOException logger.error(exception.getMessage(), exception); } if (interrupt) { throw new InterruptedIOException("packet receiver is going to close"); } if (exception != null) { throw new InterruptedIOException(exception.getMessage()); } throw new InterruptedIOException("timeout reading a packet"); } // ******************************************************** runnable methods /* (non-Javadoc) * @see java.lang.Runnable#run() */ public void run() { try { while (!interrupt && connection.isConnected()) { readAvailablePackage(); } } catch (Exception e) { exception = e; close(); } } private void readAvailablePackage() throws IOException { addPackageToList(connection.readPackage()); } private void addPackageToList(final AbstractPackage packet) { synchronized (receivedPackages) { receivedPackages.add(packet); receivedPackages.notifyAll(); } } }