1a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot/* 2a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * Copyright (c) 2011 Oracle and/or its affiliates. All rights reserved. 3a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * 4a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * Redistribution and use in source and binary forms, with or without 5a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * modification, are permitted provided that the following conditions 6a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * are met: 7a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * 8a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * - Redistributions of source code must retain the above copyright 9a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * notice, this list of conditions and the following disclaimer. 10a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * 11a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * - Redistributions in binary form must reproduce the above copyright 12a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * notice, this list of conditions and the following disclaimer in the 13a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * documentation and/or other materials provided with the distribution. 14a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * 15a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * - Neither the name of Oracle nor the names of its 16a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * contributors may be used to endorse or promote products derived 17a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * from this software without specific prior written permission. 18a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * 19a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 20a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 21a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 23a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot */ 31a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot 32a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot/* 33a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * This source code is provided to illustrate the usage of a given feature 34a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * or technique and has been deliberately simplified. Additional steps 35a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * required for a production-quality application, such as security checks, 36a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * input validation and proper error handling, might not be present in 37a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * this sample code. 38a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot */ 39a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot 40a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot 41a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robotimport java.io.IOException; 42a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robotimport java.nio.ByteBuffer; 43a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robotimport java.nio.channels.AsynchronousSocketChannel; 44a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robotimport java.nio.channels.CompletionHandler; 45a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robotimport java.util.LinkedList; 46a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robotimport java.util.Queue; 47a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robotimport java.util.concurrent.atomic.AtomicReference; 48a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot 49a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot/** 50a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * Client represents a remote connection to the chat server. 51a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * It contains methods for reading and writing messages from the 52a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * channel. 53a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * Messages are considered to be separated by newline, so incomplete 54a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * messages are buffered in the {@code Client}. 55a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * 56a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * All reads and writes are asynchronous and uses the nio2 asynchronous 57a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * elements. 58a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot */ 59a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robotclass Client { 60a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot private final AsynchronousSocketChannel channel; 61a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot private AtomicReference<ClientReader> reader; 62a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot private String userName; 63a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot private final StringBuilder messageBuffer = new StringBuilder(); 64a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot 65a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot private final Queue<ByteBuffer> queue = new LinkedList<ByteBuffer>(); 66a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot private boolean writing = false; 67a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot 68a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot public Client(AsynchronousSocketChannel channel, ClientReader reader) { 69a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot this.channel = channel; 70a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot this.reader = new AtomicReference<ClientReader>(reader); 71a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot } 72a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot 73a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot /** 74a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * Enqueues a write of the buffer to the channel. 75a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * The call is asynchronous so the buffer is not safe to modify after 76a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * passing the buffer here. 77a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * 78a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * @param buffer the buffer to send to the channel 79a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot */ 80a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot private void writeMessage(final ByteBuffer buffer) { 81a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot boolean threadShouldWrite = false; 82a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot 83a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot synchronized(queue) { 84a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot queue.add(buffer); 85a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot // Currently no thread writing, make this thread dispatch a write 86a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot if (!writing) { 87a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot writing = true; 88a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot threadShouldWrite = true; 89a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot } 90a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot } 91a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot 92a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot if (threadShouldWrite) { 93a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot writeFromQueue(); 94a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot } 95a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot } 96a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot 97a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot private void writeFromQueue() { 98a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot ByteBuffer buffer; 99a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot 100a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot synchronized (queue) { 101a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot buffer = queue.poll(); 102a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot if (buffer == null) { 103a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot writing = false; 104a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot } 105a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot } 106a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot 107a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot // No new data in buffer to write 108a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot if (writing) { 109a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot writeBuffer(buffer); 110a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot } 111a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot } 112a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot 113a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot private void writeBuffer(ByteBuffer buffer) { 114a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot channel.write(buffer, buffer, new CompletionHandler<Integer, ByteBuffer>() { 115a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot @Override 116a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot public void completed(Integer result, ByteBuffer buffer) { 117a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot if (buffer.hasRemaining()) { 118a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot channel.write(buffer, buffer, this); 119a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot } else { 120a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot // Go back and check if there is new data to write 121a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot writeFromQueue(); 122a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot } 123a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot } 124a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot 125a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot @Override 126a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot public void failed(Throwable exc, ByteBuffer attachment) { 127a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot } 128a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot }); 129a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot } 130a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot 131a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot /** 132a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * Sends a message 133a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * @param string the message 134a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot */ 135a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot public void writeStringMessage(String string) { 136a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot writeMessage(ByteBuffer.wrap(string.getBytes())); 137a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot } 138a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot 139a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot /** 140a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * Send a message from a specific client 141a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * @param client the message is sent from 142a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * @param message to send 143a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot */ 144a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot public void writeMessageFrom(Client client, String message) { 145a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot if (reader.get().acceptsMessages()) { 146a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot writeStringMessage(client.getUserName() + ": " + message); 147a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot } 148a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot } 149a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot 150a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot /** 151a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * Enqueue a read 152a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * @param completionHandler callback on completed read 153a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot */ 154a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot public void read(CompletionHandler<Integer, ? super ByteBuffer> completionHandler) { 155a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot ByteBuffer input = ByteBuffer.allocate(256); 156a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot if (!channel.isOpen()) { 157a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot return; 158a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot } 159a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot channel.read(input, input, completionHandler); 160a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot } 161a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot 162a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot /** 163a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * Closes the channel 164a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot */ 165a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot public void close() { 166a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot try { 167a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot channel.close(); 168a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot } catch (IOException e) { 169a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot e.printStackTrace(); 170a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot } 171a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot } 172a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot 173a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot /** 174a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * Run the current states actions. 175a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot */ 176a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot public void run() { 177a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot reader.get().run(this); 178a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot } 179a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot 180a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot public void setUserName(String userName) { 181a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot this.userName = userName; 182a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot } 183a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot 184a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot public void setReader(ClientReader reader) { 185a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot this.reader.set(reader); 186a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot } 187a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot 188a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot public String getUserName() { 189a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot return userName; 190a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot } 191a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot 192a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot public void appendMessage(String message) { 193a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot synchronized (messageBuffer) { 194a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot messageBuffer.append(message); 195a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot } 196a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot } 197a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot 198a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot /** 199a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * @return the next newline separated message in the buffer. null is returned if the buffer 200a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot * doesn't contain any newline. 201a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot */ 202a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot public String nextMessage() { 203a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot synchronized(messageBuffer) { 204a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot int nextNewline = messageBuffer.indexOf("\n"); 205a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot if (nextNewline == -1) { 206a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot return null; 207a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot } 208a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot String message = messageBuffer.substring(0, nextNewline + 1); 209a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot messageBuffer.delete(0, nextNewline + 1); 210a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot return message; 211a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot } 212a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot } 213a782115c262f0bc08ed2b8ffcd7d85c72c894adandroid-build-team Robot} 214