Reputation: 3982
For example, i want to read 100500 bytes to an array:
byte[] array = new byte[100500];
int offset = 0;
ByteBuffer buf = ByteBuffer.directBuffer(4096);
channel.read(buffer, null, new LambdaAdapter((count, exception, attachment) -> {
buf.get(array, offset, count);
offset += count; //will not work, offset must be final
if (offset < 100500) {
channel.read(buffer, null, /*what here? must be lambda we are currently in but we can't use it!*/)
}
//here we have our 100500 bytes inside array
});
LambdaAdapter here is simple wrapper that converts CompletionHandler to functional interface with three arguments.
Anyway. Offset can be put to 'attachment' parameter, lambda can be declared beforehand and reused as as field. However, resulting code is always ugly Ugly UGLY.
I was not able to write acceptable solution even for such simple task - what it will look like for complex protocol where reads are interleaved with writes and wrapped in complex logic?
Does anyone know suitable way to deal with async API? If you think that Scala can save the world here, feel free to use it.
Upvotes: 0
Views: 336
Reputation: 3982
I found acceptable solutions. First of all, following worth looking at: https://github.com/Netflix/RxJava
As for coding guidelines...
Async operation code should start with creation of new object, let's call it context
Void startMyAsync(String p1, int p2, Observer callback) {
return new MyAsyncContext(p1, p2, callback).start();
}
Result of async operation method is not used - let's return Void type. It is useful since compiler will check for you that every async method calls another async method or explicitly returns null.
Example of async callback:
return myAsyncMethod(param1, param2, (result, exc, att) -> {
try {
if (exc != null) {
return handleError(exc); //cleanup resources and invoke parentHandler.complete(null, exc, null)
} else {
return handleResult(result);
}
} catch (Exception e) {
return handleError(exc); //cleanup resources and invoke parentHandler.complete(null, exc, null)
}
});
Upvotes: 0
Reputation: 13535
I know how to deal with with async computations IO in general, and async IO in particular. Async program should be represented as a dataflow graph, as described in Dataflow_programming. Each node has a set of inputs, each input accepts messages or signals, and fires (goes to a thread pool) when all inputs are filled. For example, a node representing a socket channel has two inputs: one for ByteBuffers and one to indicate that the channel is free and can accept IO requests. So a node resembles a function in functional programming, but can be reused - no new objects are created for next IO operation.
Scala (and Akka) actors does not fit, as each actor has only one input. Look, however, at Scala Dataflow - I did not learn it yet, but the name is promising :).
I have developed a dataflow library for java dataflow library for java, but its IO part is somewhat outdated (I am thinking of more elegant, or at least less ugly API). Look at echo server implementation in examples subdirectory.
Upvotes: 1