use of org.bedework.convert.RecurUtil.RecurPeriods in project bw-calendar-engine by Bedework.
the class CoreEvents method updateRecurrences.
/* Delete any recurrences.
* /
private void deleteRecurrences(BwEvent val,
UpdateChanges uc,
ChangeTable changes) throws CalFacadeException {
if (changes != null) {
if (!changes.recurrenceChanged()) {
return;
}
}
clearCollection(val.getRrules());
clearCollection(val.getExrules());
clearCollection(val.getRdates());
clearCollection(val.getExdates());
deleteInstances(val, uc, new DelEventResult(false, 0));
}
private void clearCollection(Collection c) {
if (c == null) {
return;
}
c.clear();
}
private void deleteInstances(final BwEvent val,
final boolean shared) throws CalFacadeException {
// First some notifications
final List<BwRecurrenceInstance> current = dao.getInstances(val);
for (final BwRecurrenceInstance ri: current) {
notifyInstanceChange(SysEvent.SysCode.ENTITY_DELETED,
val, shared,
ri.getRecurrenceId());
}
dao.deleteInstances(val);
fixReferringAnnotations(val);
}
*/
/* 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) {
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);
}
*/
ent = changes.getEntry(PropertyInfoIndex.RDATE);
if (ent.getRemovedValues() != null) {
// rdates removed - remove the instances.
removeInstances(val, uc, overrides, ent.getRemovedValues(), shared);
}
return;
}
}
// final Map<String, BwRecurrenceInstance> updated = new HashMap<>();
final Set<String> updated = new TreeSet<>();
/* 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, authProps.getMaxYears(), authProps.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 = authProps.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 var instid = rstart.getDate();
/*
final BwRecurrenceInstance ri = new BwRecurrenceInstance();
ri.setDtstart(rstart);
ri.setDtend(rend);
ri.setRecurrenceId(instid);
ri.setMaster(val);
updated.put(instid, ri);
*/
updated.add(instid);
maxInstances--;
if (maxInstances == 0) {
// That's all you're getting from me
break;
}
}
// for (final BwRecurrenceInstance ri: current) {
for (final BwEventProxy pxy : overrides) {
final BwEventAnnotation ann = pxy.getRef();
final String rid = ann.getRecurrenceId();
if (!updated.contains(rid)) {
// Not in the new instance set - delete from db
ei.removeOverride(rid);
uc.addDeleted(rid);
notifyInstanceChange(SysEvent.SysCode.ENTITY_DELETED, val, shared, rid);
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(rid);
notifyInstanceChange(SysEvent.SysCode.ENTITY_UPDATED, val, shared,
rid);
}
*/
// Remove the entry - we've processed it.
updated.remove(rid);
}
for (final String rid : updated) {
// dao.save(ri);
uc.addAdded(rid);
notifyInstanceChange(SysEvent.SysCode.ENTITY_ADDED, val, shared, rid);
}
}
use of org.bedework.convert.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();
final BwCalendar cal = getEntityCollection(val.getColPath(), privBind, scheduling, false);
if (cal == null) {
uer.errorCode = CalFacadeException.noEventCalendar;
return uer;
}
uer.addedUpdated = true;
/* 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.isRecurringEntity()) {
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, authProps.getMaxYears(), authProps.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 = authProps.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 String rid = rstart.getDate();
if (firstRecurrenceId == null) {
firstRecurrenceId = rid;
} else if (firstRecurrenceId.equals(rid)) {
// Skip it
if (debug()) {
debug("Skipping duplicate recurid " + firstRecurrenceId);
}
continue;
}
if (recurids != null) {
/* See if we have a recurrence */
final BwEventProxy ov = recurids.get(rid);
if (ov != null) {
if (debug()) {
debug("Add override with recurid " + rid);
}
setupDependentEntities(ov);
addOverride(ov, val);
// For the moment save the instance
// dao.save(ri);
recurids.remove(rid);
}
}
// Not saving instances that don't have an override
// 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;
}
use of org.bedework.convert.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 (!ev.isRecurringEntity() && (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);
request.id(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, 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);
request.id(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);
request.id(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);
request.id(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.convert.RecurUtil.RecurPeriods in project bw-calendar-engine by Bedework.
the class BwIndexEsImpl method makeEventInstances.
private boolean makeEventInstances(final EventInfo ei, final DateLimits dl, final boolean noIndex) throws CalFacadeException {
final BwEvent ev = ei.getEvent();
/* Create a list of all instance date/times before overrides. */
final int maxYears;
final int maxInstances;
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 false;
// throw new CalFacadeException(CalFacadeException.noRecurrenceInstances);
}
int instanceCt = maxInstances;
final String stzid = ev.getDtstart().getTzid();
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<>();
BulkRequest bulkReq = null;
if (!noIndex) {
bulkReq = new BulkRequest();
}
if (debug()) {
debug("Start makeInstances");
}
/*
if (!Util.isEmpty(ei.getOverrideProxies())) {
for (BwEvent ov: ei.getOverrideProxies()) {
overrides.put(ov.getRecurrenceId(), ov.getRecurrenceId());
}
}
*/
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()));
dl.checkMin(rstart);
dl.checkMax(rend);
if (bulkReq != null) {
/*iresp = */
bulkReq = addToBulk(bulkReq, oei, ItemKind.override, rstart, rend, ov.getRecurrenceId());
}
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);
dl.checkMin(rstart);
dl.checkMax(rend);
if (bulkReq != null) {
/*iresp = */
bulkReq = addToBulk(bulkReq, ei, entity, rstart, rend, recurrenceId);
}
instanceCt--;
if (instanceCt == 0) {
// That's all you're getting from me
break;
}
}
if ((bulkReq != null) && (bulkReq.estimatedSizeInBytes() > 0)) {
flushBulkReq(bulkReq);
}
return true;
}
use of org.bedework.convert.RecurUtil.RecurPeriods in project bw-calendar-engine by Bedework.
the class Events method getInstances.
@Override
public InstancesResponse getInstances(final GetInstancesRequest req) {
final InstancesResponse resp = new InstancesResponse();
resp.setId(req.getId());
if (!req.validate(resp)) {
return resp;
}
// Use a BwEvent to build the instance set
final BwEvent ev = new BwEventObj();
try {
final BwDateTime st = req.getStartDt();
ev.setDtstart(st);
ev.setDtend(req.getEndDt());
ev.addRrule(req.getRrule());
if (!Util.isEmpty(req.getExdates())) {
for (final String dt : req.getExdates()) {
ev.addExdate(BwDateTime.makeBwDateTime(st.getDateType(), dt, st.getTzid()));
}
}
if (!Util.isEmpty(req.getRdates())) {
for (final String dt : req.getRdates()) {
ev.addRdate(BwDateTime.makeBwDateTime(st.getDateType(), dt, st.getTzid()));
}
}
final var authPars = getSvc().getAuthProperties();
final RecurPeriods rp = RecurUtil.getPeriods(ev, authPars.getMaxYears(), authPars.getMaxInstances(), req.getBegin(), req.getEnd());
resp.setInstances(rp.instances);
return resp;
} catch (final Throwable t) {
return Response.error(resp, t);
}
}
Aggregations