JavaFX/Classes/ApiCall.java

176 lines
5.2 KiB
Java

package Classes;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.json.JSONException;
import org.json.JSONObject;
import Interfaces.Callback;
import Interfaces.DelayedCallback;
import Interfaces.Event;
import Interfaces.EventObserver;
import javafx.util.Pair;
public class ApiCall implements Runnable, EventObserver {
//Methode appelée une fois que la requete s'est terminé
private Callback callback;
//connection HTTP
private HttpURLConnection connection;
//méthode HTTP
private String method;
//est ce que cet appel d'API attend un évenement pour se lancer
private Boolean isDelayed = false;
//Methode appellée une fois l'évenement arrivé, il retourne la nouvelle URL et les nouveaux parametres POST
private DelayedCallback delayedCallback;
//ID et Type de l'évenement attendu
private String eventID;
private String eventType;
//objet contenant le thread de l'appel
private Thread thread;
//si une erreur surviens durant le delayedCallback, la boucle run doit tout arreter, cette variable sert a notifier run() de ça
private Boolean shouldStop = false;
public ApiCall(String URL, String method, Callback call) {
this.callback = call;
this.method = method;
try {
//création de la connection
URL url = new URL(URL);
this.connection = (HttpURLConnection) url.openConnection();
this.connection.setRequestMethod(method);
//si on fait une requete GET, il faut interdire l'envoie de donnée POST
if(method == "GET") {
this.connection.setDoOutput(false);
}else {
this.connection.setDoOutput(true);
}
} catch (IOException e) {
this.callback.onError();
}
}
public void addHeaders(HashMap<String,String> map) {
Iterator it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pair = (Map.Entry)it.next();
this.connection.setRequestProperty((String)pair.getKey(), (String)pair.getValue());
it.remove(); // évite les erreurs en cas de modification concurente
}
}
@Override
public void run() {
//si notre appel est delayed, on endort le thread
if(this.isDelayed) {
try {
//on doit se synchroniser avec le thread avant de l'endormir
synchronized(this.thread) {
this.thread.wait();
}
} catch (InterruptedException e) {
this.callback.onError();
return;
}
}
//si il y a eu une erreur durant le delayedallback, on stope le thread
if(this.shouldStop) {
return;
}
try {
//On envoie les paramètres POST si besoin
if(this.method != "GET") {
DataOutputStream wr = new DataOutputStream (connection.getOutputStream ());
//TODO: implémenter la gestion des parametres POST
wr.flush ();
wr.close ();
}
//on récupère la réponse de la requete
InputStream is = connection.getInputStream();
BufferedReader rd = new BufferedReader(new InputStreamReader(is));
String line;
StringBuffer response = new StringBuffer();
while((line = rd.readLine()) != null) {
response.append(line);
}
rd.close();
//transformation en objet JSON
try {
//raplce null values by empty strings
JSONObject json = new JSONObject(response.toString().replaceAll(":null,", ":\"\","));
this.callback.onSuccess(json);
}catch(JSONException e) {
this.callback.onError();
}
} catch (IOException e) {
this.callback.onError();
}
}
public void send() {
//send sert juste a lancer la boucle principale run()
this.thread = new Thread(this);
this.thread.start();
}
public void setAsDelayedCall(String eventID, String eventType, DelayedCallback call) {
//on enregistre tout ce dont on a besoin pour traiter l'évenement
this.isDelayed = true;
this.delayedCallback = call;
this.eventID = eventID;
this.eventType = eventType;
}
@Override
public void handleEvent(Event e) {
//si on est un appel delayed et que l'évenement est le bon, on lance le delayedCallback
if(this.isDelayed && e.getObjectId() == this.eventID && e.getEventType() == this.eventType) {
Pair<String,HashMap<String,String>> returned = this.delayedCallback.call();
if(this.method == "GET") {
try {
//on met a jour la connection HTTP avec la nouvelle URL en gardant l'ancienne méthode HTTP
HttpURLConnection newConnection = (HttpURLConnection) new URL(returned.getKey()).openConnection();
newConnection.setRequestMethod(this.connection.getRequestMethod());
newConnection.setDoOutput(this.connection.getDoOutput());
this.connection = newConnection;
//on a fini de mettre a jour la connection, le thread principal peut reprendre
synchronized(this.thread) {
this.thread.notify();
}
} catch (IOException e1) {
//une erreur est survenue, on stope tout
this.callback.onError();
this.shouldStop = true;
synchronized(this.thread) {
this.thread.notify();
}
}
}else {
//TODO: implémenter les param POST
}
}else {
this.callback.onError();
this.shouldStop = true;
synchronized(this.thread) {
this.thread.notify();
}
}
}
}