use of net.fortuna.ical4j.model.PropertyList in project bw-calendar-engine by Bedework.
the class BwEventUtil method toEvent.
/**
* We are going to try to construct a BwEvent object from a VEvent. This
* may represent a new event or an update to a pre-existing event. In any
* case, the VEvent probably has insufficient information to completely
* reconstitute the event object so we'll get the uid first and retrieve
* the event if it exists.
*
* <p>To put it another way we're doing a diff then update.
*
* <p>If it doesn't exist, we'll first fill in the appropriate fields,
* (non-public, creator, created etc) then for both cases update the
* remaining fields from the VEvent.
*
* <p>Recurring events present some challenges. If there is no recurrence
* id the vevent represents the master entity which defines the recurrence
* rules. If a recurrence id is present then the vevent represents a
* recurrence instance override and we should not attempt to retrieve the
* actual object but the referenced instance.
*
* <p>Also, note that we sorted the components first so we get the master
* before any instances.
*
* <p>If DTSTART, RRULE, EXRULE have changed (also RDATE, EXDATE?) then any
* existing overrides are unusable. We should delete all overrides and replace
* with new ones.
*
* <p>For an update we have to keep track of which fields were present in
* the vevent and set all absent fields to null in the BwEvent.
*
* @param cb IcalCallback object
* @param cal Needed so we can retrieve the event.
* @param ical Icalendar we are converting. We check its events for
* overrides.
* @param val VEvent object
* @param diff True if we should assume we are updating existing events.
* @param mergeAttendees True if we should only update our own attendee.
* @return EventInfo object representing new entry or updated entry
* @throws CalFacadeException
*/
public static EventInfo toEvent(final IcalCallback cb, final BwCalendar cal, final Icalendar ical, final Component val, final boolean diff, final boolean mergeAttendees) throws CalFacadeException {
if (val == null) {
return null;
}
String currentPrincipal = null;
final BwPrincipal principal = cb.getPrincipal();
if (principal != null) {
currentPrincipal = principal.getPrincipalRef();
}
final boolean debug = getLog().isDebugEnabled();
@SuppressWarnings("unchecked") final Holder<Boolean> hasXparams = new Holder<Boolean>(Boolean.FALSE);
final int methodType = ical.getMethodType();
String attUri = null;
if (mergeAttendees) {
// We'll need this later.
attUri = cb.getCaladdr(cb.getPrincipal().getPrincipalRef());
}
final String colPath;
if (cal == null) {
colPath = null;
} else {
colPath = cal.getPath();
}
try {
final PropertyList pl = val.getProperties();
boolean vpoll = false;
if (pl == null) {
// Empty component
return null;
}
final int entityType;
if (val instanceof VEvent) {
entityType = IcalDefs.entityTypeEvent;
} else if (val instanceof VToDo) {
entityType = IcalDefs.entityTypeTodo;
} else if (val instanceof VJournal) {
entityType = IcalDefs.entityTypeJournal;
} else if (val instanceof VFreeBusy) {
entityType = IcalDefs.entityTypeFreeAndBusy;
} else if (val instanceof VAvailability) {
entityType = IcalDefs.entityTypeVavailability;
} else if (val instanceof Available) {
entityType = IcalDefs.entityTypeAvailable;
} else if (val instanceof VPoll) {
entityType = IcalDefs.entityTypeVpoll;
vpoll = true;
} else {
throw new CalFacadeException("org.bedework.invalid.component.type", val.getName());
}
Property prop;
// Get the guid from the component
String guid = null;
prop = pl.getProperty(Property.UID);
if (prop != null) {
testXparams(prop, hasXparams);
guid = prop.getValue();
}
if (guid == null) {
/* XXX A guid is required - but are there devices out there without a
* guid - and if so how do we handle it?
*/
throw new CalFacadeException(CalFacadeException.noGuid);
}
/* See if we have a recurrence id */
BwDateTime ridObj = null;
String rid = null;
prop = pl.getProperty(Property.RECURRENCE_ID);
if (prop != null) {
testXparams(prop, hasXparams);
ridObj = BwDateTime.makeBwDateTime((DateProperty) prop);
if (ridObj.getRange() != null) {
/* XXX What do I do with it? */
warn("TRANS-TO_EVENT: Got a recurrence id range");
}
rid = ridObj.getDate();
}
EventInfo masterEI = null;
EventInfo evinfo = null;
BwEvent ev = null;
/* If we have a recurrence id see if we already have the master (we should
* get a master + all its overrides).
*
* If so find the override and use the annnotation or if no override,
* make one.
*
* If no override retrieve the event, add it to our table and then locate the
* annotation.
*
* If there is no annotation, create one.
*
* It's possible we have been sent 'detached' instances of a recurring
* event. This may happen if we are invited to one or more instances of a
* meeting. In this case we try to retrieve the master and if it doesn't
* exist we manufacture one. We consider such an instance an update to
* that instance only and leave the others alone.
*/
/* We need this in a couple of places */
final DtStart dtStart = (DtStart) pl.getProperty(Property.DTSTART);
/* If this is a recurrence instance see if we can find the master
*/
if (rid != null) {
// See if we have a new master event. If so create a proxy to this event.
masterEI = findMaster(guid, ical.getComponents());
if (masterEI != null) {
evinfo = masterEI.findOverride(rid);
}
}
if (diff && (evinfo == null) && (cal != null) && (cal.getCalType() != BwCalendar.calTypeInbox) && (cal.getCalType() != BwCalendar.calTypePendingInbox) && (cal.getCalType() != BwCalendar.calTypeOutbox)) {
if (debug) {
debugMsg("TRANS-TO_EVENT: try to fetch event with guid=" + guid);
}
final Collection<EventInfo> eis = cb.getEvent(colPath, guid);
if (Util.isEmpty(eis)) {
// do nothing
} else if (eis.size() > 1) {
// DORECUR - wrong again
throw new CalFacadeException("More than one event returned for guid.");
} else {
evinfo = eis.iterator().next();
}
if (debug) {
if (evinfo != null) {
debugMsg("TRANS-TO_EVENT: fetched event with guid");
} else {
debugMsg("TRANS-TO_EVENT: did not find event with guid");
}
}
if (evinfo != null) {
if (rid != null) {
// We just retrieved it's master
masterEI = evinfo;
masterEI.setInstanceOnly(true);
evinfo = masterEI.findOverride(rid);
ical.addComponent(masterEI);
} else if (methodType == ScheduleMethods.methodTypeCancel) {
// This should never have an rid for cancel of entire event.
evinfo.setInstanceOnly(evinfo.getEvent().getSuppressed());
} else {
// Presumably sent an update for the entire event. No longer suppressed master
evinfo.getEvent().setSuppressed(false);
}
} else if (rid != null) {
/* Manufacture a master for the instance */
masterEI = makeNewEvent(cb, entityType, guid, colPath);
final BwEvent e = masterEI.getEvent();
// XXX This seems bogus
final DtStart mdtStart;
final String bogusDate = "19980118";
final String bogusTime = "T230000";
final Parameter par = dtStart.getParameter("VALUE");
final boolean isDateType = (par != null) && (par.equals(Value.DATE));
if (isDateType) {
mdtStart = new DtStart(new Date(bogusDate));
} else if (dtStart.isUtc()) {
mdtStart = new DtStart(bogusDate + bogusTime + "Z");
} else if (dtStart.getTimeZone() == null) {
mdtStart = new DtStart(bogusDate + bogusTime);
} else {
mdtStart = new DtStart(bogusDate + bogusTime + "Z", dtStart.getTimeZone());
}
setDates(cb.getPrincipal().getPrincipalRef(), masterEI, mdtStart, null, null);
e.setRecurring(true);
// e.addRdate(ridObj);
e.setSuppressed(true);
ical.addComponent(masterEI);
evinfo = masterEI.findOverride(rid);
masterEI.setInstanceOnly(rid != null);
}
}
if (evinfo == null) {
evinfo = makeNewEvent(cb, entityType, guid, colPath);
} else if (evinfo.getEvent().getEntityType() != entityType) {
throw new CalFacadeException("org.bedework.mismatched.entity.type", val.toString());
}
final ChangeTable chg = evinfo.getChangeset(cb.getPrincipal().getPrincipalRef());
if (rid != null) {
final String evrid = evinfo.getEvent().getRecurrenceId();
if ((evrid == null) || (!evrid.equals(rid))) {
warn("Mismatched rid ev=" + evrid + " expected " + rid);
// XXX spurious???
chg.changed(PropertyInfoIndex.RECURRENCE_ID, evrid, rid);
}
if (masterEI.getEvent().getSuppressed()) {
masterEI.getEvent().addRdate(ridObj);
}
}
ev = evinfo.getEvent();
ev.setScheduleMethod(methodType);
DtEnd dtEnd = null;
if (entityType == IcalDefs.entityTypeTodo) {
final Due due = (Due) pl.getProperty(Property.DUE);
if (due != null) {
dtEnd = new DtEnd(due.getParameters(), due.getValue());
}
} else {
dtEnd = (DtEnd) pl.getProperty(Property.DTEND);
}
final Duration duration = (Duration) pl.getProperty(Property.DURATION);
setDates(cb.getPrincipal().getPrincipalRef(), evinfo, dtStart, dtEnd, duration);
for (final Object aPl : pl) {
prop = (Property) aPl;
testXparams(prop, hasXparams);
// debugMsg("ical prop " + prop.getClass().getName());
String pval = prop.getValue();
if ((pval != null) && (pval.length() == 0)) {
pval = null;
}
final PropertyInfoIndex pi;
if (prop instanceof XProperty) {
pi = PropertyInfoIndex.XPROP;
} else {
pi = PropertyInfoIndex.fromName(prop.getName());
}
if (pi == null) {
debugMsg("Unknown property with name " + prop.getName() + " class " + prop.getClass() + " and value " + pval);
continue;
}
chg.present(pi);
switch(pi) {
case ACCEPT_RESPONSE:
/* ------------------- Accept Response -------------------- */
String sval = ((AcceptResponse) prop).getValue();
if (chg.changed(pi, ev.getPollAcceptResponse(), sval)) {
ev.setPollAcceptResponse(sval);
}
break;
case ATTACH:
/* ------------------- Attachment -------------------- */
chg.addValue(pi, getAttachment((Attach) prop));
break;
case ATTENDEE:
if (methodType == ScheduleMethods.methodTypePublish) {
if (cb.getStrictness() == IcalCallback.conformanceStrict) {
throw new CalFacadeException(CalFacadeException.attendeesInPublish);
}
if (cb.getStrictness() == IcalCallback.conformanceWarn) {
// warn("Had attendees for PUBLISH");
}
}
Attendee attPr = (Attendee) prop;
if (evinfo.getNewEvent() || !mergeAttendees) {
chg.addValue(pi, getAttendee(cb, attPr));
} else {
final String pUri = cb.getCaladdr(attPr.getValue());
if (pUri.equals(attUri)) {
/* Only update for our own attendee
* We're doing a PUT and this must be the attendee updating their
* partstat. We don't allow them to change other attendees
* whatever the PUT content says.
*/
chg.addValue(pi, getAttendee(cb, attPr));
} else {
// Use the value we currently have
boolean found = false;
for (final BwAttendee att : ev.getAttendees()) {
if (pUri.equals(att.getAttendeeUri())) {
chg.addValue(pi, att.clone());
found = true;
break;
}
}
if (!found) {
// An added attendee
final BwAttendee att = getAttendee(cb, attPr);
att.setPartstat(IcalDefs.partstatValNeedsAction);
chg.addValue(pi, att);
}
}
}
break;
case BUSYTYPE:
int ibt = BwEvent.fromBusyTypeString(pval);
if (chg.changed(pi, ev.getBusyType(), ibt)) {
ev.setBusyType(ibt);
}
break;
case CATEGORIES:
/* ------------------- Categories -------------------- */
Categories cats = (Categories) prop;
TextList cl = cats.getCategories();
String lang = getLang(cats);
if (cl != null) {
/* Got some categories */
Iterator cit = cl.iterator();
while (cit.hasNext()) {
String wd = (String) cit.next();
if (wd == null) {
continue;
}
BwString key = new BwString(lang, wd);
BwCategory cat = cb.findCategory(key);
if (cat == null) {
cat = BwCategory.makeCategory();
cat.setWord(key);
cb.addCategory(cat);
}
chg.addValue(pi, cat);
}
}
break;
case CLASS:
if (chg.changed(pi, ev.getClassification(), pval)) {
ev.setClassification(pval);
}
break;
case COMMENT:
/* ------------------- Comment -------------------- */
chg.addValue(pi, new BwString(null, pval));
break;
case COMPLETED:
if (chg.changed(pi, ev.getCompleted(), pval)) {
ev.setCompleted(pval);
}
break;
case CONTACT:
/* ------------------- Contact -------------------- */
String altrep = getAltRepPar(prop);
lang = getLang(prop);
String uid = getUidPar(prop);
BwString nm = new BwString(lang, pval);
BwContact contact = null;
if (uid != null) {
contact = cb.getContact(uid);
}
if (contact == null) {
contact = cb.findContact(nm);
}
if (contact == null) {
contact = BwContact.makeContact();
contact.setCn(nm);
contact.setLink(altrep);
cb.addContact(contact);
} else {
contact.setCn(nm);
contact.setLink(altrep);
}
chg.addValue(pi, contact);
break;
case CREATED:
if (chg.changed(pi, ev.getCreated(), pval)) {
ev.setCreated(pval);
}
break;
case DESCRIPTION:
if (chg.changed(pi, ev.getDescription(), pval)) {
ev.setDescription(pval);
}
break;
case DTEND:
break;
case DTSTAMP:
/* ------------------- DtStamp -------------------- */
ev.setDtstamp(pval);
break;
case DTSTART:
break;
case DURATION:
break;
case EXDATE:
/* ------------------- ExDate -------------------- */
chg.addValues(pi, makeDateTimes((DateListProperty) prop));
break;
case EXRULE:
/* ------------------- ExRule -------------------- */
chg.addValue(pi, pval);
break;
case FREEBUSY:
/* ------------------- freebusy -------------------- */
FreeBusy fbusy = (FreeBusy) prop;
PeriodList perpl = fbusy.getPeriods();
Parameter par = getParameter(fbusy, "FBTYPE");
int fbtype;
if (par == null) {
fbtype = BwFreeBusyComponent.typeBusy;
} else if (par.equals(FbType.BUSY)) {
fbtype = BwFreeBusyComponent.typeBusy;
} else if (par.equals(FbType.BUSY_TENTATIVE)) {
fbtype = BwFreeBusyComponent.typeBusyTentative;
} else if (par.equals(FbType.BUSY_UNAVAILABLE)) {
fbtype = BwFreeBusyComponent.typeBusyUnavailable;
} else if (par.equals(FbType.FREE)) {
fbtype = BwFreeBusyComponent.typeFree;
} else {
if (debug) {
debugMsg("Unsupported parameter " + par.getName());
}
throw new IcalMalformedException("parameter " + par.getName());
}
BwFreeBusyComponent fbc = new BwFreeBusyComponent();
fbc.setType(fbtype);
Iterator perit = perpl.iterator();
while (perit.hasNext()) {
Period per = (Period) perit.next();
fbc.addPeriod(per);
}
ev.addFreeBusyPeriod(fbc);
break;
case GEO:
/* ------------------- Geo -------------------- */
Geo g = (Geo) prop;
BwGeo geo = new BwGeo(g.getLatitude(), g.getLongitude());
if (chg.changed(pi, ev.getGeo(), geo)) {
ev.setGeo(geo);
}
break;
case LAST_MODIFIED:
if (chg.changed(pi, ev.getLastmod(), pval)) {
ev.setLastmod(pval);
}
break;
case LOCATION:
/* ------------------- Location -------------------- */
BwLocation loc = null;
// String uid = getUidPar(prop);
/* At the moment Mozilla lightning is broken and this leads to all
* sorts of problems.
if (uid != null) {
loc = cb.getLocation(uid);
}
*/
lang = getLang(prop);
BwString addr = null;
if (pval != null) {
if (loc == null) {
addr = new BwString(lang, pval);
loc = cb.findLocation(addr);
}
if (loc == null) {
loc = BwLocation.makeLocation();
loc.setAddress(addr);
cb.addLocation(loc);
}
}
BwLocation evloc = ev.getLocation();
if (chg.changed(pi, evloc, loc)) {
// CHGTBL - this only shows that it's a different location object
ev.setLocation(loc);
} else if ((loc != null) && (evloc != null)) {
// See if the value is changed
String evval = evloc.getAddress().getValue();
String inval = loc.getAddress().getValue();
if (!evval.equals(inval)) {
chg.changed(pi, evval, inval);
evloc.getAddress().setValue(inval);
}
}
break;
case ORGANIZER:
/* ------------------- Organizer -------------------- */
final BwOrganizer org = getOrganizer(cb, (Organizer) prop);
final BwOrganizer evorg = ev.getOrganizer();
final BwOrganizer evorgCopy;
if (evorg == null) {
evorgCopy = null;
} else {
evorgCopy = (BwOrganizer) evorg.clone();
}
if (chg.changed(pi, evorgCopy, org)) {
if (evorg == null) {
ev.setOrganizer(org);
} else {
evorg.update(org);
}
}
break;
case PERCENT_COMPLETE:
/* ------------------- PercentComplete -------------------- */
Integer ival = ((PercentComplete) prop).getPercentage();
if (chg.changed(pi, ev.getPercentComplete(), ival)) {
ev.setPercentComplete(ival);
}
break;
case POLL_MODE:
/* ------------------- Poll mode -------------------- */
sval = ((PollMode) prop).getValue();
if (chg.changed(pi, ev.getPollMode(), sval)) {
ev.setPollMode(sval);
}
break;
case POLL_PROPERTIES:
/* ------------------- Poll properties ---------------- */
sval = ((PollProperties) prop).getValue();
if (chg.changed(pi, ev.getPollProperties(), sval)) {
ev.setPollProperties(sval);
}
break;
case POLL_WINNER:
/* ------------------- Poll winner -------------------- */
ival = ((PollWinner) prop).getPollwinner();
if (chg.changed(pi, ev.getPollWinner(), ival)) {
ev.setPollWinner(ival);
}
break;
case PRIORITY:
/* ------------------- Priority -------------------- */
ival = ((Priority) prop).getLevel();
if (chg.changed(pi, ev.getPriority(), ival)) {
ev.setPriority(ival);
}
break;
case RDATE:
/* ------------------- RDate -------------------- */
chg.addValues(pi, makeDateTimes((DateListProperty) prop));
break;
case RECURRENCE_ID:
break;
case RELATED_TO:
/* ------------------- RelatedTo -------------------- */
final RelatedTo irelto = (RelatedTo) prop;
final BwRelatedTo relto = new BwRelatedTo();
final String parval = IcalUtil.getParameterVal(irelto, "RELTYPE");
if (parval != null) {
relto.setRelType(parval);
}
relto.setValue(irelto.getValue());
if (chg.changed(pi, ev.getRelatedTo(), relto)) {
ev.setRelatedTo(relto);
}
break;
case REQUEST_STATUS:
/* ------------------- RequestStatus -------------------- */
final BwRequestStatus rs = BwRequestStatus.fromRequestStatus((RequestStatus) prop);
chg.addValue(pi, rs);
break;
case RESOURCES:
/* ------------------- Resources -------------------- */
final TextList rl = ((Resources) prop).getResources();
if (rl != null) {
/* Got some resources */
lang = getLang(prop);
Iterator rit = rl.iterator();
while (rit.hasNext()) {
BwString rsrc = new BwString(lang, (String) rit.next());
chg.addValue(pi, rsrc);
}
}
break;
case RRULE:
/* ------------------- RRule -------------------- */
chg.addValue(pi, pval);
break;
case SEQUENCE:
/* ------------------- Sequence -------------------- */
int seq = ((Sequence) prop).getSequenceNo();
if (seq != ev.getSequence()) {
chg.changed(pi, ev.getSequence(), seq);
ev.setSequence(seq);
}
break;
case STATUS:
if (chg.changed(pi, ev.getStatus(), pval)) {
ev.setStatus(pval);
}
break;
case SUMMARY:
if (chg.changed(pi, ev.getSummary(), pval)) {
ev.setSummary(pval);
}
break;
case TRANSP:
if (chg.changed(pi, ev.getPeruserTransparency(cb.getPrincipal().getPrincipalRef()), pval)) {
BwXproperty pu = ev.setPeruserTransparency(cb.getPrincipal().getPrincipalRef(), pval);
if (pu != null) {
chg.addValue(PropertyInfoIndex.XPROP, pu);
}
}
break;
case UID:
break;
case URL:
if (chg.changed(pi, ev.getLink(), pval)) {
ev.setLink(pval);
}
break;
case XPROP:
/* ------------------------- x-property --------------------------- */
final String name = prop.getName();
if (name.equalsIgnoreCase(BwXproperty.bedeworkCost)) {
if (chg.changed(PropertyInfoIndex.COST, ev.getCost(), pval)) {
ev.setCost(pval);
}
break;
}
if (name.equalsIgnoreCase(BwXproperty.xBedeworkCategories)) {
if (checkCategory(cb, chg, ev, null, pval)) {
break;
}
}
if (name.equalsIgnoreCase(BwXproperty.xBedeworkLocation)) {
if (checkLocation(cb, chg, ev, prop)) {
break;
}
}
if (name.equalsIgnoreCase(BwXproperty.xBedeworkContact)) {
if (checkContact(cb, chg, ev, null, pval)) {
break;
}
}
/* See if this is an x-category that can be
converted to a real category
*/
final XProperty xp = (XProperty) prop;
chg.addValue(PropertyInfoIndex.XPROP, new BwXproperty(name, xp.getParameters().toString(), pval));
break;
default:
if (debug) {
debugMsg("Unsupported property with index " + pi + "; class " + prop.getClass() + " and value " + pval);
}
}
}
if (val instanceof VAvailability) {
processAvailable(cb, cal, ical, (VAvailability) val, evinfo);
} else if (!(val instanceof Available)) {
VAlarmUtil.processComponentAlarms(cb, val, ev, currentPrincipal, chg);
if (val instanceof VPoll) {
processVvoters((VPoll) val, evinfo, cb, chg, mergeAttendees);
processCandidates((VPoll) val, evinfo, chg);
}
}
/* Fix up timestamps. */
if (ev.getCreated() == null) {
if (ev.getLastmod() != null) {
ev.setCreated(ev.getLastmod());
chg.changed(PropertyInfoIndex.CREATED, null, ev.getCreated());
} else {
ev.updateDtstamp();
chg.changed(PropertyInfoIndex.CREATED, null, ev.getCreated());
chg.changed(PropertyInfoIndex.LAST_MODIFIED, null, ev.getLastmod());
}
}
if (ev.getLastmod() == null) {
// created cannot be null now
ev.setLastmod(ev.getCreated());
chg.changed(PropertyInfoIndex.LAST_MODIFIED, null, ev.getLastmod());
}
processTimezones(ev, ical, chg);
/* Remove any recipients and originator
*/
if (ev.getRecipients() != null) {
ev.getRecipients().clear();
}
ev.setOriginator(null);
if (hasXparams.value) {
/* Save a text copy of the entire event as an x-property */
Component valCopy = val.copy();
/* Remove potentially large values */
prop = valCopy.getProperty(Property.DESCRIPTION);
if (prop != null) {
prop.setValue(null);
}
prop = valCopy.getProperty(Property.ATTACH);
// Don't store the entire attachment - we just need the parameters.
if (prop != null) {
Value v = (Value) prop.getParameter(Parameter.VALUE);
if (v != null) {
prop.setValue(String.valueOf(prop.getValue().hashCode()));
}
}
chg.addValue(PropertyInfoIndex.XPROP, new BwXproperty(BwXproperty.bedeworkIcal, null, valCopy.toString()));
}
chg.processChanges(ev, true);
ev.setRecurring(new Boolean(ev.isRecurringEntity()));
if (debug) {
debugMsg(chg.toString());
debugMsg(ev.toString());
}
if (masterEI != null) {
// Just return null as this event is on its override list
return null;
}
return evinfo;
} catch (CalFacadeException cfe) {
if (debug) {
cfe.printStackTrace();
}
throw cfe;
} catch (Throwable t) {
if (debug) {
t.printStackTrace();
}
throw new CalFacadeException(t);
}
}
use of net.fortuna.ical4j.model.PropertyList in project bw-calendar-engine by Bedework.
the class RecurUtil method getRange.
/**
* Returns range of dates for this recurring event possibly bounded by
* the supplied maximum end date.
*
* @param ev the recurring event
* @param maxYears Provide an upper limit
* @return the range for this event
* @throws CalFacadeException
*/
@SuppressWarnings("unchecked")
public static RecurRange getRange(final BwEvent ev, final int maxYears) throws CalFacadeException {
PropertyList evprops = new PropertyList();
VEventUtil.doRecurring(ev, evprops);
RecurRange rr = new RecurRange();
DtStart start = ev.getDtstart().makeDtStart();
DtEnd end = ev.getDtend().makeDtEnd();
Duration duration = new Duration(null, ev.getDuration());
// boolean durSpecified = ev.getEndType() == BwEvent.endTypeDuration;
rr.rangeStart = start.getDate();
for (Object o : evprops) {
if (o instanceof RDate) {
RDate rd = (RDate) o;
for (Object o1 : rd.getDates()) {
Date d = (Date) o1;
if (d.before(rr.rangeStart)) {
rr.rangeStart = d;
}
}
}
}
/* Limit date according to system settings
*/
Dur dur = new Dur(maxYears * 365, 0, 0, 0);
Date maxRangeEnd = new Date(dur.getTime(rr.rangeStart));
if (ev.getParent() != null) {
BwDateTime pend = ev.getParent().getDtend();
if (pend != null) {
Date dt = pend.makeDate();
if (dt.before(maxRangeEnd)) {
maxRangeEnd = dt;
}
}
}
rr.rangeEnd = getLatestRecurrenceDate(evprops, start, end, duration, maxRangeEnd);
if ((rr.rangeEnd == null) || (rr.rangeEnd.after(maxRangeEnd))) {
rr.rangeEnd = maxRangeEnd;
}
return rr;
}
use of net.fortuna.ical4j.model.PropertyList in project bw-calendar-engine by Bedework.
the class RecurUtil method getPeriods.
/**
* Returns a list of instances for this recurring event possibly bounded by
* the supplied maximum end date.
*
* <p>This is mostly a copy of VEvent.getConsumedTime()
*
* @param ev the recurring event
* @param maxYears Provide an upper limit
* @param maxInstances to limit
* @param startRange null or set earliest
* @param endRange null or set latest
* @return a list of periods for this event
* @throws CalFacadeException on error
*/
public static RecurPeriods getPeriods(final BwEvent ev, final int maxYears, final int maxInstances, final String startRange, final String endRange) throws CalFacadeException {
final PropertyList evprops = new PropertyList();
VEventUtil.doRecurring(ev, evprops);
final RecurPeriods rp = new RecurPeriods();
// DtStart vstart = (DtStart)IcalUtil.getProperty(comp, Property.DTSTART);
/* BwDateTime evstart = ev.getDtstart();
String tzid = evstart.getTzid();
DtStart start = new DtStart();
if (tzid != null) {
start.setTimeZone(timezones.getTimeZone(tzid));
}
try {
start.setValue(evstart.getDtval());
} catch (Throwable t) {
throw new CalFacadeException(t);
}*/
final DtStart start = ev.getDtstart().makeDtStart();
if (startRange != null) {
try {
rp.rangeStart = new DateTime(startRange);
} catch (final Throwable t) {
throw new CalFacadeException(t);
}
} else {
// boolean durSpecified = ev.getEndType() == BwEvent.endTypeDuration;
rp.rangeStart = start.getDate();
for (final Object o : evprops) {
if (o instanceof RDate) {
final RDate rd = (RDate) o;
for (final Object o1 : rd.getDates()) {
final Date d = (Date) o1;
if (d.before(rp.rangeStart)) {
rp.rangeStart = d;
}
}
}
}
}
/* Limit date according to system settings
*/
final Dur dur = new Dur(maxYears * 365, 0, 0, 0);
Date maxRangeEnd = new Date(dur.getTime(rp.rangeStart));
if (ev.getParent() != null) {
final BwDateTime pend = ev.getParent().getDtend();
if (pend != null) {
final Date dt = pend.makeDate();
if (dt.before(maxRangeEnd)) {
maxRangeEnd = dt;
}
}
}
final DtEnd end = ev.getDtend().makeDtEnd();
if (endRange != null) {
try {
rp.rangeEnd = new DateTime(endRange);
} catch (final Throwable t) {
throw new CalFacadeException(t);
}
} else {
final Duration duration = new Duration(null, ev.getDuration());
rp.rangeEnd = getLatestRecurrenceDate(evprops, start, end, duration, maxRangeEnd);
if ((rp.rangeEnd == null) || (rp.rangeEnd.after(maxRangeEnd))) {
rp.rangeEnd = maxRangeEnd;
}
}
Period rangePeriod = new Period(new DateTime(rp.rangeStart), new DateTime(rp.rangeEnd));
VEvent vev = new VEvent();
PropertyList vevprops = vev.getProperties();
vevprops.addAll(evprops);
if (!ev.getSuppressed()) {
// Allow inclusion of master start/end
vevprops.add(start);
vevprops.add(end);
} else {
// Move start/end outside of our period
Dur evdur = new Dur(ev.getDuration());
// Ensure at least a day
Dur setback = evdur.add(new Dur(1, 0, 0, 0));
boolean dateOnly = ev.getDtstart().getDateType();
Date adjustedEnd;
if (dateOnly) {
adjustedEnd = new Date(rp.rangeStart);
} else {
adjustedEnd = new DateTime(rp.rangeStart);
}
adjustedEnd.setTime(setback.negate().getTime(rp.rangeStart).getTime());
vevprops.add(new DtEnd(adjustedEnd));
// End now before range - make start evdur before that
Date adjustedStart;
if (dateOnly) {
adjustedStart = new Date(adjustedEnd);
} else {
adjustedStart = new DateTime(adjustedEnd);
}
adjustedStart.setTime(evdur.negate().getTime(adjustedEnd).getTime());
vevprops.add(new DtStart(adjustedStart));
}
PeriodList pl = vev.calculateRecurrenceSet(rangePeriod);
/*
PeriodList periods = new PeriodList();
if (ev.getDtstart().isUTC()) {
periods.setUtc(true);
} else if (start.getDate() instanceof DateTime) {
periods.setTimeZone(((DateTime)start.getDate()).getTimeZone());
} else {
try {
periods.setTimeZone(Timezones.getDefaultTz());
} catch (Throwable t) {
throw new CalFacadeException(t);
}
}
rp.instances = periods;
// if no start date return empty list..
if (start == null) {
return rp;
}
// if an explicit event duration is not specified, derive a value for recurring
// periods from the end date..
Dur rDuration;
Dur adjustDuration;
if (duration == null) {
if (end == null) {
rDuration = new Dur(0);
adjustDuration = new Dur(0, 0, 0, 1); // 1 second fudge
} else {
rDuration = new Dur(start.getDate(), end.getDate());
adjustDuration = rDuration;
}
} else {
rDuration = duration.getDuration();
adjustDuration = rDuration;
}
// adjust range start back by duration to allow for recurrences that
// start before the range but finish inside..
// FIXME: See bug #1325558..
Date adjustedRangeStart = new DateTime(rp.rangeStart);
adjustedRangeStart.setTime(adjustDuration.negate().getTime(rp.rangeStart).getTime());
// recurrence dates..
PropertyList rDates = evprops.getProperties(Property.RDATE);
for (Iterator i = rDates.iterator(); i.hasNext();) {
RDate rdate = (RDate) i.next();
if (Value.PERIOD.equals(rdate.getParameter(Parameter.VALUE))) {
/* These fully define the period * /
for (Iterator j = rdate.getPeriods().iterator(); j.hasNext();) {
Period period = (Period) j.next();
if (period.getStart().before(rp.rangeEnd) &&
period.getEnd().after(rp.rangeStart)) {
periods.add(period);
}
}
} else {
// Create a period based on rdate and duration
DateList startDates = rdate.getDates();
for (int j = 0; j < startDates.size(); j++) {
Date startDate = (Date) startDates.get(j);
periods.add(new Period(new DateTime(startDate), rDuration));
}
}
}
Value startVal = (Value)start.getParameter(Parameter.VALUE);
if (startVal == null) {
startVal = Value.DATE_TIME;
}
// recurrence rules..
PropertyList rRules = evprops.getProperties(Property.RRULE);
for (Iterator i = rRules.iterator(); i.hasNext();) {
RRule rrule = (RRule) i.next();
Recur recur = rrule.getRecur();
// Limit nummber of instances.
DateList startDates = recur.getDates(start.getDate(),
adjustedRangeStart,
rp.rangeEnd,
startVal,
maxInstances);
// DateList startDates = rrule.getRecur().getDates(start.getDate(), rangeStart, rangeEnd, (Value) start.getParameters().getParameter(Parameter.VALUE));
for (int j = 0; j < startDates.size(); j++) {
Date startDate = (Date) startDates.get(j);
periods.add(new Period(new DateTime(startDate), rDuration));
}
}
// add initial instance if intersection with the specified period.
if (!ev.getSuppressed()) {
Period startPeriod = null;
if (!durSpecified) {
startPeriod = new Period(new DateTime(start.getDate()),
new DateTime(end.getDate()));
} else {
startPeriod = new Period(new DateTime(start.getDate()),
duration.getDuration());
}
if (rangePeriod.intersects(startPeriod)) {
periods.add(startPeriod);
}
}
// exception dates..
PropertyList exDates = evprops.getProperties(Property.EXDATE);
for (Iterator i = exDates.iterator(); i.hasNext();) {
ExDate exDate = (ExDate) i.next();
for (Iterator j = periods.iterator(); j.hasNext();) {
Period period = (Period) j.next();
DateList dl = exDate.getDates();
// for DATE-TIME instances check for DATE-based exclusions also..
if (dl.contains(period.getStart())) {
j.remove();
} else if (dl.contains(new Date(period.getStart()))) {
j.remove();
}
}
}
// exception rules..
// FIXME: exception rules should be consistent with exception dates (i.e. not use periods?)..
PropertyList exRules = evprops.getProperties(Property.EXRULE);
PeriodList exPeriods = new PeriodList();
for (Iterator i = exRules.iterator(); i.hasNext();) {
ExRule exrule = (ExRule) i.next();
// DateList startDates = exrule.getRecur().getDates(start.getDate(), adjustedRangeStart, rangeEnd, (Value) start.getParameters().getParameter(Parameter.VALUE));
DateList startDates = exrule.getRecur().getDates(start.getDate(),
rp.rangeStart,
rp.rangeEnd,
startVal);
for (Iterator j = startDates.iterator(); j.hasNext();) {
Date startDate = (Date) j.next();
exPeriods.add(new Period(new DateTime(startDate), rDuration));
}
}
// apply exceptions..
if (!exPeriods.isEmpty()) {
periods = periods.subtract(exPeriods);
}
// if periods already specified through recurrence, return..
// ..also normalise before returning.
// if (!periods.isEmpty()) {
// periods = periods.normalise();
// }
*
*/
if (pl.size() <= maxInstances) {
rp.instances = pl;
} else {
rp.instances = new TreeSet<Period>();
for (Object o : pl) {
rp.instances.add((Period) o);
if (rp.instances.size() == maxInstances) {
break;
}
}
}
return rp;
}
use of net.fortuna.ical4j.model.PropertyList in project bw-calendar-engine by Bedework.
the class VFreeUtil method toVFreeBusy.
/**
* Make a VFreeBusy object from a BwFreeBusy.
*/
/**
* @param val
* @return VFreeBusy
* @throws CalFacadeException
*/
public static VFreeBusy toVFreeBusy(final BwEvent val) throws CalFacadeException {
try {
VFreeBusy vfb = new VFreeBusy(IcalUtil.makeDateTime(val.getDtstart()), IcalUtil.makeDateTime(val.getDtend()));
PropertyList pl = vfb.getProperties();
Property prop;
/* ------------------- Attendees -------------------- */
if (val.getNumAttendees() > 0) {
for (BwAttendee att : val.getAttendees()) {
pl.add(setAttendee(att));
}
}
if (val.getNumComments() > 0) {
for (BwString str : val.getComments()) {
// LANG
pl.add(new Comment(str.getValue()));
}
}
if (val.getDtstamp() != null) {
DtStamp dts = (DtStamp) pl.getProperty(Property.DTSTAMP);
if (dts == null) {
prop = new DtStamp(new DateTime(val.getDtstamp()));
// if (pars.includeDateTimeProperty) {
// prop.getParameters().add(Value.DATE_TIME);
// }
pl.add(prop);
} else {
dts.setDateTime(new DateTime(val.getDtstamp()));
}
}
/* ------------------- freebusy -------------------- */
Collection<BwFreeBusyComponent> times = val.getFreeBusyPeriods();
if (times != null) {
for (BwFreeBusyComponent fbc : times) {
FreeBusy fb = new FreeBusy();
int type = fbc.getType();
if (type == BwFreeBusyComponent.typeBusy) {
addParameter(fb, FbType.BUSY);
} else if (type == BwFreeBusyComponent.typeFree) {
addParameter(fb, FbType.FREE);
} else if (type == BwFreeBusyComponent.typeBusyUnavailable) {
addParameter(fb, FbType.BUSY_UNAVAILABLE);
} else if (type == BwFreeBusyComponent.typeBusyTentative) {
addParameter(fb, FbType.BUSY_TENTATIVE);
} else {
throw new CalFacadeException("Bad free-busy type " + type);
}
PeriodList pdl = fb.getPeriods();
for (Period p : fbc.getPeriods()) {
// XXX inverse.ca plugin cannot handle durations.
Period np = new Period(p.getStart(), p.getEnd());
pdl.add(np);
}
pl.add(fb);
}
}
/* ------------------- Organizer -------------------- */
BwOrganizer org = val.getOrganizer();
if (org != null) {
pl.add(setOrganizer(org));
}
if (val.getUid() != null) {
pl.add(new Uid(val.getUid()));
}
return vfb;
} catch (CalFacadeException cfe) {
throw cfe;
} catch (Throwable t) {
throw new CalFacadeException(t);
}
}
use of net.fortuna.ical4j.model.PropertyList in project openolat by klemens.
the class ICalFileCalendarManager method getKalendarEvent.
/**
* Build a KalendarEvent out of a source VEvent.
* @param event
* @return
*/
private KalendarEvent getKalendarEvent(VEvent event) {
// subject
Summary eventsummary = event.getSummary();
String subject = "";
if (eventsummary != null)
subject = eventsummary.getValue();
// start
DtStart dtStart = event.getStartDate();
Date start = dtStart.getDate();
Duration dur = event.getDuration();
// end
Date end = null;
if (dur != null) {
end = dur.getDuration().getTime(start);
} else if (event.getEndDate() != null) {
end = event.getEndDate().getDate();
}
// check all day event first
boolean isAllDay = false;
Parameter dateParameter = event.getProperties().getProperty(Property.DTSTART).getParameters().getParameter(Value.DATE.getName());
if (dateParameter != null) {
isAllDay = true;
// Make sure the time of the dates are 00:00 localtime because DATE fields in iCal are GMT 00:00
// Note that start date and end date can have different offset because of daylight saving switch
java.util.TimeZone timezone = java.util.GregorianCalendar.getInstance().getTimeZone();
start = new Date(start.getTime() - timezone.getOffset(start.getTime()));
end = new Date(end.getTime() - timezone.getOffset(end.getTime()));
// adjust end date: ICal sets end dates to the next day
end = new Date(end.getTime() - (1000 * 60 * 60 * 24));
} else if (start != null && end != null && (end.getTime() - start.getTime()) == (24 * 60 * 60 * 1000)) {
// check that start has no hour, no minute and no second
java.util.Calendar cal = java.util.Calendar.getInstance();
cal.setTime(start);
isAllDay = cal.get(java.util.Calendar.HOUR_OF_DAY) == 0 && cal.get(java.util.Calendar.MINUTE) == 0 && cal.get(java.util.Calendar.SECOND) == 0 && cal.get(java.util.Calendar.MILLISECOND) == 0;
// adjust end date: ICal sets end dates to the next day
end = new Date(end.getTime() - (1000 * 60 * 60 * 24));
}
Uid eventuid = event.getUid();
String uid;
if (eventuid != null) {
uid = eventuid.getValue();
} else {
uid = CodeHelper.getGlobalForeverUniqueID();
}
RecurrenceId eventRecurenceId = event.getRecurrenceId();
String recurrenceId = null;
if (eventRecurenceId != null) {
recurrenceId = eventRecurenceId.getValue();
}
KalendarEvent calEvent = new KalendarEvent(uid, recurrenceId, subject, start, end);
calEvent.setAllDayEvent(isAllDay);
// classification
Clazz classification = event.getClassification();
if (classification != null) {
String sClass = classification.getValue();
int iClassification = KalendarEvent.CLASS_PRIVATE;
if (sClass.equals(ICAL_CLASS_PRIVATE.getValue()))
iClassification = KalendarEvent.CLASS_PRIVATE;
else if (sClass.equals(ICAL_CLASS_X_FREEBUSY.getValue()))
iClassification = KalendarEvent.CLASS_X_FREEBUSY;
else if (sClass.equals(ICAL_CLASS_PUBLIC.getValue()))
iClassification = KalendarEvent.CLASS_PUBLIC;
calEvent.setClassification(iClassification);
}
// created/last modified
Created created = event.getCreated();
if (created != null) {
calEvent.setCreated(created.getDate().getTime());
}
// created/last modified
Contact contact = (Contact) event.getProperty(Property.CONTACT);
if (contact != null) {
calEvent.setCreatedBy(contact.getValue());
}
LastModified lastModified = event.getLastModified();
if (lastModified != null) {
calEvent.setLastModified(lastModified.getDate().getTime());
}
Description description = event.getDescription();
if (description != null) {
calEvent.setDescription(description.getValue());
}
// location
Location location = event.getLocation();
if (location != null) {
calEvent.setLocation(location.getValue());
}
// links if any
PropertyList linkProperties = event.getProperties(ICAL_X_OLAT_LINK);
List<KalendarEventLink> kalendarEventLinks = new ArrayList<KalendarEventLink>();
for (Iterator<?> iter = linkProperties.iterator(); iter.hasNext(); ) {
XProperty linkProperty = (XProperty) iter.next();
if (linkProperty != null) {
String encodedLink = linkProperty.getValue();
StringTokenizer st = new StringTokenizer(encodedLink, "§", false);
if (st.countTokens() >= 4) {
String provider = st.nextToken();
String id = st.nextToken();
String displayName = st.nextToken();
String uri = st.nextToken();
String iconCss = "";
// migration: iconCss has been added later, check if available first
if (st.hasMoreElements()) {
iconCss = st.nextToken();
}
KalendarEventLink eventLink = new KalendarEventLink(provider, id, displayName, uri, iconCss);
kalendarEventLinks.add(eventLink);
}
}
}
calEvent.setKalendarEventLinks(kalendarEventLinks);
Property comment = event.getProperty(ICAL_X_OLAT_COMMENT);
if (comment != null)
calEvent.setComment(comment.getValue());
Property numParticipants = event.getProperty(ICAL_X_OLAT_NUMPARTICIPANTS);
if (numParticipants != null)
calEvent.setNumParticipants(Integer.parseInt(numParticipants.getValue()));
Property participants = event.getProperty(ICAL_X_OLAT_PARTICIPANTS);
if (participants != null) {
StringTokenizer strTok = new StringTokenizer(participants.getValue(), "§", false);
String[] parts = new String[strTok.countTokens()];
for (int i = 0; strTok.hasMoreTokens(); i++) {
parts[i] = strTok.nextToken();
}
calEvent.setParticipants(parts);
}
Property sourceNodId = event.getProperty(ICAL_X_OLAT_SOURCENODEID);
if (sourceNodId != null) {
calEvent.setSourceNodeId(sourceNodId.getValue());
}
// managed properties
Property managed = event.getProperty(ICAL_X_OLAT_MANAGED);
if (managed != null) {
String value = managed.getValue();
if ("true".equals(value)) {
value = "all";
}
CalendarManagedFlag[] values = CalendarManagedFlag.toEnum(value);
calEvent.setManagedFlags(values);
}
Property externalId = event.getProperty(ICAL_X_OLAT_EXTERNAL_ID);
if (externalId != null) {
calEvent.setExternalId(externalId.getValue());
}
Property externalSource = event.getProperty(ICAL_X_OLAT_EXTERNAL_SOURCE);
if (externalSource != null) {
calEvent.setExternalSource(externalSource.getValue());
}
// recurrence
if (event.getProperty(ICAL_RRULE) != null) {
calEvent.setRecurrenceRule(event.getProperty(ICAL_RRULE).getValue());
}
// recurrence exclusions
if (event.getProperty(ICAL_EXDATE) != null) {
calEvent.setRecurrenceExc(event.getProperty(ICAL_EXDATE).getValue());
}
return calEvent;
}
Aggregations