Parallel url get calls using Java spring RestTemplate - java

I have a list of urls and I want to hit them all in parallel and combine the result into a final Java object using Java spring RestTemplate. I'm able to achieve it buy accessing the urls in sequence, but due to performance concerns, I want to achieve them same in parallel. Looking forward to hearing your suggestions

You can use threads to perform parallel jobs.
First, make a result data class to handle the responses of your URLs
public class URLResult {
public String url;
public String response;
public Date responseTime;
// Add fields whatever you need
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getResponse() {
return response;
}
public void setResponse(String response) {
this.response = response;
}
public Date getResponseTime() {
return responseTime;
}
public void setResponseTime(Date responseTime) {
this.responseTime = responseTime;
}
}
Then use it in your threads :
public List<URLResult> list = new ArrayList<>();
public synchronized void addToList(URLResult result) {
list.add(result);
}
public void hitUrl(String url) {
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
URLResult result = new URLResult();
//here, connect to your url, get the result then set your URLResult fields
addToList(result);
}
});
thread.start();
}
At the end of the process, you will have a "list" of your results.

Related

How to create a polymorphic structure that can work for both success and error responses in Java?

I'm working on a class that will get a list of strings and process them asynchronously using CompletableFutures. Each string is processed by invoking another class that will perform several operations and return a response or throw an exception if there is an error.
I would like to aggregate the responses that I get, whether they have a valid response or an exception and return them as a list to the caller. I would like the caller to be able to expect a list of SomeResponse and be able to interpret them using polymorphism.
However, I'm stuck on determining if this can be done using polymorphism at all, given that the fields for the success and error response are completely different. I have added some pseudo code below on one alternative I have thought of. Basically have SomeResponse be an interface with an isSuccess method. This will allow the caller to know if it's an error or not. However, the caller would still have to cast it to the correct implementation in order to get the value or the error. Is there a better way to approach this? My requirement is being able to return both a success and error response for each given request in the list. If there is an exception, we don't want to abort the entire operation.
public MyProcessorClass {
private final SomeOtherClass someOtherClass;
public List<SomeResponse> process(List<String> requestList) {
return requestList.stream().map(this::procesRequest)
.collectors(Collect.tolist()):
}
private processRequest(String request) {
CompletableFuture completableFuture = CompletableFuture
.supplyAsync(() => {
return new SomeSuccessResponse(someOtherClass.execute(request));
})
.exceptionally(e -> {
return new SomeErrorResponse(e.getCause);
});
return completableFuture.get();
}
}
public interface SomeResponse {
boolean isSuccess();
}
public class SomeSuccessResponse implements SomeResponse {
private final String value;
#Getter
private final boolean success;
public SomeSuccessResponse(String value) {
this.value = value;
this.success = true;
}
}
public class SomeErrorResponse implements SomeResponse {
private final Throwable error;
#Getter
private final boolean success;
public SomeErrorResponse(Throwable error) {
this.error = error;
this.success = false;
}
}
What you want is the visitor pattern https://en.wikipedia.org/wiki/Visitor_pattern
public class Main {
interface IResponse {
void acceptHandler(IResponseHandler handler);
}
static class ResponseA implements IResponse {
#Override
public void acceptHandler(IResponseHandler handler) {
handler.handle(this);
}
}
static class ResponseB implements IResponse {
#Override
public void acceptHandler(IResponseHandler handler) {
handler.handle(this);
}
}
public interface IResponseHandler {
void handle(ResponseA response);
void handle(ResponseB responseB);
}
public static void main(String[] args) {
final IResponseHandler handler = new IResponseHandler() {
#Override
public void handle(ResponseA response) {
System.out.println("Handle ResponseA");
}
#Override
public void handle(ResponseB responseB) {
System.out.println("Handle ResponseB");
}
};
final IResponse someResponse = new ResponseA();
someResponse.acceptHandler(handler);
}
}

Expected BEGIN_ARRAY but was BEGIN_OBJECT in Retrofit

I am new to android programming and can anyone help me or point out why its giving me this error
I want to fetch some data from the server such as under the Hardware json and get the names and status, but when i call api its shows me this.
Change the line
public void onResponse(Call<List<ObjectList>> call, Response<List<ObjectList>> response) {
to
public void onResponse(Call<List<ObjectList>> call, Response<ObjectList> response) {
As per your code, you are expecting response as List. But Actual response is object. So, you need to generate model class based on your response and set in code for output.
Your Model should be like :
public class Application {
ArrayList<Object> hardware = new ArrayList<Object>();
Header HeaderObject;
ArrayList<Object> software = new ArrayList<Object>();
// Getter Methods
public Header getHeader() {
return HeaderObject;
}
// Setter Methods
public void setHeader( Header headerObject ) {
this.HeaderObject = headerObject;
}
}
public class Header {
Stamp StampObject;
private String frame_id;
private float seq;
// Getter Methods
public Stamp getStamp() {
return StampObject;
}
public String getFrame_id() {
return frame_id;
}
public float getSeq() {
return seq;
}
// Setter Methods
public void setStamp( Stamp stampObject ) {
this.StampObject = stampObject;
}
public void setFrame_id( String frame_id ) {
this.frame_id = frame_id;
}
public void setSeq( float seq ) {
this.seq = seq;
}
}
public class Stamp {
private float secs;
private float nsecs;
// Getter Methods
public float getSecs() {
return secs;
}
public float getNsecs() {
return nsecs;
}
// Setter Methods
public void setSecs( float secs ) {
this.secs = secs;
}
public void setNsecs( float nsecs ) {
this.nsecs = nsecs;
}
}
Then change below line :
public void onResponse(Call<List<ObjectList>> call, Response<Application> response) {
Change this:
#GET("system_monitor")
Call<List<ObjectList>> getHardware();
to
#GET("system_monitor")
Call<ObjectList> getHardware();
Your response return an object instead of array.
Instead of
#GET("system_monitor")
Call<List<ObjectList>> getHardware();
use
#GET("system_monitor")
Call<ObjectList> getHardware();
And then use it like below:
Call<ObjectList> call = webRequestAPI.getHardware();
call.enqueue(new Callback<ObjectList>() {
#Override
public void onResponse(Call<ObjectList> call, Response<ObjectList> response) {
if (!response.isSuccessful()) {
textViewHardwareName.setText("Code: " + response.code());
return;
}
ObjectList system_monitor = response.body();
...
}
#Override
public void onFailure(Call<ObjectList> call, Throwable t) {
textViewHardwareName.setText(t.getMessage());
}
});
The best thing for your scenario hardware and Software are as objects , which have two property
1.Name 2. Object status.
So I recommend you to create a class name as System and put there these two variables so finally your class looks like :
Class System
{
String object_name;
boolean object_status;
}
and your getter setter .
And update your model class like this
#SerializedName("hardware")
#Expose
public List<System> hardware;
#SerializedName("software")
#Expose
public List<System> software;
and change your retrofit response holder as.
public void onResponse(Call<List<ObjectList>> call, Response<ObjectList>
response) {

Retrofit 2 - RxJava : Unable to invoke no-args constructor for retrofit2.Call<RemoteDataObjectModel>

I am creating an Android app and the objective is to display a list of Pokemon which can be found using the PokeApi at https://pokeapi.co/
I have two instances, one where it works without RxJava2 and one where it doesn't work with RxJava 2. For both instances I use Retrofit 2.
For when it does not work when I include RxJava2 the error that I recieve is
D/thrown: java.lang.RuntimeException: Unable to invoke no-args constructor for retrofit2.Call<za.co.lbnkosi.discoveryassesment.domain.model.RemoteDataObjectModel>. Registering an InstanceCreator with Gson for this type may fix this problem.
At this point I have looked through a lot of Stackoverflow questions similar to this one and most if not all of them mention deserialization which for me has not worked this far.
I would like to know what the problem is or what I am doing wrong and how I can fix this issue. Below I have included the relevant code
public interface PokeApi {
//Ignore
#GET("pokemon")
Call<RemoteDataObjectModel> getPokemonList(#Query("limit") int limit, #Query("offset") int offset);
#GET("pokemon")
Observable<Call<RemoteDataObjectModel>> getPokemonList2(#Query("limit") int limit, #Query("offset") int offset);
}
public class RemoteDataObjectModel {
#SerializedName("results")
private ArrayList<RemoteDataModel> results;
public ArrayList<RemoteDataModel> getResults() {
return results;
}
public void setResults(ArrayList<RemoteDataModel> results) {
this.results = results;
}
}
public class RemoteDataModel {
#SerializedName("number")
private int number;
#SerializedName("name")
private String name;
#SerializedName("url")
private String url;
public int getNumber() {
String[] urlItems = url.split("/");
return Integer.parseInt(urlItems[urlItems.length -1]);
}
public void setNumber(int number) {
this.number = number;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}
public class RetrofitComponent {
private static RetrofitComponent INSTANCE;
private PokeApi pokeApi;
private RetrofitComponent(){
OkHttpClient okHttpClient = new OkHttpClient().newBuilder()
.connectTimeout(60, TimeUnit.SECONDS)
.readTimeout(60, TimeUnit.SECONDS)
.writeTimeout(60, TimeUnit.SECONDS)
.build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://pokeapi.co/api/v2/")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(okHttpClient)
.build();
pokeApi = retrofit.create(PokeApi.class);
}
public static RetrofitComponent getInstance() {
if (INSTANCE == null) {
INSTANCE = new RetrofitComponent();
}
return INSTANCE;
}
public Observable<Call<RemoteDataObjectModel>> getPokemonList(int limit, int offest) {
return pokeApi.getPokemonList2(30,0);
}
}
private void getPokemonList(PokeApiDataSource.PokemonListCallback callback) {
RetrofitComponent.getInstance()
.getPokemonList(100,0)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Call<RemoteDataObjectModel>>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(Call<RemoteDataObjectModel> remoteDataObjectModelCall) {
Log.d("","");
remoteDataObjectModelCall.enqueue(new Callback<RemoteDataObjectModel>() {
#Override
public void onResponse(#NotNull Call<RemoteDataObjectModel> call, #NotNull Response<RemoteDataObjectModel> response) {
loading = true;
RemoteDataObjectModel pokeApiObjects = response.body();
_arrayList = Objects.requireNonNull(pokeApiObjects).getResults();
callback.pokemonListSuccess();
}
#Override
public void onFailure(#NotNull Call<RemoteDataObjectModel> call, #NotNull Throwable t) {
loading = true;
Log.e(TAG, " onFailure: " + t.getMessage());
}
});
}
#Override
public void onError(Throwable e) {
Log.d("thrown", e.toString());
}
#Override
public void onComplete() {
}
});
}
I think Call is the class from Retrofit. It provides a callback function to get the response asynchronously. But since you are going to use RxJava, the nature of Rxjava is already asynchronous. You may not need to get the response as Call. Instead, please try this
public interface PokeApi {
// If you need to get the response body + headers ...
#GET("pokemon")
Observable<Response<RemoteDataObjectModel>> getPokemonList2(#Query("limit") int limit, #Query("offset") int offset);
// If you only need body
#GET("pokemon")
Observable<RemoteDataObjectModel> getPokemonList2(#Query("limit") int limit, #Query("offset") int offset);
// Or the better way, the result from API is only return once. So, Single is more suitable in this case
#GET("pokemon")
Single<RemoteDataObjectModel> getPokemonList2(#Query("limit") int limit, #Query("offset") int offset);
}

How to run a method inside an object with different threads simultaneously?

My setup is as described. What I want to accomplish is have the aMethod in each of my implemented classes to run in parallel. I have looked into using Futures and Runnable and I am unsure how to proceed with either process.
My first thought was try to return a Future<Boolean> instead of a regular boolean, but I am unsure as to how would I associate the result with the name that it was initially called with.
The reason why I want aMethod to run in parallel/asynchronous is because aMethod might have a http request. If there is a request, I do not want to wait for a reply to continue. I want it to do that in a separate thread and continue on to the next method.
With a lot of http requests, aClass.doMethod() takes a while to accomplish. I want to run them in parallel so I don't have to wait for each http request before continuing.
Anyone have tips on how to accomplish this?
import java.util.ArrayList;
import java.util.List;
//Strategy.java
public interface Strategy {
boolean aMethod();
}
//AStrategy.java
public class AStrategy implements Strategy {
#Override
public boolean aMethod() {
// Do a couple http requests
return true;
}
}
//BStrategy.java
public class BStrategy implements Strategy {
#Override
public boolean aMethod() {
// Do some other requests
return true;
}
}
//SomeClass.java
public class SomeClass {
String name;
Strategy aStrategy;
public SomeClass(String name, Strategy strategy) {
this.name = name;
this.aStrategy = strategy;
}
public boolean doMethod() {
return aStrategy.aMethod();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
//Just a regular pojo
//ResultsClass.java
public class ResultsClass {
String name;
boolean result;
public ResultsClass(String name, boolean result) {
this.name = name;
this.result = result;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isResult() {
return result;
}
public void setResult(boolean result) {
this.result = result;
}
}
public class AClass {
public static void main(String args[]) {
List<SomeClass> classes = new ArrayList<>();
classes.add(new SomeClass("Class 1", new AStrategy()));
classes.add(new SomeClass("Class 2", new BStrategy()));
List<ResultsClass> results = new ArrayList<>();
classes.forEach(aClass -> results.add(new ResultsClass(aClass.getName(), aClass.doMethod())));
}
}
The simplest way for you to do this is probably to use a ThreadPoolExecutor, make your strategy classes runnable or wrap them in runnables, and submit them to the executor. Once all are submitted, you can block on the futures until the threads complete and you can retrieve the results from the futures.

Determine When LoopJ has concluded all background connections

Im trying to determine when LoopJ has finished all background thread http calls. So that i can then display the results of an array that is populated based on the results of my onSuccess methods.
First off, I have a String[] of file names. I'm then looping through the array and creating loopj connections like such.
ArrayList<String> files_to_update = new ArrayList<String>(file_names.length);
AsyncHttpClient client = new AsyncHttpClient();
for (final String file_name : file_names) {
client.get(BASE_URL + file_name, new AsyncHttpResponseHandler() {
public void onStart() {
Local_Last_Modified_Date = preferences.getString(file_name, "");
}
public void onSuccess(int statusCode, Header[] headers, byte[] response) {
Server_Last_Modified_Date = headers[3].getValue();
}
#Override
public void onFinish() {
if (!Local_Last_Modified_Date.trim().equalsIgnoreCase(Server_Last_Modified_Date.trim())) {
files_to_update.add(file_name);
}
}
});
}
What i'm doing here is comparing 2 date strings, The first Local_Last_Modified_Date is pulled from a preference file and the 2nd is determined by the last-modified date in the header. and then compared in the OnFinish(). This determines if the file needs to be update because the server file is newer than the preference date. Now! i know this is not the best way for comparing dates, however it will work interm for what i'm trying to do.
The issue i'm having is determining that all of the background http calls from loopj have completed so that i can now display the results of array list in a list dialog or whatever ui element i choose. I've tried looping through the arraylist, but because the loopj / http connections are background threads, the loop gets executed prior to the completion of all of the connection and therefore displays an empty or not populated fully array.
Is there a if conditional that i can write to determine if loopj has not finished executing all of the connection and when it has then execute my ui code?
The following code should address your problem:
Class file: UploadRunner.java
public class UploadRunner extends AsyncHttpResponseHandler implements Runnable {
private final AsyncHttpClient client;
private final ArrayList<String> filesList;
private final int filesCount;
private final Handler handler;
private String baseURI;
private boolean isFired;
private int filesCounter;
// Use in case you have no AHC ready beforehand.
public UploadRunner(ArrayList<String> filesList) {
this(new AsyncHttpClient(), filesList);
}
public UploadRunner(
AsyncHttpClient client,
ArrayList<String> filesList,
Handler handler
) {
assert null != client;
assert null != filesList;
assert null != handler;
this.client = client;
this.filesList = filesList;
this.handler = handler;
this.baseURI = "";
this.filesCount = filesList.size();
this.filesCounter = 0;
}
public String getBaseURI() {
return baseURI;
}
public void setBaseURI(String uri) {
baseURI = uri;
}
#Override
public void run() {
// Request to download all files.
for(final String file : filesList) {
client.get(baseURI + file, this);
}
}
#Override
public void onSuccess(int statusCode, Header[] headers, byte[] response) {
// This shouldn't happen really...
if(isFired) {
return;
}
// One more file downloaded.
filesCounter++;
// If all files downloaded, fire the callback.
if(filesCounter >= filesCount) {
isFired = true;
handler.onFinish(getLastModificationDate(headers));
}
}
private String getLastModificationDate(Header[] headers) {
// Simple mechanism to get the date, but maybe a proper one
// should be implemented.
return headers[3].getValue();
}
public static interface Handler {
public void onFinish(String lastModificationDate);
// TODO: Add onError() maybe?
}
}
In this case, you encapsulate the uploading mechanism in one place, plus expose just an interface for calling back a handler when all files are uploaded.
Typical use case:
// TODO: This typically should run in a different thread.
public class MyTask implements UploadRunner.Handler, Runnable {
private final static BASE_URI = "http://www.example.com/";
private final AsyncHttpClient client = new AsyncHttpClient();
private final ArrayList<String> filesList = new ArrayList<>();
#Override
public void run() {
filesList.add("1.png");
filesList.add("2.png");
filesList.add("3.png");
filesList.add("4.png");
filesList.add("5.png");
// Create a new runner.
UploadRunner ur = new UploadRunner(client, filesList, this);
// Set base URI.
ur.setBaseURI(BASE_URI);
// Spring the runner to life.
ur.run();
}
#Override
public void onFinish(String lastModificationDate) {
// All files downloaded, and last modification date is supplied to us.
}
}

Categories