use of org.bedework.icalendar.RecurUtil.RecurPeriods in project bw-calendar-engine by Bedework.
the class BwIndexEsImpl method reindexEvent.
private boolean reindexEvent(final ReindexResponse.Failure resp, final String indexName, final SearchHit sh, final EventInfo ei, final BulkProcessor bulkProcessor) {
try {
/* If it's not recurring or a stand-alone instance index it */
final BwEvent ev = ei.getEvent();
if ((uidsMap != null) && (ev.getLocationUid() == null)) {
final String locuid = uidsMap.get(ev.getUid());
if (locuid != null) {
uidsSet++;
ev.setLocationUid(locuid);
}
}
if (!restoreEvProps(resp, ei)) {
return false;
}
if (!ev.testRecurring() && (ev.getRecurrenceId() == null)) {
final EsDocInfo doc = makeDoc(resp, ei, ItemKind.master, ev.getDtstart(), ev.getDtend(), // ev.getRecurrenceId(),
null, null);
if (doc == null) {
return false;
}
final IndexRequest request = new IndexRequest(indexName, sh.type(), doc.getId());
request.source(doc.getSource());
bulkProcessor.add(request);
return true;
}
if (ev.getRecurrenceId() != null) {
errorReturn(resp, "Not implemented - index of single override");
return false;
}
if (!addOverrides(resp, idxpars.getUserIndexName(), ei)) {
return false;
}
final int maxYears;
final int maxInstances;
final DateLimits dl = new DateLimits();
if (ev.getPublick()) {
maxYears = unauthpars.getMaxYears();
maxInstances = unauthpars.getMaxInstances();
} else {
maxYears = authpars.getMaxYears();
maxInstances = authpars.getMaxInstances();
}
final RecurPeriods rp = RecurUtil.getPeriods(ev, maxYears, maxInstances);
if (rp.instances.isEmpty()) {
errorReturn(resp, "No instances for an alleged recurring event.");
return false;
}
final String stzid = ev.getDtstart().getTzid();
int instanceCt = maxInstances;
final boolean dateOnly = ev.getDtstart().getDateType();
/* First build a table of overrides so we can skip these later
*/
final Map<String, String> overrides = new HashMap<>();
if (!Util.isEmpty(ei.getOverrides())) {
for (final EventInfo oei : ei.getOverrides()) {
final BwEvent ov = oei.getEvent();
overrides.put(ov.getRecurrenceId(), ov.getRecurrenceId());
final String dtstart;
if (ov.getDtstart().getDateType()) {
dtstart = ov.getRecurrenceId().substring(0, 8);
} else {
dtstart = ov.getRecurrenceId();
}
final BwDateTime rstart = BwDateTime.makeBwDateTime(ov.getDtstart().getDateType(), dtstart, stzid);
final BwDateTime rend = rstart.addDuration(BwDuration.makeDuration(ov.getDuration()));
final EsDocInfo doc = makeDoc(resp, oei, ItemKind.override, rstart, rend, ov.getRecurrenceId(), dl);
if (doc == null) {
return false;
}
final IndexRequest request = new IndexRequest(indexName, sh.type(), doc.getId());
request.source(doc.getSource());
bulkProcessor.add(request);
instanceCt--;
}
}
for (final Period p : rp.instances) {
String dtval = p.getStart().toString();
if (dateOnly) {
dtval = dtval.substring(0, 8);
}
final BwDateTime rstart = BwDateTime.makeBwDateTime(dateOnly, dtval, stzid);
if (overrides.get(rstart.getDate()) != null) {
// Overrides indexed separately - skip this instance.
continue;
}
final String recurrenceId = rstart.getDate();
dtval = p.getEnd().toString();
if (dateOnly) {
dtval = dtval.substring(0, 8);
}
final BwDateTime rend = BwDateTime.makeBwDateTime(dateOnly, dtval, stzid);
final EsDocInfo doc = makeDoc(resp, ei, entity, rstart, rend, recurrenceId, dl);
if (doc == null) {
return false;
}
final IndexRequest request = new IndexRequest(indexName, sh.type(), doc.getId());
request.source(doc.getSource());
bulkProcessor.add(request);
instanceCt--;
if (instanceCt == 0) {
// That's all you're getting from me
break;
}
}
// </editor-fold>
// <editor-fold desc="Emit the master event with a date range covering the entire period.">
final BwDateTime dtstart = BwDateTime.makeBwDateTime(dateOnly, dl.minStart, stzid);
final BwDateTime dtend = BwDateTime.makeBwDateTime(dateOnly, dl.maxEnd, stzid);
final EsDocInfo doc = makeDoc(resp, ei, ItemKind.master, dtstart, dtend, null, null);
if (doc == null) {
return false;
}
final IndexRequest request = new IndexRequest(indexName, sh.type(), doc.getId());
request.source(doc.getSource());
bulkProcessor.add(request);
// </editor-fold>
return true;
} catch (final Throwable t) {
errorReturn(resp, t);
return false;
}
}
use of org.bedework.icalendar.RecurUtil.RecurPeriods in project bw-calendar-engine by Bedework.
the class CoreEvents method updateRecurrences.
/* XXX This is a bit brute force but it will do for the moment. We have to
* turn a set of rules into a set of changes. If we'd preserved the rules
* prior to this I guess we could figure out the differences without querying
* the db.
*
* For the moment create a whole set of instances and then query the db to see if
* they match.
*/
@SuppressWarnings("unchecked")
private void updateRecurrences(final EventInfo ei, final UpdateEventResult uc, final Collection<BwEventProxy> overrides, final boolean shared) throws CalFacadeException {
final BwEvent val = ei.getEvent();
final ChangeTable changes = val.getChangeset(currentPrincipal());
if (!changes.isEmpty()) {
if (!changes.recurrenceChanged()) {
return;
}
if (!changes.recurrenceRulesChanged()) {
// We can handle exdate and rdate changes.
ChangeTableEntry ent = changes.getEntry(PropertyInfoIndex.EXDATE);
if (ent.getAddedValues() != null) {
// exdates added - remove the instances.
removeInstances(val, uc, overrides, ent.getAddedValues(), shared);
}
if (ent.getRemovedValues() != null) {
// exdates removed - add the instances.
addInstances(val, uc, overrides, ent.getRemovedValues(), shared);
}
ent = changes.getEntry(PropertyInfoIndex.RDATE);
if (ent.getAddedValues() != null) {
// rdates added - add the instances.
addInstances(val, uc, overrides, ent.getAddedValues(), shared);
}
if (ent.getRemovedValues() != null) {
// rdates removed - remove the instances.
removeInstances(val, uc, overrides, ent.getRemovedValues(), shared);
}
return;
}
}
final Map<String, BwRecurrenceInstance> updated = new HashMap<>();
/* Get all the times for this event. - this could be a problem. Need to
limit the number. Should we do this in chunks, stepping through the
whole period?
*/
final RecurPeriods rp = RecurUtil.getPeriods(val, getAuthprops().getMaxYears(), getAuthprops().getMaxInstances());
if (rp.instances.isEmpty()) {
// No instances for an alleged recurring event.
// XXX Mark the master as non-recurring to stop it disappearing
val.setRecurring(false);
// throwException(CalFacadeException.noRecurrenceInstances);
}
final String stzid = val.getDtstart().getTzid();
/* try {
val.setLatestDate(Timezones.getUtc(rp.rangeEnd.toString(), stzid));
} catch (Throwable t) {
throwException(new CalFacadeException(t));
} */
int maxInstances = getAuthprops().getMaxInstances();
final boolean dateOnly = val.getDtstart().getDateType();
for (final Period p : rp.instances) {
String dtval = p.getStart().toString();
if (dateOnly) {
dtval = dtval.substring(0, 8);
}
final BwDateTime rstart = BwDateTime.makeBwDateTime(dateOnly, dtval, stzid);
dtval = p.getEnd().toString();
if (dateOnly) {
dtval = dtval.substring(0, 8);
}
final BwDateTime rend = BwDateTime.makeBwDateTime(dateOnly, dtval, stzid);
final BwRecurrenceInstance ri = new BwRecurrenceInstance();
ri.setDtstart(rstart);
ri.setDtend(rend);
ri.setRecurrenceId(ri.getDtstart().getDate());
ri.setMaster(val);
updated.put(ri.getRecurrenceId(), ri);
maxInstances--;
if (maxInstances == 0) {
// That's all you're getting from me
break;
}
}
final List<BwRecurrenceInstance> current = dao.getInstances(val);
for (final BwRecurrenceInstance ri : current) {
final BwRecurrenceInstance updri = updated.get(ri.getRecurrenceId());
if (updri == null) {
// Not in the new instance set - delete from db
ei.removeOverride(ri.getRecurrenceId());
dao.delete(ri);
uc.addDeleted(ri);
notifyInstanceChange(SysEvent.SysCode.ENTITY_DELETED, val, shared, ri.getRecurrenceId());
continue;
}
/* Found instance with same recurrence id. Is the start and end the same
*/
if (!ri.getDtstart().equals(updri.getDtstart()) || !ri.getDtend().equals(updri.getDtend())) {
ri.setDtstart(updri.getDtstart());
ri.setDtend(updri.getDtend());
dao.update(ri);
uc.addUpdated(ri);
notifyInstanceChange(SysEvent.SysCode.ENTITY_UPDATED, val, shared, ri.getRecurrenceId());
}
// Remove the entry - we've processed it.
updated.remove(ri.getRecurrenceId());
}
for (final BwRecurrenceInstance ri : updated.values()) {
dao.save(ri);
uc.addAdded(ri);
notifyInstanceChange(SysEvent.SysCode.ENTITY_ADDED, val, shared, ri.getRecurrenceId());
}
}
use of org.bedework.icalendar.RecurUtil.RecurPeriods in project bw-calendar-engine by Bedework.
the class BwIndexEsImpl method indexEvent.
private IndexResponse indexEvent(final EventInfo ei) throws CalFacadeException {
try {
/* If it's not recurring or a stand-alone instance index it */
final BwEvent ev = ei.getEvent();
if (!ev.testRecurring() && (ev.getRecurrenceId() == null)) {
return indexEvent(ei, ItemKind.master, ev.getDtstart(), ev.getDtend(), // ev.getRecurrenceId(),
null, null);
}
if (ev.getRecurrenceId() != null) {
error("Not implemented - index of single override");
return null;
}
/* Delete all instances of this event: we'll do a delete by query
* We need to find all with the same path and uid.
*/
/* TODO - do a query for all recurrence ids and delete the ones
we don't want.
*/
deleteEvent(ei);
/* Create a list of all instance date/times before overrides. */
final int maxYears;
final int maxInstances;
final DateLimits dl = new DateLimits();
if (ev.getPublick()) {
maxYears = unauthpars.getMaxYears();
maxInstances = unauthpars.getMaxInstances();
} else {
maxYears = authpars.getMaxYears();
maxInstances = authpars.getMaxInstances();
}
final RecurPeriods rp = RecurUtil.getPeriods(ev, maxYears, maxInstances);
if (rp.instances.isEmpty()) {
// No instances for an alleged recurring event.
return null;
// throw new CalFacadeException(CalFacadeException.noRecurrenceInstances);
}
final String stzid = ev.getDtstart().getTzid();
int instanceCt = maxInstances;
final boolean dateOnly = ev.getDtstart().getDateType();
/* First build a table of overrides so we can skip these later
*/
final Map<String, String> overrides = new HashMap<>();
/*
if (!Util.isEmpty(ei.getOverrideProxies())) {
for (BwEvent ov: ei.getOverrideProxies()) {
overrides.put(ov.getRecurrenceId(), ov.getRecurrenceId());
}
}
*/
final IndexResponse iresp;
if (!Util.isEmpty(ei.getOverrides())) {
for (final EventInfo oei : ei.getOverrides()) {
final BwEvent ov = oei.getEvent();
overrides.put(ov.getRecurrenceId(), ov.getRecurrenceId());
final String start;
if (ov.getDtstart().getDateType()) {
start = ov.getRecurrenceId().substring(0, 8);
} else {
start = ov.getRecurrenceId();
}
final BwDateTime rstart = BwDateTime.makeBwDateTime(ov.getDtstart().getDateType(), start, stzid);
final BwDateTime rend = rstart.addDuration(BwDuration.makeDuration(ov.getDuration()));
/*iresp = */
indexEvent(oei, ItemKind.override, rstart, rend, ov.getRecurrenceId(), dl);
instanceCt--;
}
}
for (final Period p : rp.instances) {
String dtval = p.getStart().toString();
if (dateOnly) {
dtval = dtval.substring(0, 8);
}
final BwDateTime rstart = BwDateTime.makeBwDateTime(dateOnly, dtval, stzid);
if (overrides.get(rstart.getDate()) != null) {
// Overrides indexed separately - skip this instance.
continue;
}
final String recurrenceId = rstart.getDate();
dtval = p.getEnd().toString();
if (dateOnly) {
dtval = dtval.substring(0, 8);
}
final BwDateTime rend = BwDateTime.makeBwDateTime(dateOnly, dtval, stzid);
/*iresp = */
indexEvent(ei, entity, rstart, rend, recurrenceId, dl);
instanceCt--;
if (instanceCt == 0) {
// That's all you're getting from me
break;
}
}
// </editor-fold>
// <editor-fold desc="Emit the master event with a date range covering the entire period.">
final BwDateTime start = BwDateTime.makeBwDateTime(dateOnly, dl.minStart, stzid);
final BwDateTime end = BwDateTime.makeBwDateTime(dateOnly, dl.maxEnd, stzid);
iresp = indexEvent(ei, ItemKind.master, start, end, null, null);
return iresp;
} catch (final CalFacadeException cfe) {
throw cfe;
} catch (final Throwable t) {
throw new CalFacadeException(t);
}
}
use of org.bedework.icalendar.RecurUtil.RecurPeriods in project bw-calendar-engine by Bedework.
the class CoreEvents method doRecurrence.
/* Retrieves the overides for a recurring event and if required,
* retrieves the instances.
*
* The overrides we retrieve are optionally limited by date.
*
* The CalDAV spec requires that we retrieve all overrides which fall within
* the given date range AND all instances in that date range including
* overriden instances that WOULD have fallen in that range had they not been
* overriden.
*
* Thus we need to search both overrides and instances - unless no date range
* is given in which case all overrides will appear along with the instances.
*
* If the calendars parameter is non-null, as it usually will be for a call
* from getEvents, we limit the result to instances that appear within that
* set of calendars. This handles the case of an overriden instance moved to a
* different calendar, for example the trash.
*/
@SuppressWarnings("unchecked")
private void doRecurrence(final CoreEventInfo cei, final RecurringRetrievalMode recurRetrieval) throws CalFacadeException {
final BwEvent master = cei.getEvent();
final Set<String> overrides = new HashSet<>();
final CurrentAccess ca = cei.getCurrentAccess();
// Always fetch all overrides
final Collection<BwEventAnnotation> ovs = dao.eventQuery(BwEventAnnotation.class, null, null, null, master, // overrides
true, // recurRetrieval);
null);
if (ovs != null) {
for (final BwEventAnnotation override : ovs) {
final CoreEventInfo ocei = makeOverrideProxy(override, ca);
cei.addOverride(ocei);
overrides.add(ocei.getEvent().getRecurrenceId());
}
}
if ((recurRetrieval == null) || (recurRetrieval.mode != Rmode.expanded)) {
return;
}
/* Create a list of all instance date/times before overrides. */
final int maxYears;
final int maxInstances;
maxYears = getAuthprops().getMaxYears();
maxInstances = getAuthprops().getMaxInstances();
final RecurPeriods rp = RecurUtil.getPeriods(master, maxYears, maxInstances);
if (rp.instances.isEmpty()) {
// No instances for an alleged recurring event.
return;
// throw new CalFacadeException(CalFacadeException.noRecurrenceInstances);
}
final String stzid = master.getDtstart().getTzid();
final boolean dateOnly = master.getDtstart().getDateType();
/* Emit all instances that aren't overridden. */
final TreeSet<CoreEventInfo> ceis = new TreeSet<>();
for (final Period p : rp.instances) {
String dtval = p.getStart().toString();
if (dateOnly) {
dtval = dtval.substring(0, 8);
}
final BwDateTime rstart = BwDateTime.makeBwDateTime(dateOnly, dtval, stzid);
if (overrides.contains(rstart.getDate())) {
// Overrides built separately - skip this instance.
continue;
}
final String recurrenceId = rstart.getDate();
dtval = p.getEnd().toString();
if (dateOnly) {
dtval = dtval.substring(0, 8);
}
final BwDateTime rend = BwDateTime.makeBwDateTime(dateOnly, dtval, stzid);
final BwRecurrenceInstance inst = new BwRecurrenceInstance(rstart, rend, recurrenceId, master, null);
final CoreEventInfo instcei = makeInstanceProxy(inst, ca);
if (instcei != null) {
// if (debug) {
// debugMsg("Ev: " + proxy);
// }
ceis.add(instcei);
}
}
cei.setInstances(ceis);
}
use of org.bedework.icalendar.RecurUtil.RecurPeriods in project bw-calendar-engine by Bedework.
the class CoreEvents method addEvent.
@Override
public UpdateEventResult addEvent(final EventInfo ei, final boolean scheduling, final boolean rollbackOnError) throws CalFacadeException {
final BwEvent val = ei.getEvent();
final Collection<BwEventProxy> overrides = ei.getOverrideProxies();
final long startTime = System.currentTimeMillis();
RecuridTable recurids = null;
final UpdateEventResult uer = new UpdateEventResult();
uer.addedUpdated = true;
final BwCalendar cal = getEntityCollection(val.getColPath(), privBind, scheduling, false);
/* Indicate if we want sharing notifications of changes */
final boolean shared = cal.getPublick() || cal.getShared();
final CollectionInfo collInf = cal.getCollectionInfo();
if (!Util.isEmpty(overrides)) {
if (!val.testRecurring()) {
throwException(CalFacadeException.overridesForNonRecurring);
}
recurids = new RecuridTable(overrides);
}
if (val.getUid() == null) {
throwException(CalFacadeException.noEventGuid);
}
if (val.getName() == null) {
throwException(CalFacadeException.noEventName);
}
/* The guid must not exist in the same calendar. We assign a guid if
* one wasn't assigned already. However, the event may have come with a guid
* (caldav, import, etc) so we need to check here.
*
* It also ensures our guid allocation is working OK
*/
if (collInf.uniqueKey) {
String name = calendarGuidExists(val, false, true);
if (name == null) {
name = calendarGuidExists(val, true, true);
}
if (name != null) {
throwException(CalFacadeException.duplicateGuid, name);
}
}
/* Similarly for event names which must be unique within a collection.
* Note that a duplicate name is essentially overwriting an event with a
* new uid - also disallowed.
*/
if ((val.getEntityType() != IcalDefs.entityTypeAvailable) && (calendarNameExists(val, false, true) || calendarNameExists(val, true, true))) {
throwException(CalFacadeException.duplicateName, val.getName());
}
setupDependentEntities(val);
/* Remove any tombstoned event in the collection with same uid */
deleteTombstoned(val.getColPath(), val.getUid());
/* If it's a recurring event see what we can do to optimize searching
* and retrieval
*/
if ((val instanceof BwEventAnnotation) || !val.getRecurring()) {
dao.save(val);
if (!getForRestore()) {
notify(SysEvent.SysCode.ENTITY_ADDED, val, shared);
}
stat(StatsEvent.createTime, startTime);
indexEntity(ei);
return uer;
}
/* Get all the times for this event. - this could be a problem. Need to
limit the number. Should we do this in chunks, stepping through the
whole period?
*/
final RecurPeriods rp = RecurUtil.getPeriods(val, getAuthprops().getMaxYears(), getAuthprops().getMaxInstances());
if (rp.instances.isEmpty()) {
// No instances for an alleged recurring event.
if (rollbackOnError) {
throwException(CalFacadeException.noRecurrenceInstances, val.getUid());
}
uer.addedUpdated = false;
uer.errorCode = CalFacadeException.noRecurrenceInstances;
stat(StatsEvent.createTime, startTime);
indexEntity(ei);
return uer;
}
/* We can save the master at this point */
dao.save(val);
final String stzid = val.getDtstart().getTzid();
final TimeZone stz = null;
/* try {
if (stzid != null) {
stz = Timezones.getTz(stzid);
}
val.setLatestDate(Timezones.getUtc(rp.rangeEnd.toString(),
stzid));
} catch (Throwable t) {
throwException(new CalFacadeException(t));
} */
int maxInstances = getAuthprops().getMaxInstances();
final boolean dateOnly = val.getDtstart().getDateType();
/* There appears to be a bug in ical4j in which the first instance gets
* duplicated. Rather than change that code and run the risk of breaking
* all recurrences I'll just look for that duplicate.
*/
String firstRecurrenceId = null;
for (final Period p : rp.instances) {
String dtval = p.getStart().toString();
if (dateOnly) {
dtval = dtval.substring(0, 8);
}
final BwDateTime rstart = BwDateTime.makeBwDateTime(dateOnly, dtval, stzid);
final DateTime edt = p.getEnd();
if (!dateOnly && (stz != null)) {
edt.setTimeZone(stz);
}
dtval = edt.toString();
if (dateOnly) {
dtval = dtval.substring(0, 8);
}
final BwDateTime rend = BwDateTime.makeBwDateTime(dateOnly, dtval, stzid);
final BwRecurrenceInstance ri = new BwRecurrenceInstance();
ri.setDtstart(rstart);
ri.setDtend(rend);
ri.setRecurrenceId(ri.getDtstart().getDate());
ri.setMaster(val);
if (firstRecurrenceId == null) {
firstRecurrenceId = ri.getRecurrenceId();
} else if (firstRecurrenceId.equals(ri.getRecurrenceId())) {
// Skip it
if (debug) {
debugMsg("Skipping duplicate recurid " + firstRecurrenceId);
}
continue;
}
if (recurids != null) {
/* See if we have a recurrence */
final String rid = ri.getRecurrenceId();
final BwEventProxy ov = recurids.get(rid);
if (ov != null) {
if (debug) {
debugMsg("Add override with recurid " + rid);
}
setupDependentEntities(ov);
addOverride(ov, ri);
recurids.remove(rid);
}
}
dao.save(ri);
maxInstances--;
if (maxInstances == 0) {
// That's all you're getting from me
break;
}
}
if ((recurids != null) && (recurids.size() != 0)) {
/* We removed all the valid overrides - we are left with those
* with recurrence ids that don't match.
*/
if (rollbackOnError) {
throwException(CalFacadeException.invalidOverride);
}
uer.failedOverrides = recurids.values();
}
if (!getForRestore()) {
notify(SysEvent.SysCode.ENTITY_ADDED, val, shared);
}
indexEntity(ei);
stat(StatsEvent.createTime, startTime);
return uer;
}
Aggregations