use of org.bedework.calfacade.svc.EventInfo in project bw-calendar-engine by Bedework.
the class BwSysIntfImpl method fromIcal.
@Override
public SysiIcalendar fromIcal(final CalDAVCollection col, final IcalendarType ical, final IcalResultType rtype) throws WebdavException {
// Ensure open
getSvci();
boolean rollback = true;
try {
BwCalendar bwcol = null;
if (col != null) {
bwcol = unwrap(col.resolveAlias(true));
}
Icalendar ic = trans.fromIcal(bwcol, ical, // diff the contents
true);
if (rtype == IcalResultType.OneComponent) {
if (ic.getComponents().size() != 1) {
throw new WebdavBadRequest(CaldavTags.validCalendarObjectResource);
}
if (!(ic.getComponents().iterator().next() instanceof EventInfo)) {
throw new WebdavBadRequest(CaldavTags.validCalendarObjectResource);
}
} else if (rtype == IcalResultType.TimeZone) {
if (ic.getTimeZones().size() != 1) {
throw new WebdavBadRequest("Expected one timezone");
}
}
SysiIcalendar sic = new MySysiIcalendar(this, ic);
rollback = false;
return sic;
} catch (WebdavException wde) {
throw wde;
} catch (IcalMalformedException ime) {
throw new WebdavForbidden(CaldavTags.validCalendarData, ime.getMessage());
} catch (Throwable t) {
if (debug) {
error(t);
}
// Assume bad data in some way
throw new WebdavForbidden(CaldavTags.validCalendarObjectResource, t.getMessage());
} finally {
if (rollback) {
try {
getSvci().rollbackTransaction();
} catch (Throwable t) {
}
}
}
}
use of org.bedework.calfacade.svc.EventInfo in project bw-calendar-engine by Bedework.
the class BwIndexEsImpl method reindex.
private void reindex(final ReindexResponse resp, final String indexName, final String docType) {
// Only retrieve masters - we'll query for the overrides
final QueryBuilder qb = getFilters(RecurringRetrievalMode.entityOnly).getAllForReindex(docType);
// 1 minute
final int timeoutMillis = 60000;
final TimeValue tv = new TimeValue(timeoutMillis);
final int batchSize = 100;
final Client cl = getClient(resp);
if (cl == null) {
return;
}
checkUidsMap();
// Start with default index as source
targetIndex = Util.buildPath(false, idxpars.getUserIndexName());
final BulkProcessor bulkProcessor = BulkProcessor.builder(cl, new BulkListener()).setBulkActions(batchSize).setConcurrentRequests(3).setFlushInterval(tv).build();
SearchResponse scrollResp = cl.prepareSearch(targetIndex).setSearchType(SearchType.SCAN).setScroll(tv).setQuery(qb).setSize(batchSize).execute().actionGet();
// Switch to new index
targetIndex = indexName;
// Scroll until no hits are returned
while (true) {
for (final SearchHit hit : scrollResp.getHits().getHits()) {
final String dtype = hit.getType();
resp.incProcessed();
if ((resp.getProcessed() % 250) == 0) {
info("processed " + docType + ": " + resp.getProcessed());
}
if (dtype.equals(docTypeUpdateTracker)) {
continue;
}
resp.getStats().inc(docToType.getOrDefault(dtype, unreachableEntities));
final ReindexResponse.Failure hitResp = new ReindexResponse.Failure();
final Object entity = makeEntity(hitResp, hit, null);
if (entity == null) {
warn("Unable to build entity " + hit.sourceAsString());
resp.incTotalFailed();
if (resp.getTotalFailed() < 50) {
resp.addFailure(hitResp);
}
continue;
}
if (entity instanceof BwShareableDbentity) {
final BwShareableDbentity ent = (BwShareableDbentity) entity;
try {
principal = BwPrincipal.makePrincipal(ent.getOwnerHref());
} catch (final CalFacadeException cfe) {
errorReturn(resp, cfe);
return;
}
}
if (entity instanceof EventInfo) {
// This might be a single event or a recurring event.
final EventInfo ei = (EventInfo) entity;
final BwEvent ev = ei.getEvent();
if (ev.getRecurring()) {
resp.incRecurring();
}
if (!reindexEvent(hitResp, indexName, hit, ei, bulkProcessor)) {
warn("Unable to iondex event " + hit.sourceAsString());
resp.incTotalFailed();
if (resp.getTotalFailed() < 50) {
resp.addFailure(hitResp);
}
}
} else {
final EsDocInfo doc = makeDoc(resp, entity);
if (doc == null) {
if (resp.getStatus() != ok) {
resp.addFailure(hitResp);
}
continue;
}
final IndexRequest request = new IndexRequest(indexName, hit.type(), doc.getId());
request.source(doc.getSource());
bulkProcessor.add(request);
if (entity instanceof BwEventProperty) {
if (!cacheEvprop(hitResp, (BwEventProperty) entity)) {
resp.addFailure(hitResp);
}
}
}
}
scrollResp = cl.prepareSearchScroll(scrollResp.getScrollId()).setScroll(tv).execute().actionGet();
// Break condition: No hits are returned
if (scrollResp.getHits().getHits().length == 0) {
break;
}
}
try {
bulkProcessor.awaitClose(10, TimeUnit.MINUTES);
} catch (final InterruptedException e) {
errorReturn(resp, "Final bulk close was interrupted. Records may be missing", failed);
}
if (uidsSet > 0) {
info("Uids set: " + uidsSet);
info("uidOverridesSet: " + uidOverridesSet);
}
uidsMap = null;
uidsOverideMap = null;
}
use of org.bedework.calfacade.svc.EventInfo 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.calfacade.svc.EventInfo in project bw-calendar-engine by Bedework.
the class BwIndexEsImpl method getSearchResult.
@Override
public List<SearchResultEntry> getSearchResult(final SearchResult sres, final int offset, final int num, final int desiredAccess) throws CalFacadeException {
if (debug) {
debug("offset: " + offset + ", num: " + num);
}
final EsSearchResult res = (EsSearchResult) sres;
res.pageStart = offset;
final SearchRequestBuilder srb = getClient().prepareSearch(searchIndexes);
if (res.curQuery != null) {
srb.setQuery(res.curQuery);
}
srb.setSearchType(SearchType.QUERY_THEN_FETCH).setPostFilter(res.curFilter).setFrom(res.pageStart);
final int size;
if (num < 0) {
size = (int) sres.getFound();
} else {
size = num;
}
// TODO - need a configurable absolute max size for fetches
srb.setSize(size);
final List<SearchResultEntry> entities = new ArrayList<>(size);
if (!Util.isEmpty(res.curSort)) {
SortOrder so;
for (final SortTerm st : res.curSort) {
if (st.isAscending()) {
so = SortOrder.ASC;
} else {
so = SortOrder.DESC;
}
srb.addSort(new FieldSortBuilder(ESQueryFilter.makePropertyRef(st.getProperties())).order(so));
}
}
if (res.requiresSecondaryFetch) {
// Limit to href then fetch those
srb.addField(ESQueryFilter.hrefJname);
}
final SearchResponse resp = srb.execute().actionGet();
if (resp.status() != RestStatus.OK) {
if (debug) {
debug("Search returned status " + resp.status());
}
}
final SearchHits hitsResp = resp.getHits();
if ((hitsResp.getHits() == null) || (hitsResp.getHits().length == 0)) {
return entities;
}
// Break condition: No hits are returned
if (hitsResp.hits().length == 0) {
return entities;
}
final List<SearchHit> hits;
if (res.requiresSecondaryFetch) {
hits = multiFetch(hitsResp, res.recurRetrieval);
if (hits == null) {
return entities;
}
} else {
hits = Arrays.asList(hitsResp.getHits());
}
final Map<String, Collection<BwEventAnnotation>> overrides = new HashMap<>();
final Collection<EventInfo> masters = new TreeSet<>();
EntityBuilder.checkFlushCache(currentChangeToken());
/* If we are retrieving events with a time range query and we are asking for the
* master + overrides then we need to check that the master really has an
* instance in the given time range */
final boolean checkTimeRange = (res.recurRetrieval.mode == Rmode.overrides) && ((res.latestStart != null) || (res.earliestEnd != null));
final Set<String> excluded = new TreeSet<>();
for (final SearchHit hit : hits) {
res.pageStart++;
final String dtype = hit.getType();
if (dtype == null) {
throw new CalFacadeException("org.bedework.index.noitemtype");
}
final String kval = hit.getId();
if (kval == null) {
throw new CalFacadeException("org.bedework.index.noitemkey");
}
final EntityBuilder eb = getEntityBuilder(hit.sourceAsMap());
Object entity = null;
switch(dtype) {
case docTypeCollection:
entity = eb.makeCollection();
break;
case docTypeCategory:
entity = eb.makeCat();
break;
case docTypeContact:
entity = eb.makeContact();
break;
case docTypeLocation:
entity = eb.makeLocation();
break;
case docTypeEvent:
case docTypePoll:
entity = eb.makeEvent(kval, res.recurRetrieval.mode == Rmode.expanded);
final EventInfo ei = (EventInfo) entity;
final BwEvent ev = ei.getEvent();
final Response evrestResp = new Response();
restoreEvProps(evrestResp, ei);
if (evrestResp.getStatus() != ok) {
warn("Failed restore of ev props: " + evrestResp);
}
final Acl.CurrentAccess ca = res.accessCheck.checkAccess(ev, desiredAccess, true);
if ((ca == null) || !ca.getAccessAllowed()) {
continue;
}
ei.setCurrentAccess(ca);
if (ev instanceof BwEventAnnotation) {
if (excluded.contains(ev.getUid())) {
continue;
}
// Treat as override
final Collection<BwEventAnnotation> ov = overrides.computeIfAbsent(ev.getHref(), k -> new TreeSet<>());
ov.add((BwEventAnnotation) ev);
continue;
}
if (checkTimeRange && dtype.equals(docTypeEvent) && ev.getRecurring()) {
if (Util.isEmpty(RecurUtil.getPeriods(ev, 99, 1, res.latestStart, res.earliestEnd).instances)) {
excluded.add(ev.getUid());
continue;
}
}
masters.add(ei);
break;
}
entities.add(new SearchResultEntry(entity, dtype, hit.getScore()));
}
for (final EventInfo ei : masters) {
final BwEvent ev = ei.getEvent();
if (ev.getRecurring()) {
final Collection<BwEventAnnotation> ov = overrides.get(ev.getHref());
if (ov != null) {
for (final BwEventAnnotation ann : ov) {
final BwEvent proxy = new BwEventProxy(ann);
ann.setTarget(ev);
ann.setMaster(ev);
final EventInfo oei = new EventInfo(proxy);
ei.addOverride(oei);
}
}
}
}
return entities;
}
use of org.bedework.calfacade.svc.EventInfo in project bw-calendar-engine by Bedework.
the class BwIndexEsImpl method fetchEvent.
@Override
public GetEntityResponse<EventInfo> fetchEvent(final String href) throws CalFacadeException {
final GetEntityResponse<EventInfo> resp = new GetEntityResponse<>();
final String recurrenceId;
final String hrefNorid;
// Check validity
final int pos = href.lastIndexOf("/");
if (pos < 0) {
throw new RuntimeException("Bad href: " + href);
}
final int fragPos = href.lastIndexOf("#");
if (fragPos < pos) {
hrefNorid = href;
recurrenceId = null;
} else {
hrefNorid = href.substring(0, fragPos);
recurrenceId = href.substring(fragPos + 1);
}
final FilterBuilder fltr = getFilters(null).singleEventFilter(href, recurrenceId);
final SearchHit hit = fetchEntity(docTypeEvent, fltr);
if (hit == null) {
return notFound(resp);
}
final EntityBuilder eb = getEntityBuilder(hit.sourceAsMap());
final EventInfo ei = eb.makeEvent(hit.getId(), false);
if (ei == null) {
return notFound(resp);
}
final BwEvent ev = ei.getEvent();
final Acl.CurrentAccess ca = accessCheck.checkAccess(ev, privRead, true);
if ((ca == null) || !ca.getAccessAllowed()) {
return notFound(resp);
}
ei.setCurrentAccess(ca);
if (ev.getRecurrenceId() != null) {
// Single instance
resp.setEntity(ei);
return resp;
}
addOverrides(resp, idxpars.getUserIndexName(), ei);
return resp;
}
Aggregations