@Override
  public ExportResult<CalendarContainerResource> export(UUID jobId, TokensAndUrlAuthData authData,
      Optional<ExportInformation> exportInformation) {
    if (exportInformation.isPresent()) {
      // TODO support pagination
      throw new UnsupportedOperationException();
    }
    Request.Builder calendarsBuilder = getBuilder(baseUrl + CALENDARS_SUBPATH, authData);

    List<CalendarModel> calendarModels = new ArrayList<>();
    try (Response graphResponse = client.newCall(calendarsBuilder.build()).execute()) {
      ResponseBody body = graphResponse.body();
      if (body == null) {
        return new ExportResult<>(
            new Exception("Error retrieving contacts: response body was null"));
      }
      String graphBody = new String(body.bytes());
      Map graphMap = objectMapper.reader().forType(Map.class).readValue(graphBody);

      // TODO String nextLink = (String) graphMap.get(ODATA_NEXT);
      // TODO ContinuationData continuationData = nextLink == null
      // ? null : new ContinuationData(new GraphPagination(nextLink));

      @SuppressWarnings("unchecked")
      List<Map<String, Object>> rawCalendars = (List<Map<String, Object>>) graphMap.get("value");
      if (rawCalendars == null) {
        return new ExportResult<>(ExportResult.ResultType.END);
      }
      for (Map<String, Object> rawCalendar : rawCalendars) {

        TransformResult<CalendarModel> result =
            transformerService.transform(CalendarModel.class, rawCalendar);
        if (result.hasProblems()) {
          // discard
          // FIXME log problem
          continue;
        }

        calendarModels.add(result.getTransformed());
      }
    } catch (IOException e) {
      e.printStackTrace(); // FIXME log error
      return new ExportResult<>(e);
    }

    List<CalendarEventModel> calendarEventModels = new ArrayList<>();

    for (CalendarModel calendarModel : calendarModels) {
      String id = calendarModel.getId();
      Request.Builder eventsBuilder = getBuilder(calculateEventsUrl(id), authData);

      try (Response graphResponse = client.newCall(eventsBuilder.build()).execute()) {
        ResponseBody body = graphResponse.body();
        if (body == null) {
          return new ExportResult<>(
              new Exception("Error retrieving calendar: response body was null"));
        }
        String graphBody = new String(body.bytes());
        Map graphMap = objectMapper.reader().forType(Map.class).readValue(graphBody);

        // TODO String nextLink = (String) graphMap.get(ODATA_NEXT);
        // TODO ContinuationData continuationData = nextLink == null
        // ? null : new ContinuationData(new GraphPagination(nextLink));

        @SuppressWarnings("unchecked")
        List<Map<String, Object>> rawEvents = (List<Map<String, Object>>) graphMap.get("value");
        if (rawEvents == null) {
          return new ExportResult<>(ExportResult.ResultType.END);
        }

        for (Map<String, Object> rawEvent : rawEvents) {
          Map<String, String> properties = new HashMap<>();
          properties.put(CALENDAR_ID, id);
          TransformResult<CalendarEventModel> result =
              transformerService.transform(CalendarEventModel.class, rawEvent, properties);
          if (result.hasProblems()) {
            // discard
            // FIXME log problem
            continue;
          }
          calendarEventModels.add(result.getTransformed());
        }

      } catch (IOException e) {
        e.printStackTrace(); // FIXME log error
        return new ExportResult<>(e);
      }
    }

    CalendarContainerResource resource =
        new CalendarContainerResource(calendarModels, calendarEventModels);
    return new ExportResult<>(ExportResult.ResultType.END, resource, null);
  }
Exports Outlook calendar information using the Microsoft Graph API.
extensions/data-transfer/portability-data-transfer-microsoft/src/main/java/org/datatransferproject/transfer/microsoft/calendar/MicrosoftCalendarExporter.java