Created
August 12, 2014 11:30
-
-
Save sadikovi/5c5d2c92948ee02df08b to your computer and use it in GitHub Desktop.
Bunch of Java classes that allow you to read a Google Calender and output all user's calenders/events in a structured way as json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package project1; | |
import java.io.UnsupportedEncodingException; | |
import java.text.SimpleDateFormat; | |
import java.util.Date; | |
import java.util.HashMap; | |
import java.net.URLEncoder; | |
import org.json.JSONObject; | |
public class APIManager { | |
private static final String API_KEY = "YOUR-API-KEY"; | |
private static final String CLIENT_ID = "YOUR-CLIENT-ID"; | |
private static final String CLIENT_SECRET = "YOUR-CLIENT-SECRET"; | |
// url for checking token info | |
private static final String TOKEN_INFO_URL = "https://www.googleapis.com/oauth2/v1/tokeninfo"; | |
// url for refresh token | |
private static final String REFRESH_TOKEN_URL = "https://accounts.google.com/o/oauth2/token"; | |
// url for retrieving calendar lists | |
private static final String CALENDARLIST_URL = "https://www.googleapis.com/calendar/v3/users/me/calendarList"; | |
// url for retrieving event lists | |
private static final String EVENTLIST_URL = "https://www.googleapis.com/calendar/v3/calendars"; | |
// utf-8 encoding | |
private static final String ENCODING = "UTF-8"; | |
public APIManager() { | |
super(); | |
} | |
/** | |
* Checks whether accessToken is valid or not. | |
* If it is not valid, then send request with refresh token to update access token. | |
* Otherwise, return access token. | |
* | |
* @param accessToken | |
* @param refreshToken | |
* @return | |
*/ | |
public static String obtainAccessToken(String accessToken, String refreshToken) { | |
String urlString = TOKEN_INFO_URL + "?access_token=" + accessToken; | |
try { | |
// get token info | |
String result = NetworkManager.retriveDataFromUrl(urlString, NetworkManager.GET, null, null); | |
JSONObject tokenJson = new JSONObject(result); | |
// if result includes :"error" we try to get access token by using refresh token | |
if (tokenJson.has("error")) { | |
HashMap<String, String> params = new HashMap<String, String>(); | |
params.put("client_id", CLIENT_ID); | |
params.put("client_secret", CLIENT_SECRET); | |
params.put("refresh_token", refreshToken); | |
params.put("grant_type", "refresh_token"); | |
String repeat = NetworkManager.retriveDataFromUrl(REFRESH_TOKEN_URL, NetworkManager.POST, null, params); | |
JSONObject json = new JSONObject(repeat); | |
return json.getString("access_token"); | |
} else { | |
return accessToken; | |
} | |
} catch (Exception e) { | |
return ""; | |
} | |
} | |
/** | |
* Returns json string as String, representing calendars for particular access token. | |
* | |
* @param accessToken | |
* @return | |
*/ | |
public static String getCalendarLists(String accessToken) { | |
String urlString = CALENDARLIST_URL + "?" + | |
"fields=items(id%2Csummary)" + | |
"&key=" + API_KEY + | |
"&access_token=" + accessToken; | |
try { | |
String result = NetworkManager.retriveDataFromUrl(urlString, NetworkManager.GET, null, null); | |
return result; | |
} catch (Exception e) { | |
return "{\"error\" : \"" + e.getMessage() + "\" }"; | |
} | |
} | |
/** | |
* Returns events for particular calendar. | |
* Day offset provides range of timeMin and timeMax for events. | |
* | |
* @param accessToken | |
* @param calendarId | |
* @param dayOffset | |
* @return | |
*/ | |
public static String getEventsForCalendar(String accessToken, String calendarId, int dayOffset) { | |
String dateFormat = "yyyy-MM-dd'T'00:00:00'Z'"; | |
long currentTimeStamp = System.currentTimeMillis() / 1000L; | |
long offsetTimeStamp = currentTimeStamp + dayOffset*24*3600; | |
String timeMin = new SimpleDateFormat(dateFormat).format(new Date(currentTimeStamp * 1000)); | |
String timeMax = new SimpleDateFormat(dateFormat).format(new Date(offsetTimeStamp * 1000)); | |
// try encoding calendar id, as it can contain symbols like "#" etc. | |
try { | |
calendarId = URLEncoder.encode(calendarId, ENCODING); | |
} catch (UnsupportedEncodingException e) { | |
calendarId = calendarId.replace("#", "%23"); | |
} | |
String urlString = EVENTLIST_URL + "/" + calendarId + "/events?" + | |
"timeMax=" + timeMax + | |
"&timeMin=" + timeMin + | |
"&fields=items(description%2Cid%2Ckind%2Clocation%2Csummary)" + | |
"&key="+API_KEY + | |
"&access_token=" + accessToken; | |
try { | |
String result = NetworkManager.retriveDataFromUrl(urlString, NetworkManager.GET, null, null); | |
return result; | |
} catch (Exception e) { | |
return "{\"error\" : \"" + e.getMessage() + "\" }"; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package project1; | |
import java.io.IOException; | |
import java.util.Date; | |
import java.net.MalformedURLException; | |
import java.security.KeyManagementException; | |
import java.security.NoSuchAlgorithmException; | |
import java.text.SimpleDateFormat; | |
import org.json.*; | |
import java.util.HashMap; | |
public class Main { | |
public Main() { | |
super(); | |
} | |
public static void main(String[] args) throws NoSuchAlgorithmException, | |
KeyManagementException, | |
MalformedURLException, | |
IOException { | |
String accessToken = "ya29.XwB1ey41cXk9QRwAAAD7eqvBAexybHZOyanLFwfud0Wn9408TgjX1iNC5ZpuGA"; | |
String refreshToken = "1/EAy446VlsEoGD190XAcMxB6T4S8NbTNh9SUr6cefxvk"; | |
System.out.println(getCalendarsAndEvents(accessToken, false, refreshToken, 10)); | |
} | |
/** | |
* Returns json with calendar data and events. | |
* If "checkToken" is true, method will call "obtainAccessToken" method to make sure that access token is valid. | |
* dayOffse is offset between max event date and min event date. | |
* | |
* @param accessToken | |
* @param checkToken | |
* @param refreshToken | |
* @param dayOffset | |
* @return | |
*/ | |
private static String getCalendarsAndEvents(String accessToken, boolean checkToken, String refreshToken, int dayOffset) { | |
if (checkToken) | |
accessToken = APIManager.obtainAccessToken(accessToken, refreshToken); | |
String calendarsString = APIManager.getCalendarLists(accessToken); | |
JSONObject json = new JSONObject(calendarsString); | |
if (json.has("error")) | |
return calendarsString; | |
String result = "{ \"calendars\" : ["; | |
JSONArray calendars = json.getJSONArray("items"); | |
for (int i=0; i<calendars.length(); i++) { | |
String id = calendars.getJSONObject(i).getString("id"); | |
String summary = calendars.getJSONObject(i).getString("summary"); | |
result += "{ \"id\" : \"" + id + "\", \"summary\" : \"" + summary + "\", "; | |
String eventsString = APIManager.getEventsForCalendar(accessToken, id, dayOffset); | |
result += eventsString.substring(1, eventsString.length()-1) + " }" + ((i<calendars.length()-1)?",":""); | |
} | |
result += " ] }"; | |
return result; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package project1; | |
import java.io.BufferedReader; | |
import java.io.IOException; | |
import java.io.InputStreamReader; | |
import java.io.DataOutputStream; | |
import java.net.MalformedURLException; | |
import java.net.URL; | |
import javax.net.ssl.HttpsURLConnection; | |
import java.security.KeyManagementException; | |
import java.security.NoSuchAlgorithmException; | |
import java.security.SecureRandom; | |
import java.security.cert.CertificateException; | |
import java.security.cert.X509Certificate; | |
import java.util.HashMap; | |
import javax.net.ssl.*; | |
public class NetworkManager { | |
public static final String GET = "GET"; | |
public static final String POST = "POST"; | |
public NetworkManager() { | |
super(); | |
} | |
/** | |
* Sends HTTP request and receives json data (preferably). | |
* If error happened, would return json: {error: "response error message", code : "http response code"} | |
* | |
* @param urlString | |
* @param method | |
* @param headerParams | |
* @param params | |
* @return | |
* @throws NoSuchAlgorithmException | |
* @throws KeyManagementException | |
* @throws MalformedURLException | |
* @throws IOException | |
*/ | |
public static String retriveDataFromUrl(String urlString, String method, HashMap<String, String> headerParams, HashMap<String, String> params) throws NoSuchAlgorithmException, | |
KeyManagementException, | |
MalformedURLException, | |
IOException { | |
// configure the SSLContext with a TrustManager | |
// I hate this part, though necessary to send https requests | |
SSLContext ctx = SSLContext.getInstance("TLS"); | |
ctx.init(new KeyManager[0], new TrustManager[] {new DefaultTrustManager()}, new SecureRandom()); | |
SSLContext.setDefault(ctx); | |
// prepare connection | |
URL url = new URL(urlString); | |
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection(); | |
conn.setRequestMethod(method); | |
// set header params | |
if (headerParams != null) | |
for (String key : headerParams.keySet()) | |
conn.setRequestProperty(key, headerParams.get(key)); | |
// check if it is post, and set up request body | |
if (method.equals(POST)) { | |
String postParams = ""; | |
if (params != null) | |
for (String key : params.keySet()) | |
postParams += "&" + key + "=" + params.get(key); | |
conn.setDoOutput(true); | |
DataOutputStream wr = new DataOutputStream(conn.getOutputStream()); | |
// substring is simply to eliminate leading "&". I know, should have done better, though lack of time... | |
wr.writeBytes(postParams.substring(1)); | |
wr.flush(); | |
wr.close(); | |
} | |
// still ssl... | |
conn.setHostnameVerifier(new HostnameVerifier() { | |
@Override | |
public boolean verify(String arg0, SSLSession arg1) { | |
return true; | |
} | |
}); | |
// get response body | |
if (conn.getResponseCode() == HttpsURLConnection.HTTP_OK) { | |
String line; | |
StringBuffer result = new StringBuffer(); | |
BufferedReader bf = new BufferedReader(new InputStreamReader(conn.getInputStream())); | |
while (true) { | |
line = bf.readLine(); | |
if (line == null) | |
break; | |
result.append(line); | |
} | |
conn.disconnect(); | |
return result.toString(); | |
} else { | |
return "{\"code\" : \"" + conn.getResponseCode() + "\", \"error\" : \"" + conn.getResponseMessage() + "\" }"; | |
} | |
} | |
private static class DefaultTrustManager implements X509TrustManager { | |
@Override | |
public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {} | |
@Override | |
public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {} | |
@Override | |
public X509Certificate[] getAcceptedIssuers() { | |
return null; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I wrote classes with a simple output, as System.Out.println(). To somehow figure out how it works, you need to run Main.java (method "getCalendarsAndEvents" in particular). I did not know, whether I was allowed to use framework for Google Calendar API, so I did not use it. Notice, that it uses Json library (http://www.json.org/java/index.html) to work with json objects correctly (it would take me a lot of time to code that).
Output for "getCalendarsAndEvents(accessToken, false, refreshToken, 10)":
{
"calendars": [{
"id": "[email protected]",
"summary": "[email protected]",
"items": []
}, {
"id": "en-gb.australian#[email protected]",
"summary": "Holidays in Australia",
"items": [{
"kind": "calendar#event",
"id": "20140813_60o30chj6go30e1g60o30dr4ck",
"summary": "Royal National Agricultural Show Day Queensland",
"description": "Public holiday in: Queensland"
}]
}, {
"id": "p#[email protected]",
"summary": "Weather",
"items": [{
"kind": "calendar#event",
"id": "20140812_weatherP",
"summary": "Forecast for Christchurch (12° | 2°)"
}, {
"kind": "calendar#event",
"id": "20140813_weatherP",
"summary": "Forecast for Christchurch (11° | 1°)"
}, {
"kind": "calendar#event",
"id": "20140814_weatherP",
"summary": "Forecast for Christchurch (8° | 3°)"
}, {
"kind": "calendar#event",
"id": "20140815_weatherP",
"summary": "Forecast for Christchurch (15° | 3°)"
}]
}]
}