Java tutorial
/** * Licensed to Jasig under one or more contributor license * agreements. See the NOTICE file distributed with this work * for additional information regarding copyright ownership. * Jasig licenses this file to you 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 org.jasig.portlet.calendar.mvc.controller; import net.fortuna.ical4j.data.CalendarOutputter; import net.fortuna.ical4j.model.Calendar; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jasig.portlet.calendar.CalendarConfiguration; import org.jasig.portlet.calendar.adapter.CalendarEventsDao; import org.jasig.portlet.calendar.adapter.CalendarException; import org.jasig.portlet.calendar.adapter.ICalendarAdapter; import org.jasig.portlet.calendar.dao.CalendarStore; import org.jasig.portlet.calendar.mvc.CalendarDisplayEvent; import org.jasig.portlet.calendar.mvc.CalendarHelper; import org.jasig.portlet.calendar.mvc.JsonCalendarEventWrapper; import org.jasig.portlet.calendar.util.DateUtil; import org.joda.time.DateMidnight; import org.joda.time.DateTime; import org.joda.time.DateTimeZone; import org.joda.time.Interval; import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.DateTimeFormatterBuilder; import org.springframework.beans.BeansException; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Required; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.portlet.ModelAndView; import org.springframework.web.portlet.bind.annotation.ActionMapping; import org.springframework.web.portlet.bind.annotation.ResourceMapping; import javax.annotation.Resource; import javax.portlet.*; import javax.servlet.http.HttpServletResponse; import java.util.*; @Controller @RequestMapping("VIEW") public class AjaxCalendarController extends AbstractBYUHelper implements ApplicationContextAware { protected final Log log = LogFactory.getLog(this.getClass()); @ActionMapping(params = "action=showDatePicker") public void toggleShowDatePicker(@RequestParam(value = "show") String show, ActionRequest request, ActionResponse response) { try { request.getPreferences().setValue("showDatePicker", show); request.getPreferences().store(); } catch (Exception exception) { log.info("Exception encountered saving preference: PREFERENCE=showDatePicker, EXCEPTION=" + exception); } } @ResourceMapping public ModelAndView getEventList(ResourceRequest request, ResourceResponse response) throws Exception { // Pull parameters out of the resourceId final String resourceId = request.getResourceID(); final String[] resourceIdTokens = resourceId.split("-"); final String startDate = resourceIdTokens[0]; final int days = Integer.parseInt(resourceIdTokens[1]); final boolean refresh = resourceIdTokens.length > 2 ? Boolean.valueOf(resourceIdTokens[2]) : false; final long startTime = System.currentTimeMillis(); final List<String> errors = new ArrayList<String>(); final Map<String, Object> model = new HashMap<String, Object>(); final PortletSession session = request.getPortletSession(); // get the user's configured time zone final String timezone = (String) session.getAttribute("timezone"); final DateTimeZone tz = DateTimeZone.forID(timezone); // get the period for this request final Interval interval = DateUtil.getInterval(startDate, days, request); final Set<CalendarDisplayEvent> calendarEvents = helper.getEventList(errors, interval, request); int index = 0; final Set<JsonCalendarEventWrapper> events = new TreeSet<JsonCalendarEventWrapper>(); for (CalendarDisplayEvent e : calendarEvents) { events.add(new JsonCalendarEventWrapper(e, index++)); } /* * Transform the event set into a map keyed by day. This code is * designed to separate events by day according to the user's configured * time zone. This ensures that we keep complicated time-zone handling * logic out of the JavaScript. * * Events are keyed by a string uniquely representing the date that is * still orderable. So that we can display a more user-friendly date * name, we also create a map representing date display names for each * date keyed in this response. */ // define a DateFormat object that uniquely identifies dates in a way // that can easily be ordered DateTimeFormatter orderableDf = new DateTimeFormatterBuilder().appendYear(4, 4).appendLiteral("-") .appendMonthOfYear(2).appendLiteral("-").appendDayOfMonth(2).toFormatter().withZone(tz); // define a DateFormat object that can produce user-facing display // names for dates DateTimeFormatter displayDf = new DateTimeFormatterBuilder().appendDayOfWeekText().appendLiteral(" ") .appendMonthOfYearText().appendLiteral(" ").appendDayOfMonth(1).toFormatter().withZone(tz); // define "today" and "tomorrow" so we can display these specially in the // user interface DateMidnight now = new DateMidnight(tz); String today = orderableDf.print(now); String tomorrow = orderableDf.print(now.plusDays(1)); Map<String, String> dateDisplayNames = new HashMap<String, String>(); Map<String, List<JsonCalendarEventWrapper>> eventsByDay = new LinkedHashMap<String, List<JsonCalendarEventWrapper>>(); for (JsonCalendarEventWrapper event : events) { String day = orderableDf.print(event.getEvent().getDayStart()); // if we haven't seen this day before, add entries to the event // and date name maps if (!eventsByDay.containsKey(day)) { // add a list for this day to the eventsByDay map eventsByDay.put(day, new ArrayList<JsonCalendarEventWrapper>()); // Add an appropriate day name for this date to the date names // map. If the day appears to be today or tomorrow display a // special string value. Otherwise, use the user-facing date // format object if (today.equals(day)) { dateDisplayNames.put(day, "Today"); } else if (tomorrow.equals(day)) { dateDisplayNames.put(day, "Tomorrow"); } else { dateDisplayNames.put(day, displayDf.print(event.getEvent().getDayStart())); } } // add the event to the by-day map eventsByDay.get(day).add(event); } if (log.isTraceEnabled()) { log.trace("Prepared the following eventsByDay collection for user '" + request.getRemoteUser() + "':" + eventsByDay); } model.put("dateMap", eventsByDay); model.put("dateNames", dateDisplayNames); model.put("viewName", "jsonView"); model.put("errors", errors); String etag = String.valueOf(model.hashCode()); String requestEtag = request.getETag(); // if the request ETag matches the hash for this response, send back // an empty response indicating that cached content should be used if (!refresh && request.getETag() != null && etag.equals(requestEtag)) { if (log.isTraceEnabled()) { log.trace("Sending an empty response (due to matched ETag and " + "refresh=false) for user '" + request.getRemoteUser() + "'"); } response.getCacheControl().setExpirationTime(1); response.getCacheControl().setETag(etag); response.getCacheControl().setUseCachedContent(true); response.setProperty(ResourceResponse.HTTP_STATUS_CODE, Integer.toString(HttpServletResponse.SC_NOT_MODIFIED)); // returning null appears to cause the response to be committed // before returning to the portal, so just use an empty view return new ModelAndView("empty", Collections.<String, String>emptyMap()); } if (log.isTraceEnabled()) { log.trace("Sending a full response for user '" + request.getRemoteUser() + "' and refresh=" + refresh); } // create new content with new validation tag response.getCacheControl().setETag(etag); response.getCacheControl().setExpirationTime(1); long overallTime = System.currentTimeMillis() - startTime; log.debug("AjaxCalendarController took " + overallTime + " ms to produce JSON model"); return new ModelAndView("json", model); } @ResourceMapping(value = "exportUserCalendar") public String exportCalendar(ResourceRequest request, ResourceResponse response, @RequestParam("configurationId") Long id) { CalendarConfiguration calendarConfig = calendarStore.getCalendarConfiguration(id); CalendarException exception = null; try { // get an instance of the adapter for this calendar ICalendarAdapter adapter = (ICalendarAdapter) applicationContext .getBean(calendarConfig.getCalendarDefinition().getClassName()); DateTime intervalStart = new DateTime().minusYears(1); DateTime intervalEnd = new DateTime().plusYears(1); Interval interval = new Interval(intervalStart, intervalEnd); Calendar calendar = calendarEventsDao.getCalendar(adapter, calendarConfig, interval, request); // Calendars should be fairly small, so no need to save file to disk or // buffer to calculate size. response.setContentType("text/calendar"); response.addProperty("Content-disposition", "attachment; filename=calendar.ics"); CalendarOutputter calendarOut = new CalendarOutputter(); calendarOut.output(calendar, response.getWriter()); response.flushBuffer(); return null; } catch (NoSuchBeanDefinitionException ex) { exception = new CalendarException("Calendar adapter class instance could not be found", ex); } catch (Exception ex) { exception = new CalendarException("Error sending calendar " + calendarConfig.getCalendarDefinition().getName() + " to user for downloading", ex); } // Allow container to handle exceptions and give HTTP error throw exception; } @Autowired(required = true) private CalendarHelper helper; @Autowired(required = true) private CalendarEventsDao calendarEventsDao; // @Autowired(required = true) // private ICalendarSetDao calendarSetDao; private CalendarStore calendarStore; @Required @Resource(name = "calendarStore") public void setCalendarStore(CalendarStore calendarStore) { this.calendarStore = calendarStore; } private ApplicationContext applicationContext; public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } }