Observing closeable resources to be closed when the subscriber is removed/disposed - java

I'm working on a small subsystem that integrates two simple components using RxJava 2.
These two components work in a simple client-server manner where the first component produces observable data opening a resource under the hood.
The resource is not exposed to the second component.
Moreover, it must be open as long as the observable is in use, however the observable object cannot determine when it should be closed.
Speaking in code, an example implementation is like this:
private Disposable disposable;
public void onCreate() {
final Maybe<Object> maybeResource = Maybe.defer(() -> {
System.out.println("open");
// here is the resource under the hood, it is encapsulated in the observable and never gets exposed
final Closeable resource = () -> { };
return Maybe.just(resource)
.doOnDispose(() -> {
// this "destructor" is never called, resulting in a resource leak
System.out.println("close");
resource.close();
})
// arbitrary data, does not represent the data I'm working with, but it hides the resource away
.map(closeable -> new Object());
});
disposable = maybeResource.subscribe(data -> System.out.println("process: " + data));
}
public void onUserWorflow() {
// ...
System.out.println("... ... ...");
// ...
}
public void onDestroy() {
disposable.dispose();
}
The output I'd anticipate to get is:
open
process: <...>
... ... ...
close <-- this is never produced
but the last line, close, is never produced as the doOnDispose method is not invoked and does not work as I might think it's supposed to.
Therefore the resource gets never released.
There is also Maybe.using that does a similar thing, but it does not allow to "span" across the "user workflow".
Is there an RxJava/RxJava 2 way that allows managing "closeable" resources closed on disposing a subscriber?

i guess you need to use Observable.create() instead of Maybe.
Something like that:
final Observable<Object> resourceObservable = Observable.create<Object> {(emitter ->
// do you staff
emitter.onNext(new Object()); //to make observable emit something
emitter.setCancellable (
System.out.println("close");
resource.close();
)
);
disposable = resourceObservable.subscribe(data -> System.out.println("process: " + data));

Related

How to wrap an asynchronous Java lib in Android Kotlin?

I would like to use a Java Library inside of my Kotlin Android App, but I am relatively new to Kotlin and need some advice. The Library basically looks like this:
public interface Listener{
void onResult(Result res)
}
public class Client{
public Client(){}
public void setListener(Listener l){}
public void start(){} // Starts Thread(s) (so it's non-blocking), does some server calls, computes result, calls listener.onResult(res) after computation is finished.
public void cancel(){}
}
Yes, I know, I could just call the functions directly and use it like in java, but is that the Kotlin way?
I read, doing a similar task (using an asynchronous function, which takes a callback parameter) would be done by wrapping it in a coroutine/suspend function structure.
But I don't know howto adapt this for my Problem(?) or is it the wrong approach?
If you want to make this into a nice easy Kotlin suspending function, it would be like this:
suspend fun doTheThing() : Result {
val c = Client()
try {
//suspend until the listener fires or we're cancelled
return suspendCancellableCoroutine {
cont ->
c.setListener {
result -> cont.resume(result)
}
c.start()
}
} catch (e: Exception) {
// If someone cancels the parent job, our job will complete exceptionally
// before the client is done. Cancel the client since we don't need it
// anymore
c.cancel()
throw e
}
}
I don't see a way in your interface for the client to indicate failure. If that's part of Result then you probably want to turn that into an exception in the listener

Equivalent of VertX CompositeFuture in RxJava

The VertX example for when you need to query multiple asynchronous resources and use them all in a single operation is:
Future<HttpServer> httpServerFuture = Future.future();
httpServer.listen(httpServerFuture.completer());
Future<NetServer> netServerFuture = Future.future();
netServer.listen(netServerFuture.completer());
CompositeFuture.all(httpServerFuture, netServerFuture).setHandler(ar -> {
if (ar.succeeded()) {
// All servers started
} else {
// At least one server failed
}
});
We need to query two different databases and then use the results in business logic, but the flow is equivalent.
What's the VertX/RxJava equivalent?
Currently people are doing this by nesting a new .flatMap() call every time they need a new variable. I'm left feeling there must be a better way...
We don't actually need the queries to be concurrent but we need to cache both results and pass them to the business logic at the same time some how.
there are many ways to do this, but i've tried to pick an approach that tacks closely to your sample:
#Override
public void start(Future<Void> startFuture) throws Exception {
final HttpServer httpServer = vertx.createHttpServer();
final Completable initializeHttpServer = httpServer.rxListen().toCompletable();
final NetServer netServer = vertx.createNetServer();
final Completable initializeNetServer = netServer.rxListen().toCompletable();
initializeHttpServer.andThen(initializeNetServer)
.subscribe(
() -> { /* All servers started */ },
error -> { /* At least one server failed */ }
);
}
the rxListen() invocations are converted into Completable instances, which are then run serially upon subscription.
the subscriber's onComplete callback will be invoked when both servers are done binding to their respective ports, or...
the onError callback will be invoked if an exception occurs
(also, fwiw, "nesting" flatMap operations for something as trivial as this shouldn't be necessary. "chaining" such operations, however, would be idiomatic usage).
hope that helps!
--UPDATE--
having read the question more carefully, i now see that you were actually asking about how to handle the results of two discrete asynchronous operations.
an alternative to flatMap'ing your way to combining the results would be to use the zip operator, like so:
#Override
public void start(Future<Void> startFuture) throws Exception {
final Single<String> dbQuery1 = Single.fromCallable(() -> { return "db-query-result-1"; });
final Single<String> dbQuery2 = Single.fromCallable(() -> { return "db-query-result-2"; });
Single.zip(dbQuery1, dbQuery2, (result1, result2) -> {
// handle the results from both db queries
// (with Pair being a standard tuple-like class)
return new Pair(result1, result2);
})
.subscribe(
pair -> {
// handle the results
},
error -> {
// something went wrong
}
);
}
per the docs, zip allows you to specify a series of reactive types (Single, Observable, etc) along with a function to transform all the results at once, with the central idea being that it will not emit anything until all the sources have emitted once (or more, depending on the reactive type).

Using try-with-resources with things that are not "resources"

I have a continuously running service that I want stopped cleanly if it hits an exception. This fits well with the try with resources paradigm but it's not really a resource that needs to be "closed".
To clarify based on comments, my code looks something like this
class Service {
Resource resource;
State state;
boolean keepRunning = false;
void start() {
keepRunning = true;
resource = new Resource()
new Thread(() -> {
while(keepRunning) {
Data data = resources.pull();
state.update(data);
... // Do stuff with state
}
}).start();
}
void stop() {
keepRunning = false;
}
}
class Main {
void run() {
Service service = new Service();
service.start();
}
}
Is there a pattern that lets me use the syntactic sugar that try-with-resources provides while still not abusing try-with-resources with things that are not resources?
Of course, it is totally okay to use try-with-resources with anything you want. The requirement is that it implements the interface AutoCloseable (documentation). With that interface you will need to implement a close method, which then is called by the try-with-resources construct.
That is why this interface is there, you are allowed to implement it for your own classes.
For example if you have a service that needs to be probably shut down, also in error case, you may use AutoCloseable and implement the close method probably.
However it's meaningless and will confuse readers of your program if you make something AutoCloseable where there is totally no intuition what close means on this object. In such cases you should probably look for other constructs.
It's a bit like implementing Iterable such that you can use the enhanced for loop like:
for (Item item : myObject) {
...
}
You may do it, if it makes sense. Otherwise it will confuse people.

What is the difference between RxJava 2 Cancellable and Disposable?

I want to create an Observable from view click listener using RxJava 2. I started from the simplest implementation (I don't use lambdas here to show you different types in this method):
Observable<View> viewObservable = Observable.create(new ObservableOnSubscribe<View>() {
#Override
public void subscribe(#NonNull ObservableEmitter<View> e) throws Exception {
mNewWordView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View value) {
if (!e.isDisposed()) {
e.onNext(value);
}
}
});
}
});
Then I thought about the way to set onClickListener to null if it is not needed further. I found that there are two methods with similar (as for me) names:
e.setCancellable(Cancellable c); and
e.setDisposable(Disposable d);
What is the difference between them and which should I use?
From the Javadoc:
[Cancellable is] A functional interface that has a single cancel method that can throw.
The Disposable is not a functional interface plus when implementing its dispose() method, you are not allowed to throw checked exceptions.
In contrast, many non-RxJava components return a Closeable or AutoCloseable which are defined via throws IOException and throws Exception and are somewhat of a burden because you'd need try-catch it.
For example, you'd want to use setCancellable when you work with a file:
Observable.create((ObservableEmitter<byte[]> e) -> {
FileInputStream fin = new FileInputStream("raw.dat");
e.setCancellable(fin::close);
byte[] buffer = new byte[4096];
for (;;) {
int r = fin.read(buffer);
if (r < 0) {
break;
}
e.onNext(buffer);
}
e.onComplete();
});
and you'd use setDisposable if you use a Scheduler:
Observable.create((ObservableEmitter<Event> e) -> {
Worker worker = Schedulers.io().createWorker();
e.setDisposable(worker);
eventSource.onEvent(es ->
worker.schedule(() -> e.onNext(es))
);
});
The Cancellable ends up getting wrapped into a Disposable so the final effect is the same for either call. The difference is that Disposable has more features that you might not want to implement, so the simple Cancellable interface is there as an alternative.
If you just want to dispose something when the observable ends use Cancellable. If you have a resource that might be disposed because of some external reason you want to implement Disposable to implement the Disposable.isDisposed() method.
Do note that the methods are mutually exclusive. Only a single disposable or cancellable can be registered at once. Calling both overwrites the first one.

ListenableFuture callback execution order

Guava's ListenableFuture library provides a mechanism for adding callbacks to future tasks. This is done as follows:
ListenableFuture<MyClass> future = myExecutor.submit(myCallable);
Futures.addCallback(future, new FutureCallback<MyClass>() {
#Override
public void onSuccess(#Nullable MyClass myClass) {
doSomething(myClass);
}
#Override
public void onFailure(Throwable t) {
printWarning(t);
}}, myCallbackExecutor);
}
You can wait for a ListenableFuture to complete by calling its get function. For instance:
MyClass myClass = future.get();
My question is, are all callbacks for a certain future guaranteed to run before the get terminates. I.e. if there is a future with many callbacks on many callback executors registered, will all the callbacks complete before get returns?
Edit
My use case is, I pass a builder around to many classes. Each class populates one field of the builder. I want all fields to be populated asynchronously because each field requires an external query to generate the data for the field. I want the user who calls my asyncPopulateBuilder to receive a Future on which she can call get and be assured that all the fields have been populated. The way I thought to do it is as follows:
final Builder b;
ListenableFuture<MyClass> future = myExecutor.submit(myCallable);
Futures.addCallback(future, new FutureCallback<MyClass>() {
#Override
public void onSuccess(#Nullable MyClass myClass) {
b.setMyClass(myClass);
}
#Override
public void onFailure(Throwable t) {
printWarning(t);
}}, myCallbackExecutor);
}
// Do the same thing for all other fields.
What is the recommended way to block until all fields are populated in such a case?
Callbacks are not guaranteed to run before get returns. More on that below.
As for how to address this use case, I would suggest turning the query for each field's data into a separate Future, combining them with allAsList+transform, and taking action on that. (We may someday provide a shortcut for the "combine" step.)
ListenableFuture<MyClass> future = myExecutor.submit(myCallable);
final ListenableFuture<Foo> foo =
Futures.transform(
future,
new Function<MyClass, Foo>() { ... },
myCallbackExecutor);
final ListenableFuture<Bar> bar = ...;
final ListenableFuture<Baz> baz = ...;
ListenableFuture<?> allAvailable = Futures.allAsList(foo, bar, baz);
ListenableFuture<?> allSet = Futures.transform(
allAvailable,
new Function<Object, Object>() {
#Override
public Object apply(Object ignored) {
// Use getUnchecked, since we know they already succeeded:
builder.setFoo(Futures.getUnchecked(foo));
builder.setFoo(Futures.getUnchecked(bar));
builder.setFoo(Futures.getUnchecked(baz));
return null;
}
}
};
Now the user can call allSet.get() to await population.
(Or maybe you want for allSet to be a Future<Builder> so that the user is handed a reference to the builder. Or maybe you don't need a full-on Future at all, only a CountDownLatch, in which you could use addCallback instead of transform and count down the latch at the end of the callback.)
This approach may also simplify error handling.
RE: "Do callbacks run before get?"
First, I am pretty sure that we don't guarantee this anywhere in the spec, so thanks for asking rather than just going for it :) If you do end up wanting to rely on some behavior of the current implementation, please file an issue so that we can add documentation and tests.
Second, if I take your question very literally, what you're asking for isn't possible: If get() waits for all listeners to complete, then any listener that calls get() will hang!
A slightly more lenient version of your question is "Will all the listeners at least start before get() returns?" This turns out to be impossible, too: Suppose that I attach two listeners to the same Future to be run with directExecutor(). Both listeners simply call get() and return. One of the listeners has to run first. When it calls get(), it will hang, since the second listener hasn't started yet -- nor can it until the first listener is done. (More generally, it can be dangerous to rely on any given Executor to execute a task promptly.)
A still more lenient version is "Will the Future at least call submit() for each of the listeners before get() returns?" But this ends up with a problem in the same scenario as I just described: Calling submit(firstListener) on a directExecutor() runs the task and calls get(), which can't complete until the second listener is started, which can't happen until the first listener completes.
If anything, it's starting to sound much more likely that get() will return before any listeners execute. But thanks to the unpredictability of thread scheduling, we can't rely on that, either. (And again: It's not documented, so please don't rely on it unless you ask for it to be documented!)
final Builder b;
CountDownLatch latch = new CountDownLatch(1);
ListenableFuture<MyClass> future = myExecutor.submit(myCallable);
Futures.addCallback(future, new FutureCallback<MyClass>() {
#Override
public void onSuccess(#Nullable MyClass myClass) {
b.setMyClass(myClass);
latch.countDown();
}
#Override
public void onFailure(Throwable t) {
printWarning(t);
latch.countDown();
}, myCallbackExecutor);
try {
latch.await();
} catch (InterruptedException e) {
LOG.error("something InterruptedException", e);
} finally {
myCallbackExecutor.shutdown();
}
Edit
code is inspired by #Chris Povirk
(Or maybe you want for allSet to be a Future so that the user is handed a reference to the builder. Or maybe you don't need a full-on Future at all, only a CountDownLatch, in which you could use addCallback instead of transform and count down the latch at the end of the callback.)
This approach may also simplify error handling.

Categories