/**
* Copyright (C) 2014-2016 LinkedIn Corp. (pinot-core@linkedin.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.linkedin.pinot.transport.common;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.util.concurrent.ImmediateExecutor;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.Assert;
import org.testng.annotations.Test;
import com.linkedin.pinot.Checkable;
import com.linkedin.pinot.TestUtils;
import com.linkedin.pinot.common.response.ServerInstance;
public class ResponseFutureTest {
protected static Logger LOGGER = LoggerFactory.getLogger(ResponseFutureTest.class);
/*
* Future Handle provided to the request sender to asynchronously wait for response.
* We use guava API for implementing Futures.
*/
public static class ResponseFuture extends AsyncResponseFuture<ByteBuf> {
public ResponseFuture(ServerInstance key) {
super(key, "");
}
}
@Test
public void testResponseFutureOtherCases() throws Exception {
ServerInstance s = new ServerInstance("localhost", 8080);
// A Future is cancelled but gets a message after that. get() called before cancellation
{
ResponseFuture f = new ResponseFuture(s);
ResponseFutureClientRunner runner = new ResponseFutureClientRunner(f);
ThreadPoolExecutor executor =
new ThreadPoolExecutor(1, 1, 1, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
executor.execute(runner);
runner.waitForAboutToGet(); // No guarantees as this only ensures the thread is started but not blocking in get().
Thread.sleep(100);
f.cancel(false);
String message = "dummy Message";
setResponse(f, message);
runner.waitForDone();
Assert.assertTrue(runner.isCancelled(), "Cancelled ?");
Assert.assertTrue(runner.isDone(), "Is Done ? ");
Assert.assertNull(runner.getMessage(), "No Reponse :");
Assert.assertNull(runner.getError(), "No Error :");
executor.shutdown();
}
// A Future is cancelled but gets a message after that. get() called after cancellation
{
ResponseFuture f = new ResponseFuture(s);
ResponseFutureClientRunner runner = new ResponseFutureClientRunner(f);
f.cancel(false);
String message = "dummy Message";
setResponse(f, message);
ThreadPoolExecutor executor =
new ThreadPoolExecutor(1, 1, 1, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
executor.execute(runner);
runner.waitForAboutToGet(); // No guarantees as this only ensures the thread is started but not blocking in get().
Thread.sleep(100);
runner.waitForDone();
Assert.assertTrue(runner.isCancelled(), "Cancelled ?");
Assert.assertTrue(runner.isDone(), "Is Done ? ");
Assert.assertNull(runner.getMessage(), "No Reponse :");
Assert.assertNull(runner.getError(), "No Error :");
executor.shutdown();
}
// A Future is cancelled but gets an exception after that. get() called before cancellation
{
ResponseFuture f = new ResponseFuture(s);
ResponseFutureClientRunner runner = new ResponseFutureClientRunner(f);
ThreadPoolExecutor executor =
new ThreadPoolExecutor(1, 1, 1, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
executor.execute(runner);
runner.waitForAboutToGet(); // No guarantees as this only ensures the thread is started but not blocking in get().
Thread.sleep(100);
f.cancel(false);
f.onError(new Exception("dummy"));
runner.waitForDone();
Assert.assertTrue(runner.isCancelled(), "Cancelled ?");
Assert.assertTrue(runner.isDone(), "Is Done ? ");
Assert.assertNull(runner.getMessage(), "No Reponse :");
Assert.assertNull(runner.getError(), "No Error :");
executor.shutdown();
}
// A Future is cancelled but gets an exception after that. get() called after cancellation
{
ResponseFuture f = new ResponseFuture(s);
ResponseFutureClientRunner runner = new ResponseFutureClientRunner(f);
f.cancel(false);
f.onError(new Exception("dummy"));
ThreadPoolExecutor executor =
new ThreadPoolExecutor(1, 1, 1, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
executor.execute(runner);
runner.waitForAboutToGet(); // No guarantees as this only ensures the thread is started but not blocking in get().
Thread.sleep(100);
runner.waitForDone();
Assert.assertTrue(runner.isCancelled(), "Cancelled ?");
Assert.assertTrue(runner.isDone(), "Is Done ? ");
Assert.assertNull(runner.getMessage(), "No Reponse :");
Assert.assertNull(runner.getError(), "No Error :");
executor.shutdown();
}
// Throw Exception. Then we try to cancel. Future Client calls get() before exception
{
ResponseFuture f = new ResponseFuture(s);
ResponseFutureClientRunner runner = new ResponseFutureClientRunner(f);
ThreadPoolExecutor executor =
new ThreadPoolExecutor(1, 1, 1, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
executor.execute(runner);
runner.waitForAboutToGet(); // No guarantees as this only ensures the thread is started but not blocking in get().
Thread.sleep(100);
Exception expectedError = new Exception("error processing");
f.onError(expectedError);
f.cancel(false);
runner.waitForDone();
// Now we know listener executed
Assert.assertFalse(runner.isCancelled(), "Cancelled ?");
Assert.assertTrue(runner.isDone(), "Is Done ? ");
Assert.assertNull(runner.getMessage(), "No Reponse :");
Assert.assertEquals(runner.getError(), expectedError, "Error");
executor.shutdown();
}
// Throw Exception. Then we try to cancel. Future Client calls get() after exception
{
ResponseFuture f = new ResponseFuture(s);
ResponseFutureClientRunner runner = new ResponseFutureClientRunner(f);
Exception expectedError = new Exception("error processing");
f.onError(expectedError);
f.cancel(false);
ThreadPoolExecutor executor =
new ThreadPoolExecutor(1, 1, 1, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
executor.execute(runner);
runner.waitForAboutToGet(); // No guarantees as this only ensures the thread is started but not blocking in get().
Thread.sleep(100);
runner.waitForDone();
// Now we know listener executed
Assert.assertFalse(runner.isCancelled(), "Cancelled ?");
Assert.assertTrue(runner.isDone(), "Is Done ? ");
Assert.assertNull(runner.getMessage(), "No Reponse :");
Assert.assertEquals(runner.getError(), expectedError, "Error");
executor.shutdown();
}
// Set Response. Then we try to cancel. Future Client calls get() before response
{
ResponseFuture f = new ResponseFuture(s);
ResponseFutureClientRunner runner = new ResponseFutureClientRunner(f);
ThreadPoolExecutor executor =
new ThreadPoolExecutor(1, 1, 1, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
executor.execute(runner);
runner.waitForAboutToGet(); // No guarantees as this only ensures the thread is started but not blocking in get().
Thread.sleep(100);
String message = "dummy Message";
setResponse(f, message);
f.cancel(false);
runner.waitForDone();
// Now we know runner executed
Assert.assertFalse(runner.isCancelled(), "Cancelled ?");
Assert.assertTrue(runner.isDone(), "Is Done ? ");
Assert.assertEquals(runner.getMessage(), message, "Response Check:");
Assert.assertNull(runner.getError(), "No Error :");
executor.shutdown();
}
// Set Response. Then we try to cancel. Future Client calls get() after response
{
ResponseFuture f = new ResponseFuture(s);
ResponseFutureClientRunner runner = new ResponseFutureClientRunner(f);
String message = "dummy Message";
setResponse(f, message);
f.cancel(false);
ThreadPoolExecutor executor =
new ThreadPoolExecutor(1, 1, 1, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
executor.execute(runner);
runner.waitForAboutToGet(); // No guarantees as this only ensures the thread is started but not blocking in get().
Thread.sleep(100);
runner.waitForDone();
// Now we know runner executed
Assert.assertFalse(runner.isCancelled(), "Cancelled ?");
Assert.assertTrue(runner.isDone(), "Is Done ? ");
Assert.assertEquals(runner.getMessage(), message, "Response Check:");
Assert.assertNull(runner.getError(), "No Error :");
executor.shutdown();
}
// Set Response. Then an exception happens. Future Client calls get() before response
{
ResponseFuture f = new ResponseFuture(s);
ResponseFutureClientRunner runner = new ResponseFutureClientRunner(f);
ThreadPoolExecutor executor =
new ThreadPoolExecutor(1, 1, 1, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
executor.execute(runner);
runner.waitForAboutToGet(); // No guarantees as this only ensures the thread is started but not blocking in get().
Thread.sleep(100);
String message = "dummy Message";
setResponse(f, message);
f.onError(new Exception("dummy"));
runner.waitForDone();
// Now we know runner executed
Assert.assertFalse(runner.isCancelled(), "Cancelled ?");
Assert.assertTrue(runner.isDone(), "Is Done ? ");
Assert.assertEquals(runner.getMessage(), message, "Response Check:");
Assert.assertNull(runner.getError(), "No Error :");
executor.shutdown();
}
// Set Response. then an exception gets processed. Future Client calls get() after response
{
ResponseFuture f = new ResponseFuture(s);
ResponseFutureClientRunner runner = new ResponseFutureClientRunner(f);
String message = "dummy Message";
setResponse(f, message);
f.onError(new Exception("dummy"));
ThreadPoolExecutor executor =
new ThreadPoolExecutor(1, 1, 1, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
executor.execute(runner);
runner.waitForAboutToGet(); // No guarantees as this only ensures the thread is started but not blocking in get().
Thread.sleep(100);
runner.waitForDone();
// Now we know runner executed
Assert.assertFalse(runner.isCancelled(), "Cancelled ?");
Assert.assertTrue(runner.isDone(), "Is Done ? ");
Assert.assertEquals(runner.getMessage(), message, "Response Check:");
Assert.assertNull(runner.getError(), "No Error :");
executor.shutdown();
}
// Throw Exception. Then a valid response arrives. Future Client calls get() before exception
{
ResponseFuture f = new ResponseFuture(s);
ResponseFutureClientRunner runner = new ResponseFutureClientRunner(f);
ThreadPoolExecutor executor =
new ThreadPoolExecutor(1, 1, 1, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
executor.execute(runner);
runner.waitForAboutToGet(); // No guarantees as this only ensures the thread is started but not blocking in get().
Thread.sleep(100);
Exception expectedError = new Exception("error processing");
f.onError(expectedError);
String message = "dummy Message";
setResponse(f, message);
runner.waitForDone();
// Now we know listener executed
Assert.assertFalse(runner.isCancelled(), "Cancelled ?");
Assert.assertTrue(runner.isDone(), "Is Done ? ");
Assert.assertNull(runner.getMessage(), "No Reponse :");
Assert.assertEquals(runner.getError(), expectedError, "Error");
executor.shutdown();
}
// Throw Exception. Then a valid response arrives. Future Client calls get() after exception
{
ResponseFuture f = new ResponseFuture(s);
ResponseFutureClientRunner runner = new ResponseFutureClientRunner(f);
Exception expectedError = new Exception("error processing");
f.onError(expectedError);
String message = "dummy Message";
setResponse(f, message);
ThreadPoolExecutor executor =
new ThreadPoolExecutor(1, 1, 1, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
executor.execute(runner);
runner.waitForAboutToGet(); // No guarantees as this only ensures the thread is started but not blocking in get().
Thread.sleep(100);
runner.waitForDone();
// Now we know listener executed
Assert.assertFalse(runner.isCancelled(), "Cancelled ?");
Assert.assertTrue(runner.isDone(), "Is Done ? ");
Assert.assertNull(runner.getMessage(), "No Reponse :");
Assert.assertEquals(runner.getError(), expectedError, "Error");
executor.shutdown();
}
}
@Test
public void testResponseFuture() throws Exception {
ServerInstance s = new ServerInstance("localhost", 8080);
//Cancelled Future. Future Client calls get() before cancel()
{
ResponseFuture f = new ResponseFuture(s);
ResponseFutureClientRunner runner = new ResponseFutureClientRunner(f);
ThreadPoolExecutor executor =
new ThreadPoolExecutor(1, 1, 1, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
executor.execute(runner);
runner.waitForAboutToGet(); // No guarantees as this only ensures the thread is started but not blocking in get().
Thread.sleep(100);
f.cancel(false);
runner.waitForDone();
Assert.assertTrue(runner.isCancelled(), "Cancelled ?");
Assert.assertTrue(runner.isDone(), "Is Done ? ");
Assert.assertNull(runner.getMessage(), "No Reponse :");
Assert.assertNull(runner.getError(), "No Error :");
executor.shutdown();
}
//Cancelled Future. Future Client calls get() after cancel()
{
ResponseFuture f = new ResponseFuture(s);
ResponseFutureClientRunner runner = new ResponseFutureClientRunner(f);
f.cancel(false);
ThreadPoolExecutor executor =
new ThreadPoolExecutor(1, 1, 1, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
executor.execute(runner);
runner.waitForDone();
Assert.assertTrue(runner.isCancelled(), "Cancelled ?");
Assert.assertTrue(runner.isDone(), "Is Done ? ");
Assert.assertNull(runner.getMessage(), "No Reponse :");
Assert.assertNull(runner.getError(), "No Error :");
executor.shutdown();
}
// Throw Exception. Future Client calls get() before exception
{
ResponseFuture f = new ResponseFuture(s);
ResponseFutureClientRunner runner = new ResponseFutureClientRunner(f);
ThreadPoolExecutor executor =
new ThreadPoolExecutor(1, 1, 1, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
executor.execute(runner);
runner.waitForAboutToGet(); // No guarantees as this only ensures the thread is started but not blocking in get().
Thread.sleep(100);
Exception expectedError = new Exception("error processing");
f.onError(expectedError);
runner.waitForDone();
// Now we know listener executed
Assert.assertFalse(runner.isCancelled(), "Cancelled ?");
Assert.assertTrue(runner.isDone(), "Is Done ? ");
Assert.assertNull(runner.getMessage(), "No Reponse :");
Assert.assertEquals(runner.getError(), expectedError, "Error");
executor.shutdown();
}
// Throw Exception. Future Client calls get() after exception
{
ResponseFuture f = new ResponseFuture(s);
ResponseFutureClientRunner runner = new ResponseFutureClientRunner(f);
Exception expectedError = new Exception("error processing");
f.onError(expectedError);
ThreadPoolExecutor executor =
new ThreadPoolExecutor(1, 1, 1, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
executor.execute(runner);
runner.waitForDone();
// Now we know listener executed
Assert.assertFalse(runner.isCancelled(), "Cancelled ?");
Assert.assertTrue(runner.isDone(), "Is Done ? ");
Assert.assertNull(runner.getMessage(), "No Reponse :");
Assert.assertEquals(runner.getError(), expectedError, "Error");
executor.shutdown();
}
// Set Response. Future Client calls get() before response
{
ResponseFuture f = new ResponseFuture(s);
ResponseFutureClientRunner runner = new ResponseFutureClientRunner(f);
ThreadPoolExecutor executor =
new ThreadPoolExecutor(1, 1, 1, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
executor.execute(runner);
runner.waitForAboutToGet(); // No guarantees as this only ensures the thread is started but not blocking in get().
Thread.sleep(100);
String message = "dummy Message";
setResponse(f, message);
runner.waitForDone();
// Now we know runner executed
Assert.assertFalse(runner.isCancelled(), "Cancelled ?");
Assert.assertTrue(runner.isDone(), "Is Done ? ");
Assert.assertEquals(runner.getMessage(), message, "Response Check:");
Assert.assertNull(runner.getError(), "No Error :");
executor.shutdown();
}
// Set Response. Future Client calls get() after response
{
ResponseFuture f = new ResponseFuture(s);
ResponseFutureClientRunner runner = new ResponseFutureClientRunner(f);
String message = "dummy Message";
setResponse(f, message);
ThreadPoolExecutor executor =
new ThreadPoolExecutor(1, 1, 1, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
executor.execute(runner);
runner.waitForDone();
// Now we know runner executed
Assert.assertFalse(runner.isCancelled(), "Cancelled ?");
Assert.assertTrue(runner.isDone(), "Is Done ? ");
Assert.assertEquals(runner.getMessage(), message, "Response Check:");
Assert.assertNull(runner.getError(), "No Error :");
executor.shutdown();
}
}
@Test
public void testResponseFutureListener() throws Exception {
ServerInstance s = new ServerInstance("localhost", 8080);
// Cancelled future. Listener added before cancelling
{
ResponseFuture f = new ResponseFuture(s);
FutureListener listener = new FutureListener(f);
WaitForCompletion w = new WaitForCompletion(listener);
f.cancel(false);
TestUtils.assertWithBackoff(w, 10, 1000, 2, 1, 2);
// Now we know listener executed
Assert.assertTrue(listener.isCancelled(), "Cancelled ?");
Assert.assertEquals(listener.getNumRuns(), 1, "Num Runs of listener");
Assert.assertTrue(listener.isDone(), "Is Done ? ");
Assert.assertNull(listener.getMessage(), "No Reponse :");
Assert.assertNull(listener.getError(), "No Error :");
listener.close();
}
// Cancelled future. Listener added after cancelling
{
ResponseFuture f = new ResponseFuture(s);
FutureListener listener = new FutureListener(f);
WaitForCompletion w = new WaitForCompletion(listener);
f.cancel(false);
TestUtils.assertWithBackoff(w, 10, 1000, 2, 1, 2);
// Now we know listener executed
Assert.assertTrue(listener.isCancelled(), "Cancelled ?");
Assert.assertEquals(listener.getNumRuns(), 1, "Num Runs of listener");
Assert.assertTrue(listener.isDone(), "Is Done ? ");
Assert.assertNull(listener.getMessage(), "No Reponse :");
Assert.assertNull(listener.getError(), "No Error :");
listener.close();
}
// Throw Exception. Listener added before exception
{
ResponseFuture f = new ResponseFuture(s);
FutureListener listener = new FutureListener(f);
WaitForCompletion w = new WaitForCompletion(listener);
Exception expectedError = new Exception("error processing");
f.onError(expectedError);
TestUtils.assertWithBackoff(w, 10, 1000, 2, 1, 2);
// Now we know listener executed
Assert.assertFalse(listener.isCancelled(), "Cancelled ?");
Assert.assertEquals(listener.getNumRuns(), 1, "Num Runs of listener");
Assert.assertTrue(listener.isDone(), "Is Done ? ");
Assert.assertNull(listener.getMessage(), "No Reponse :");
Assert.assertEquals(listener.getError(), expectedError, "Error");
}
// Throw Exception. Listener added after exception
{
ResponseFuture f = new ResponseFuture(s);
FutureListener listener = new FutureListener(f);
Exception expectedError = new Exception("error processing");
f.onError(expectedError);
WaitForCompletion w = new WaitForCompletion(listener);
TestUtils.assertWithBackoff(w, 10, 1000, 2, 1, 2);
// Now we know listener executed
Assert.assertFalse(listener.isCancelled(), "Cancelled ?");
Assert.assertEquals(listener.getNumRuns(), 1, "Num Runs of listener");
Assert.assertTrue(listener.isDone(), "Is Done ? ");
Assert.assertNull(listener.getMessage(), "No Reponse :");
Assert.assertEquals(listener.getError(), expectedError, "Error");
}
// Set Response. Listener added before response
{
ResponseFuture f = new ResponseFuture(s);
FutureListener listener = new FutureListener(f);
WaitForCompletion w = new WaitForCompletion(listener);
String message = "dummy Message";
setResponse(f, message);
TestUtils.assertWithBackoff(w, 10, 1000, 2, 1, 2);
// Now we know listener executed
Assert.assertFalse(listener.isCancelled(), "Cancelled ?");
Assert.assertEquals(listener.getNumRuns(), 1, "Num Runs of listener");
Assert.assertTrue(listener.isDone(), "Is Done ? ");
Assert.assertEquals(listener.getMessage(), message, "Response Check:");
Assert.assertNull(listener.getError(), "No Error :");
listener.close();
}
// Set Response. Listener added after response
{
ResponseFuture f = new ResponseFuture(s);
FutureListener listener = new FutureListener(f);
String message = "dummy Message";
setResponse(f, message);
WaitForCompletion w = new WaitForCompletion(listener);
TestUtils.assertWithBackoff(w, 10, 1000, 2, 1, 2);
// Now we know listener executed
Assert.assertFalse(listener.isCancelled(), "Cancelled ?");
Assert.assertEquals(listener.getNumRuns(), 1, "Num Runs of listener");
Assert.assertTrue(listener.isDone(), "Is Done ? ");
Assert.assertEquals(listener.getMessage(), message, "Response Check:");
Assert.assertNull(listener.getError(), "No Error :");
listener.close();
}
}
private static void setResponse(ResponseFuture f, String message) {
ByteBuf b = Unpooled.wrappedBuffer(message.getBytes());
f.onSuccess(b);
}
private static class WaitForCompletion implements Checkable {
private final FutureListener _listener;
public WaitForCompletion(FutureListener f) {
_listener = f;
}
@Override
public boolean runCheck() throws AssertionError {
boolean isCalled = false;
synchronized (_listener) {
isCalled = _listener.isCalled();
}
return isCalled;
}
}
private static class ResponseFutureClientRunner implements Runnable {
private boolean _isDone;
private boolean _isCancelled;
private String _message;
private Throwable _error;
private final ResponseFuture _future;
private final CountDownLatch _latch = new CountDownLatch(1);
private final CountDownLatch _endLatch = new CountDownLatch(1);
public ResponseFutureClientRunner(ResponseFuture f) {
_future = f;
}
public void waitForAboutToGet() throws InterruptedException {
_latch.await();
}
public void waitForDone() throws InterruptedException {
_endLatch.await();
}
@Override
public synchronized void run() {
LOGGER.info("Running Future runner !!");
ByteBuf message = null;
try {
_latch.countDown();
message = _future.getOne();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
_isDone = _future.isDone();
_isCancelled = _future.isCancelled();
if (null != message) {
byte[] m = new byte[message.readableBytes()];
message.readBytes(m);
_message = new String(m);
}
Map<ServerInstance, Throwable> errorMap = _future.getError();
if ((null != errorMap) && (!errorMap.isEmpty())) {
_error = errorMap.values().iterator().next();
}
_endLatch.countDown();
LOGGER.info("End Running Listener !!");
}
public boolean isDone() {
return _isDone;
}
public boolean isCancelled() {
return _isCancelled;
}
public String getMessage() {
return _message;
}
public Throwable getError() {
return _error;
}
public ResponseFuture getFuture() {
return _future;
}
}
private static class FutureListener implements Runnable {
private int _numRuns = 0;
private boolean _isCalled;
private boolean _isDone;
private boolean _isCancelled;
private String _message;
private Throwable _error;
private final ResponseFuture _future;
private Executor _executor = null;
public FutureListener(ResponseFuture f) {
_future = f;
LinkedBlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>();
queue.add(this);
//_executor = new ThreadPoolExecutor(1, 1, 1, TimeUnit.HOURS, queue);
_executor = ImmediateExecutor.INSTANCE;
f.addListener(this, _executor);
}
@Override
public synchronized void run() {
_isCalled = true;
_numRuns++;
LOGGER.info("Running Listener !!");
//try{ throw new Exception("dummy"); } catch(Exception e) {e.printStackTrace();}
_isDone = _future.isDone();
_isCancelled = _future.isCancelled();
ByteBuf message = null;
try {
message = _future.getOne();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (null != message) {
byte[] m = new byte[message.readableBytes()];
message.readBytes(m);
_message = new String(m);
}
Map<ServerInstance, Throwable> errorMap = _future.getError();
if ((null != errorMap) && (!errorMap.isEmpty())) {
_error = errorMap.values().iterator().next();
}
LOGGER.info("End Running Listener !!");
}
public void close() {
//_executor.shutdown();
}
public boolean isCalled() {
return _isCalled;
}
public boolean isDone() {
return _isDone;
}
public boolean isCancelled() {
return _isCancelled;
}
public String getMessage() {
return _message;
}
public Throwable getError() {
return _error;
}
public int getNumRuns() {
return _numRuns;
}
}
}