package com.casamind.adware.server.servlet.gdata;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.logging.Logger;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.casamind.adware.server.domain.Ad;
import com.casamind.adware.server.domain.Schedule;
import com.casamind.adware.server.domain.Slot;
import com.casamind.adware.server.proxy.DatastoreProxy;
import com.casamind.adware.server.proxy.GDataCalendarProxy;
import com.casamind.adware.shared.GoogleCalendarTaskTypes;
import com.google.appengine.api.taskqueue.QueueFactory;
import com.google.appengine.api.taskqueue.TaskOptions;
import com.google.apphosting.api.DeadlineExceededException;
import com.google.gdata.data.DateTime;
import com.google.gdata.data.PlainTextConstruct;
import com.google.gdata.data.batch.BatchOperationType;
import com.google.gdata.data.calendar.CalendarEventEntry;
import com.google.gdata.data.calendar.CalendarEventFeed;
import com.google.gdata.data.extensions.When;
import com.google.gdata.util.ServiceException;
@SuppressWarnings("serial")
public class CalendarHandler extends HttpServlet {
private static final Logger log = Logger.getLogger(CalendarHandler.class.getName());
private String gdataCalendarLogin, gdataCalendarPassword, calendarFeedUrl,
publishedScheduleCalendarName;
private SimpleDateFormat logFormatter, calFormatter;
private GDataCalendarProxy proxy;
private long gdataThreadSleep;
private long gdataConnectTimeout;
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
ServletContext context = config.getServletContext();
gdataThreadSleep = Long.parseLong(context.getInitParameter("gdataThreadSleep"));
gdataConnectTimeout = Long.parseLong(context.getInitParameter("gdataConnectTimeout"));
gdataCalendarLogin = context.getInitParameter("gdataCalendarLogin");
gdataCalendarPassword = context.getInitParameter("gdataCalendarPassword");
calendarFeedUrl = context.getInitParameter("calendarFeedUrl");
publishedScheduleCalendarName = context.getInitParameter("publishedScheduleCalendarName");
proxy = new GDataCalendarProxy(calendarFeedUrl, gdataCalendarLogin, gdataCalendarPassword, gdataThreadSleep, gdataConnectTimeout);
logFormatter = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm");
calFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
}
@Override
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
log.info("Entering GDataCalendarServlet...");
String task = req.getParameter("task");
Long entityId = Long.parseLong(req.getParameter("entityId"));
if (task.equals(GoogleCalendarTaskTypes.SCHEDULE)) {
log.info("Peforming schedule update task...");
doSchedule(entityId);
} else if (task.equals(GoogleCalendarTaskTypes.DELETE)) {
log.info("Peforming event deletion task...");
deleteEventEntry(entityId);
}
log.info("Exiting GDataCalendarServlet...");
resp.getWriter().println("Finished at: " + new Date());
}
private void deleteEventEntry(Long entityId) {
log.info("Deleting calendar event entries for withdrawn slot with entityId: " + entityId);
Slot slot = DatastoreProxy.getSlotById(entityId);
if (slot != null) {
log.info("Purging Google Calendar from '" + logFormatter.format(slot.getStartDate()) + "' to '" + logFormatter.format(slot.getEndDate()) + "'");
try {
CalendarEventFeed rangeFeed = proxy.getEventsRangeFeed(slot.getStartDate(), slot.getEndDate());
List<CalendarEventEntry> entriesToDelete = new ArrayList<CalendarEventEntry>();
entriesToDelete.addAll(rangeFeed.getEntries());
int size = entriesToDelete.size();
while (size > 0) {
log.info("Adding " + size + " event entries to mass deletion batch...");
proxy.batchEntries(entriesToDelete, BatchOperationType.DELETE);
rangeFeed = proxy.getEventsRangeFeed(slot.getStartDate(), slot.getEndDate());
entriesToDelete.clear();
entriesToDelete.addAll(rangeFeed.getEntries());
size = entriesToDelete.size();
}
log.info("Finshed mass deletion batch.");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ServiceException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else {
log.warning("No slot found with entityId=" + entityId + ". Will exit servlet.");
}
}
private void doSchedule(Long scheduleId) {
log.info("scheduleId = " + scheduleId);
if (scheduleId != null) {
Schedule schedule = DatastoreProxy.getScheduleById(scheduleId);
if (schedule != null) {
List<Long> adIds = schedule.getAdIds();
if (adIds.size() > 0) {
log.info("Found " + adIds.size() + " ads");
log.info("Purging Google Calendar from '" + logFormatter.format(schedule.getMinDate()) + "' to '" + logFormatter.format(schedule.getMaxDate()) + "'");
try {
Calendar calendar = Calendar.getInstance();
calendar.setTime(schedule.getMinDate());
calendar.add(Calendar.DAY_OF_YEAR, -2);
Date minDate = calendar.getTime();
CalendarEventFeed rangeFeed = proxy.getEventsRangeFeed(minDate, schedule.getMaxDate());
List<CalendarEventEntry> entriesToDelete = new ArrayList<CalendarEventEntry>();
entriesToDelete.addAll(rangeFeed.getEntries());
int size = entriesToDelete.size();
while (size > 0) {
log.info("Adding " + size + " event entries to mass deletion batch...");
proxy.batchEntries(entriesToDelete, BatchOperationType.DELETE);
rangeFeed = proxy.getEventsRangeFeed(minDate, schedule.getMaxDate());
entriesToDelete.clear();
entriesToDelete.addAll(rangeFeed.getEntries());
size = entriesToDelete.size();
}
log.info("Finshed mass deletion batch.");
List<CalendarEventEntry> entriesToInsert = new ArrayList<CalendarEventEntry>();
for (Long id : adIds) {
if (id != null) {
Ad ad = DatastoreProxy.getAdById(id);
if (ad != null) {
CalendarEventEntry eventEntry = new CalendarEventEntry();
String title, content, attendee;
title = ad.getProduct() + " (" + ad.getCompany() + ")";
eventEntry.setTitle(new PlainTextConstruct(title));
// EventWho who = new EventWho();
// who.setValueString(attendee);
// who.setEmail("casamind.avicena@gmail.com");
// eventEntry.getParticipants().add(who);
content = ad.getSlogan() + "\n" + ad.getText();
if (ad.getResourceURLs() != null) {
for (String resource : ad.getResourceURLs()) {
content += "\n" + resource;
}
}
eventEntry.setContent(new PlainTextConstruct(content));
DateTime startTime = DateTime.parseDateTime(calFormatter.format(ad.getStartTime()));
DateTime endTime = DateTime.parseDateTime(calFormatter.format(ad.getEndTime()));
When eventTimes = new When();
eventTimes.setStartTime(startTime);
eventTimes.setEndTime(endTime);
eventEntry.addTime(eventTimes);
entriesToInsert.add(eventEntry);
log.info("Added event: " + title + "\tFrom: " + startTime + "\tto: " + endTime);
}
}
}
int j = 0, k = 0;
size = entriesToInsert.size();
// Google Calendar batches are limited to 25 operation
log.info("Preparing mass insertion batch for " + entriesToInsert.size() + " entries...");
while (j < size) {
List<CalendarEventEntry> entries = new ArrayList<CalendarEventEntry>();
while (k < 25 && j + k < size) {
entries.add(entriesToInsert.get(j));
k++;
j++;
}
log.info("Adding " + k + " event entries to mass insertion batch...");
proxy.batchEntries(entries, BatchOperationType.INSERT);
k = 0;
}
log.info("Batched mass deletion for " + entriesToInsert.size() + " entries.");
log.info("Finshed mass insertion batch.");
} catch (ServiceException e) {
e.printStackTrace();
} catch (DeadlineExceededException e) {
// reschedule the same task due to AppEngine servlet
// execution timeout
QueueFactory.getQueue("gdata").add(TaskOptions.Builder.withUrl("/tasks/gdata/calendar").param("task", GoogleCalendarTaskTypes.SCHEDULE).param("entityId", scheduleId.toString()));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} else {
log.warning("Reterned Schedule entity was null!\n Exiting servlet...");
}
} else {
log.warning("'scheduleId' is null!");
}
}
}