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.
Related
I am trying to throw a custom exception
class NumberFormatException extends Exception
{
public NumberFormatException() {}
//Constructor that accepts a message
public NumberFormatException(String message)
{
super(message);
}
}
Later, I am throwing this exception using
throw new NumberFormatException("Exception found");
and later on catching it using
catch(NumberFormatException e)
{
System.out.println(e);
}
It prints something like
NumberFormatException: Exception found
Is it possible to print something like:
java.lang.NumberFormatException: Exception found
The constraint is the catch code can't be modified i.e
catch(NumberFormatException e)
{
System.out.println(e);
}
You are trying to get Canonical name of exception class and here is how you can get it:
catch(NumberFormatException e)
{
System.out.println(e.getClass().getCanonicalName());
}
Refer javadoc for more : getCanonicalName
Override toString In your NumberFormatException class :
class MyException extends Exception{
String message;
public MyException(String string) {
this.message = string;
}
#Override
public String toString() {
String s = getClass().getCanonicalName();
String message = this.message;
return (message != null) ? (s + ": " + message) : s;
}
}
Source : Throwable
Here is a full code testing the method :
package first;
class MyException extends Exception{
String message;
public MyException(String string) {
this.message = string;
}
#Override
public String toString() {
String s = getClass().getCanonicalName();
String message = this.message;
return (message != null) ? (s + ": " + message) : s;
}
}
public class TestingMyException{
public static void main(String[] args) {
try{
throw new MyException("This works !");
}catch(MyException e){
System.out.println(e);
}
}
}
Output
first.MyException: This works !
Since my class is defined in the package named first of my root, the result prints first.MyException.
So you also have to check if your class is not defined in the default package. Otherwise, you'll not get anything but :
MyException: This works !
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
}
}
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)
For some reason I am missing part of the stack trace, the actual root of the exception.
public void method1(){
try{
method2();
}
catch(SearchException e){
logger.error("Search error", e.getMessage(), e);
}
}
private void method2(){
try{
//Logic which potentially can throw exception
....
....
}
catch(Exception e){
throw new SearchException("Error during execution Module A", e);
}
}
public class SearchException extends Exception{
public SearchException(String message, Throwable cause) {
super(message, cause);
}
}
Anyone knows a reason why I am missing part of stacktrace where fist place exception happened? Could you suggest a correct way of handling/logging exceptions?
super(message, cause);
The message will be the detailMessage of Throwable class. And it will be used in toString method and source cause(Exception) will be ignored.
358 public String toString() {
359 String s = getClass().getName();// class Name
360 String message = getLocalizedMessage();// detailMessage
361 return (message != null) ? (s + ": " + message) : s;
362 }
You may override the toString method in custom Exception class.
class SearchException extends Exception{
String str=null;
public SearchException(String str,Throwable th){
super( th);
this.str=str;
}
public String toString(){
return super.toString() +" - "+ str;
}
}
This customized form will print -
Search error
-----java.lang.NullPointerException-------SearchException: java.lang.NullPointerException - Error during execution Module A
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);
}