ews-java-api icon indicating copy to clipboard operation
ews-java-api copied to clipboard

CalendarView isn't pagable

Open dotCipher opened this issue 9 years ago • 18 comments

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.

dotCipher avatar May 01 '15 20:05 dotCipher

We're using service.findItems() for this, not sure what the advantage of CalendarFolder is?

MikeN123 avatar May 02 '15 07:05 MikeN123

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?

dotCipher avatar May 03 '15 07:05 dotCipher

I'm just guessing here, but can't you just cast the Items 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.

MikeN123 avatar May 03 '15 07:05 MikeN123

I could cast, but the call to service.findItems() would not allow me to filter based off date (as a CalendarView would).

dotCipher avatar May 03 '15 19:05 dotCipher

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());

MikeN123 avatar May 03 '15 20:05 MikeN123

@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?

serious6 avatar May 04 '15 13:05 serious6

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.

evpaassen avatar May 04 '15 14:05 evpaassen

@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 ?

dotCipher avatar May 05 '15 06:05 dotCipher

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 avatar May 05 '15 21:05 serious6

@serious6 +1 that seems like a good idea

dotCipher avatar May 05 '15 22:05 dotCipher

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.

MikeN123 avatar May 06 '15 08:05 MikeN123

Either way, would it make sense to allow CalendarView to contain a page offset instead of just using 0 ?

dotCipher avatar May 07 '15 04:05 dotCipher

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.

MikeN123 avatar May 11 '15 19:05 MikeN123

I will have some tests on that in the next few days. Besides PR are welcome.

serious6 avatar May 13 '15 07:05 serious6

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

mikebell90 avatar Oct 13 '15 22:10 mikebell90

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 avatar Aug 18 '16 07:08 Larvalis

@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.

djma avatar Jan 04 '19 00:01 djma

That is jnfact exactly what I meant by the tricky comment I made :;

mikebell90 avatar Jan 04 '19 00:01 mikebell90