ews-java-api
ews-java-api copied to clipboard
CalendarView isn't pagable
After taking a look at the CalendarView
and ItemView
, I noticed the difference of CalendarView
only inheriting from ViewBase
while ItemView
is a child of PagedView
. I get the following exception for large queries of calendar data:
microsoft.exchange.webservices.data.ServiceResponseException: You have exceeded the maximum number of objects that can be returned for the find operation. Use paging to reduce the result size and try your request again.
And line 141 in CalendarFolder.java seems to always call the initial offset of 0 for any view query.
If there is something I am missing, please let me know, otherwise I wanted to flag this as a potential issue for anyone querying large amounts of calendar data.
We're using service.findItems()
for this, not sure what the advantage of CalendarFolder
is?
Well if I want to get a set of Appointment
objects from a given start and end date, but the number of returned results exceeds the maximum items to be returned. I would be unable to query this using service.findItems()
since the CalendarView
doesn't extend PagedView
. Unless I am missing something?
I'm just guessing here, but can't you just cast the Item
s from service.findItems()
to an Appointment
?
I agree the findAppointments()
method should probably be fixed (well, the CalendarView
should), but maybe there are already Appointment
objects returned.
I could cast, but the call to service.findItems()
would not allow me to filter based off date (as a CalendarView
would).
Yes it does, something like this should work: (don't ask me why we're using java.sql.Date
here, I'm just copying the code as is and still need to figure this out)
SearchFilter filter = new SearchFilter.IsGreaterThanOrEqualTo(AppointmentSchema.Start,
new java.sql.Date(new Date().getTime()));
ItemView view = new ItemView(PAGE_SIZE);
view.setPropertySet(PropertySet.IdOnly);
FindItemsResults<Item> items;
do {
items = service.findItems(getDelegatedFolderId(), filter, view);
...
if (items.isMoreAvailable()) {
view.setOffset(items.getNextPageOffset());
}
} while (items.isMoreAvailable());
@dotCipher do you want to create a PR on the CalendarView issue?
@MikeN123 hopefully we dont force the use of java.sql.Date
:smile: here. Have you finished your investigations yet?
If you pass an Object into the SearchFilter value, it gets converted to a String when writing the request XML. That's done by calling the toString()
method, which returns a yyyy-MM-dd
date string in case of a java.sql.Date
.
So using a java.sql.Date
here is kind of a hack, but it would work. Other formats may or may not be possible and you may or may not need to specify a timezone, depending on your situation.
@MikeN123 I stand corrected, but it might be more concise to have this part of the CalendarView
.
@serious6 If it makes sense and agreed on, I would gladly add it.
@evpaassen Is there a less hacky way that you know of than making the call using SearchFilter
with java.sql.Date
?
hmm maybe we can have a default parsing pattern for the dates and also add a constructor with a SimpleDateFOrmat as parameter to enable users to add their own.
@serious6 +1 that seems like a good idea
I don't think we need a constructor with an SDF, it should be enough to overload the method with a Date
instead of a Object
parameter and do the correct formatting on that object.
Either way, would it make sense to allow CalendarView
to contain a page offset instead of just using 0 ?
That 0 is not the one you would need to edit, as the paging is done serverside. CalendarView
probably needs to extend PagedView
instead of ViewBase
for that to work.
I will have some tests on that in the next few days. Besides PR are welcome.
I am fairly certain this is simply correct behavior. The SERVER SIDE of this will not support paging for CalendarView. You have to "fake it", which is a little tricky and error prone
For those looking for a workaround/ faking of the paging, you use do a do-while like this
boolean hasMoreAppointments = true;
do {
FindItemsResults<Appointment> results = exchangeService.findAppointments(folderId, calendarView);
// TODO Save results for processing after do-while
if (results.isMoreAvailable()) {
Appointment appointment = results.getItems().get(results.getItems().size() - 1);
calendarView.setStartDate(appointment.getStart());
} else {
hasMoreAppointments = false;
}
} while (hasMoreAppointments);
@Larvalis 's workaround is not completely correct -- it will contain duplicates since setting startDate to the last appointment's start date will make that appointment show up again in the next batch of results. It can also get stuck in an infinite loop if the number of appointments with the same startDate exceeds the batch size.
That is jnfact exactly what I meant by the tricky comment I made :;