Aggregate PropertyChanged events from the collection into one IObservable<EventPattern<PropertyChangedEventArgs>> - system.reactive

I have collection of INotifyPropertyChanged objects and would like to stream all PropertyChanged events into a single observable sequence for further processing.
Here is a code
IObservable<EventPattern<PropertyChangedEventArgs>> _allEvents = null;
// Items contains collection of item, which implements INotifyPropertyChanged
foreach (var item in Items)
{
var seq = Observable.FromEventPattern<PropertyChangedEventArgs>(item, "PropertyChanged");
if (_allEvents == null)
_allEvents = seq;
else
_allEvents.Merge(seq);
}
// subscribe to the aggregated observable sequence
if (_allEvents != null)
_allEvents.Subscribe(evt => Trace.WriteLine(" Property Changed -> " + evt.EventArgs.PropertyName));
A single Subscribe doesn't work here for some reason in the aggregated sequence.
Looks like I aggregated (using Reactive Extensions's Merge function) incorrectly. But, subscribe inside the loop works perfectly.
Can anybody assist me here, how to aggregate a many event streams into one with reactive extensions?
Thanks

Try this:
var _allEvents = Observable
.Merge(Items
.Select(item => Observable
.FromEventPattern<PropertyChangedEventArgs>(item, "PropertyChanged")));
_allEvents.Subscribe(evt => Trace.WriteLine(" Property Changed -> " + evt.EventArgs.PropertyName));
The reason your approach doesn't work is that you were calling IObservable<T> Observable.Merge<T>(this IObservable<T> first, IObservable<T> second). The return type of this is a resulting observable. I think you might have been thinking that Merge modified the Observable, but you can think of Observables as immutable (sort of). The way to get your approach to work would have been:
_allEvents = _allEvents.Merge(seq);
But... yuck. Don't do that.

Related

Compare List<String> to Flux<String> in non blocking way

How to compare List to Flux in non blocking way
Below the code in blocking way
public static void main(String[] args) {
List<String> all = List.of("A", "B", "C", "D");
Flux<String> valid = Flux.just("A", "D");
Map<Boolean, List<String>> collect = all.stream()
.collect(Collectors.groupingBy(t -> valid.collectList().block().contains(t)));
System.out.println(collect.get(Boolean.TRUE));
System.out.println(collect.get(Boolean.FALSE));
}
how to get it working in non-blocking way?
Above is an example of what i am trying to do in web application. I receive list of object which is List all. Then i query database which return Flux . Flux returned by database will be subset of List all. I need to prepare two lists. List of items which are present in Flux of valid and List of items which are not present in Flux of valid
EDIT:
I converted Flux to Mono and List to Mono,
public static void main(String[] args) {
Mono<List<String>> all = Mono.just(List.of("A", "B", "C", "D"));
Mono<List<String>> valid = Mono.just(List.of("A", "D"));
var exist = all.flatMap(a -> valid.map(v -> a.stream().collect(Collectors.groupingBy(v::contains))));
System.out.println(exist.block().get(Boolean.TRUE));
System.out.println(exist.block().get(Boolean.FALSE));
}
There is no straightforward way of achieve this in reactive programming without breaking some of its semantics.
If you reflect back on what reactive programming tris to achieve and your problem statement, you should notice that those won't play well that much together.
Reactive programming, as the name suggests, is about reacting to events which in your case would be valid items emitted from your datastore. In a typical situation, you should have been programming your statement to compute some assertions around the emitted valid items then emit these (or some other transformations downstream). Unfortunately, you won't be able to compute the all and valid items intersection and diversion without stopping at some point (otherwise how would you know that an item you assumed non-valid is not emitted at some point by the valid publisher).
Though, to achieve the desired behavior, you will lean on memory to buffer items then trigger your validations.
Retrieving valid items should be achievable using the filterWhen operator paired with the hasElement one:
Flux<String> validItems = Flux.fromIterable(all)
.filterWhen(valid::hasElement);
To retrieve the invalid items, you can collect all and validItems merged together then filter out elements that do appear more than once:
Flux<String> inValidItems = Flux.fromIterable(all)
.mergeWith(validItems)
.collectList()
.flatMapIterable(list -> list.stream().filter(item -> Collections.frequency(list, item) == 1).collect(Collectors.toList()));

Filter RxJava/ReactiveX Observable based on Observable condition

I need to filter a Stream of observable Values based on some condition which is modeled as Observable inside my Value.
class ValueObject {
BehaviorSubject<Boolean> condition = ...;
}
...
valueObjects.filter(valueObject -> condition).subscribe(valueObject -> ...);
My goal is to have the stream firing if a) a new Value was pushed or b) the condition for the filter changed.
(Bonus: do that same thing with lists of ValueObjects (Observable<List<ValueObject>>) and that ugly Object[]-combineLatest...)
Is there some kind of best practice for that problem? Thanks.

Multicast sticky observable with on subscribe/on dispose behavior

I'm trying to create an Observable with the following characteristics:
allows multiple concurrent and/or consecutive subscribers
emits the last emitted item to every new subscriber
does something when the first subscriber subscribes, and when the last subscription is disposed
A BehaviorSubject with doOnSubscribe/doOnDispose satisfies #1 and #2, but runs subscribe/dispose for every subscriber instead of only the first and last. Adding share satisfies #1 and #3, but only emits the last emitted item to the first concurrent subscriber.
I came up with a solution that seems to work but feels like an ugly hack:
AtomicInteger subs = new AtomicInteger();
Observable<String> test = BehaviorSubject.createDefault("foo")
.doOnSubscribe(x -> {
if(subs.getAndIncrement() == 0) {
// do something
}
})
.doOnDispose(() -> {
if(subs.decrementAndGet() == 0) {
// do something
}
});
Is there an existing operator or combination of operators that achieves the same effect?
Use the replay operator with argument 1 i.e.
yourObservable.replay(1)
Edit: You are right that replay will return a connectedObservable and that the refcount operator will make it behave like on Observable i.e.
yourObservable.replay(1).refcount()

How can I convert an observable to a maybe?

There are new convenience methods added to rxjava2 added to accomplish a similar thing.
toSingle() converts an Observable that emits a single item into a Single that emits that item
toObservable() converts a Single into an Observable that emits the item emitted by the Single and then completes
How do can I convert an Observable to a Maybe?
(source: http://reactivex.io/documentation/single.html)
You can't directly convert an Observable into a Maybe, because it wouldn't know what to emit in that context: is it the first element? the last? the product of some processing to the elements?
You can, however, decide on that and do what you want:
final Observable<Boolean> sourceBooleans = Observable.just(true, true, false);
final Maybe<Boolean> firstMaybe = sourceBooleans.firstElement();
final Maybe<Boolean> lastMaybe = sourceBooleans.lastElement();
final Maybe<Boolean> secondMaybe = sourceBooleans.elementAt(1);
final Observable<Integer> sourceNumbers = Observable.just(1, 2, 3, 4);
final Maybe<Integer> firstEven = sourceNumbers
.filter(it -> it % 2 == 0)
.firstElement()
You can see what methods return Maybe in the Observable implementation
Note that you can't go from Observable to Single directly either, without choosing what it should emit: there's no toSingle in the Observable class, but methods that return a Single instead (like first(), last(), etc.)

Handling errors in an observable sequence using Rx

Is there a way to have an observable sequence to resume execution with the next element in the sequence if an error occurs?
From this post it looks like you need to specify a new observable sequence in Catch() to resume execution, but what if you needed to just continue processing with the next element in the sequence instead? Is there a way to achieve this?
UPDATE:
The scenario is as follows:
I have a bunch of elements that I need to process. The processing is made up of a bunch of steps. I have
decomposed the steps into tasks that I would like to compose.
I followed the guidelines for ToObservable() posted here
to convert by tasks to an observables for composition.
so basically I'm doing somethng like so -
foreach(element in collection)
{
var result = from aResult in DoAAsync(element).ToObservable()
from bResult in DoBAsync(aResult).ToObservable()
from cResult in DoCAsync(bResult).ToObservable()
select cResult;
result.subscribe( register on next and error handlers here)
}
or I could something like this:
var result =
from element in collection.ToObservable()
from aResult in DoAAsync(element).ToObservable()
from bResult in DoBAsync(aResult).ToObservable()
from cResult in DoCAsync(bResult).ToObservable()
select cResult;
What is the best way here to continue processing other elements even if let's say the processing of
one of the elements throws an exception. I would like to be able to log the error and move on ideally.
Both James & Richard made some good points, but I don't think they have given you the best method for solving your problem.
James suggested using .Catch(Observable.Never<Unit>()). He was wrong when he said that "will ... allow the stream to continue" because once you hit an exception the stream must end - that is what Richard pointed out when he mentioned the contract between observers and observables.
Also, using Never in this way will cause your observables to never complete.
The short answer is that .Catch(Observable.Empty<Unit>()) is the correct way to change a sequence from one that ends with an error to one that ends with completion.
You've hit on the right idea of using SelectMany to process each value of the source collection so that you can catch each exception, but you're left with a couple of issues.
You're using tasks (TPL) just to turn a function call into an observable. This forces your observable to use task pool threads which means that the SelectMany statement will likely produce values in a non-deterministic order.
Also you hide the actual calls to process your data making refactoring and maintenance harder.
I think you're better off creating an extension method that allows the exceptions to be skipped. Here it is:
public static IObservable<R> SelectAndSkipOnException<T, R>(
this IObservable<T> source, Func<T, R> selector)
{
return
source
.Select(t =>
Observable.Start(() => selector(t)).Catch(Observable.Empty<R>()))
.Merge();
}
With this method you can now simply do this:
var result =
collection.ToObservable()
.SelectAndSkipOnException(t =>
{
var a = DoA(t);
var b = DoB(a);
var c = DoC(b);
return c;
});
This code is much simpler, but it hides the exception(s). If you want to hang on to the exceptions while letting your sequence continue then you need to do some extra funkiness. Adding a couple of overloads to the Materialize extension method works to keep the errors.
public static IObservable<Notification<R>> Materialize<T, R>(
this IObservable<T> source, Func<T, R> selector)
{
return source.Select(t => Notification.CreateOnNext(t)).Materialize(selector);
}
public static IObservable<Notification<R>> Materialize<T, R>(
this IObservable<Notification<T>> source, Func<T, R> selector)
{
Func<Notification<T>, Notification<R>> f = nt =>
{
if (nt.Kind == NotificationKind.OnNext)
{
try
{
return Notification.CreateOnNext<R>(selector(nt.Value));
}
catch (Exception ex)
{
ex.Data["Value"] = nt.Value;
ex.Data["Selector"] = selector;
return Notification.CreateOnError<R>(ex);
}
}
else
{
if (nt.Kind == NotificationKind.OnError)
{
return Notification.CreateOnError<R>(nt.Exception);
}
else
{
return Notification.CreateOnCompleted<R>();
}
}
};
return source.Select(nt => f(nt));
}
These methods allow you to write this:
var result =
collection
.ToObservable()
.Materialize(t =>
{
var a = DoA(t);
var b = DoB(a);
var c = DoC(b);
return c;
})
.Do(nt =>
{
if (nt.Kind == NotificationKind.OnError)
{
/* Process the error in `nt.Exception` */
}
})
.Where(nt => nt.Kind != NotificationKind.OnError)
.Dematerialize();
You can even chain these Materialize methods and use ex.Data["Value"] & ex.Data["Selector"] to get the value and selector function that threw the error out.
I hope this helps.
The contract between IObservable and IObserver is OnNext*(OnCompelted|OnError)? which is upheld by all operators, even if not by the source.
Your only choice is to re-subscribe to the source using Retry, but if the source returns the IObservable instance for every description you won't see any new values.
Could you supply more information on your scenario? Maybe there is another way of looking at it.
Edit: Based on your updated feedback, it sounds like you just need Catch:
var result =
from element in collection.ToObservable()
from aResult in DoAAsync(element).ToObservable().Log().Catch(Observable.Empty<TA>())
from bResult in DoBAsync(aResult).ToObservable().Log().Catch(Observable.Empty<TB>())
from cResult in DoCAsync(bResult).ToObservable().Log().Catch(Observable.Empty<TC>())
select cResult;
This replaces an error with an Empty which would not trigger the next sequence (since it uses SelectMany under the hood.