GWT- Asynchronous call delay - gwt

I have a problem with RPC call in GWT.
Below is an example code snippet:
I have four columns in my UI with effdate and enddate as column header.
The values are not displaying in order. The first column value is displaying in 3rd column.
most of the time the order changes. Displaying randomly.
I guess the RPC call to the server side method for each count is delayed.
and I found out by debugging the server side method, the effdate and end date that i am passing for first loop is executing 2nd or 3rd sometimes. It is shuffling.
Can any one help me with this. what changes i need to do in my code to get correct values displayed in UI.
Any idea on this?
count=4;
List finalList = new arrayList();
for(i=0;i<count;count++)
{
effdate= list.get(countincr);
enddate= list.get(countincr+1);
//call to server side method to fetch values from DB by passing effdate and end date as parameter.
grp.ratecalc(startdate,enddate,new AsyncCallback<List<grVo>>()
{
public void onfailure(throwable caught)
{
sys.out.print("failure");
}
public void onsuccess(List<grVo> result)
{
List grpList= new GrpVO();
rate = result.get(0).getrate();
rate1 = result.get(0).getrate1();
grpList.setrate();
grpList.setrate1();
setting values in bean for the remaining values in the result.
finalList.add(grpList);
if(finalList.size()== count)
{
//calling a method to populate the values
methoddisplay(finalList);
}
}
}
);
countincr+=2;
} //end of for loop`

You can use a map instead of your finallist to keep track of the request and response.
I have made some changes to your code.(Its incomplete. plz make necessary changes).
int count=4;
Map<Integer,Object> map = new HashMap<Integer, Object>();
for(int i=0;i<count;count++)
{ final int index=i;
effdate= list.get(countincr);
enddate= list.get(countincr+1);
grp.ratecalc(startdate,enddate,new AsyncCallback<List<grVo>>()
{
public void onfailure(throwable caught) {
sys.out.print("failure");
}
public void onsuccess(List<grVo> result){
List grpList= new GrpVO();
rate = result.get(0).getrate();
rate1 = result.get(0).getrate1();
grpList.setrate();
grpList.setrate1();
map.put(index, grpList);
//check all items are put on the map and populate values.
}
}
);
countincr+=2;
}
Here index is used to identify the requset and response.
All the response GrpVO objects are put into the map along with its index.
Finally you have to generate your final list from the map.
Hope this works.

Related

how to merge the response of webClient call after calling 5 times and save the complete response in DB

i have scenario like:
i have to check the table if entry is available in DB then if available i need to call the same external api n times using webclient, collect all the response and save them in DB. if entry is not available in DB call the old flow.
here is my implementation. need suggestions to improve it. without for-each
public Mono<List<ResponseObject>> getdata(String id, Req obj) {
return isEntryInDB(id) //checking the entry in DB
.flatMap(
x -> {
final List<Mono<ResponseObject>> responseList = new ArrayList<>();
IntStream.range(0, obj.getQuantity()) // quantity decides how many times api call t happen
.forEach(
i -> {
Mono<ResponseObject> responseMono =
webClientCall(
id,
req.getType())
.map(
res ->
MapperForMappingDataToDesriedFormat(res));
responseList.add(responseMono);
});
return saveToDb(responseList);
})
.switchIfEmpty(oldFlow(id, req)); //if DB entry is not there take this existing flow.
need some suggestions to improve it without using foreach.
I would avoid using IntStream and rather use native operator to reactor called Flux in this case.
You can replace, InsStream.range with Flux.range. Something like this:
return isEntryPresent("123")
.flatMapMany(s -> Flux.range(0, obj.getQuantity())
.flatMap(this::callApi))
.collectList()
.flatMap(this::saveToDb)
.switchIfEmpty(Mono.defer(() ->oldFlow(id, req)));
private Mono<Object> saveToDb(List<String> stringList){
return Mono.just("done");
}
private Mono<String> callApi(int id) {
return Mono.just("iterating" + id);
}
private Mono<String> isEntryPresent(String id) {
return Mono.just("string");
}

BehaviorSubject adding the same value

Hi I have a BehaviorSubject with a simple type int, I add the value 5 to it and then add another value 5. The stream listener sent me two events.
How to force check the values and not send an event if the value is equal to the last value.
Sample code:
class TestBloc {
TestBloc(){
testBehavior.stream.listen((event) {
print('Event value = $event');
});
addValueToStream();
addValueToStream();
}
final testBehavior = BehaviorSubject<int>();
void addValueToStream() {
testBehavior.add(5);
}
}
What you're looking for is distinct() method of BehaviorSubject().
Take a look at this from the documentation:
Skips data events if they are equal to the previous data event.
The returned stream provides the same events as this stream, except
that it never provides two consecutive data events that are equal.
That is, errors are passed through to the returned stream, and data
events are passed through if they are distinct from the most recently
emitted data event.
and here is how you implement it:
class TestBloc {
TestBloc() {
testBehavior.distinct((a, b) => a == b).listen((event) {
print('Event value = $event');
});
addValueToStream();
addValueToStream();
}
final testBehavior = BehaviorSubject<int>();
void addValueToStream() {
testBehavior.add(5);
}
}

How to do Async Http Call with Apache Beam (Java)?

Input PCollection is http requests, which is a bounded dataset. I want to make async http call (Java) in a ParDo , parse response and put results into output PCollection. My code is below. Getting exception as following.
I cound't figure out the reason. need a guide....
java.util.concurrent.CompletionException: java.lang.IllegalStateException: Can't add element ValueInGlobalWindow{value=streaming.mapserver.backfill.EnrichedPoint#2c59e, pane=PaneInfo.NO_FIRING} to committed bundle in PCollection Call Map Server With Rate Throttle/ParMultiDo(ProcessRequests).output [PCollection]
Code:
public class ProcessRequestsFn extends DoFn<PreparedRequest,EnrichedPoint> {
private static AsyncHttpClient _HttpClientAsync;
private static ExecutorService _ExecutorService;
static{
AsyncHttpClientConfig cg = config()
.setKeepAlive(true)
.setDisableHttpsEndpointIdentificationAlgorithm(true)
.setUseInsecureTrustManager(true)
.addRequestFilter(new RateLimitedThrottleRequestFilter(100,1000))
.build();
_HttpClientAsync = asyncHttpClient(cg);
_ExecutorService = Executors.newCachedThreadPool();
}
#DoFn.ProcessElement
public void processElement(ProcessContext c) {
PreparedRequest request = c.element();
if(request == null)
return;
_HttpClientAsync.prepareGet((request.getRequest()))
.execute()
.toCompletableFuture()
.thenApply(response -> { if(response.getStatusCode() == HttpStatusCodes.STATUS_CODE_OK){
return response.getResponseBody();
} return null; } )
.thenApply(responseBody->
{
List<EnrichedPoint> resList = new ArrayList<>();
/*some process logic here*/
System.out.printf("%d enriched points back\n", result.length());
}
return resList;
})
.thenAccept(resList -> {
for (EnrichedPoint enrichedPoint : resList) {
c.output(enrichedPoint);
}
})
.exceptionally(ex->{
System.out.println(ex);
return null;
});
}
}
The Scio library implements a DoFn which deals with asynchronous operations. The BaseAsyncDoFn might provide you the handling you need. Since you're dealing with CompletableFuture also take a look at the JavaAsyncDoFn.
Please note that you necessarily don't need to use the Scio library, but you can take the main idea of the BaseAsyncDoFn since it's independent of the rest of the Scio library.
The issue that your hitting is that your outputting outside the context of a processElement or finishBundle call.
You'll want to gather all your outputs in memory and output them eagerly during future processElement calls and at the end within finishBundle by blocking till all your calls finish.

RxJava: Merge multiple singles and complete after some have failed

I would like to merge two Single<MyData> such that if one of them fails but the other one succeeds then the error of the one that failed and the emission from the other one are reported, and then the resulting Single<MyData> (or Observable<MyData>) completes.
If both Single<MyData> fail then the result should also fail and also be marked as failed.
What I would like to have at the end is:
If both succeed then the emitted values and a producer marked as completed.
If one succeeds and the other fails, the emitted value, the thrown error and the producer marked as complete.
If all fail, the errors and the producer marked as failed.
It's like an 'OR' operation
This is not possible. There is only a single terminal event allowed. The contract for Single is success|error. If you need to receive a next event as well, you should consider to use Observable instead. The contract for Observable is next* complete|error, but you'll still not get a complete.
Observable.mergeDelayError(single1.toObservable(), single2.toObservable())
This can be accomplished with Single.create(SingleOnSubscribe). If your return type is Single<MyData> only one of the responses can be returned, but you could also modify this to instead return a Single<List<MyData>> or some other RxJava structure like Flowable<MyData> that supports multiple returns. In this example, the Single<MyData> returns whichever call returns last because that was the simplest to implement.
public Single<MyData> getCombinedSingle(List<Single<MyData>> singles) {
return Single.create(new SingleOnSubscribe<MyData> {
private boolean encounteredError = false;
private MyData myData;
#Override
public void subscribe(#NonNull Emitter<MyData> emitter) {
List<Disposable> disposables = new ArrayList<>();
Consumer<MyData> myDataConsumer = myData -> {
this.MyData = myData;
checkForFinish(emitter, disposables);
}
Consumer<Throwable> throwableConsumer = throwable -> {
throwable.printStackTrace();
encounteredError = true;
checkForFinish(emitter, disposables);
}
for (Single single: singles) {
disposables.put(single.subscribe(myDataConsumer, throwableConsumer);
}
}
private void checkForFinish(SingleEmitter<MyData> emitter, List<Disposable> disposables) {
if (disposables1.stream().allMatch(Disposable::isDisposed)) {
if (encounteredError) {
emitter.onError(new Throwable());
} else {
emitter.onSuccess(myData);
}
}
}
}
}
This could be modified to return a Throwable from the original Singles if needed.

GWT Async call execution order problem

I have a problem with a throw execution in GWT. So I want to show a simple String list in Client side located on "Server Side". Ok, I have in my Main class this atributes:
private final GreetingServiceAsync greetingService = Util.getInstance(); // This is like > typing GWT.create( GreetingService.class );
public ArrayList songs = new ArrayList();
and in my onModuleLoad() method I have a call to another private method that make the Async call to the Server class:
songs.addAll(getSongsList());
So my getSongsList method is as follow:
public ArrayList<String> getSongsList() {
final int defaultSize = 4;
final ArrayList<String> temp = new ArrayList<String>();
GWT.log("Enter in getSongsLists");
greetingService.greetSongMostPopular(defaultSize,
new AsyncCallback<ArrayList<String>>() {
public void onSuccess(ArrayList<String> result) {
GWT.log("Result is:" + result);
temp.addAll(result);
GWT.log("Case 1 TEMP= " + temp);
}
public void onFailure(Throwable caught) {
// throw new
// UnsupportedOperationException("Not supported yet.");
Window.alert("Error greeting data");
}
});
GWT.log("CASE 2 TEMP = " + temp);
return temp;
}
My problem is that in Case 1 I get
[INFO] [MainModule] - Case 1 TEMP= [Song 1, Song 2, Song 3, Song 4]
but in CASE 2 I get the ArrayList empty!!!
[INFO] [MainModule] - Case 1 TEMP= []
What am I doing wrong?
Thanks in advance!
The call to greetSongsMostPopular is asynchronous. This means that the call begins and the code continues directly to the next line of code, in your case GWT.log("CASE 2 TEMP..."). When this line of code is executed, the results are not yet available and you end up with an empty list.
Later, in the background, onSuccess is called with the results. At this point you should call a function to process the results. You can use a pattern similar to the AsyncCallback class, with an onSuccess and onFailure so the caller of this code can handle both cases, or you can just have the caller pass in their own AsyncCallback instance which would make it a thin wrapper around your greetSongsMostPopular RPC function.
This is normal : the callback is called when your server send the answer but the greetSongMostPopular return imediatly.
The call is asynchronous.
All code must be done in the callback (call a function)
Here is the exact process :
greetingService.greetSongMostPopular is called
temp is empty
the second GWT.log is called : temp is always empty
the getSongsList method return : temp is always empty
the server send the answer to the callback : temp is filled
You are not doing anything wrong. This is expected since you are not dealing with synchronous calls. So the case 2 is only invoked after the asynchronous call returns from the server side.