/* Copyright (c) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.calendar;
import com.google.gdata.client.Query;
import com.google.gdata.client.calendar.CalendarQuery;
import com.google.gdata.client.calendar.CalendarService;
import com.google.gdata.data.DateTime;
import com.google.gdata.data.Link;
import com.google.gdata.data.PlainTextConstruct;
import com.google.gdata.data.batch.BatchOperationType;
import com.google.gdata.data.batch.BatchStatus;
import com.google.gdata.data.batch.BatchUtils;
import com.google.gdata.data.calendar.CalendarEntry;
import com.google.gdata.data.calendar.CalendarEventEntry;
import com.google.gdata.data.calendar.CalendarEventFeed;
import com.google.gdata.data.calendar.CalendarFeed;
import com.google.gdata.data.calendar.WebContent;
import com.google.gdata.data.extensions.ExtendedProperty;
import com.google.gdata.data.extensions.Recurrence;
import com.google.gdata.data.extensions.Reminder;
import com.google.gdata.data.extensions.Reminder.Method;
import com.google.gdata.data.extensions.When;
import com.google.gdata.util.ServiceException;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.TimeZone;
/**
* Demonstrates basic Calendar Data API operations on the event feed using the
* Java client library:
*
* <ul>
* <li>Retrieving the list of all the user's calendars</li>
* <li>Retrieving all events on a single calendar</li>
* <li>Performing a full-text query on a calendar</li>
* <li>Performing a date-range query on a calendar</li>
* <li>Creating a single-occurrence event</li>
* <li>Creating a recurring event</li>
* <li>Creating a quick add event</li>
* <li>Creating a web content event</li>
* <li>Updating events</li>
* <li>Adding reminders and extended properties</li>
* <li>Deleting events via batch request</li>
* </ul>
*/
public class EventFeedDemo {
// The base URL for a user's calendar metafeed (needs a username appended).
private static final String METAFEED_URL_BASE =
"https://www.google.com/calendar/feeds/";
// The string to add to the user's metafeedUrl to access the event feed for
// their primary calendar.
private static final String EVENT_FEED_URL_SUFFIX = "/private/full";
// The URL for the metafeed of the specified user.
// (e.g. http://www.google.com/feeds/calendar/jdoe@gmail.com)
private static URL metafeedUrl = null;
// The URL for the event feed of the specified user's primary calendar.
// (e.g. http://www.googe.com/feeds/calendar/jdoe@gmail.com/private/full)
private static URL eventFeedUrl = null;
/**
* Prints a list of all the user's calendars.
*
* @param service An authenticated CalendarService object.
* @throws ServiceException If the service is unable to handle the request.
* @throws IOException Error communicating with the server
*/
private static void printUserCalendars(CalendarService service)
throws IOException, ServiceException {
// Send the request and receive the response:
CalendarFeed resultFeed = service.getFeed(metafeedUrl, CalendarFeed.class);
System.out.println("Your calendars:");
System.out.println();
for (int i = 0; i < resultFeed.getEntries().size(); i++) {
CalendarEntry entry = resultFeed.getEntries().get(i);
System.out.println("\t" + entry.getTitle().getPlainText());
}
System.out.println();
}
/**
* Prints the titles of all events on the calendar specified by
* {@code feedUri}.
*
* @param service An authenticated CalendarService object.
* @throws ServiceException If the service is unable to handle the request.
* @throws IOException Error communicating with the server.
*/
private static void printAllEvents(CalendarService service)
throws ServiceException, IOException {
// Send the request and receive the response:
CalendarEventFeed resultFeed = service.getFeed(eventFeedUrl,
CalendarEventFeed.class);
System.out.println("All events on your calendar:");
System.out.println();
for (int i = 0; i < resultFeed.getEntries().size(); i++) {
CalendarEventEntry entry = resultFeed.getEntries().get(i);
System.out.println("\t" + entry.getTitle().getPlainText());
}
System.out.println();
}
/**
* Prints the titles of all events matching a full-text query.
*
* @param service An authenticated CalendarService object.
* @param query The text for which to query.
* @throws ServiceException If the service is unable to handle the request.
* @throws IOException Error communicating with the server.
*/
private static void fullTextQuery(CalendarService service, String query)
throws ServiceException, IOException {
Query myQuery = new Query(eventFeedUrl);
myQuery.setFullTextQuery("Tennis");
CalendarEventFeed resultFeed = service.query(myQuery,
CalendarEventFeed.class);
System.out.println("Events matching " + query + ":");
System.out.println();
for (int i = 0; i < resultFeed.getEntries().size(); i++) {
CalendarEventEntry entry = resultFeed.getEntries().get(i);
System.out.println("\t" + entry.getTitle().getPlainText());
}
System.out.println();
}
/**
* Prints the titles of all events in a specified date/time range.
*
* @param service An authenticated CalendarService object.
* @param startTime Start time (inclusive) of events to print.
* @param endTime End time (exclusive) of events to print.
* @throws ServiceException If the service is unable to handle the request.
* @throws IOException Error communicating with the server.
*/
private static void dateRangeQuery(CalendarService service,
DateTime startTime, DateTime endTime) throws ServiceException,
IOException {
CalendarQuery myQuery = new CalendarQuery(eventFeedUrl);
myQuery.setMinimumStartTime(startTime);
myQuery.setMaximumStartTime(endTime);
// Send the request and receive the response:
CalendarEventFeed resultFeed = service.query(myQuery,
CalendarEventFeed.class);
System.out.println("Events from " + startTime.toString() + " to "
+ endTime.toString() + ":");
System.out.println();
for (int i = 0; i < resultFeed.getEntries().size(); i++) {
CalendarEventEntry entry = resultFeed.getEntries().get(i);
System.out.println("\t" + entry.getTitle().getPlainText());
}
System.out.println();
}
/**
* Helper method to create either single-instance or recurring events. For
* simplicity, some values that might normally be passed as parameters (such
* as author name, email, etc.) are hard-coded.
*
* @param service An authenticated CalendarService object.
* @param eventTitle Title of the event to create.
* @param eventContent Text content of the event to create.
* @param recurData Recurrence value for the event, or null for
* single-instance events.
* @param isQuickAdd True if eventContent should be interpreted as the text of
* a quick add event.
* @param wc A WebContent object, or null if this is not a web content event.
* @return The newly-created CalendarEventEntry.
* @throws ServiceException If the service is unable to handle the request.
* @throws IOException Error communicating with the server.
*/
private static CalendarEventEntry createEvent(CalendarService service,
String eventTitle, String eventContent, String recurData,
boolean isQuickAdd, WebContent wc) throws ServiceException, IOException {
CalendarEventEntry myEntry = new CalendarEventEntry();
myEntry.setTitle(new PlainTextConstruct(eventTitle));
myEntry.setContent(new PlainTextConstruct(eventContent));
myEntry.setQuickAdd(isQuickAdd);
myEntry.setWebContent(wc);
// If a recurrence was requested, add it. Otherwise, set the
// time (the current date and time) and duration (30 minutes)
// of the event.
if (recurData == null) {
Calendar calendar = new GregorianCalendar();
DateTime startTime = new DateTime(calendar.getTime(), TimeZone
.getDefault());
calendar.add(Calendar.MINUTE, 30);
DateTime endTime = new DateTime(calendar.getTime(),
TimeZone.getDefault());
When eventTimes = new When();
eventTimes.setStartTime(startTime);
eventTimes.setEndTime(endTime);
myEntry.addTime(eventTimes);
} else {
Recurrence recur = new Recurrence();
recur.setValue(recurData);
myEntry.setRecurrence(recur);
}
// Send the request and receive the response:
return service.insert(eventFeedUrl, myEntry);
}
/**
* Creates a single-occurrence event.
*
* @param service An authenticated CalendarService object.
* @param eventTitle Title of the event to create.
* @param eventContent Text content of the event to create.
* @return The newly-created CalendarEventEntry.
* @throws ServiceException If the service is unable to handle the request.
* @throws IOException Error communicating with the server.
*/
private static CalendarEventEntry createSingleEvent(CalendarService service,
String eventTitle, String eventContent) throws ServiceException,
IOException {
return createEvent(service, eventTitle, eventContent, null, false, null);
}
/**
* Creates a quick add event.
*
* @param service An authenticated CalendarService object.
* @param quickAddContent The quick add text, including the event title, date
* and time.
* @return The newly-created CalendarEventEntry.
* @throws ServiceException If the service is unable to handle the request.
* @throws IOException Error communicating with the server.
*/
private static CalendarEventEntry createQuickAddEvent(
CalendarService service, String quickAddContent) throws ServiceException,
IOException {
return createEvent(service, null, quickAddContent, null, true, null);
}
/**
* Creates a web content event.
*
* @param service An authenticated CalendarService object.
* @param title The title of the web content event.
* @param type The MIME type of the web content event, e.g. "image/gif"
* @param url The URL of the content to display in the web content window.
* @param icon The icon to display in the main Calendar user interface.
* @param width The width of the web content window.
* @param height The height of the web content window.
* @return The newly-created CalendarEventEntry.
* @throws ServiceException If the service is unable to handle the request.
* @throws IOException Error communicating with the server.
*/
private static CalendarEventEntry createWebContentEvent(
CalendarService service, String title, String type, String url,
String icon, String width, String height) throws ServiceException,
IOException {
WebContent wc = new WebContent();
wc.setHeight(height);
wc.setWidth(width);
wc.setTitle(title);
wc.setType(type);
wc.setUrl(url);
wc.setIcon(icon);
return createEvent(service, title, null, null, false, wc);
}
/**
* Creates a new recurring event.
*
* @param service An authenticated CalendarService object.
* @param eventTitle Title of the event to create.
* @param eventContent Text content of the event to create.
* @return The newly-created CalendarEventEntry.
* @throws ServiceException If the service is unable to handle the request.
* @throws IOException Error communicating with the server.
*/
private static CalendarEventEntry createRecurringEvent(
CalendarService service, String eventTitle, String eventContent)
throws ServiceException, IOException {
// Specify a recurring event that occurs every Tuesday from May 1,
// 2007 through September 4, 2007. Note that we are using iCal (RFC 2445)
// syntax; see http://www.ietf.org/rfc/rfc2445.txt for more information.
String recurData = "DTSTART;VALUE=DATE:20070501\r\n"
+ "DTEND;VALUE=DATE:20070502\r\n"
+ "RRULE:FREQ=WEEKLY;BYDAY=Tu;UNTIL=20070904\r\n";
return createEvent(service, eventTitle, eventContent, recurData, false,
null);
}
/**
* Updates the title of an existing calendar event.
*
* @param entry The event to update.
* @param newTitle The new title for this event.
* @return The updated CalendarEventEntry object.
* @throws ServiceException If the service is unable to handle the request.
* @throws IOException Error communicating with the server.
*/
private static CalendarEventEntry updateTitle(CalendarEventEntry entry,
String newTitle) throws ServiceException, IOException {
entry.setTitle(new PlainTextConstruct(newTitle));
return entry.update();
}
/**
* Adds a reminder to a calendar event.
*
* @param entry The event to update.
* @param numMinutes Reminder time, in minutes.
* @param methodType Method of notification (e.g. email, alert, sms).
* @return The updated EventEntry object.
* @throws ServiceException If the service is unable to handle the request.
* @throws IOException Error communicating with the server.
*/
private static CalendarEventEntry addReminder(CalendarEventEntry entry,
int numMinutes, Method methodType) throws ServiceException, IOException {
Reminder reminder = new Reminder();
reminder.setMinutes(numMinutes);
reminder.setMethod(methodType);
entry.getReminder().add(reminder);
return entry.update();
}
/**
* Adds an extended property to a calendar event.
*
* @param entry The event to update.
* @return The updated EventEntry object.
* @throws ServiceException If the service is unable to handle the request.
* @throws IOException Error communicating with the server.
*/
private static CalendarEventEntry addExtendedProperty(
CalendarEventEntry entry) throws ServiceException, IOException {
// Add an extended property "id" with value 1234 to the EventEntry entry.
// We specify the complete schema URL to avoid namespace collisions with
// other applications that use the same property name.
ExtendedProperty property = new ExtendedProperty();
property.setName("http://www.example.com/schemas/2005#mycal.id");
property.setValue("1234");
entry.addExtension(property);
return entry.update();
}
/**
* Makes a batch request to delete all the events in the given list. If any of
* the operations fails, the errors returned from the server are displayed.
* The CalendarEntry objects in the list given as a parameters must be entries
* returned from the server that contain valid edit links (for optimistic
* concurrency to work). Note: You can add entries to a batch request for the
* other operation types (INSERT, QUERY, and UPDATE) in the same manner as
* shown below for DELETE operations.
*
* @param service An authenticated CalendarService object.
* @param eventsToDelete A list of CalendarEventEntry objects to delete.
* @throws ServiceException If the service is unable to handle the request.
* @throws IOException Error communicating with the server.
*/
private static void deleteEvents(CalendarService service,
List<CalendarEventEntry> eventsToDelete) throws ServiceException,
IOException {
// Add each item in eventsToDelete to the batch request.
CalendarEventFeed batchRequest = new CalendarEventFeed();
for (int i = 0; i < eventsToDelete.size(); i++) {
CalendarEventEntry toDelete = eventsToDelete.get(i);
// Modify the entry toDelete with batch ID and operation type.
BatchUtils.setBatchId(toDelete, String.valueOf(i));
BatchUtils.setBatchOperationType(toDelete, BatchOperationType.DELETE);
batchRequest.getEntries().add(toDelete);
}
// Get the URL to make batch requests to
CalendarEventFeed feed = service.getFeed(eventFeedUrl,
CalendarEventFeed.class);
Link batchLink = feed.getLink(Link.Rel.FEED_BATCH, Link.Type.ATOM);
URL batchUrl = new URL(batchLink.getHref());
// Submit the batch request
CalendarEventFeed batchResponse = service.batch(batchUrl, batchRequest);
// Ensure that all the operations were successful.
boolean isSuccess = true;
for (CalendarEventEntry entry : batchResponse.getEntries()) {
String batchId = BatchUtils.getBatchId(entry);
if (!BatchUtils.isSuccess(entry)) {
isSuccess = false;
BatchStatus status = BatchUtils.getBatchStatus(entry);
System.out.println("\n" + batchId + " failed (" + status.getReason()
+ ") " + status.getContent());
}
}
if (isSuccess) {
System.out.println("Successfully deleted all events via batch request.");
}
}
/**
* Instantiates a CalendarService object and uses the command line arguments
* to authenticate. The CalendarService object is used to demonstrate
* interactions with the Calendar data API's event feed.
*
* @param args Must be length 2 and contain a valid username/password
*/
public static void main(String[] args) {
CalendarService myService = new CalendarService("exampleCo-exampleApp-1");
// Set username and password from command-line arguments.
if (args.length != 2) {
usage();
return;
}
String userName = args[0];
String userPassword = args[1];
// Create the necessary URL objects.
try {
metafeedUrl = new URL(METAFEED_URL_BASE + userName);
eventFeedUrl = new URL(METAFEED_URL_BASE + userName
+ EVENT_FEED_URL_SUFFIX);
} catch (MalformedURLException e) {
// Bad URL
System.err.println("Uh oh - you've got an invalid URL.");
e.printStackTrace();
return;
}
try {
myService.setUserCredentials(userName, userPassword);
// Demonstrate retrieving a list of the user's calendars.
printUserCalendars(myService);
// Demonstrate various feed queries.
System.out.println("Printing all events");
printAllEvents(myService);
System.out.println("Full text query");
fullTextQuery(myService, "Tennis");
dateRangeQuery(myService, DateTime.parseDate("2007-01-05"), DateTime
.parseDate("2007-01-07"));
// Demonstrate creating a single-occurrence event.
CalendarEventEntry singleEvent = createSingleEvent(myService,
"Tennis with Mike", "Meet for a quick lesson.");
System.out.println("Successfully created event "
+ singleEvent.getTitle().getPlainText());
// Demonstrate creating a quick add event.
CalendarEventEntry quickAddEvent = createQuickAddEvent(myService,
"Tennis with John April 11 3pm-3:30pm");
System.out.println("Successfully created quick add event "
+ quickAddEvent.getTitle().getPlainText());
// Demonstrate creating a web content event.
CalendarEventEntry webContentEvent = createWebContentEvent(myService,
"World Cup", "image/gif",
"http://www.google.com/logos/worldcup06.gif",
"http://www.google.com/calendar/images/google-holiday.gif", "276",
"120");
System.out.println("Successfully created web content event "
+ webContentEvent.getTitle().getPlainText());
// Demonstrate creating a recurring event.
CalendarEventEntry recurringEvent = createRecurringEvent(myService,
"Tennis with Dan", "Weekly tennis lesson.");
System.out.println("Successfully created recurring event "
+ recurringEvent.getTitle().getPlainText());
// Demonstrate updating the event's text.
singleEvent = updateTitle(singleEvent, "Important meeting");
System.out.println("Event's new title is \""
+ singleEvent.getTitle().getPlainText() + "\".");
// Demonstrate adding a reminder. Note that this will only work on a
// primary calendar.
singleEvent = addReminder(singleEvent, 15, Method.EMAIL);
System.out.println("Set a "
+ singleEvent.getReminder().get(0).getMinutes()
+ " minute " + singleEvent.getReminder().get(0).getMethod()
+ " reminder for the event.");
// Demonstrate adding an extended property.
singleEvent = addExtendedProperty(singleEvent);
// Demonstrate deleting the entries with a batch request.
List<CalendarEventEntry> eventsToDelete =
new ArrayList<CalendarEventEntry>();
eventsToDelete.add(singleEvent);
eventsToDelete.add(quickAddEvent);
eventsToDelete.add(webContentEvent);
eventsToDelete.add(recurringEvent);
deleteEvents(myService, eventsToDelete);
} catch (IOException e) {
// Communications error
System.err.println("There was a problem communicating with the service.");
e.printStackTrace();
} catch (ServiceException e) {
// Server side error
System.err.println("The server had a problem handling your request.");
e.printStackTrace();
}
}
/**
* Prints the command line usage of this sample application.
*/
private static void usage() {
System.out.println("Syntax: EventFeedDemo <username> <password>");
System.out.println("\nThe username and password are used for "
+ "authentication. The sample application will modify the specified "
+ "user's calendars so you may want to use a test account.");
}
}