/** * Returns a cached onset for the specified date. * * @param date * @return a cached onset date or null if no cached onset is applicable for the specified date */ private DateTime getCachedOnset(final Date date) { int index = Arrays.binarySearch(onsetsMillisec, date.getTime()); if (index >= 0) { return onsetsDates[index]; } else { int insertionIndex = -index - 1; return onsetsDates[insertionIndex - 1]; } }
/** * Build recurring properties from ical recurrence. * * @param r * @return RecurTyp filled in * @throws Throwable */ public static RecurType doRecur(final Recur r) throws Throwable { RecurType rt = new RecurType(); rt.setFreq(FreqRecurType.fromValue(r.getFrequency())); if (r.getCount() > 0) { rt.setCount(BigInteger.valueOf(r.getCount())); } Date until = r.getUntil(); if (until != null) { UntilRecurType u = new UntilRecurType(); XcalUtil.initUntilRecur(u, until.toString()); } if (r.getInterval() > 0) { rt.setInterval(String.valueOf(r.getInterval())); } listFromNumberList(rt.getBysecond(), r.getSecondList()); listFromNumberList(rt.getByminute(), r.getMinuteList()); listFromNumberList(rt.getByhour(), r.getHourList()); if (r.getDayList() != null) { List<String> l = rt.getByday(); for (Object o : r.getDayList()) { l.add(((WeekDay) o).getDay()); } } listFromNumberList(rt.getByyearday(), r.getYearDayList()); intlistFromNumberList(rt.getBymonthday(), r.getMonthDayList()); listFromNumberList(rt.getByweekno(), r.getWeekNoList()); intlistFromNumberList(rt.getBymonth(), r.getMonthList()); bigintlistFromNumberList(rt.getBysetpos(), r.getSetPosList()); return rt; }
@Override @SuppressWarnings("unchecked") public String encode(List<CalendarEvent> events) { if (events == null || events.isEmpty()) { throw new IllegalArgumentException("The calendar events must be defined to encode them"); } Calendar calendarIcs = new Calendar(); calendarIcs.getProperties().add(new ProdId("-//Silverpeas//iCal4j 1.1//FR")); calendarIcs.getProperties().add(Version.VERSION_2_0); calendarIcs.getProperties().add(CalScale.GREGORIAN); List<VEvent> iCalEvents = new ArrayList<VEvent>(); ByteArrayOutputStream output = new ByteArrayOutputStream(10240); for (CalendarEvent event : events) { Date startDate = anICal4JDateCodec().encode(event.getStartDate()); Date endDate = anICal4JDateCodec().encode(event.getEndDate()); VEvent iCalEvent; if (event.isOnAllDay() && startDate.equals(endDate)) { iCalEvent = new VEvent(startDate, event.getTitle()); } else { iCalEvent = new VEvent(startDate, endDate, event.getTitle()); } // Generate UID iCalEvent.getProperties().add(generator.generateUid()); // Add recurring data if any if (event.isRecurring()) { CalendarEventRecurrence eventRecurrence = event.getRecurrence(); Recur recur = anICal4JRecurrenceCodec().encode(eventRecurrence); iCalEvent.getProperties().add(new RRule(recur)); iCalEvent.getProperties().add(exceptionDatesFrom(eventRecurrence)); } // Add Description iCalEvent.getProperties().add(new Description(event.getDescription())); // Add Classification iCalEvent.getProperties().add(new Clazz(event.getAccessLevel())); // Add Priority iCalEvent.getProperties().add(new Priority(event.getPriority())); // Add location if any if (!event.getLocation().isEmpty()) { iCalEvent.getProperties().add(new Location(event.getLocation())); } // Add event URL if any if (event.getUrl() != null) { try { iCalEvent.getProperties().add(new Url(event.getUrl().toURI())); } catch (URISyntaxException ex) { throw new EncodingException(ex.getMessage(), ex); } } // Add Categories TextList categoryList = new TextList(event.getCategories().asArray()); if (!categoryList.isEmpty()) { iCalEvent.getProperties().add(new Categories(categoryList)); } // Add attendees for (String attendee : event.getAttendees().asList()) { try { iCalEvent.getProperties().add(new Attendee(attendee)); } catch (URISyntaxException ex) { throw new EncodingException("Malformed attendee URI: " + attendee, ex); } } iCalEvents.add(iCalEvent); } calendarIcs.getComponents().addAll(iCalEvents); CalendarOutputter outputter = new CalendarOutputter(); try { outputter.output(calendarIcs, output); return output.toString(CharEncoding.UTF_8); } catch (Exception ex) { throw new EncodingException( "The encoding of the events in iCal formatted text has failed!", ex); } finally { IOUtils.closeQuietly(output); } }
// private Date calculateOnset(DateProperty dateProperty) { // return calculateOnset(dateProperty.getValue()); // } // private DateTime calculateOnset(Date date) throws ParseException { return calculateOnset(date.toString()); }
/** * Returns the latest applicable onset of this observance for the specified date. * * @param date the latest date that an observance onset may occur * @return the latest applicable observance date or null if there is no applicable observance * onset for the specified date */ public final Date getLatestOnset(final Date date) { if (initialOnset == null) { try { initialOnset = applyOffsetFrom(calculateOnset(((DtStart) getProperty(Property.DTSTART)).getDate())); } catch (ParseException e) { Log log = LogFactory.getLog(Observance.class); log.error("Unexpected error calculating initial onset", e); // XXX: is this correct? return null; } } // observance not applicable if date is before the effective date of this observance.. if (date.before(initialOnset)) { return null; } if ((onsetsMillisec != null) && (onsetLimit == null || date.before(onsetLimit))) { return getCachedOnset(date); } Date onset = initialOnset; Date initialOnsetUTC; // get first onset without adding TZFROM as this may lead to a day boundary // change which would be incompatible with BYDAY RRULES // we will have to add the offset to all cacheable onsets try { initialOnsetUTC = calculateOnset(((DtStart) getProperty(Property.DTSTART)).getDate()); } catch (ParseException e) { Log log = LogFactory.getLog(Observance.class); log.error("Unexpected error calculating initial onset", e); // XXX: is this correct? return null; } // collect all onsets for the purposes of caching.. final DateList cacheableOnsets = new DateList(); cacheableOnsets.setUtc(true); cacheableOnsets.add(initialOnset); // check rdates for latest applicable onset.. final PropertyList rdates = getProperties(Property.RDATE); for (final Iterator i = rdates.iterator(); i.hasNext(); ) { final RDate rdate = (RDate) i.next(); for (final Iterator j = rdate.getDates().iterator(); j.hasNext(); ) { try { final DateTime rdateOnset = applyOffsetFrom(calculateOnset((Date) j.next())); if (!rdateOnset.after(date) && rdateOnset.after(onset)) { onset = rdateOnset; } /* * else if (rdateOnset.after(date) && rdateOnset.after(onset) && (nextOnset == null || * rdateOnset.before(nextOnset))) { nextOnset = rdateOnset; } */ cacheableOnsets.add(rdateOnset); } catch (ParseException e) { Log log = LogFactory.getLog(Observance.class); log.error("Unexpected error calculating onset", e); } } } // check recurrence rules for latest applicable onset.. final PropertyList rrules = getProperties(Property.RRULE); for (final Iterator i = rrules.iterator(); i.hasNext(); ) { final RRule rrule = (RRule) i.next(); // include future onsets to determine onset period.. final Calendar cal = Dates.getCalendarInstance(date); cal.setTime(date); cal.add(Calendar.YEAR, 10); onsetLimit = Dates.getInstance(cal.getTime(), Value.DATE_TIME); final DateList recurrenceDates = rrule.getRecur().getDates(initialOnsetUTC, onsetLimit, Value.DATE_TIME); for (final Iterator j = recurrenceDates.iterator(); j.hasNext(); ) { final DateTime rruleOnset = applyOffsetFrom((DateTime) j.next()); if (!rruleOnset.after(date) && rruleOnset.after(onset)) { onset = rruleOnset; } /* * else if (rruleOnset.after(date) && rruleOnset.after(onset) && (nextOnset == null || * rruleOnset.before(nextOnset))) { nextOnset = rruleOnset; } */ cacheableOnsets.add(rruleOnset); } } // cache onsets.. Collections.sort(cacheableOnsets); DateTime cacheableOnset = null; this.onsetsMillisec = new long[cacheableOnsets.size()]; this.onsetsDates = new DateTime[onsetsMillisec.length]; for (int i = 0; i < onsetsMillisec.length; i++) { cacheableOnset = (DateTime) cacheableOnsets.get(i); onsetsMillisec[i] = cacheableOnset.getTime(); onsetsDates[i] = cacheableOnset; } return onset; }