ok, so i'm trying to implement rxJava2 with retrofit2. The goal is to make a call only once and broadcast the results to different classes. For exmaple: I have a list of geofences in my backend. I need that list in my MapFragment to dispaly them on the map, but I also need that data to set the pendingIntent service for the actual trigger.
I tried following this awnser, but I get all sorts of errors:
Single Observable with Multiple Subscribers
The current situation is as follow:
GeofenceRetrofitEndpoint:
public interface GeofenceEndpoint {
#GET("geofences")
Observable<List<Point>> getGeofenceAreas();
}
GeofenceDAO:
public class GeofenceDao {
#Inject
Retrofit retrofit;
private final GeofenceEndpoint geofenceEndpoint;
public GeofenceDao(){
InjectHelper.getRootComponent().inject(this);
geofenceEndpoint = retrofit.create(GeofenceEndpoint.class);
}
public Observable<List<Point>> loadGeofences() {
return geofenceEndpoint.getGeofenceAreas().subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.share();
}
}
MapFragment / any other class where I need the results
private void getGeofences() {
new GeofenceDao().loadGeofences().subscribe(this::handleGeoResponse, this::handleGeoError);
}
private void handleGeoResponse(List<Point> points) {
// handle response
}
private void handleGeoError(Throwable error) {
// handle error
}
What am I doing wrong, because when I call new GeofenceDao().loadGeofences().subscribe(this::handleGeoResponse, this::handleGeoError); it's doing a separate call each time. Thx
new GeofenceDao().loadGeofences() returns two different instances of the Observable. share() only applies to the instance, not the the method. If you want to actually share the observable, you'd have to subscribe to the same instance. You could share the it with a (static) member loadGeofences.
private void getGeofences() {
if (loadGeofences == null) {
loadGeofences = new GeofenceDao().loadGeofences();
}
loadGeofences.subscribe(this::handleGeoResponse, this::handleGeoError);
}
But be careful not to leak the Obserable.
Maybe it's not answering your question directly, however I'd like to suggest you a little different approach:
Create a BehaviourSubject in your GeofenceDao and subscribe your retrofit request to this subject. This subject will act as a bridge between your clients and api, by doing this you will achieve:
Response cache - handy for screen rotations
Replaying response for every interested observer
Subscription between clients and subject doesn't rely on subscription between subject and API so you can break one without breaking another
Related
I kind of hit the wall with DeferredResult. We have really old pattern where we have Interfaces that contains all rest annotations and implementation of them. Also other clients (microservices) uses those interfaces to map communicate with each others (they are importing them as a module and make proxy rest calls). But there is a problem somebody hacked a bit this approach and we had two different declarations one for clients without DeferredResult and one with it on implementation side. When we tried to reflect changes for clients there is a problem a lot of them needs to change a way of communication. So i've been thinking of removing DeferredResult from method signature and just use result.
My question is how to do it in non blocking way in Spring?
Let's say i have this kind of code
#Component
public class ExampleSO implements ExampleSOController {
private final MyServiceSO myServiceSO;
public ExampleSO(MyServiceSO myServiceSO) {
this.myServiceSO = myServiceSO;
}
#Override
public DeferredResult<SOResponse> justForTest() {
CompletableFuture<SOResponse> responseCompletableFuture = myServiceSO.doSomething();
DeferredResult<SOResponse> result = new DeferredResult<>(1000L);
responseCompletableFuture.whenCompleteAsync(
(res, throwable) -> result.setResult(res)
);
return result;
}
}
where:
#RestController
public interface ExampleSOController {
#PostMapping()
DeferredResult<SOResponse> justForTest();
}
and:
#Component
public class MyServiceSO {
public CompletableFuture<SOResponse> doSomething() {
CompletableFuture<SOResponse> completableFuture = new CompletableFuture<>();
Executors.newCachedThreadPool().submit(() -> {
Thread.sleep(500);
completableFuture.complete(new SOResponse());
return null;
});
return completableFuture;
}
}
How could i achieve something like this:
#RestController
public interface ExampleSOController {
#PostMapping()
SOResponse justForTest();
}
Without removing async benefits ?
I am trying to implement a content-based router in my Akka actor system and according to this document the ConsistentHashingRouter is the way to go. After reading through its official docs, I still find myself confused as to how to use this built-in hashing router. I think that’s because the router itself is hash/key-based, and the example the Akka doc author chose to use was a scenario involving key-value based caches…so I can’t tell which keys are used by the cache and which ones are used by the router!
Let’s take a simple example. Say we have the following messages:
interface Notification {
// Doesn’t matter what’s here.
}
// Will eventually be emailed to someone.
class EmailNotification implements Notification {
// Doesn’t matter what’s here.
}
// Will eventually be sent to some XMPP client and on to a chatroom somewhere.
class ChatOpsNotifications implements Notification {
// Doesn’t matter what’s here.
}
etc. In theory we might have 20 Notification impls. I’d like to be able to send a Notification to an actor/router at runtime and have that router route it to the correct NotificationPubisher:
interface NotificationPublisher<NOTIFICATION implements Notification> {
void send(NOTIFICATION notification)
}
class EmailNotificationPublisher extends UntypedActor implements NotificationPubisher<EmailNotification> {
#Override
void onReceive(Object message) {
if(message instanceof EmailNotification) {
send(message as EmailNotification)
}
}
#Override
void send(EmailNotification notification) {
// Use Java Mail, etc.
}
}
class ChatOpsNotificationPublisher extends UntypedActor implements NotificationPubisher<ChatOpsNotification> {
#Override
void onReceive(Object message) {
if(message instanceof ChatOpsNotification) {
send(message as ChatOpsNotification)
}
}
#Override
void send(ChatOpsNotification notification) {
// Use XMPP/Jabber client, etc.
}
}
Now I could do this routing myself, manually:
class ReinventingTheWheelRouter extends UntypedActor {
// Inject these via constructor
ActorRef emailNotificationPublisher
ActorRef chatOpsNotificationPublisher
// ...20 more publishers, etc.
#Override
void onReceive(Object message) {
ActorRef publisher
if(message instanceof EmailNotification) {
publisher = emailNotificationPublisher
} else if(message instanceof ChatOpsNotification) {
publisher = chatOpsNotificationPublisher
} else if(...) { ... } // 20 more publishers, etc.
publisher.tell(message, self)
}
}
Or I could use the Akka-Camel module to defined a Camel-based router and send Notifications off to the Camel router, but it seems that Akka aready has this built-in solution, so why not use it? I just cant figure out how to translate the Cache example from those Akka docs to my Notification example here. What’s the purpose of the “key” in the ConsistentHashingRouter? What would the code look like to make this work?
Of course I would appreciate any answer that helps me solve this, but would greatly prefer Java-based code snippets if at all possible. Scala looks like hieroglyphics to me.
I agree that a Custom Router is more appropriate than ConsistentHashingRouter. After reading the docs on custom routers, it seems I would:
Create a GroupBase impl and send messages to it directly (notificationGroup.tell(notification, self)); then
The GroupBase impl, say, NotificationGroup would provide a Router instance that was injected with my custom RoutingLogic impl
When NotificationGroup receives a message, it executes my custom RoutingLogic#select method which determines which Routee (I presume some kind of an actor?) to send the message to
If this is correct (and please correct me if I’m wrong), then the routing selection magic happens here:
class MessageBasedRoutingLogic implements RoutingLogic {
#Override
Routee select(Object message, IndexedSeq<Routee> candidates) {
// How can I query the Routee interface and deterine whether the message at-hand is in fact
// appropriate to be routed to the candidate?
//
// For instance I'd like to say "If message is an instance of
// an EmailNotification, send it to EmailNotificationPublisher."
//
// How do I do this here?!?
if(message instanceof EmailNotification) {
// Need to find the candidate/Routee that is
// the EmailNotificationPublisher, but how?!?
}
}
}
But as you can see I have a few mental implementation hurdles to cross. The Routee interface doesn’t really give me anything I can intelligently use to decide whether a particular Routee (candidate) is correct for the message at hand.
So I ask: (1) How can I map messages to Routees (effectively performing the route selection/logic)? (2) How do I add my publishers as routees in the first place? And (3) Do my NotificationPublisher impls still need to extend UntypedActor or should they now implement Routee?
Here is a simple little A/B router in Scala. I hope this helps even though you wanted a Java based answer. First the routing logic:
class ABRoutingLogic(a:ActorRef, b:ActorRef) extends RoutingLogic{
val aRoutee = ActorRefRoutee(a)
val bRoutee = ActorRefRoutee(b)
def select(msg:Any, routees:immutable.IndexedSeq[Routee]):Routee = {
msg match{
case "A" => aRoutee
case _ => bRoutee
}
}
}
The key here is that I am passing in my a and b actor refs in the constructor and then those are the ones I am routing to in the select method. Then, a Group for this logic:
case class ABRoutingGroup(a:ActorRef, b:ActorRef) extends Group {
val paths = List(a.path.toString, b.path.toString)
override def createRouter(system: ActorSystem): Router =
new Router(new ABRoutingLogic(a, b))
val routerDispatcher: String = Dispatchers.DefaultDispatcherId
}
Same thing here, I am making the actors I want to route to available via the constructor. Now a simple actor class to act as a and b:
class PrintingActor(letter:String) extends Actor{
def receive = {
case msg => println(s"I am $letter and I received letter $msg")
}
}
I will create two instances of this, each with a different letter assignment so we can verify that the right ones are getting the right messages per the routing logic. Lastly, some test code:
object RoutingTest extends App{
val system = ActorSystem()
val a = system.actorOf(Props(classOf[PrintingActor], "A"))
val b = system.actorOf(Props(classOf[PrintingActor], "B"))
val router = system.actorOf(Props.empty.withRouter(ABRoutingGroup(a,b)))
router ! "A"
router ! "B"
}
If you ran this, you would see:
I am A and I received letter A
I am B and I received letter B
It's a very simple example, but one that shows one way to do what you want to do. I hope you can bridge this code into Java and use it to solve your problem.
Our application is getting complex, it has mainly 3 flow and have to process based on one of the 3 type. Many of these functionalities overlap each other.
So currently code is fully of if-else statements, it is all messed up and not organised. How to make a pattern so that 3 flows are clearly separated from each other but making use of power of re-usability.
Please provide some thoughts, this is a MVC application, where we need to produce and consume web servicees using jaxb technology.
May be you can view the application as a single object as input on which different strategies needs to be implemented based on runtime value.
You did not specify what your if-else statements are doing. Say they filtering depending on some value.
If I understand your question correctly, you want to look at Factory Pattern.
This is a clean approach, easy to maintain and produces readable code. Adding or removing a Filter is also easy, Just remove the class and remove it from FilterFactory hashmap.
Create an Interface : Filter
public interface Filter {
void Filter();
}
Create a Factory which returns correct Filter according to your value. Instead of your if-else now you can just use the following :
Filter filter = FilterFactory.getFilter(value);
filter.filter();
One common way to write FilterFactory is using a HashMap inside it.
public class FilterFactory{
static HashMap<Integer, Filter> filterMap;
static{
filterMap = new HashMap<>();
filterMap.put(0,new Filter0());
...
}
// this function will change depending on your needs
public Filter getFilter(int value){
return filterMap.get(value);
}
}
Create your three(in your case) Filters like this: (With meaningful names though)
public class Filter0 implements Filter {
public void filter(){
//do something
}
}
NOTE: As you want to reuse some methods, create a FilterUtility class and make all your filters extend this class so that you can use all the functions without rewriting them.
Your question is very broad and almost impossible to answer without some description or overview of the structure of your application. However, I've been in a similar situation and this is the approach I took:
Replace conditions with Polymorphism where possible
it has mainly 3 flow and have to process based on this one of the 3
type. Many of these functionalities overlap each other.
You say your project has 3 main flows and that much of the code overlaps each other. This sounds to me like a strategy pattern:
You declare an interface that defines the tasks performed by a Flow.
public interface Flow{
public Data getData();
public Error validateData();
public void saveData();
public Error gotoNextStep();
}
You create an abstract class that provides implementation that is common to all 3 flows. (methods in this abstract class don't have to be final, but you definitely want to consider it carefully.)
public abstract class AbstractFlow{
private FlowManager flowManager
public AbstractFlow(FlowManager fm){
flowManager = fm;
}
public final void saveData(){
Data data = getData();
saveDataAsXMl(data);
}
public final Error gotoNextStep(){
Error error = validateData();
if(error != null){
return error;
}
saveData();
fm.gotoNextStep();
return null;
}
}
Finally, you create 3 concrete classes that extend from the abstract class and define concrete implementation for the given flow.
public class BankDetailsFlow extends AbstractFlow{
public BankDetailsData getData(){
BankDetailsData data = new BankDetailsData();
data.setSwiftCode(/*get swift code somehow*/);
return data;
}
public Error validateData(){
BankDetailsData data = getData();
return validate(data);
}
public void onFormSubmitted(){
Error error = gotoNextStep();
if(error != null){
handleError(error);
}
}
}
Lets take example, suppose you have model say "Data" [which has some attributes and getters,setters, optional methods].In context of Mobile application ,in particular Android application there can be two modes Off-line or On-line. If device is connected to network , data is sent to network else stored to local database of device.
In procedural way someone can , define two models as OnlineData,OfflineData and write code as[The code is not exact ,its just like pseudo code ]:
if(Connection.isConnected()){
OnlineData ond=new OnlineData();
ond.save();//save is called which stores data on server using HTTP.
}
else{
OfflineData ofd=new Onlinedata();
ofd.save();//save is called which stores data in local database
}
A good approach to implement this is using OOPS principles :
Program to interface not Implementation
Lets see How to DO THIS.
I am just writing code snippets that will be more effectively represent what I mean.The snippets are as follows:
public interface Model {
long save();//save method
//other methods .....
}
public class OnlineData extends Model {
//attributes
public long save(){
//on-line implementation of save method for Data model
}
//implementation of other methods.
}
public class OfflineData extends Model {
//attributes
public long save(){
//off-line implementation of save method for Data model
}
//implementation of other methods.
}
public class ObjectFactory{
public static Model getDataObject(){
if(Connection.isConnected())
return new OnlineData();
else
return new OfflineData();
}
}
and Here is code that your client class should use:
public class ClientClass{
public void someMethod(){
Model model=ObjectFactory.getDataObject();
model.save();// here polymorphism plays role...
}
}
Also this follows:
Single Responsibility Principle [SRP]
because On-line and Off-line are two different responsibilities which we can be able to integrate in Single save() using if-else statement.
After loong time I find opensource rule engine frameworks like "drools" is a great alternative to fit my requirement.
I am starting to embrace reactive programming a bit more, and I'm trying to apply it to my typical business problems. One pattern I often design with is database-driven classes. I have some defined unit class like ActionProfile whose instances are managed by an ActionProfileManager, which creates the instances off a database table and stores them in a Map<Integer,ActionProfile> where Integer is the actionProfileId key. The ActionProfileManager may clear and re-import the data periodically, and notify all dependencies to re-pull from its map.
public final class ActionProfileManager {
private volatile ImmutableMap<Integer,ActionProfile> actionProfiles;
private ActionProfileManager() {
this.actionProfiles = importFromDb();
}
public void refresh() {
this.actionProfiles = importFromDb();
notifyEventBus();
}
//called by clients on their construction or when notifyEventBus is called
public ActionProfile forKey(int actionProfileId) {
return actionProfiles.get(actionProfiles);
}
private ImmutableMap<Integer,ActionProfile> importFromDb() {
return ImmutableMap.of(); //import data here
}
private void notifyEventBus() {
//notify event through EventBus here
}
}
However, if I want this to be more reactive creating the map would kind of break the monad. One approach I could do is make the Map itself an Observable, and return a monad that looks up a specific key for the client. However the intermediate imperative operations may not be ideal, especially if I start using the rxjava-jdbc down the road. But the hashmap may help lookup performance significantly in intensive cases.
public final class ActionProfileManager {
private final BehaviorSubject<ImmutableMap<Integer,ActionProfile>> actionProfiles;
private ActionProfileManager() {
this.actionProfiles = BehaviorSubject.create(importFromDb());
}
public void refresh() {
actionProfiles.onNext(importFromDb());
}
public Observable<ActionProfile> forKey(int actionProfileId) {
return actionProfiles.map(m -> m.get(actionProfileId));
}
private ImmutableMap<Integer,ActionProfile> importFromDb() {
return ImmutableMap.of(); //import data here
}
}
Therefore, the most reactive approach to me seems to be just pushing everything from the database on each refresh through an Observable<ActionProfile> and filtering for the last matching ID for the client.
public final class ActionProfileManager {
private final ReplaySubject<ActionProfile> actionProfiles;
private ActionProfileManager() {
this.actionProfiles = ReplaySubject.create();
importFromDb();
}
public void refresh() {
importFromDb();
}
public Observable<ActionProfile> forKey(int actionProfileId) {
return actionProfiles.filter(m -> m.getActionProfileID() == actionProfileId).last();
}
private void importFromDb() {
// call onNext() on actionProfiles and pass each new ActionProfile coming from database
}
}
Is this the optimal approach? What about old data causing memory leaks and not being GC'd? Is it more practical to maintain the map and make it observable?
What is the most optimal reactive approach above to data driven classes? Or is there a better way I have not discovered?
Using BehaviorSubject is the right thing to do here if you don't care about earlier values.
Note most post discouraging Subjects were written in the early days of Rx.NET and is mostly quoted over and over again without much thought. I attribute this to the possibility that such authors didn't really understand how Subjects work or run into some problems with them and just declared they shouldn't be used.
I think Subjects are a great way to multicast events (coming from a single thread usually) where you control or you are the source of the events and the event dispatching is somewhat 'global' (such as listening to mouse move events).
Right now I am exploring some options for an android learning project.
I am trying to communicate with my rails api (also a learning project).
After doing some research, I think I have settled on a scheme that uses retrofit and otto.
What I end up with is this.
When I want to make a call to my rails server (in this case to do a signup) I do this in the activity.
mBus.post(new SignupRequestEvent(new UserRequestParams(mName,mEmail,mPassword,mPasswordConfirmation )));
and then in the same activity I have this.
#Subscribe
public void onSignupCompleted(SignupCompletedEvent event) {
System.out.println(String.format("in onSignupCompleted, got token = %s ", event.getParams().getToken()));
}
The problem here is that, as it stands, every api request type and it corresponding response type would be a unique event type and require it's own class, which seems like a lot of boiler plate type of code.
For example to handle sign in and sign out I would need these two classes:
public class SignupRequestEvent {
protected UserRequestParams mSignupParams;
public SignupRequestEvent(UserRequestParams signupParams) {
mSignupParams = signupParams;
}
public UserRequestParams getParams() {
return mSignupParams;
}
}
public class SignupCompletedEvent {
private SignupCompletedParams mSignupCompletedParams;
public SignupCompletedParams getParams() {
return mSignupCompletedParams;
}
public SignupCompletedEvent(SignupCompletedParams signupCompletedParams) {
mSignupCompletedParams = signupCompletedParams;
}
}
And I think most of the event classes would be pretty much identical.
I am thinking I should just have 2 events for api calls , one for requests and one for responses, but then each method that receives an api response event would need to check if it is a response to the desired request.
This option would mean something like this:
ApiRequestEvent apiRequestEvent = new ApiRequestEvent();
apiRequestEvent.setAction("SIGNUP");
apiRequestEvent.setParameters(new UserRequestParams(mName,mEmail,mPassword,mPasswordConfirmation ));
mBus.post(apiRequestEvent);
and then to handle the response something like this:
#Subscribe
public void onSignupCompleted(ApiResponseAvailable event) {
if (event.getResponseTo != "SIGNUP") return;
System.out.println(String.format("in onSignupCompleted, got token = %s ", event.getParams().getToken()));
Maybe there is a way to use generics?
Can someone explain how to effectively use an event bus when there are a set of events that can be grouped together like this?
You're overthinking it - just go ahead and create a message object for each event.