Search in sources :

Example 1 with BwRecurrenceInstance

use of org.bedework.calfacade.BwRecurrenceInstance in project bw-calendar-engine by Bedework.

the class RecurUtil method fromRecurrencId.

/**
 * Generate a recurrence instance for the given master event
 * based on the recurrenceId and the date/time info in the master.
 *
 * @param master event
 * @param recurrenceId for the instance.
 * @return instance object filled in.
 * @throws CalFacadeException
 */
public static BwRecurrenceInstance fromRecurrencId(final BwEvent master, String recurrenceId) throws CalFacadeException {
    final String stzid = master.getDtstart().getTzid();
    final boolean dateOnly = master.getDtstart().getDateType();
    final BwDateTime rstart = BwDateTime.makeBwDateTime(dateOnly, recurrenceId, stzid);
    final BwDateTime rend = rstart.addDuration(BwDuration.makeDuration(master.getDuration()));
    final BwRecurrenceInstance ri = new BwRecurrenceInstance();
    ri.setDtstart(rstart);
    ri.setDtend(rend);
    ri.setRecurrenceId(ri.getDtstart().getDate());
    ri.setMaster(master);
    return ri;
}
Also used : BwRecurrenceInstance(org.bedework.calfacade.BwRecurrenceInstance) BwDateTime(org.bedework.calfacade.BwDateTime)

Example 2 with BwRecurrenceInstance

use of org.bedework.calfacade.BwRecurrenceInstance 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());
    }
}
Also used : BwDateTime(org.bedework.calfacade.BwDateTime) HashMap(java.util.HashMap) Period(net.fortuna.ical4j.model.Period) BwEvent(org.bedework.calfacade.BwEvent) BwRecurrenceInstance(org.bedework.calfacade.BwRecurrenceInstance) ChangeTable(org.bedework.calfacade.util.ChangeTable) ChangeTableEntry(org.bedework.calfacade.util.ChangeTableEntry) RecurPeriods(org.bedework.icalendar.RecurUtil.RecurPeriods)

Example 3 with BwRecurrenceInstance

use of org.bedework.calfacade.BwRecurrenceInstance in project bw-calendar-engine by Bedework.

the class CoreEvents method deleteInstances.

/* 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
    // noinspection unchecked
    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);
}
Also used : BwRecurrenceInstance(org.bedework.calfacade.BwRecurrenceInstance)

Example 4 with BwRecurrenceInstance

use of org.bedework.calfacade.BwRecurrenceInstance in project bw-calendar-engine by Bedework.

the class CoreEvents method deleteEvent.

@Override
public DelEventResult deleteEvent(final EventInfo ei, final boolean scheduling, final boolean reallyDelete) throws CalFacadeException {
    final DelEventResult der = new DelEventResult(false, 0);
    BwEvent ev = ei.getEvent();
    final boolean isMaster = ev.testRecurring() && (ev.getRecurrenceId() == null);
    final boolean isInstance = (ev.getRecurrenceId() != null) && (ev instanceof BwEventProxy);
    if (!isInstance && ev.unsaved()) {
        final CoreEventInfo cei = getEvent(ev.getColPath(), ev.getName(), RecurringRetrievalMode.overrides);
        if (cei == null) {
            return der;
        }
        ev = cei.getEvent();
    }
    final long startTime = System.currentTimeMillis();
    final int desiredAccess;
    final boolean shared;
    try {
        final BwCalendar col = getEntityCollection(ev.getColPath(), privAny, scheduling, false);
        shared = col.getPublick() || col.getShared();
        if (!scheduling) {
            desiredAccess = privUnbind;
        } else {
            /* Delete message while tidying up in/outbox.
         * Set desiredAccess to something that works.
         *  */
            final CalendarWrapper cw = (CalendarWrapper) col;
            desiredAccess = cw.getLastDesiredAccess();
        }
        ac.checkAccess(ev, desiredAccess, false);
    } catch (final CalFacadeException cfe) {
        dao.rollback();
        throw cfe;
    }
    if (!reallyDelete && ev.getTombstoned()) {
        // no-op - just pretend
        der.eventDeleted = true;
        return der;
    }
    if (isMaster) {
        // Master event - delete all instances and overrides.
        deleteInstances(ev, shared);
        notifyDelete(reallyDelete, ev, shared);
        if (reallyDelete) {
            dao.delete(ev);
        } else {
            tombstoneEvent(ev);
        }
        der.eventDeleted = true;
        stat(StatsEvent.deleteTime, startTime);
        unindexEntity(ei);
        return der;
    }
    if (isInstance) {
        /* Deleting a single instance. Delete any overrides, delete the instance
       * and add an exdate to the master.
       */
        final BwEventProxy proxy = (BwEventProxy) ev;
        final BwEventAnnotation ann = proxy.getRef();
        BwEvent master = ann.getMaster();
        if (master.unsaved()) {
            final CoreEventInfo cei = getEvent(master.getColPath(), master.getName(), RecurringRetrievalMode.overrides);
            if (cei == null) {
                return der;
            }
            master = cei.getEvent();
        }
        /* Fetch the instance so we can delete it */
        final BwRecurrenceInstance inst = dao.getInstance(master, ev.getRecurrenceId());
        if (inst == null) {
            stat(StatsEvent.deleteTime, startTime);
            return der;
        }
        notifyDelete(true, ev, shared);
        dao.delete(inst);
        if (!ann.unsaved()) {
            // der.alarmsDeleted = deleteAlarms(ann);
            ann.getAttendees().clear();
            dao.delete(ann);
        }
        final BwDateTime instDate = inst.getDtstart();
        if (!master.getRdates().remove(instDate)) {
            // Wasn't an rdate event
            master.addExdate(instDate);
        }
        master.updateLastmod();
        dao.update(master);
        der.eventDeleted = true;
        stat(StatsEvent.deleteTime, startTime);
        indexEntity(ei.getRetrievedEvent());
        return der;
    }
    // Single non recurring event.
    BwEvent deletee = ev;
    if (ev instanceof BwEventProxy) {
        // Deleting an annotation
        deletee = ((BwEventProxy) ev).getRef();
    }
    // I think we need something like this -- fixReferringAnnotations(deletee);
    // XXX This could be wrong.
    /* If this is a proxy we should only delete alarmas attached to the
     * proxy - any attached to the underlying event should be left alone.
     */
    // der.alarmsDeleted = deleteAlarms(deletee);
    // sess.delete(sess.merge(deletee));
    notifyDelete(reallyDelete, ev, shared);
    if (reallyDelete) {
        clearCollection(ev.getAttendees());
        dao.delete(deletee);
    } else {
        tombstoneEvent(deletee);
    }
    der.eventDeleted = true;
    stat(StatsEvent.deleteTime, startTime);
    unindexEntity(ei);
    return der;
}
Also used : BwDateTime(org.bedework.calfacade.BwDateTime) CoreEventInfo(org.bedework.calcorei.CoreEventInfo) BwEvent(org.bedework.calfacade.BwEvent) BwCalendar(org.bedework.calfacade.BwCalendar) BwEventProxy(org.bedework.calfacade.BwEventProxy) CalFacadeException(org.bedework.calfacade.exc.CalFacadeException) BwRecurrenceInstance(org.bedework.calfacade.BwRecurrenceInstance) BwEventAnnotation(org.bedework.calfacade.BwEventAnnotation) CalendarWrapper(org.bedework.calfacade.wrappers.CalendarWrapper)

Example 5 with BwRecurrenceInstance

use of org.bedework.calfacade.BwRecurrenceInstance in project bw-calendar-engine by Bedework.

the class CoreEvents method updateProxy.

/* Called by updateEvent to update a proxied event (annotation) or an
   * override.
   */
private void updateProxy(final BwEventProxy proxy) throws CalFacadeException {
    /* if this is a proxy for a recurrence instance of our own event
       then the recurrence instance should point at this override.
       Otherwise we just update the event annotation.
     */
    final BwEventAnnotation override = proxy.getRef();
    if (debug) {
        debugMsg("Update override event " + override);
    }
    BwEvent mstr = override.getTarget();
    while (mstr instanceof BwEventAnnotation) {
        /* XXX The master may itself be an annotated event. We should really
         stop when we get to that point
       */
        /*
      BwEventProxy tempProxy = new BwEventProxy(mstr);
      if (some-condition-holds) {
        break;
      }
      */
        mstr = ((BwEventAnnotation) mstr).getTarget();
    }
    // if (mstr.getOwner().equals(getUser()) &&
    if (mstr.testRecurring()) {
        // A recurring event - retrieve the instance
        final BwRecurrenceInstance inst = dao.getInstance(mstr, override.getRecurrenceId());
        if (inst == null) {
            if (debug) {
                debugMsg("Cannot locate instance for " + mstr + "with recurrence id " + override.getRecurrenceId());
            }
            throwException(CalFacadeException.cannotLocateInstance, mstr + "with recurrence id " + override.getRecurrenceId());
            // satisfy intellij
            return;
        }
        // XXX Force owner????
        override.setOwnerHref(mstr.getOwnerHref());
        dao.saveOrUpdate(override);
        // sess.flush();
        if (inst.getOverride() == null) {
            inst.setOverride(override);
            dao.save(inst);
        }
        /* Update the lastmod on the master event */
        mstr.setDtstamps(getCurrentTimestamp());
        dao.update(mstr);
    } else {
        dao.saveOrUpdate(override);
    }
    proxy.setChangeFlag(false);
}
Also used : BwRecurrenceInstance(org.bedework.calfacade.BwRecurrenceInstance) BwEventAnnotation(org.bedework.calfacade.BwEventAnnotation) BwEvent(org.bedework.calfacade.BwEvent)

Aggregations

BwRecurrenceInstance (org.bedework.calfacade.BwRecurrenceInstance)12 BwDateTime (org.bedework.calfacade.BwDateTime)8 BwEvent (org.bedework.calfacade.BwEvent)7 BwEventAnnotation (org.bedework.calfacade.BwEventAnnotation)6 BwEventProxy (org.bedework.calfacade.BwEventProxy)5 Period (net.fortuna.ical4j.model.Period)3 CoreEventInfo (org.bedework.calcorei.CoreEventInfo)3 BwCalendar (org.bedework.calfacade.BwCalendar)3 RecurPeriods (org.bedework.icalendar.RecurUtil.RecurPeriods)3 TreeSet (java.util.TreeSet)2 Dur (net.fortuna.ical4j.model.Dur)2 CollectionInfo (org.bedework.calfacade.BwCalendar.CollectionInfo)2 CalFacadeException (org.bedework.calfacade.exc.CalFacadeException)2 EventInfo (org.bedework.calfacade.svc.EventInfo)2 ArrayList (java.util.ArrayList)1 HashMap (java.util.HashMap)1 HashSet (java.util.HashSet)1 DateTime (net.fortuna.ical4j.model.DateTime)1 TimeZone (net.fortuna.ical4j.model.TimeZone)1 CurrentAccess (org.bedework.access.Acl.CurrentAccess)1