Emitting 2 observables, processing the result and then emitting another one - java

I have the following task to perform:
I need to emit 2 observables (obs1 & obs2) process their results and then call another observable (obs3) and process its results and if possible that while processing the results of obs3 have access to the results of obs1 and obs2.
This is my draft code which doesn't do the trick, how can I alter it.
public void executeFind(String session_id, long template_id, GameModelType game_model) {
Observable<RxMessage<byte[]>> userObs = context.getUser(session_id);
Observable<Game> gameObs = context.findGame(template_id, game_model, GameStateType.WAITING);
Observable.zip(userObs, gameObs, new Func2<RxMessage<byte[]>, Game, GameObject>() {
#Override
public GameObject call(RxMessage<byte[]> userRawReply, ActiveGame game) {
..
..
return context.updateGame(game.getGameData())
.subscribe(new Action1<GameObject>() {
#Override
public void call(GameObject updateReply) {
..
..
}
});
return userReply;
}
});
}
This doesn't really work - I can write a code which uses explicit calls to .flatMap\subscribe for each Observable but results in many nested calls which is obviously poor usage of the framework.
What is the right way to solve this??
Thank you!
EDIT:
I've found this solution to work, but I'm still wondering whether there is a "cleaner" way to achieve this:
public void executeFind(ReplyMessage<JsonObject> replyObj, String session_id, long template_id, GameModelType game_model) throws CommandException {
rx.Observable<GameObject> userObs = context.getUser(session_id);
rx.Observable<Game> gameObs = context.findGame(template_id, game_model, GameStateType.WAITING);
rx.Observable.zip(userObs, gameObs, new Func2<GameObject, Game, List<Object>>() {
#Override
public List<Object> call(GameObject userReply, Game game) {
User user = ...;
final List<Object> results = new ArrayList<Object>(3);
results.add(ErrorCodes.STATUS_OK);
results.add(user);
results.add(game);
context.updateGame(game.getGameData()).subscribe(new Action1<GameObject>() {
#Override
public void call(GameObject updateReply) {
...
}
});
return results;
}
}).subscribe(new Action1<List<Object>>() {
#Override
public void call(List<Object> results) {
int status = (int) results.get(0);
User user = (User) results.get(1);
Game game = (Game) results.get(2);
}
});
}

I would code this thing with the following idea in mind. May be map can be replace with flatMap if that's relevant for your use case. Also note I have only used Java 8 lambdas syntax, but for more readability I strongly advises you to have simple and well named methods (and use them with a method reference) for each of these functions/actions as it will raise understandability of the code (That's what we do on mockito, but everyone should do it in their own code base).
public void executeFind(ReplyMessage<JsonObject> reply_obj, String session_id, long template_id, GameModelType game_model) throws CommandException {
Observable<GameObject> userObs = context.getUser(session_id);
Observable<Game> gameObs = context.findGame(template_id, game_model, GameStateType.WAITING);
Observable.zip(userObs, gameObs, (userReply, game) -> {
User user = ...;
return GameOfUser.gameFound(game, user);
}).map(gou -> {
context.updateGame(gou.gameData()).susbcribe(...);
return gou;
}).subscribe(gou -> ...);
}

Related

Is there any way to get Akka Streams' groupedWithin to emit empty groups?

In the following code, tick emits a new object every three seconds. I'm trying to count the number of emitted objects every second using groupedWithin (which ignores empty groups). Is there any way in Akka Streams for the following code to print 0 in periods when tick does not emit any objects?
Source.tick(Duration.ZERO, Duration.ofSeconds(3), new Object())
.groupedWithin(Integer.MAX_VALUE, Duration.ofSeconds(1))
.map(List::size)
.runWith(Sink.foreach(e -> System.out.println(e)), materializer);
In other words, I'd like the output of this code to be this sequence: 1 0 0 1 0 0 1 ... (every second) instead of 1 1 1 ... (every three seconds).
EDIT: This is the best workaround I have come up with so far (using keepAlive to send some special objects if the upstream is idle):
Source.tick(Duration.ZERO, Duration.ofSeconds(3), new Object())
.keepAlive(Duration.ofSeconds(1), KeepAliveElement::new)
.groupedWithin(Integer.MAX_VALUE, Duration.ofSeconds(1))
.map(lst -> lst.stream().filter(e -> !(e instanceof KeepAliveElement)).collect(Collectors.toList()))
.map(List::size)
.runWith(Sink.foreach(e -> System.out.println(e)), materializer);
Is there any better way to do this?
I thought this would be of normal difficulty, I was wrong. One thing I wanted to do is to ensure that the flow counting items that pass through the stream does not keep a reference to each item it sees: if many items pass in the aggregation period, you will end up with an unnecessarily big list in memory (even if only for a second) and the performance penalty to add (many) items to it. The following solution, although complex, keeps only a counter.
NOTE: Although I tested the happy scenario, I cannot say this is battle-proven, so use with caution!
Based on Akka's GroupedWeightedWithin and the documentation here:
public class CountInPeriod<T> extends GraphStage<FlowShape<T, Integer>> {
public Inlet<T> in = Inlet.<T>create("CountInPeriod.in");
public Outlet<Integer> out = Outlet.<Integer>create("CountInPeriod.out");
private FlowShape<T, Integer> shape = FlowShape.of(in, out);
private Duration duration;
public CountInPeriod(Duration duration) {
this.duration = duration;
}
#Override
public GraphStageLogic createLogic(Attributes inheritedAttributes) {
return new TimerGraphStageLogic(shape) {
private int counter = 0;
private int bufferPushCounter = -1;
{
setHandler(in, new AbstractInHandler() {
#Override public void onPush() throws Exception, Exception {
grab(in);
counter++;
pull(in);
}
});
setHandler(out, new AbstractOutHandler() {
#Override public void onPull() throws Exception, Exception {
if (bufferPushCounter >= 0) {
push(out, bufferPushCounter);
bufferPushCounter = -1;
}
}
});
}
#Override
public void preStart() throws Exception, Exception {
scheduleWithFixedDelay(CountInPeriod.class, duration, duration);
pull(in);
}
#Override
public void onTimer(Object timerKey) throws Exception, Exception {
if (isAvailable(out)) emitCounter();
else bufferPush();
}
private void emitCounter() {
push(out, counter);
counter = 0;
bufferPushCounter = -1;
}
private void bufferPush() {
bufferPushCounter = counter;
counter = 0;
}
};
}
#Override
public FlowShape<T, Integer> shape() {
return shape;
}
}
Test code:
public class GroupTicked {
final static ActorSystem as = ActorSystem.create("as");
public static void main(String... args) throws Exception {
CompletionStage<Done> done = Source.tick(Duration.ZERO, Duration.ofSeconds(3), new Object())
.take(7) // to finish in finite time...
.via(new CountInPeriod<>(Duration.ofSeconds(1)))
.runWith(Sink.foreach(e -> System.out.println(System.currentTimeMillis() + " -> " + e)), as);
done.thenAccept(x -> as.terminate());
}
}

Java 8 - usage of Consumer's andThen

I have below POC to use Java 8 feature.
I want to update DB after accept method. Is it good to go with andThen()? When is this method called? Who calls it?
What is the basic use of andThen() method? Looking at the docs was confusing.
public class StockTest {
public static void main(String[] args) {
List<Trader> traders = new ArrayList<>();
Random random = new Random();
// Initializing trading a/c's.
for (int i = 0; i < 10; i++) {
Trader trader = new Trader((random.nextInt(100) + 1) * 3);
traders.add(trader);
}
// Display Trade accounts.
System.out.println("Before Bonus, Units are:");
for (Trader trader : traders) {
System.out.print(trader.getUnits() + "\t");
}
// Add bonus to each trader.
traders.forEach(new Consumer<Trader>() {
#Override
public void accept(Trader trader) {
trader.updateBonus(2);
}
#Override
public Consumer<Trader> andThen(Consumer<? super Trader> after)
{
System.out.println("In andThen");
return Consumer.super.andThen(after);
}
});
// Display Trade accounts after bonus applied..
System.out.println("\nAfter bonus:");
for (Trader trader : traders) {
System.out.print(trader.getUnits() + "\t");
}
}
}
class Trader {
private int units;
public Trader(int initialUnits) {
this.units = initialUnits;
}
public int getUnits() {
return units;
}
public void setUnits(int units) {
this.units = units;
}
public void updateBonus(int bonusUnits) {
this.units = this.units * bonusUnits;
}
}
Please help with some example or use cases to utilize this method
In short andThen is used to chain consumers, so the input will go to first and second consumer, lke below:
Consumer<Trader> consumer1 = new Consumer<Trader>() {
#Override
public void accept(Trader trader) {
trader.updateBonus(2);
}
};
Consumer<Trader> consumer2 = new Consumer<Trader>() {
#Override
public void accept(Trader trader) {
// do something
}
};
// Add bonus to each trader.
traders.forEach(consumer1.andThen(consumer2));
So here the Trader will be passed to consumer1, then to consumer2 and so on.
You don't have to implement this method, or override it. When it comes to Consumers, implement only the accept.
andThen method is a helper tool to join consumers. Instead of passing the input to all of them in a loop.
You use andThen when you want to chain the logic of two Consumers. consumer1.andThen(consumer2) first calls the accept method of consumer1 and then calls the accept method of consumer2.
Overriding the default implementation of andThen makes little sense and prevents you from using lambda expressions/method references.
andThen can be used to chain two Consumers:
traders.forEach(((Consumer<Trader>)(trader -> trader.updateBonus(2))).andThen(trader -> System.out.println("some more processing")));
Of course, in this example you can simply put the logic of the two Consumers in a single Consumer:
traders.forEach(trader -> {trader.updateBonus(2);
System.out.println("some more processing");});
It makes more sense to use andThen when you are chaining two existing Consumers:
Consumer<Trader> traderConsumer1 = trader -> trader.updateBonus(2);
Consumer<Trader> traderConsumer2 = trader -> System.out.println(trader);
traders.forEach(traderConsumer1.andThen(traderConsumer2));

Rx-Java: Creating a configurable Observable

I'm new to RxJava, and I am wondering how I can create a configurable Observable? Let's imagine I could write a DB-to-DB transfer like this:
srcDb.getObservable(Bean.class)
.sql(selectSql)
.params(selectParams)
.subscribe(
trgDb.getSubscriber(Bean.class)
.sql(insertSql)
);
I can already do that with the Subscriber, but how can I get some small configuration in the same fashion to the Observable itself?
There's 2 ways you can do that:
Option #1: have your own objects do the configuration, and then have an execute(), query() or toObservable() that switches domains:
srcDb
.find(Bean.class)
.sql(selectSql)
.params(selectParams)
.execute()
.subscribe(
trgDb.getSubscriber(Bean.class)
.sql(insertSql)
);
Option #2: use .compose() to re-use common operations:
srcDb
.getObservable(Bean.class)
.compose(addSQLParameters())
.subscribe(
trgDb.getSubscriber(Bean.class)
.sql(insertSql)
);
<T> Transformer<T,T> addSQLParameters() {
return obs -> obs.sql(selectSql).params(selectParams);
}
I would suggest you use option #1, as it allows much better management of your part of the code.
Maybe I found an acceptable way around this. It seems that what I need to do here is a double-binding outside of the Observable instantiation itself. E.g. I need a DbObservable and DbOnSubscribe pair which is counting on each other, something like this:
DbObservable class:
public class DbObservable<T> extends Observable<T> {
//Some parameter
private String sql;
protected DbObservable(DbOnSubscribe<T> onSub) {
super(onSub);
}
//Getter for DbOnSubscribe
public String getSql() {
return sql;
}
//Chain parameter modifier
public DbObservable<T> sql(String sql) {
this.sql = sql;
return this;
}
}
DbOnSubscribe class:
public class DbOnSubscribe<T> implements Observable.OnSubscribe<T> {
private DbObservable<T> dbObservable;
#Override
public void call(Subscriber<? super T> subscriber) {
String sql = dbObservable.getSql(); //Access SQL param
subscriber.onNext( (T) sql ); //Use subscriber
subscriber.onCompleted();
}
//Set back-reference
public void setDbObservable(DbObservable<T> dbObservable) {
this.dbObservable = dbObservable;
}
}
And finally our assumed DbConnector class:
public class DbConnector {
public DbObservable<String> getObservable() {
DbOnSubscribe<String> onSub = new DbOnSubscribe<String>();
DbObservable<String> obs = new DbObservable<>(onSub);
onSub.setDbObservable(obs);
return obs;
}
}
So when I try it out ...
public class DbObservableTest {
public static void main(String[] args) {
DbConnector srcDb = new DbConnector();
srcDb.getObservable()
.sql("some SQL")
.subscribe(System.out::println);
}
}
... it really works! It prints out the "some SQL".
Conclusion
If you want to be super-clean and don't mind one or 2 extra lines of code, go for a builder as proposed by Joel and Tassos Bassoukos.
If you're not afraid of a little bit more complicated code (which should be always encapsulated somewhere) and you really want those parameters to be inside your own Observable, you can try the double-binding way
Any more options?

How to process items emitted by an Observable with access to values from another?

I need to perform an async call_1, catch its Observable reply_1, then make another async call_2 and when processing its reply_2 I also need access to the reply_1.
I've tried something like:
public rx.Observable<Game> findGame(long templateId, GameModelType game_model, GameStateType state) {
rx.Observable<RxMessage<byte[]>> ebs = context.getGameTemplate(templateId);
return context.findGame(templateId, state) // findGame returns rx.Observable<RxMessage<byte[]>>
.flatMap(new Func1<RxMessage<byte[]>, rx.Observable<Game>>() {
#Override
public Observable<Game> call(RxMessage<byte[]> gameRawReply) {
Game game = null;
switch(game_model) {
case SINGLE: {
ebs.subscribe(new Action1<RxMessage<byte[]>>() {
#Override
public void call(RxMessage<byte[]> t1) {
game = singleGames.get(0);
}
});
}
}
return rx.Observable.from(game);
}
});
}
I'm still having problem compiling this method because of final issues of game.
Is this the right way to do work on this problem or there is a much natural way to accomplish what I'm trying to.
If I understand what you want to do correctly, I think the natural way to solve this would be zip:
You have two Observables that asynchronously emit their results, namely ebs and the return value of context.findGame(...).
You can combine their result by doing something like this:
public rx.Observable<Game> findGame(long templateId, GameModelType game_model, GameStateType state) {
rx.Observable<RxMessage<byte[]>> ebs = context.getGameTemplate(templateId);
rx.Observable<RxMessage<byte[]>> gameObs = context.findGame(templateId, state);
return Observable.zip(gameObs, ebs, new Func2<RxMessage<byte[]>, RxMessage<byte[]>, Game>() {
#Override
public Game call(RxMessage<byte[]> gameRawReply, RxMessage<byte[]> t1) {
Game game = null;
switch(game_model) {
case SINGLE: {
game = singleGames.get(0);
}
}
return game;
}
});
}
The Func2 - the third argument of zip - will be called when both of your source Observables have called their onNext. It will be used to combine the values they emit to a new value of type Game and this will be emitted to subscribers of the resulting Observable.
EDIT: Some more information...
Note that I changed the return of call() from Observable<Game> to just Game. Otherwise the result of zip would not have been an Observable<Game> but an Observable<Observable<Game>>. Unlike map and flatMap there is only zip in rx - no flatZip. But since you always want to emit exactly one game for each pair of input items (one from ebs, one from gameObs) that's not a problem in this case.
Also, the call() of the Func2 could now be further simplified to just:
#Override
public Game call(RxMessage<byte[]> gameRawReply, RxMessage<byte[]> t1) {
switch(game_model) {
case SINGLE: {
return singleGames.get(0);
}
}
}

How to return String in anonymous class for a method returning void

I'm bit confused. I have the following:
public static String showInputDialog() {
Form frm = new Form();
final Command cmd = new Command("Ok");
final TextField txt = new TextField("Enter the text", null, 1024, 0);
frm.addCommand(cmd);
frm.append(txt);
frm.setCommandListener(new CommandListener() {
public void commandAction(Command c, Displayable d) {
if (c == cmd) {
return txt.getString(); // Error !!
} else {
return null; // Error !!
}
}
});
}
As you can see, I want to return the input dialog string, while the anonymous class method should return void. How can I resolve this problem?
This does not work as you expected.
I see there are already some solutions, but I feel a bit more discussion about what is actually going on might be helpful.
When you call the frm.setCommandListener(new CommandListener() { ... }) the code presents the user with a dialog where she can type in some text and submit, but the code does not stop and wait until the user finishes.
Instead the code continues to execute - without yielding the result. Only after the user finished typing and submits, you get called back to process the result - which might happen much later, or not at all.
I guess you have some code calling this method like:
public void someMethod(int foo, String bar) {
[...]
String result = MyInputForm.showInputDialog();
// do something with the result
System.out.println("hey, got a result "+ result);
[...]
}
Instead you need to reorganize this. First write a helper class handling the result:
public static class MyCallBack {
public MyCallBack(... /* here pass in what you need to process the result*/) {
... remember necessary stuff in instance variables
}
public void processResult(String result) {
// do something with the result
System.out.println("hey, got a result "+ result);
[...]
}
}
then the calling side does just:
public void someMethod(int foo, String bar) {
[...]
MyInputForm.showInputDialog( new MyCallBack(... here pass in stuff ...) );
[...]
}
and the actual code has to be changed to:
public static String showInputDialog(final MyCallBack callback) {
Form frm = new Form();
final Command cmd = new Command("Ok");
final TextField txt = new TextField("Enter the text", null, 1024, 0);
frm.addCommand(cmd);
frm.append(txt);
frm.setCommandListener(new CommandListener() {
public void commandAction(Command c, Displayable d) {
if (c == cmd) {
return callback.processResult(txt.getString());
} else {
return; // or just omit the else part
}
}
});
}
Two issues:
this way of programming feels pretty backwards, but it is really the way it works.
what feels not right is that I need to define a second helper class aside of the CommandListener. That is really not good style. I hope it can be improved, but as I do not see the complete code (which would be too much information anyway), I have to leave it to you to improve the code and get rid of the clutter. While I feel you want to have a modular, reusable input dialog helper, this might not be the best approach; better define the Form,TextField and Command directly where you need the result and get that running. Make it reusable in a second step after you get it running.
You don't need to return it if you instead do something with the String or store it somewhere, for example:
static String result;
public String commandAction(Command c, Displayable d) {
if (c == cmd) {
result = txt.getString();
} else {
result = null;
}
}
Although you'll have threading issues to deal with.
Given that CommandListener is fixed, 2 possible options are
Use a class member variable in the outer class & assign to that variable instead
private static String myText;
...
public static String showInputDialog() {
...
frm.setCommandListener(new CommandListener() {
public void commandAction(Command c, Displayable d) {
if (c == cmd) {
myText = txt.getString();
} else {
myText = null;
}
}
});
}
or Create a concrete implementation of your CommandListener and set the return value as a property of the new implementation
I would have a look at making the method/variable in this snippet non-static...
You cant return the string because you dont know when the listener will be called.
You can do something with it once you have the string though.
public static void showInputDialog() {
StringHandler sh = new StringHandler();
frm.setCommandListener(new CommandListener() {
public void commandAction(Command c, Displayable d) {
if (c == cmd) {
sh.handle(txt.getString());
} else {
sh.handle(null);
}
}
});}
public class StringHandler {
public void handle(String s){
// Do something with that string.
}
}

Categories