Alternatives to the official (and ugly) Sequential composition - java

In vertx guides, the sequential composition for chaining async calls is shown below:
FileSystem fs = vertx.fileSystem();
Future<Void> startFuture = Future.future();
Future<Void> fut1 = Future.future();
fs.createFile("/foo", fut1.completer());
fut1.compose(v -> {
// When the file is created (fut1), execute this:
Future<Void> fut2 = Future.future();
fs.writeFile("/foo", Buffer.buffer(), fut2.completer());
return fut2;
}).compose(v -> {
// When the file is written (fut2), execute this:
fs.move("/foo", "/bar", startFuture.completer());
},
// mark startFuture it as failed if any step fails.
startFuture);
Is it just me or is this code really cumbersome and hard to read?
There should be another way without falling into the callback hell.
It's a pity there are so few blog posts on vertx, any ideas are much appreciated.

these days the de facto library for writing asynchronous, non-blocking code on the JVM is RxJava. if you're not familiar i'd say it's highly worth your while to take a look as one of the many benefits is the ability to write "flows" as compositional streams that aren't quite as callback hell-y as the JDK's Futures were.
luckily, Vert.x is integrated with RxJava. as an example, here is your snippet rewritten using RxJava artifacts:
#Override
public void start(Future<Void> startFuture) throws Exception {
final FileSystem fs = vertx.fileSystem();
fs.rxCreateFile("/foo")
.andThen(fs.rxWriteFile("/foo", Buffer.buffer()))
.andThen(fs.rxMove("/foo", "/bar"))
.subscribe(
() -> {
startFuture.complete();
},
error -> {
startFuture.fail(error);
}
);
}
much more concise and readable.
note:
use RxJava 2 as it has superceded RxJava 1
...both versions, however, are supported in Vert.x, with their respective artifacts living in separate namespaces:
io.vertx.rxjava for version RxJava 1 artifacts
io.vertx.reactivex for version RxJava 2 artifacts
hope that helps!

Related

Conversion from Observable to Mono in Kotlin

Trying to insert in couchbase and that has observable return type but want mono,hence did this.
Its compiling but at run time its getting stuck forever at the conversion stage (i.e Mono.from { obs }).
fun saveScopeId(scopeId: ScopeId): Mono<ScopeId> {
val obs = scopeRepository.couchbaseOperations.insert(scopeId)
return Mono.from<ScopeId> { obs }
}
Observable can generate multiple values but if you can guarantee that it will be one item (I assume this is why you want to use Mono here) you can use Mono.fromDirect in this way:
Mono.fromDirect(yourObservable.toFlowable(BackpressureStrategy.BUFFER));
As you can see in example, there is toFlowable method used.
You should see the other backpressure strategies: here
This way we can achieve but not sure about the performance part.
As there Rx -> Rx -> Reactor conversion. Can someone tell me by looking into couchbase SDK 4.x (introduced recently), only if there are some conversion issue.
Mono.fromDirect(RxReactiveStreams.toPublisher(scopeRepository.couchbaseOperations.insert(scope)))
Try this but this thread blocking model.
public Mono<String> GetData(Observable<String> inputData) {
return Mono.fromCallable(() -> inputData.blockingFirst(""));
}

Selecting Data from Room without observing

I need to select data from a table, manipulate it and then insert it into another table. This only happens when the app is opened for the first time that day and this isn't going to be used in the UI. I don't want to use LiveData because it doesn't need to be observed but when I was looking into how to do it, most people say I should use LiveData. I've tried using AsyncTask but I get the error "Cannot access database on the main thread since it may potentially....".
Here is the code for my AsyncTask
public class getAllClothesArrayAsyncTask extends AsyncTask<ArrayList<ClothingItem>, Void, ArrayList<ClothingItem>[]> {
private ClothingDao mAsyncDao;
getAllClothesArrayAsyncTask(ClothingDao dao) { mAsyncDao = dao;}
#Override
protected ArrayList<ClothingItem>[] doInBackground(ArrayList<ClothingItem>... arrayLists) {
List<ClothingItem> clothingList = mAsyncDao.getAllClothesArray();
ArrayList<ClothingItem> arrayList = new ArrayList<>(clothingList);
return arrayLists;
}
}
And this is how I'm calling it in my activity
mClothingViewModel = new ViewModelProvider(this).get(ClothingViewModel.class);
clothingItemArray = mClothingViewModel.getClothesArray();
What is the best practice in this situation?
Brief summary:
Room really doesn't allow to do anything (query|insert|update|delete) on main thread. You can switch off this control on RoomDatabaseBuilder, but you better shouldn't.
If you don't care about UI, minimally you can just to put your ROOM-ish code (Runnable) to one of - Thread, Executor, AsyncTask (but it was deprecated last year)... I've put examples below
Best practices in this one-shot operation to DB I think are Coroutines (for those who use Kotlin at projects) and RxJava (for those who use Java, Single|Maybe as a return types). They give much more possibilities but you should invest your time to get the point of these mechanisms.
To observe data stream from Room there are LiveData, Coroutines Flow, RxJava (Flowable).
Several examples of using Thread-switching with lambdas enabled (if you on some purpose don't want to learn more advanced stuff):
Just a Thread
new Thread(() -> {
List<ClothingItem> clothingList = mAsyncDao.getAllClothesArray();
// ... next operations
});
Executor
Executors.newSingleThreadExecutor().submit(() -> {
List<ClothingItem> clothingList = mAsyncDao.getAllClothesArray();
// ... next operations
});
AsyncTask
AsyncTask.execute(() -> {
List<ClothingItem> clothingList = mAsyncDao.getAllClothesArray();
// ... next operations
});
If you use Repository pattern you can put all this thread-switching there
Another useful link to read about life after AsyncTask deprecation

Azure Blob Storage Java SDK: Why isn't asynchronous working?

I am still spinning up on the Azure Storage Java SDK 10 and its use of reactive programming the paradigm. I wrote the following method to asynchronously download a blob to a byte stream as fast as possible. When I use the synchronous version (below), it works properly. When I comment out the blockingAwait() and uncomment the subscribe, the write and the doOnComplete never are executed... Basically, the run just falls out of the bottom of the method back to the caller. I am sure that I have made an asynchronous processing mistake, and hope that someone can steer me in the correct direction. By the way, I was surprised to find that there are very few samples of downloading to a stream rather than to a file... Hopefully, this posting will help others.
Thank you for your time and interest in my problem...
override fun downloadBlob(url: String, downloadStream: OutputStream) {
BlockBlobURL(URL(url), pipeline)
.download(null, null, false, null)
.flatMapCompletable { response ->
FlowableUtil.collectBytesInBuffer(response.body(null))
.map {
Channels.newChannel(downloadStream).write(it)
}.toCompletable()
}.doOnComplete {
println("The blob was downloaded...")
}.blockingAwait()
//.subscribe()
}
Here is the code that is calling the above method:
fun getAerialImageBlobStream(aerialImageUrl: String): MapOutputStream {
val aerialImageStream = MapOutputStream()
blobStorage.downloadBlob(aerialImageUrl, aerialImageStream)
return aerialImageStream
}

How to aggregate different async sources into a Single using RxJava2?

Let's say I have this synchronous method:
public FruitBowl getFruitBowl() {
Apple apple = getApple(); // IO intensive
Banana banana = getBanana(); // CPU intensive
return new FruitBowl(apple, banana);
}
I can use the Java concurrency API to turn it into an async method, which would turn out somewhat like this:
public Future<FruitBowl> getFruitBowl() {
Future<Apple> appleFuture = getAppleAsync(); // IO intensive
Future<Banana> bananaFuture = getBananaAsync(); // CPU intensive
return createFruitBowlAsync(appleFuture, bananaFuture); // Awaits appleFuture and bananaFuture and then returns a new FruitBowl
}
What is the idiomatic Rx way of doing this while taking advantage of it's schedulers (io and computation) and return a Single?
You can use the zip operator. And for each of the async operation define a different thread. If you don't do so, the methods will be executed one after the other, on the same thread.
I would create an Observable version of both methods, in order to return respectively Observable<Apple> and Observable<Banana> and use them in this way:
Observalbe.zip(getAppleObservable().subscribeOn(Schedulers.newThread()),
getBananaObservable().subscribeOn(Schedulers.newThread()),
(apple, banana) -> new FruitBowl(apple, banana)))
.subscribe(/* do your work here with FruitBowl object */);
Here more details about how to parallelize operations with zip operator

Converting Akka Sources to RxJava2 Flowable?

I'm currently using the following code to convert an Akka Source (such as received from reading a file using Akka's FileIO) to a RxJava2 Flowable:
private Flowable<Buffer> akkaConversion(Source<ByteString, NotUsed> data,
Flow<ByteString, ByteString, NotUsed> compType) {
final Publisher<ByteString> uncompressedData =
data.via(compType)
.runWith(Sink.asPublisher(AsPublisher.WITHOUT_FANOUT), this.materializer);
return Flowable.fromPublisher(uncompressedData)
.map(bytes -> Buffer.buffer(bytes.toArray()));
}
My problem with this (working) solution is, that, at least as far as I currently understand it, the .runWith() method call already runs the code, i.e. gathers all the data from the given Source, buffers it and then puts it into a Publisher. Is there any way around having to run it at this point? I would like to just define the conversion at this point without the materializer and only run everything once something subscribes to the Flowable at a later point.
Thanks!
Use defer (sidenote: I had to do this many times because Akka Sources are one shot):
private Flowable<Buffer> akkaConversion(Source<ByteString, NotUsed> data,
Flow<ByteString, ByteString, NotUsed> compType) {
return Flowable.defer(() -> data.via(compType)
.runWith(Sink.asPublisher(AsPublisher.WITHOUT_FANOUT), this.materializer)
).map(bytes -> Buffer.buffer(bytes.toArray()));
}

Categories

Resources