Skip to content

Instantly share code, notes, and snippets.

@sadikovi
Created August 12, 2014 11:30
Show Gist options
  • Save sadikovi/5c5d2c92948ee02df08b to your computer and use it in GitHub Desktop.
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
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() + "\" }";
}
}
}
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;
}
}
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;
}
}
}
@sadikovi
Copy link
Author

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°)"
}]
}]
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment