@ -34,6 +34,8 @@ public class Main
{
{
public static final String baseUrl = "https://www.strava.com/api/v3/" ;
public static final String baseUrl = "https://www.strava.com/api/v3/" ;
public static final String tokenUrl = "https://www.strava.com/api/v3/oauth/token" ;
public static final String tokenUrl = "https://www.strava.com/api/v3/oauth/token" ;
private static final int retryTimes = 20 ;
private static final int httpCodeLimitReached = 429 ;
private static int athleteId = 0 ;
private static int athleteId = 0 ;
private static JSONParser parser = new JSONParser ( ) ;
private static JSONParser parser = new JSONParser ( ) ;
private static String testRequest ;
private static String testRequest ;
@ -95,6 +97,10 @@ public class Main
/ / get general information
/ / get general information
JSONObject athleteInfo = saveGeneralInformation ( token ) ;
JSONObject athleteInfo = saveGeneralInformation ( token ) ;
if ( athleteInfo = = null ) / / error getting General Information
{
athleteInfo = new JSONObject ( ) ;
}
athleteInfo . put ( "activities" , allActivities ) ;
athleteInfo . put ( "activities" , allActivities ) ;
try
try
@ -127,9 +133,10 @@ public class Main
String requestUrlExtension = "activities/" + id + "/streams?"
String requestUrlExtension = "activities/" + id + "/streams?"
+ "keys=[time,distance,latlng,altitude,velocity_smooth,heartrate,"
+ "keys=[time,distance,latlng,altitude,velocity_smooth,heartrate,"
+ "cadence,watts,temp,moving,grade_smooth]&key_by_type=true" ;
+ "cadence,watts,temp,moving,grade_smooth]&key_by_type=true" ;
String json = makeOneGetRequest ( requestUrlExtension , token ) ;
if ( json . isEmpty ( ) | | json . isBlank ( ) | | json . equals ( "" ) )
String json = makeGetRequestWithRetry ( requestUrlExtension , token ) ; ;
if ( json = = null | | json . isEmpty ( ) | | json . isBlank ( ) | | json . equals ( "" ) )
{
{
return data ;
return data ;
}
}
@ -179,9 +186,9 @@ public class Main
int pageIndex = 1 ;
int pageIndex = 1 ;
while ( true )
while ( true )
{
{
String requestExtension = "athlete/activities?page=" + pageIndex ;
String json = makeOne GetRequest ( requestExtension , token ) ;
if ( json . isEmpty ( ) | | json . isBlank ( ) | | json . equals ( "" ) | | json . equals ( "[]" ) ) / / don ' t know where the last page is . . .
String requestExtension = "athlete/activities?per_page=500&p age=" + pageIndex ;
String json = makeGetRequestWithRetry ( requestExtension , token ) ;
if ( json = = null | | json . isEmpty ( ) | | json . isBlank ( ) | | json . equals ( "" ) | | json . equals ( "[]" ) ) / / don ' t know where the last page is . . .
{
{
break ;
break ;
}
}
@ -217,6 +224,53 @@ public class Main
return result ;
return result ;
}
}
/ * *
* Method is used to find the next request window : It tries the same request again after 5 minutes .
* After a set number of times ( retryTimes ) it stops if it still wasn ' t successful .
* @param urlExtension UrlExtension for the request
* @param token Token for the request
* @return Data as a String or { @code null } if there is no data
* /
static String makeGetRequestWithRetry ( String urlExtension , String token )
{
String json = null ;
int count = 0 ;
do
{
try
{
json = makeOneGetRequest ( urlExtension , token ) ;
}
catch ( ResponseCodeWrongException e )
{
/ / tried enough times , so stop now
if ( count > = retryTimes )
{
return null ;
}
/ / request limit is reached , try again later
if ( e . getResponseCode ( ) = = httpCodeLimitReached )
{
count + + ;
}
else / / some other error : try only one other time !
{
count = retryTimes ;
}
/ / Sleep for 5 minutes and try to get the next 15 min request window
try
{
TimeUnit . MINUTES . sleep ( 5 ) ;
}
catch ( InterruptedException e1 )
{
}
}
} while ( json = = null ) ;
return json ;
}
/ * *
/ * *
* Extracts an athletes general information .
* Extracts an athletes general information .
*
*
@ -232,7 +286,8 @@ public class Main
String meas_pref = "measurement_preference" ; / / Possible values = feet , meters
String meas_pref = "measurement_preference" ; / / Possible values = feet , meters
String weight = "weight" ;
String weight = "weight" ;
String json = makeOneGetRequest ( "athlete" , token ) ;
String json = makeGetRequestWithRetry ( "athlete" , token ) ;
JSONObject toSave = new JSONObject ( ) ;
JSONObject toSave = new JSONObject ( ) ;
try
try
@ -291,8 +346,9 @@ public class Main
* @param token Identification / authorization token of the
* @param token Identification / authorization token of the
* athlete
* athlete
* @return The response as a String , an empty String in case of error .
* @return The response as a String , an empty String in case of error .
* @throws ResponseCodeWrongException If there was an http error
* /
* /
static String makeOneGetRequest ( String requestUrlExtension , String token )
static String makeOneGetRequest ( String requestUrlExtension , String token ) throws ResponseCodeWrongException
{
{
if ( testRequest ! = null )
if ( testRequest ! = null )
{
{
@ -335,20 +391,21 @@ public class Main
*
*
* @param connection Connection to the site
* @param connection Connection to the site
* @return Response as a String
* @return Response as a String
* @throws IOException in case of error
* @throws IOException in case of error with the stream
* @throws ResponseCodeWrongException if no data was read because of http problems
* /
* /
static String getResponse ( HttpsURLConnection connection ) throws IOException
static String getResponse ( HttpsURLConnection connection ) throws IOException , ResponseCodeWrongException
{
{
StringBuilder result = new StringBuilder ( ) ;
StringBuilder result = new StringBuilder ( ) ;
int responseCode = connection . getResponseCode ( ) ;
int responseCode = connection . getResponseCode ( ) ;
if ( responseCode ! = HttpURLConnection . HTTP_OK )
if ( responseCode ! = HttpURLConnection . HTTP_OK )
{
{
/ / excluded error messages appearing on missing streams
if ( responseCode ! = HttpURLConnection . HTTP_NOT_FOUND )
/ / excluded error messages appearing on missing streams and reached rate limit
if ( responseCode ! = HttpURLConnection . HTTP_NOT_FOUND & & responseCode ! = httpCodeLimitReached )
{
{
writeError ( "Wrong response code: " + responseCode ) ;
writeError ( "Wrong response code: " + responseCode ) ;
}
}
return "" ;
throw new ResponseCodeWrongException ( responseCode ) ;
}
}
try ( Reader reader = new BufferedReader (
try ( Reader reader = new BufferedReader (
@ -372,8 +429,9 @@ public class Main
* @param data Triplet containing : a the client_id , b the client_secret , c the
* @param data Triplet containing : a the client_id , b the client_secret , c the
* refresh_token
* refresh_token
* @return The response as a String , an empty String in case of error .
* @return The response as a String , an empty String in case of error .
* @throws ResponseCodeWrongException If there was an http error
* /
* /
static String makeOnePostRequest ( Triplet data )
static String makeOnePostRequest ( Triplet data ) throws ResponseCodeWrongException
{
{
HttpsURLConnection connection = null ;
HttpsURLConnection connection = null ;
try
try
@ -423,7 +481,41 @@ public class Main
* /
* /
static Tuple getAccessToken ( Triplet refreshInfo )
static Tuple getAccessToken ( Triplet refreshInfo )
{
{
String json = makeOnePostRequest ( refreshInfo ) ;
String json = null ;
int count = 0 ;
do
{
try
{
json = makeOnePostRequest ( refreshInfo ) ;
}
catch ( ResponseCodeWrongException e )
{
/ / tried enough times , so stop now
if ( count > = retryTimes )
{
return null ;
}
/ / request limit is reached , try again later
if ( e . getResponseCode ( ) = = httpCodeLimitReached )
{
count + + ;
}
else / / some other error : try only one other time !
{
count = retryTimes ;
}
/ / Sleep for 5 minutes and try to get the next 15 min request window
try
{
TimeUnit . MINUTES . sleep ( 5 ) ;
}
catch ( InterruptedException e1 )
{
}
}
} while ( json = = null ) ;
try
try
{
{
Object obj = parser . parse ( json ) ;
Object obj = parser . parse ( json ) ;
@ -476,41 +568,3 @@ public class Main
}
}
}
}
}
}
class Tuple
{
private String a ;
private String b ;
public Tuple ( String a , String b )
{
this . a = a ;
this . b = b ;
}
public String getA ( )
{
return a ;
}
public String getB ( )
{
return b ;
}
}
class Triplet extends Tuple
{
private String c ;
public Triplet ( String a , String b , String c )
{
super ( a , b ) ;
this . c = c ;
}
public String getC ( )
{
return c ;
}
}