public int enqueue(int messageNo, IMessage message, MessageFuture future) throws IOException { QueueEntry qe = new QueueEntry(); qe.messageNo = messageNo; qe.score = computeMessageScore(messageNo, message); qe.messageClass = message.getClass(); qe.messageStream = messenger.serializeMessage(message); qe.future = future; if (LogUtil.isLogAvailable()) { // precompute the expected queue size...this is because the writer thread may quickly pick // up the queue item which, while swell, means the debug output may be confusing int newExpectedQueueSize = queue.size() + 1; Log.i( TAG, "Message " + qe.messageNo + " enqueued, it's a " + qe.messageClass.getSimpleName() + ", " + qe.messageStream.available() + " bytes in length, " + newExpectedQueueSize + " entries in the queue"); } queue.add(qe); return qe.messageNo; }
/** * Write one message (or part of a message) to the connected output stream. * * <p>This may write a partial message, if the message is bigger than our output buffer. If this * is the case, the queue entry is readded to the priority queue and given another chance to write * more data. This is repeated until the message is completely sent. Note that this means other, * higher priority messages may jump the line while this message is in the middle of sending its * data. This is ok, and how we allow the system to send command messages when long transfer * messages are in progress. * * @throws IOException */ public void writeOne() throws IOException { // process canceled entires first processCanceled(); // then process the next entry to be sent QueueEntry qe = nextQueueEntry(); if (qe != null) { int read = qe.messageStream.read(outBytes); if (LogUtil.isLogAvailable()) { Log.d( TAG, "Message " + qe.messageNo + " written, it's a " + qe.messageClass.getSimpleName() + ", " + read + " bytes in length"); } outStream.write(outBytes, 0, read); int left = qe.messageStream.available(); // if there are bytes left to write, add this message back into the queue // to write at the next opportunity if (left > 0) { if (LogUtil.isLogAvailable()) { Log.d(TAG, "Message " + qe.messageNo + ", " + left + " bytes left to write"); } queue.add(qe); } else { qe.future.setFinished(true); // otherwise, we're done if (LogUtil.isLogAvailable()) { Log.i(TAG, "Message " + qe.messageNo + " finished writing"); } } } }
private void processCanceled() throws IOException { Set<Integer> canceled = new HashSet<Integer>(); synchronized (queueLock) { canceled.addAll(this.canceled); this.canceled.clear(); } for (int messageNo : canceled) { QueueEntry found = removeQueueEntry(messageNo); if (found != null) { if (LogUtil.isLogAvailable()) { Log.d(TAG, "Message " + messageNo + " canceled"); } PacketFormat cancelPacket = new PacketFormat(messageNo, new byte[0]); cancelPacket.addControlCode(ControlCode.Cancelled); ByteArrayOutputStream baos = new ByteArrayOutputStream(); cancelPacket.serialize(baos); found.messageStream = new ByteArrayInputStream(baos.toByteArray()); found.score = messageNo * CANCEL_TRANSFER_SCORE_MULTIPLIER; queue.add(found); } } }