diff --git a/src/it/reyboz/bustorino/backend/FiveTAPIFetcher.java b/src/it/reyboz/bustorino/backend/FiveTAPIFetcher.java
index 3d36871..5b8baf5 100644
--- a/src/it/reyboz/bustorino/backend/FiveTAPIFetcher.java
+++ b/src/it/reyboz/bustorino/backend/FiveTAPIFetcher.java
@@ -1,428 +1,392 @@
/*
BusTO - Backend components
Copyright (C) 2018 Fabio Mazza
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
package it.reyboz.bustorino.backend;
import android.support.annotation.Nullable;
import android.util.Log;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
public class FiveTAPIFetcher implements ArrivalsFetcher{
- private static final String SECRET_KEY="759C97DC7D115966C30FD9169BB200D9";
private static final String DEBUG_NAME = "FiveTAPIFetcher";
+ private final Map defaultHeaders = getDefaultHeaders();
final static LinkedList apiDays = new LinkedList<>(Arrays.asList("dom","lun","mar","mer","gio","ven","sab"));
@Override
public Palina ReadArrivalTimesAll(String stopID, AtomicReference res) {
//set the date for the request as now
Palina p = new Palina(stopID);
//request parameters
String response = performAPIRequest(QueryType.ARRIVALS,stopID,res);
if(response==null) {
if(res.get()==result.SERVER_ERROR_404) {
Log.w(DEBUG_NAME,"Got 404, either the server failed, or the stop was not found, or the hack is not working anymore");
res.set(result.EMPTY_RESULT_SET);
}
return p;
}
try {
List routes = parseArrivalsServerResponse(response, res);
for(Route r: routes){
p.addRoute(r);
}
} catch (JSONException ex){
res.set(result.PARSER_ERROR);
return null;
}
res.set(result.OK);
p.sortRoutes();
return p;
}
List parseArrivalsServerResponse(String JSONresponse, AtomicReference res) throws JSONException{
ArrayList routes = new ArrayList<>(3);
/*
Slight problem:
"longName": ==> DESCRIPTION
"name": "13N",
"departures": [
{
"arrivalTimeInt": 1272,
"time": "21:12",
"rt": false
}]
"lineType": "URBANO" ==> URBANO can be either bus or tram or METRO
*/
JSONArray arr;
try{
arr = new JSONArray(JSONresponse);
String type;
Route.Type routetype;
for(int i =0; i parseDirectionsFromResponse(String response) throws IllegalArgumentException,JSONException{
if(response == null || response.length()==0) throw new IllegalArgumentException("Response string is null or void");
ArrayList routes = new ArrayList<>(10);
JSONArray lines =new JSONArray(response);
for(int i=0; i 1) {
String secondo = exploded[exploded.length-2];
if (secondo.contains("festivo")) {
festivo = Route.FestiveInfo.FESTIVO;
} else if (secondo.contains("feriale")) {
festivo = Route.FestiveInfo.FERIALE;
} else if(secondo.contains("lun. - ven")) {
serviceDays = Route.reduced_week;
} else if(secondo.contains("sab - fest.")){
serviceDays = Route.weekend;
festivo = Route.FestiveInfo.FESTIVO;
} else {
/*
Log.d(DEBUG_NAME,"Parsing details of line "+lineName+" branchid "+branchid+":\n\t"+
"Couldn't find a the service days\n"+
"Description: "+secondo+","+description
);
*/
}
if(exploded.length>2){
switch (exploded[exploded.length-3].trim()) {
case "bus":
t = Route.Type.BUS;
break;
case "tram":
//never happened, but if it could happen you can get it
t = Route.Type.TRAM;
break;
default:
//nothing
}
}
} else //only one piece
if(description.contains("festivo")){
festivo = Route.FestiveInfo.FESTIVO;
} else if(description.contains("feriale")){
festivo = Route.FestiveInfo.FERIALE;
}
if(t == Route.Type.UNKNOWN &&(lineName.trim().equals("10")|| lineName.trim().equals("15"))) t= Route.Type.TRAM;
if(direction.contains("-")){
//Sometimes the actual filtered direction still remains the full line (including both extremes)
direction = direction.split("-")[1];
}
Route r = new Route(lineName.trim(),direction.trim(),t,new ArrayList<>());
if(serviceDays.length>0) r.serviceDays = serviceDays;
r.festivo = festivo;
r.branchid = branchid;
r.description = description.trim();
r.setStopsList(Arrays.asList(stops.split(",")));
routes.add(r);
}
return routes;
}
public List getDirectionsForStop(String stopID, AtomicReference res) {
String response = performAPIRequest(QueryType.DETAILS,stopID,res);
List routes;
try{
routes = parseDirectionsFromResponse(response);
res.set(result.OK);
} catch (JSONException | IllegalArgumentException e) {
e.printStackTrace();
res.set(result.PARSER_ERROR);
routes = null;
}
return routes;
}
public ArrayList getAllStopsFromGTT(AtomicReference res){
String response = performAPIRequest(QueryType.STOPS_ALL,null,res);
if(response==null) return null;
ArrayList stopslist;
try{
JSONObject responseJSON = new JSONObject(response);
JSONArray stops = responseJSON.getJSONArray("stops");
stopslist = new ArrayList<>(stops.length());
for (int i=0;i getAllLinesFromGTT(AtomicReference res){
String resp = performAPIRequest(QueryType.LINES,null,res);
if(resp==null) {
return null;
}
ArrayList routes = null;
try {
JSONArray lines = new JSONArray(resp);
routes = new ArrayList<>(lines.length());
for(int i = 0; i getHeadersForRequest(String url) throws UnsupportedEncodingException, NoSuchAlgorithmException {
- final Date d = new Date();
+ public static Map getDefaultHeaders(){
HashMap param = new HashMap<>();
- param.put("TOKEN",getAccessToken(url,d));
- param.put("TIMESTAMP",String.valueOf(d.getTime()));
- param.put("Accept-Encoding","gzip");
+ param.put("Host","www.5t.torino.it");
param.put("Connection","Keep-Alive");
-
+ param.put("Accept-Encoding", "gzip");
return param;
-
}
/**
* Create and perform the network request. This method adds parameters and returns the result
* @param t type of request to be performed
* @param stopID optional parameter, stop ID which you need for passages and branches
* @param res result container
* @return a String which contains the result of the query, to be parsed
*/
@Nullable
public static String performAPIRequest(QueryType t,@Nullable String stopID, AtomicReference res){
URL u;
Map param;
try {
String address = getURLForOperation(t,stopID);
//Log.d(DEBUG_NAME,"The address to query is: "+address);
- param = getHeadersForRequest(address);
+ param = getDefaultHeaders();
u = new URL(address);
- } catch (UnsupportedEncodingException | NoSuchAlgorithmException |MalformedURLException e) {
+ } catch (UnsupportedEncodingException |MalformedURLException e) {
e.printStackTrace();
res.set(result.PARSER_ERROR);
return null;
}
String response = networkTools.queryURL(u,res,param);
return response;
}
- /**
- * Get the Token needed to access the API
- * @param URL the URL of the request
- * @return token
- * @throws NoSuchAlgorithmException if the system doesn't support MD5
- * @throws UnsupportedEncodingException if we made mistakes in writing utf-8
- */
- private static String getAccessToken(String URL,Date d) throws NoSuchAlgorithmException,UnsupportedEncodingException{
- MessageDigest md = MessageDigest.getInstance("MD5");
- String strippedQuery = URL.replace("http://www.5t.torino.it/proxyws","");
- //return the time in milliseconds
- long timeMilli = d.getTime();
- StringBuilder sb = new StringBuilder();
- sb.append(strippedQuery);
- sb.append(timeMilli);
- sb.append(SECRET_KEY);
- String stringToBeHashed = sb.toString();
- //Log.d(DEBUG_NAME,"Hashing string: "+stringToBeHashed);
- md.reset();
- byte[] data = md.digest(stringToBeHashed.getBytes("UTF-8"));
- sb = new StringBuilder();
- for (byte b : data){
- sb.append(String.format("%02x",b));
- }
- String result = sb.toString();
- //Log.d(DEBUG_NAME,"getting token:\n\treduced URL: "+strippedQuery+"\n\ttimestamp: "+timeMilli+"\nTOKEN:"+result.toLowerCase());
- return result.toLowerCase();
- }
-
/**
* Get the right url for the operation you are doing, to be fed into the queryURL method
* @param t type of operation
* @param stopID stop on which you are working on
* @return the Url to go to
* @throws UnsupportedEncodingException if it cannot be converted to utf-8
*/
public static String getURLForOperation(QueryType t,@Nullable String stopID) throws UnsupportedEncodingException {
final StringBuilder sb = new StringBuilder();
- sb.append("http://www.5t.torino.it/proxyws/ws2.1/rest/");
+ sb.append("http://www.5t.torino.it/ws2.1/rest/");
if(t!=QueryType.LINES) sb.append("stops/");
switch (t){
case ARRIVALS:
sb.append(URLEncoder.encode(stopID,"utf-8"));
sb.append("/departures");
break;
case DETAILS:
sb.append(URLEncoder.encode(stopID,"utf-8"));
sb.append("/branches/details");
break;
case STOPS_ALL:
sb.append("all");
break;
case STOPS_VERSION:
sb.append("version");
break;
case LINES:
sb.append("lines/all");
break;
}
return sb.toString();
}
public enum QueryType {
ARRIVALS, DETAILS,STOPS_ALL, STOPS_VERSION,LINES
}
}
diff --git a/src/it/reyboz/bustorino/backend/FiveTAPIVolleyRequest.java b/src/it/reyboz/bustorino/backend/FiveTAPIVolleyRequest.java
index 4377bc3..1152efb 100644
--- a/src/it/reyboz/bustorino/backend/FiveTAPIVolleyRequest.java
+++ b/src/it/reyboz/bustorino/backend/FiveTAPIVolleyRequest.java
@@ -1,137 +1,131 @@
/*
BusTO - Backend components
Copyright (C) 2019 Fabio Mazza
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
package it.reyboz.bustorino.backend;
import android.support.annotation.Nullable;
import android.util.Log;
import com.android.volley.*;
import com.android.volley.toolbox.HttpHeaderParser;
import org.json.JSONException;
import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
/**
* Class to handle request with the Volley Library
*/
public class FiveTAPIVolleyRequest extends Request {
private static final String LOG_TAG = "BusTO-FiveTAPIVolleyReq";
private ResponseListener listener;
final private String url,stopID;
final private AtomicReference resultRef;
final private FiveTAPIFetcher fetcher;
final private FiveTAPIFetcher.QueryType type;
private FiveTAPIVolleyRequest(int method, String url, String stopID, FiveTAPIFetcher.QueryType kind,
ResponseListener listener,
@Nullable Response.ErrorListener errorListener) {
super(method, url, errorListener);
this.url = url;
this.resultRef = new AtomicReference<>();
this.fetcher = new FiveTAPIFetcher();
this.listener = listener;
this.stopID = stopID;
this.type = kind;
}
@Nullable
public static FiveTAPIVolleyRequest getNewRequest(FiveTAPIFetcher.QueryType type, String stopID,
ResponseListener listener, @Nullable Response.ErrorListener errorListener){
String url;
try {
url = FiveTAPIFetcher.getURLForOperation(type,stopID);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
Log.e(LOG_TAG,"Cannot get an URL for the operation");
return null;
}
- return new FiveTAPIVolleyRequest(Method.POST,url,stopID,type,listener,errorListener);
+ return new FiveTAPIVolleyRequest(Method.GET,url,stopID,type,listener,errorListener);
}
@Override
protected Response parseNetworkResponse(NetworkResponse response) {
if(response.statusCode != 200)
return Response.error(new VolleyError("Response Error Code "+response.statusCode));
final String stringResponse = new String(response.data);
List routeList;
try{
switch (type){
case ARRIVALS:
routeList = fetcher.parseArrivalsServerResponse(stringResponse,resultRef);
break;
case DETAILS:
routeList = fetcher.parseDirectionsFromResponse(stringResponse);
break;
default:
//empty
return Response.error(new VolleyError("Invalid query type"));
}
} catch (JSONException e) {
resultRef.set(Fetcher.result.PARSER_ERROR);
//e.printStackTrace();
Log.w("FivetVolleyParser","JSON Exception in parsing response of: "+url);
return Response.error(new ParseError(response));
}
if(resultRef.get()== Fetcher.result.PARSER_ERROR){
return Response.error(new ParseError(response));
}
final Palina p = new Palina(stopID);
p.setRoutes(routeList);
p.sortRoutes();
return Response.success(p, HttpHeaderParser.parseCacheHeaders(response));
}
@Override
protected void deliverResponse(Palina p) {
listener.onResponse(p,type);
}
@Override
- public Map getHeaders() throws AuthFailureError {
- Map headers;
- try{
- headers = FiveTAPIFetcher.getHeadersForRequest(url);
- } catch (UnsupportedEncodingException | NoSuchAlgorithmException e) {
- e.printStackTrace();
- throw new AuthFailureError("Cannot get the token for the authorization");
- }
- return headers;
+ public Map getHeaders() {
+ return FiveTAPIFetcher.getDefaultHeaders();
+
}
//from https://stackoverflow.com/questions/21867929/android-how-handle-message-error-from-the-server-using-volley
@Override
protected VolleyError parseNetworkError(VolleyError volleyError){
if(volleyError.networkResponse != null && volleyError.networkResponse.data != null){
volleyError = new NetworkError(volleyError.networkResponse);
}
return volleyError;
}
public interface ResponseListener{
void onResponse(Palina result, FiveTAPIFetcher.QueryType type);
}
//public interface ErrorListener extends Response.ErrorListener{}
}