how to store handler result into JsonArray vertx? - java

I am facing a problem,I can't store the handler result into Json Array.Every time the array is empty . I tried to use Future but it still the same problem, here is my code :
static void getCaraReferTypeDocBin(RoutingContext routingContext){
String ids = routingContext.request().getParam("ids");
logger.debug(ids);
String[] idsArray = ids.split(",");
JsonArray caraRefTypeDocBin = new JsonArray();
for (int i = 0; i <idsArray.length ; i++) {
GET.getCaraTypeDocBin(Integer.parseInt(idsArray[i]), res->{
if (res.succeeded()){
logger.debug(res.result());
caraRefTypeDocBin.add(res.result());
}else{
logger.debug(res.cause().getMessage());
}
});
}
logger.debug(caraRefTypeDocBin);
}
this is getCaraReferTypeDocBin implementation :
public static void getCaraTypeDocBin(int id ,Handler<AsyncResult<JsonArray>> resultHandler) {
JsonArray pIn = new JsonArray();
pIn.add(new JsonObject().put("pos", 2).put("type", OracleTypes.NUMBER).put("val", id));
JsonArray pOut = new JsonArray().add(new JsonObject().put("pos", 1).put("type", OracleTypes.CURSOR));
DB.cursor(SQL.LIST_CARA_TYPE_DOC_BIN,pIn,pOut, res -> {
if (res.succeeded()) {
try {
resultHandler.handle(Future.succeededFuture(res.result().getJsonArray("1")));
}catch (Exception e){
logger.error(e);
resultHandler.handle(Future.failedFuture(Error.ERROR_OCCURED.toString()));
}
} else {
resultHandler.handle(Future.failedFuture(res.cause().getMessage()));
}
});
}

In async systems api with futures should be written something like this:
private Future<String> loadFromDb() {
Future<String> f = Future.future();
//some internal loading from db
String result = "fromDb";
//when loading completes, pass it to future result
f.complete(result);
return f;
}
And how it uses:
private void handleSo(RoutingContext routingContext) {
loadFromDb()
.map(new Function<String, JsonArray>() {
#Override
public JsonArray apply(String fromDb) {
//map to json
return new JsonArray(...);
}
})
.setHandler(
new Handler<AsyncResult<JsonArray>>() {
#Override
public void handle(AsyncResult<JsonArray> result) {
routingContext.response().end(result.result().toString());
}
}
);
}
You are using futures wrong. You example simple and you haven't async chains (where result calculates based on previous result etc), so instead futures, you can simple use callback:
private void loadFromDb(Handler<String> handler) {
String result = "fromDb";
handler.handle(result);
}
private void handleSo(RoutingContext routingContext) {
loadFromDb(new Handler<String>() {
#Override
public void handle(String fromDb) {
routingContext.response().end(new JsonArray(...).toString());
}
});
}
Upd You need collect results from multiple async calls doc. Don't know how to implement it with you callback style api. But with futures it's not problem:
private void handleSo(RoutingContext routingContext) {
List<Future> futures = new ArrayList<>();
for (int i = 0; i < 10; i++) {
//make 10 async calls
futures.add(loadFromDb()
.map(new Function<String, JsonObject>() {
#Override
public JsonObject apply(String fromDb) {
return new JsonObject().put("data", fromDb);
}
}));
}
CompositeFuture.all(futures)
.map(new Function<CompositeFuture, JsonArray>() {
#Override
public JsonArray apply(CompositeFuture compositeFuture) {
JsonArray array = new JsonArray();
List<JsonObject> jsons = compositeFuture.result().list();
jsons.forEach(jsonObject -> array.add(jsonObject));
return array;
}
})
.setHandler(new Handler<AsyncResult<JsonArray>>() {
#Override
public void handle(AsyncResult<JsonArray> res) {
routingContext.response().end(res.result().toString());
}
});
}

GET.getCaraTypeDocBin() runs asynchronously, right? And I assume there's something time-consuming in there like hitting a remote API? So the loop will run in milliseconds, kicking off all the requests, and then the "logger.debugs" will happen, and only then will the callbacks start to do caraRefTypeDocBin.add(res.result());
If I'm right, you should see the results logged before the empty array.

Related

RxJava not displaying the data

I am new in RXjava. I have impliment it in my project but it is not getting the data and didnot display it. what is the problem here?
My viewModel
public LiveData<Resource<List<Item>>> makeApiCallTopArticles() {
final MutableLiveData<Resource<List<Item>>> mediumObjectsList = new MutableLiveData<>();
mediumObjectsList.setValue(Resource.loading());
APIService apiService = RetroInstant.getRetroMediumClient().create(APIService.class);
Observable<CnnResponse> observable = apiService.getNewsObjectsList("http://rss.cnn.com/rss/cnn_topstories.rss",
"", "25");
Observer<CnnResponse> observer = new Observer<CnnResponse>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(CnnResponse value) {
List<Item> articles = new ArrayList<>();
assert value != null;
List<Item> responce = value.getItems();
for (int i = 0; i < Objects.requireNonNull(responce).size(); i ++) {
if (!Objects.equals(Objects.requireNonNull(responce.get(i).getEnclosure()).getLink(), null) && !Objects.equals(responce.get(i).getTitle(), "")) {
articles.add(responce.get(i));
}
}
mediumObjectsList.postValue(Resource.success(articles));
}
#Override
public void onError(Throwable e) {
}
#Override
public void onComplete() {
}
};
observable.subscribe(observer);
return mediumObjectsList;
}
ViewModel before I added RXjava
public LiveData<Resource<List<Item>>> makeApiCallTopArticles() {
final MutableLiveData<Resource<List<Item>>> mediumObjectsList = new MutableLiveData<>();
mediumObjectsList.setValue(Resource.loading());
APIService apiService = RetroInstant.getRetroMediumClient().create(APIService.class);
Call<CnnResponse> call = apiService.getNewsObjectsList("http://rss.cnn.com/rss/cnn_topstories.rss",
"", "25");
call.enqueue(new Callback<CnnResponse>() {
#Override
public void onResponse(#NotNull Call<CnnResponse> call, #NotNull Response<CnnResponse> response) {
List<Item> articles = new ArrayList<>();
assert response.body() != null;
List<Item> responce = response.body().getItems();
for (int i = 0; i < Objects.requireNonNull(responce).size(); i ++) {
if (!Objects.equals(Objects.requireNonNull(responce.get(i).getEnclosure()).getLink(), null) && !Objects.equals(responce.get(i).getTitle(), "")) {
articles.add(responce.get(i));
}
}
mediumObjectsList.postValue(Resource.success(articles));
}
#Override
public void onFailure(#NotNull Call<CnnResponse> call, #NotNull Throwable t) {
mediumObjectsList.setValue(Resource.error(t.getMessage() != null ? t.getMessage() : "Unknown Error"));
}
});
return mediumObjectsList;
}
.......................................................................................................................................................................................
Try to add logs to: onNext and onError method. Just to understand that you really receive a response or maybe you have some errors during the request. If you receive an error that can be a reason.
When you're using Rx you should use schedulers to avoid perform long term operation on the main thread. replace you subscription with:
observable.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(observer);
Try this,
observable
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(observer);

How to Access the Callable Task's input parameter inside thenAccept Method?

I have the following methods to invoke some logic in a non-blocking way.
public void runParallelFunctions(Callable<Map<String, String>> invokerTask) {
Supplier<Map<String, String>> taskSupplier = () -> {
try {
Thread.sleep(4000);
return invokerTask.call();
} catch (Exception e) {
System.out.println(e);
}
return new HashMap<>();
};
for (int i = 0; i < 5; i++) {
CompletableFuture.supplyAsync(taskSupplier::get, executorService)
.thenAccept(this::printResultsFromParallelInvocations);
}
System.out.println("Doing other work....");
}
private void printResultsFromParallelInvocations(Map<String, String> result) {
result.forEach((key, value) -> System.out.println(key + ": " + value));
}
Below is the Callable I'm passing to the runParallelFunctions method above.
public Callable<Map<String, String>> createLambdaInvokerTask(final String payload) {
return () -> invokeLambda(payload);
}
How can I access the payload parameter of createLambdaInvokerTask method in my printResultsFromParallelInvocations method? I need to concatenate the payload parameter to the result and print it. Any advice would be much appreciated.

How to use Observable zip with rxjava2 to get multiple responses back?

I have a java android app with I am using retrofit/rxjava2 to make multiple requests to my api. I want to wait until all the requests have completed then return the responses. So far I am able to create the requests but I can not get any responses. The code only does the first request.
I used this tutorial, https://github.com/fakefacebook/Retrofit-2-with-Rxjava-multiple-request. But it still doesn't work....
public static void checkDB(List<String> list) {
if (list.isEmpty()) {
//no tags to check
} else {
System.out.println("list is not empty");
MyAPIendpoint apiService = RetrofitAPI.getClient().create(MyAPIendpoint.class);
List<Observable<Bmwvehiclemain2>> requests = new ArrayList<>();
for (String t : list) {
requests.add(apiService.getVehByRfidtag(t));
}
Observable.zip(requests, new Function<Object[], List<Bmwvehiclemain2>>() {
#Override
public List<Bmwvehiclemain2> apply(Object[] objects) throws Exception {
List<Bmwvehiclemain2> newList = new ArrayList<>();
for (Object response : objects) {
newList.add((Bmwvehiclemain2) response);
}
return newList;
}
}).subscribe(
new Consumer<List<Bmwvehiclemain2>>() {
#Override
public void accept(List<Bmwvehiclemain2> newList) throws Exception {
}
},
new Consumer<Throwable>() {
#Override
public void accept(Throwable e) throws Exception {
}
});
}
}
It will only do the first request.

data structures in java to make changes apply from one process to other synchronously

I am trying to make two methods generator and consumer to run synchronously.I have tried queue but unable to achieve.
I am using the below code
#Override
protected List<ConfigIssue> init() {
client = new RtmClientBuilder(endpoint, appkey)
.setListener(new RtmClientAdapter() {
})
.build();
SubscriptionAdapter listener = new SubscriptionAdapter() {
#Override
public void onSubscriptionData(SubscriptionData data) {
for (AnyJson json : data.getMessages()) {
queue.add(json);
}
}
};
client.createSubscription(channel, SubscriptionMode.SIMPLE, listener);
client.start();
return super.init();
}
#Override
public String produce(String lastSourceOffset, int maxBatchSize, BatchMaker batchMaker) throws StageException {
long nextSourceOffset = 0;
if (lastSourceOffset != null) {
nextSourceOffset = Long.parseLong(lastSourceOffset);
}
if (messageQueue.size() != 0) {
for (AnyJson json : queue) {
Record record = getContext().createRecord("some-id::" + nextSourceOffset);
Map<String, Field> map = new HashMap<>();
map.put("fieldName", Field.create(json.toString()));
record.set(Field.create(map));
batchMaker.addRecord(record);
++nextSourceOffset;
messageQueue.remove();
}
}
return String.valueOf(nextSourceOffset);
}
I am trying to Sync both init method and produce method.Since init method start first and produce method start later they are not in sync.Can it be achieved by multi threading?How?

Play Test - Data persistence issues - POSTed data is not available when using GET

I'm working on a Play 2.0 based RESTful API implementation and when I'm trying to run the test cases (CRUD operations), I see the POSTed request content (Successful 201 response) is not available when I do a GET operation in subsequent test case.
Please take a look at my JUnit test class -
public class TagTest {
public static FakeApplication app;
private static String AUTH_HEADER = "Authorization";
private static String AUTH_VALUE = "Basic a25paadsfdfasdfdsfasdmeSQxMjM=";
private static int tagId = 0;
private static Map<String, String> postDataMap = new HashMap<String, String>();
private static Map<String, String> updateDataMap = new HashMap<String, String>();
private static String searchText = null;
#BeforeClass
public static void setUpBeforeClass() {
// Set up new FakeApplication before running any tests
app = Helpers.fakeApplication();
Helpers.start(app);
postDataMap.put("text", "Created");
updateDataMap.put("text", "Updated");
searchText = "Date"; // case insensitive substring pattern for "Updated"
}
#Test
public void createTagTest() {
app = Helpers.fakeApplication();
running(fakeApplication(), new Runnable() {
public void run() {
JsonNode json = Json.toJson(postDataMap);
FakeRequest request=new FakeRequest().withJsonBody(json);
Result result = callAction(controllers.routes.ref.Application.createTag(),request.withHeader(TagTest.AUTH_HEADER, TagTest.AUTH_VALUE));
Map<String, String> headerMap = Helpers.headers(result);
String location = headerMap.get(Helpers.LOCATION);
String tagIdStr = location.replace("/tags/","");
try {
tagId = Integer.parseInt(tagIdStr);
assertThat(status(result)).isEqualTo(Helpers.CREATED);
System.out.println("Tag Id : "+tagId+" Location : "+headerMap.get(Helpers.LOCATION)); // Here I'm getting resource URI from API which means it is successful run
} catch (NumberFormatException e) {
System.out.println("Inside NumberFormatException");
e.printStackTrace();
assertThat(0).isEqualTo(1);
}
System.out.println("createTagTest is successful");
}
});
}
#Test
public void getTagTest() {
app = Helpers.fakeApplication();
running(fakeApplication(), new Runnable() {
public void run() {
FakeRequest request = new FakeRequest();
Result result = callAction(controllers.routes.ref.Application.getTag(tagId), request.withHeader(TagTest.AUTH_HEADER, TagTest.AUTH_VALUE));
String content = contentAsString(result);
if(content.length()==0) {
assertThat(status(result)).isEqualTo(Helpers.NO_CONTENT);
} else {
assertThat(status(result)).isEqualTo(Helpers.OK);
}
System.out.println("getTagTest is successful");
}
});
}
#Test
public void updateTagTest() {
app = Helpers.fakeApplication();
running(fakeApplication(), new Runnable(){
public void run() {
JsonNode json = Json.toJson(updateDataMap);
FakeRequest request = new FakeRequest().withJsonBody(json);
Result result = callAction(controllers.routes.ref.Application.updateTag(tagId),
request.withHeader(TagTest.AUTH_HEADER, TagTest.AUTH_VALUE));
assertThat(status(result)).isEqualTo(Helpers.OK);
System.out.println("updateTagTest is successful");
}
});
}
#Test
public void getAllTagsTest() {
app = Helpers.fakeApplication();
running(fakeApplication(), new Runnable() {
public void run() {
FakeRequest request = new FakeRequest();
Result result = callAction(controllers.routes.ref.Application.getAllTags(null), request.withHeader(TagTest.AUTH_HEADER, TagTest.AUTH_VALUE));
String content = contentAsString(result);
System.out.println(content);
if(content.length()==0) {
System.out.println("No content");
assertThat(status(result)).isEqualTo(Helpers.NO_CONTENT);
} else {
System.out.println("Content");
assertThat(status(result)).isEqualTo(Helpers.OK);
}
System.out.println("getAllTagsTest is successful");
}
});
}
#Test
public void getTagsByTextTest() {
app = Helpers.fakeApplication();
running(fakeApplication(), new Runnable() {
public void run() {
FakeRequest request = new FakeRequest();
Result result = callAction(controllers.routes.ref.Application.getAllTags(searchText), request.withHeader(TagTest.AUTH_HEADER, TagTest.AUTH_VALUE));
String content = contentAsString(result);
if(content.length()==0) {
assertThat(status(result)).isEqualTo(Helpers.NO_CONTENT);
} else {
assertThat(status(result)).isEqualTo(Helpers.OK);
}
System.out.println("getAllTagsByTextTest is successful");
}
});
}
#Test
public void deleteTagTest() {
app = Helpers.fakeApplication();
running(fakeApplication(), new Runnable() {
public void run() {
FakeRequest request = new FakeRequest();
Result result = callAction(controllers.routes.ref.Application.deleteTag(tagId), request.withHeader(TagTest.AUTH_HEADER, TagTest.AUTH_VALUE));
assertThat(status(result)).isEqualTo(Helpers.OK);
System.out.println("deleteTagTest is successful");
}
});
}
#AfterClass
public static void tearDownAfterClass() {
// Stop FakeApplication after all tests complete
Helpers.stop(app);
}
}
When I run the test, Tag is created but it was not picked up in the subsequent test when trying to do GET /tags/1 and resulted in 204 No content.
Please throw some light what could be the reason behind this. Another observation is, it worked yesterday and all of a sudden this issue has come into picture.
Great help if someone can help me resolve this issue.
JUnit does not support an ordered sequence of test methods. That's a feature--not a bug. Tests should be independent. As a result, you can't guarantee that getTagTest comes after createTagTest. Sometimes it will; sometimes it won't.
The individual operations should have their own test fixtures with the appropriate preconditions defined with #BeforeClass.
If you insist on a defined order, then use dependsOnMethods in TestNG.

Categories