I dont understand this statement about closing over the actor ref in the callback.
Currently I am using
public void onReceive(Object message) throws Exception {
ActorRef senderActorRef = getSender(); //never close over a future
if (message instanceof String) {
Future<String> f =akka.dispatch.Futures.future(new Callable<String>() {
public String call() {
String value= jedisWrapper.getString("name");
senderActorRef.tell((String) message,ActorRef.noSender());
return "what";
}
}, ex);
f.onSuccess(new OnSuccessExtension(), ex);
}
}
private final class OnSuccessExtension extends OnSuccess {
#Override
public void onSuccess(Object arg0) throws Throwable {
log.info("what");
}
}
Is this the right way to use it?
How can I pass the Sender Actor ref in the OnSuccess method?
Also whats the difference between onSuccess and OnComplete ?
If I want to use onComplete how would I use it?
Answer: Pass the Sender Actor Ref in the constructor. The answer given by another user.
OnSuccess is a specialized form of OnComplete.
OnComplete useage from Akka docs
final ExecutionContext ec = system.dispatcher();
future.onComplete(new OnComplete<String>() {
public void onComplete(Throwable failure, String result) {
if (failure != null) {
//We got a failure, handle it here
} else {
// We got a result, do something with it
}
}
}, ec);
Pass it in the constructor:
public void onReceive(Object message) throws Exception {
final ActorRef senderActorRef = getSender(); //never close over a future
if (message instanceof String) {
Future<String> f = // ...
f.onSuccess(new OnSuccessExtension(senderActorRef), ex);
}
}
private final class OnSuccessExtension extends OnSuccess {
private final ActorRef senderActorRef;
public OnSuccessExtension(ActorRef senderActorRef) {
this.senderActorRef = senderActorRef;
}
#Override
public void onSuccess(Object arg0) throws Throwable {
log.info("what");
// use senderActorRef
}
}
Related
I have a java SDK,which use OkHttp client(4.0.0) to get token from IAM server and return token to application.The relation may like this:Applicaiton Sync call SDK,SDK Async call IAM.Refer to this answerJava - Retrieving Result from OkHttp Asynchronous GET,the code like:
The Async Class:
class BaseAsyncResult<T> {
private final CompletableFuture<T> future = new CompletableFuture<>();
T getResult() {
try {
return future.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
return null;
}
void onFailure(IOException e) {
future.completeExceptionally(e);
}
void onResponse(Response response) throws IOException {
String bodyString = Objects.requireNonNull(response.body()).string();
future.complete(IasClientJsonUtil.json2Pojo(bodyString, new TypeReference<T>() {}));
}
}
Okhttp call like this:
public void invoke(Request request, BaseAsyncResult result) {
okHttpClient.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(#NotNull Call call, #NotNull IOException e) {
result.onFailure(e);
}
#Override
public void onResponse(#NotNull Call call, #NotNull Response response) throws IOException {
result.onResponse(response);
}
});
}
The application use sdk code like,iasClient is a wrapper of okhttp client :
BaseAsyncResult<AuthenticationResponse> iasAsyncResult = new BaseAsyncResult();
iasClient.invoke(request, iasAsyncResult);
AuthenticationResponse result = iasAsyncResult.getResult();
The erroe message:
java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to x.x.x.AuthenticationResponse
What have I missed?
You need to make sure jackson knows which class to deserialize the value to . In this case, you are asking Jackson to deserialize the response to a TypeReference , which will resolve to a Map by default unless you specify the class (in this case, AuthenticationResponse ) . The Future resolves to a linkedHashMap due to this and causes the class cast.
try replacing the below line .
future.complete(IasClientJsonUtil.json2Pojo(bodyString, new TypeReference<T>() {}));
with
future.complete(IasClientJsonUtil.json2Pojo(bodyString, new TypeReference<AuthenticationResponse>() {}));
One method from #Arpan Kanthal is add a private Class type variable to BaseAsyncResult and then use that class in your json2Pojo function,then the BaseAsyncResult may like this:
public class BaseAsyncResult<T> {
private final CompletableFuture<T> future = new CompletableFuture<>();
private Class<T> classType;
public BaseAsyncResult(Class<T> classType) {
this.classType = classType;
}
public T getResult() {
try {
return future.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
return null;
}
void onFailure(IOException e) {
future.completeExceptionally(e);
}
void onResponse(Response response) throws IOException {
future.complete(JacksonUtil.json2Pojo(response.body().string(), classType));
}
}
I'm sure this is a very stupid question, but still I would like to know, is it possible to cast the global variable cause dynamically, in other words without using the instanceof operator ?
The reason for this question is, I feel the instanceof operator is not doing anything great here, it's just casting the cause statically, but in either case it's creating a new IOException(cause)
Because the cause is of type Object, I had to type cast it to either String or Throwable.
private Object cause; // global variable
//...
if (failed)
throw cause instanceof String ? new IOException((String) cause) : new IOException((Throwable) cause);
Below is the actual code snippet where the two overridden methods will be called asynchronously.
public class Command implements ResponseListener {
private Object cause;
// ...
#Override
public void messageReceived(String message, String status) {
// ...
if (!status.equals(MyConstants.COMPLD_MSG)) {
this.cause = status + " received for " + command.split(":")[0] + message;
this.failed = true;
}
doNotify();
}
#Override
public void exceptionCaught(Throwable cause) {
this.cause = cause;
this.failed = true;
doNotify();
}
public void waitForResponse(int cmdTimeout) throws IOException, InterruptedException {
// ...
if (failed)
throw cause instanceof String ? new IOException((String) cause) : new IOException((Throwable) cause);
}
}
Why not having always a Throwable for your cause variable ? Throwable seems more adapted to express a failure than a String. Plus it avoids you to use the "ugly" operator instanceof.
public class Command implements ResponseListener {
private Throwable cause;
// ...
#Override
public void messageReceived(String message, String status) {
// ...
if (!status.equals(MyConstants.COMPLD_MSG)) {
this.cause = new Throwable(status + " received for " + command.split(":")[0] + message);
this.failed = true;
}
doNotify();
}
#Override
public void exceptionCaught(Throwable cause) {
this.cause = cause;
this.failed = true;
doNotify();
}
public void waitForResponse(int cmdTimeout) throws IOException, InterruptedException {
// ...
if (failed)
throw new IOException(cause);
}
}
Update after discussion below:
public class Command implements ResponseListener {
private String cause;
// ...
#Override
public void messageReceived(String message, String status) {
// ...
if (!status.equals(MyConstants.COMPLD_MSG)) {
this.cause = status + " received for " + command.split(":")[0] + message;
this.failed = true;
}
doNotify();
}
#Override
public void exceptionCaught(Throwable cause) {
if(cause.getMessage().isEmpty()) {
this.cause = cause.toString();
}
else {
this.cause = cause.getMessage();
}
this.failed = true;
doNotify();
}
public void waitForResponse(int cmdTimeout) throws IOException, InterruptedException {
// ...
if (failed)
throw new IOException(cause);
}
}
As there is no common superclass of String and Throwable that would be acceptable as parameter to IOException, you have to cast it to one or the other, and in order to determine what to cast it to, you have to use instanceof.
Class.cast and Class.isAssignableFrom methods may be used as dynamic counterparts of cast and instanceof operators respectively.
I'm writing an Android messaging application, and 1 class is calling another class, and I wish for the calling class to wait for the callee class to complete before carrying on.
Caller Class (MessageManagement) code snippet is as follows:
private static Messenger myMessenger;
try {
Message msg = Message.obtain();
msg.arg1 = constructedMessage.length();
msg.arg2 = -1;
msg.obj = constructedMessage;
Log.d(TAG, "Calling myMessenger.send()");
myMessenger.send(msg);
Log.d(TAG, "Sent");
} catch (Exception e) {
e.printStackTrace();
}
// Wait here until myMessenger completes its task
doOtherStuff();
Right now, doOtherStuff() starts and finishes before myMessenger starts. I need myMessenger to complete before doOtherStuff() starts.
I've read about wait() and notify() but I'm not sure how to implement it here, or whether it's the right choice.
Some background about the flow of the program. It's basically a messaging app that I inherited, so I'm not exactly sure of its framework. From what I can tell tracing the flow of the code:
When an SMS message is received, the SMS receiver BroadcastReceiver(SmsReceiver) handles it, getting the sender address and message body, then calling a SMS handler service(HandleSmsService), which then calls the caller class in a runnable with the following code:
HandleSmsService
public class HandleSmsService extends Service {
private String message;
private MessageManagement messageManager;
private Handler timeoutHandler = new Handler();
#Override
public void onStart(Intent intent, intent startid) {
message = intent.getExtras().getString("message");
messageManager = new MessageManagement(this);
timeoutHandler.postDelayed(runnable, 10);
}
private Runnable runnable = new Runnable() {
#Override
public void run() {
try {
messageManager.handleMessage(message);
stopSelf();
} catch (Exception e) {
e.printStackTrace();
}
}
};
MessageManagement is my caller class, and MessageManagement.handleMessage() is the top most code snippet presented earlier.
The MessageManagement.handleMessage() apparently calls another Handler in the callee class when it calls myMessenger.send(msg). This Handler code is as follows:
private Handler smsHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
// do some stuff
}
};
I'm assuming the posted code is running on the MainThread and the reason why you are using a handler is that something asynchronous is done on another thread when receiving that message.
In that case, you can't use wait on the thread, as it will lock up the UI and probably cause an application not responding error.
Without changing too much of your code, one way to do it is to nest a listener in your constructedMessage for e.g.
public class DoStuffRequest {
private OnFinishListener mOnFinishListener;
private boolean isCanceled;
private String mMessage;
public interface OnFinishListener {
public void onFinish();
}
public DoStuffRequest(String message) {
mMessage = message;
}
public OnFinishListener getOnFinishListener() {
return mOnFinishListener;
}
public void setOnFinishListener(OnFinishListener onFinishListener) {
mOnFinishListener = onFinishListener;
}
public void cancel() {
isCanceled = true;
}
public void notifyFinish() {
if (!isCanceled && mOnFinishListener != null) {
mOnFinishListener.onFinish();
}
}
public String getMessage() {
return mMessage;
}
}
then use some along the line of this to get the ball rolling:
private static Messenger myMessenger;
private DoStuffRequest mRequest;
...
private void send(String message) {
mRequest = new DoStuffRequest(message);
mRequest.setOnFinishListener(new ConstructedMessage.OnFinishListener() {
#Override
public void onFinish() {
doOtherStuff();
}
});
try {
Message msg = Message.obtain();
msg.arg1 = constructedMessage.length();
msg.arg2 = -1;
msg.obj = constructedMessage;
Log.d(TAG, "Calling myMessenger.send()");
myMessenger.send(msg);
Log.d(TAG, "Sent");
} catch (Exception e) {
e.printStackTrace();
}
}
private void doThisIfYouWantToCancel() {
if (mRequest != null) {
mRequest.cancel();
}
}
your Handler/Service code can now call constructedMessage.finish() when the async stuff is done. Depending on what doOtherStuff() does (e.g. when manipulating the UI), you might want to do this on the MainThread (the code i've written above is NOT thread safe and i assume you are calling the listener on the MainThread).
Also remember to call constructedMessage.cancel() in case you do not want to get notified any more (e.g. you are leaving the activity/fragment).
this is just one way to do it, depending on your needs, some other methods might be a better choice.
I guess it should look something like this:
try {
Message msg = Message.obtain(handler, new Runnable() {
#Override
public void run() {
doOtherStuff();
}
});
msg.arg1 = constructedMessage.length();
msg.arg2 = -1;
msg.obj = constructedMessage;
Log.d(TAG, "Calling myMessenger.send()");
msg.sendToTarget();
Log.d(TAG, "Sent");
} catch (Exception e) {
e.printStackTrace();
}
The other way to do this using native means:
private static Messenger myMessenger = new Messenger(new Handler(new Handler.Callback() {
#Override
public boolean handleMessage(Message msg) {
// do something what you need
if (msg.getTarget() != null) {
msg.sendToTarget();
}
return false;
}
}));
try {
final Message msg = Message.obtain();
msg.setTarget(new Handler(new Handler.Callback() {
#Override
public boolean handleMessage(Message msg) {
doOtherStuff();
return false;
}
}));
msg.arg1 = constructedMessage.length();
msg.arg2 = -1;
msg.obj = constructedMessage;
Log.d(TAG, "Calling myMessenger.send()");
myMessenger.send(msg);
Log.d(TAG, "Sent");
} catch (final Exception e) {
e.printStackTrace();
}
I want to write a netty based client. It should have method public String send(String msg); which should return response from the server or some future - doesen't matter. Also it should be multithreaded. Like this:
public class Client {
public static void main(String[] args) throws InterruptedException {
Client client = new Client();
}
private Channel channel;
public Client() throws InterruptedException {
EventLoopGroup loopGroup = new NioEventLoopGroup();
Bootstrap b = new Bootstrap();
b.group(loopGroup).channel(NioSocketChannel.class).handler(new ChannelInitializer<SocketChannel>() {
#Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new StringDecoder()).
addLast(new StringEncoder()).
addLast(new ClientHandler());
}
});
channel = b.connect("localhost", 9091).sync().channel();
}
public String sendMessage(String msg) {
channel.writeAndFlush(msg);
return ??????????;
}
}
And I don't get how can I retrieve response from server after I invoke writeAndFlush(); What should I do?
Also I use Netty 4.0.18.Final
Returning a Future<String> for the method is simple, we are going to implement the following method signature:
public Futute<String> sendMessage(String msg) {
The is relatively easy to do when you are known with the async programming structures. To solve the design problem, we are going to do the following steps:
When a message is written, add a Promise<String> to a ArrayBlockingQueue<Promise>
This will serve as a list of what messages have recently been send, and allows us to change our Future<String> objects return result.
When a message arrives back into the handler, resolve it against the head of the Queue
This allows us to get the correct future to change.
Update the state of the Promise<String>
We call promise.setSuccess() to finally set the state on the object, this will propagate back to the future object.
Example code
public class ClientHandler extends SimpleChannelInboundHandler<String> {
private ChannelHandlerContext ctx;
private BlockingQueue<Promise<String>> messageList = new ArrayBlockingQueue<>(16);
#Override
public void channelActive(ChannelHandlerContext ctx) {
super.channelActive(ctx);
this.ctx = ctx;
}
#Override
public void channelInactive(ChannelHandlerContext ctx) {
super.channelInactive(ctx);
synchronized(this){
Promise<String> prom;
while((prom = messageList.poll()) != null)
prom.setFailure(new IOException("Connection lost"));
messageList = null;
}
}
public Future<String> sendMessage(String message) {
if(ctx == null)
throw new IllegalStateException();
return sendMessage(message, ctx.executor().newPromise());
}
public Future<String> sendMessage(String message, Promise<String> prom) {
synchronized(this){
if(messageList == null) {
// Connection closed
prom.setFailure(new IllegalStateException());
} else if(messageList.offer(prom)) {
// Connection open and message accepted
ctx.writeAndFlush(message).addListener();
} else {
// Connection open and message rejected
prom.setFailure(new BufferOverflowException());
}
return prom;
}
}
#Override
protected void messageReceived(ChannelHandlerContext ctx, String msg) {
synchronized(this){
if(messageList != null) {
messageList.poll().setSuccess(msg);
}
}
}
}
Documentation breakdown
private ChannelHandlerContext ctx;
Used to store our reference to the ChannelHandlerContext, we use this so we can create promises
private BlockingQueue<Promise<String>> messageList = new ArrayBlockingQueue<>();
We keep the past messages in this list so we can change the result of the future
public void channelActive(ChannelHandlerContext ctx)
Called by netty when the connection becomes active. Init our variables here.
public void channelInactive(ChannelHandlerContext ctx)
Called by netty when the connection becomes inactive, either due to error or normal connection close.
protected void messageReceived(ChannelHandlerContext ctx, String msg)
Called by netty when a new message arrives, here pick out the head of the queue, and then we call setsuccess on it.
Warning advise
When using futures, there is 1 thing you need to lookout for, do not call get() from 1 of the netty threads if the future isn't done yet, failure to follow this simple rule will either result in a deadlock or a BlockingOperationException.
You can find the sample in netty project.
We can save the result into the last handler's custom fields. In the following code, it is handler.getFactorial() that is what we want.
refer to http://www.lookatsrc.com/source/io/netty/example/factorial/FactorialClient.java?a=io.netty:netty-all
FactorialClient.java
public final class FactorialClient {
static final boolean SSL = System.getProperty("ssl") != null;
static final String HOST = System.getProperty("host", "127.0.0.1");
static final int PORT = Integer.parseInt(System.getProperty("port", "8322"));
static final int COUNT = Integer.parseInt(System.getProperty("count", "1000"));
public static void main(String[] args) throws Exception {
// Configure SSL.
final SslContext sslCtx;
if (SSL) {
sslCtx = SslContextBuilder.forClient()
.trustManager(InsecureTrustManagerFactory.INSTANCE).build();
} else {
sslCtx = null;
}
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.handler(new FactorialClientInitializer(sslCtx));
// Make a new connection.
ChannelFuture f = b.connect(HOST, PORT).sync();
// Get the handler instance to retrieve the answer.
FactorialClientHandler handler =
(FactorialClientHandler) f.channel().pipeline().last();
// Print out the answer.
System.err.format("Factorial of %,d is: %,d", COUNT, handler.getFactorial());
} finally {
group.shutdownGracefully();
}
}
}
public class FactorialClientHandler extends SimpleChannelInboundHandler<BigInteger> {
private ChannelHandlerContext ctx;
private int receivedMessages;
private int next = 1;
final BlockingQueue<BigInteger> answer = new LinkedBlockingQueue<BigInteger>();
public BigInteger getFactorial() {
boolean interrupted = false;
try {
for (;;) {
try {
return answer.take();
} catch (InterruptedException ignore) {
interrupted = true;
}
}
} finally {
if (interrupted) {
Thread.currentThread().interrupt();
}
}
}
#Override
public void channelActive(ChannelHandlerContext ctx) {
this.ctx = ctx;
sendNumbers();
}
#Override
public void channelRead0(ChannelHandlerContext ctx, final BigInteger msg) {
receivedMessages ++;
if (receivedMessages == FactorialClient.COUNT) {
// Offer the answer after closing the connection.
ctx.channel().close().addListener(new ChannelFutureListener() {
#Override
public void operationComplete(ChannelFuture future) {
boolean offered = answer.offer(msg);
assert offered;
}
});
}
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
private void sendNumbers() {
// Do not send more than 4096 numbers.
ChannelFuture future = null;
for (int i = 0; i < 4096 && next <= FactorialClient.COUNT; i++) {
future = ctx.write(Integer.valueOf(next));
next++;
}
if (next <= FactorialClient.COUNT) {
assert future != null;
future.addListener(numberSender);
}
ctx.flush();
}
private final ChannelFutureListener numberSender = new ChannelFutureListener() {
#Override
public void operationComplete(ChannelFuture future) throws Exception {
if (future.isSuccess()) {
sendNumbers();
} else {
future.cause().printStackTrace();
future.channel().close();
}
}
};
}
Calling channel.writeAndFlush(msg); already returns a ChannelFuture. To handle the result of this method call, you could add a listener to the future like this:
future.addListener(new ChannelFutureListener() {
public void operationComplete(ChannelFuture future) {
// Perform post-closure operation
// ...
}
});
(this is taken from the Netty documentation see: Netty doc)
In netty, MessageEvent (wrapper for messages) has a method Object getMessage() to get the real carried message from the network. Reading the source I noticed they heavily use the instanceof operator to switch among methods.
However, having a wide variety of message types I would like to avoid a method like this:
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
if (e.getMessage() instanceof MessageType1) {
...
} else if (e.getMessage() instanceof MessageType2) {
...
} ... {
...
} else if (e.getMessage() instanceof MessageTypeN) {
...
} else {
ctx.sendUpstream(e);
}
}
Writing different methods taking advantage of polymorphism would be much better, like:
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
// MessageType implements Message
if (e.getMessage() instanceof Message) {
handleMessage(ctx, (Message) e.getMessage());
} else {
ctx.sendUpstream(e);
}
}
void handleMessage(ChannelHandlerContext ctx, MessageType1 m) {
...
}
...
void handleMessage(ChannelHandlerContext ctx, MessageTypeN m) {
...
}
But i cannot due to downcasting limitations. Is there a clean way to do this or am I tied to instanceof cascade?
I could bring the logic out the Handler using .doSomething() methods inside Message sub-types but I'd like to keep the business logic inside the netty pipeline.
Solved applying Visitor Pattern:
public interface Handler {
void handleMessage(ChannelHandlerContext ctx, MessageType1 m);
void handleMessage(ChannelHandlerContext ctx, MessageType2 m);
...
void handleMessage(ChannelHandlerContext ctx, MessageTypeN m);
}
then:
#Sharable
public class MessageHandler extends SimpleChannelHandler implements Handler {
...
#Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
if (e.getMessage() instanceof Message) {
Message m = (Message) e.getMessage();
m.handleTo(ctx, this);
} else {
ctx.sendUpstream(e);
}
}
#Override
public void handleMessage(ChannelHandlerContext ctx, MessageType1 m) {
...
}
and
public interface Message {
/*
* Will be {
* handler.handleMessage(ctx, this);
* }
* everywhere.
*/
void handleTo(ChannelHandlerContext ctx, Handler handler);
}