gt:         if ((repeatByMonthDay == null || repeatByMonthDay.length == 0)
context: package org.exoplatform.extension.exchange.service.util;
  
  import java.io.ByteArrayInputStream;
  import java.text.SimpleDateFormat;
  import java.time.LocalDate;
  import java.time.temporal.ChronoUnit;
  import java.util.*;
  import java.util.Calendar;
  import java.util.stream.Collectors;
  
  import org.apache.commons.codec.digest.DigestUtils;
  import org.apache.commons.io.output.ByteArrayOutputStream;
  import org.apache.commons.lang.StringUtils;
  import org.apache.tika.mime.MimeTypes;
  
  import org.exoplatform.calendar.service.*;
  import org.exoplatform.calendar.service.impl.JCRDataStorage;
  import org.exoplatform.calendar.service.impl.NewUserListener;
  import org.exoplatform.commons.utils.CommonsUtils;
  import org.exoplatform.commons.utils.DateUtils;
  import org.exoplatform.commons.utils.ListAccess;
  import org.exoplatform.container.PortalContainer;
  import org.exoplatform.extension.exchange.service.CorrespondenceService;
  import org.exoplatform.services.log.ExoLogger;
  import org.exoplatform.services.log.Log;
  import org.exoplatform.services.organization.*;
  
  import microsoft.exchange.webservices.data.core.PropertySet;
  import microsoft.exchange.webservices.data.core.enumeration.property.*;
  import microsoft.exchange.webservices.data.core.enumeration.property.time.*;
  import microsoft.exchange.webservices.data.core.enumeration.service.calendar.AppointmentType;
  import microsoft.exchange.webservices.data.core.exception.service.local.ServiceLocalException;
  import microsoft.exchange.webservices.data.core.exception.service.local.ServiceObjectPropertyException;
  import microsoft.exchange.webservices.data.core.service.item.Appointment;
  import microsoft.exchange.webservices.data.core.service.schema.AppointmentSchema;
  import microsoft.exchange.webservices.data.property.complex.*;
  import microsoft.exchange.webservices.data.property.complex.recurrence.DayOfTheWeekCollection;
  import microsoft.exchange.webservices.data.property.complex.recurrence.pattern.Recurrence;
  import microsoft.exchange.webservices.data.property.complex.recurrence.pattern.Recurrence.*;
  import microsoft.exchange.webservices.data.property.complex.time.TimeZoneDefinition;
  
  /**
   * @author Boubaker Khanfir
   */
  @SuppressWarnings("all")
  public class CalendarConverterUtils {
  
    private static final TimeZone           DEFAULT_TIME_ZONE             = TimeZone.getDefault();
  
    private static final int                DEFAULT_TIMEZONE_RAW_OFFSET   = DEFAULT_TIME_ZONE.getRawOffset();
  
    private static final Log                LOG                           = ExoLogger.getLogger(CalendarConverterUtils.class);
  
    public static final SimpleDateFormat    RECURRENCE_ID_FORMAT          = new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'");
  
    private static final String             EXCHANGE_CALENDAR_NAME_PREFIX = "EXCH";
  
    private static final String             EXCHANGE_CALENDAR_ID_PREFIX   = "EXCH";
  
    private static final String             EXCHANGE_EVENT_ID_PREFIX      = "ExcangeEvent";
  
    // This variable is used to save the time zone used in exchange server
    private static String                   exchange_remote_time_zone     = "GMT";
  
    // Reuse the object and save memory instead of instantiating this every call
    private static final ThreadLocal<Query> queryThreadLocal              = new ThreadLocal<>();
  
    private CalendarConverterUtils() {
    }
  
    /**
     * Converts from Exchange Calendar Event to eXo Calendar Event.
     * 
     * @param event
     * @param appointment
     * @param username
     * @param storage
     * @param userHandler
     * @throws Exception
     */
    public static void convertExchangeToExoEvent(CalendarEvent event,
                                                 Appointment appointment,
                                                 String username,
                                                 JCRDataStorage storage,
                                                 UserHandler userHandler) throws Exception {
      if (event.getId() == null || event.getId().isEmpty()) {
        event.setId(getEventId(appointment.getId().getUniqueId()));
      }
      if (event.getEventType() == null) {
        event.setEventType(CalendarEvent.TYPE_EVENT);
        event.setCalType("" + org.exoplatform.calendar.service.Calendar.TYPE_PRIVATE);
      }
      event.setLocation(appointment.getLocation());
      if (appointment.getSubject() != null)
      {
        event.setSummary(appointment.getSubject());
      } else {
        event.setSummary("");
      }
      setEventStatus(event, appointment);
      setEventDates(event, appointment, username);
      setEventPriority(event, appointment);
      setEventCategory(event, appointment, username, storage);
      setEventParticipants(event, appointment, userHandler);
      setEventReminder(event, appointment, username);
  
      if (appointment.getSensitivity() != null && !appointment.getSensitivity().equals(Sensitivity.Normal)) {
        event.setPrivate(true);
      } else {
        event.setPrivate(false);
      }
      setEventAttachements(event, appointment);
      // This have to be last thing to load because of BAD EWS API impl
      setEventDescription(event, appointment);
    }
  
    /**
     * Converts from Exchange Calendar Recurring Master Event to eXo Calendar
     * Event.
     * 
     * @param event
     * @param appointment
     * @param username
     * @param storage
     * @param userHandler
     * @throws Exception
     */
    @SuppressWarnings("deprecation")
    public static void convertExchangeToExoMasterRecurringCalendarEvent(CalendarEvent event,
                                                                        Appointment appointment,
                                                                        String username,
                                                                        JCRDataStorage storage,
                                                                        UserHandler userHandler) throws Exception {
      convertExchangeToExoEvent(event, appointment, username, storage, userHandler);
      appointment = Appointment.bind(appointment.getService(), appointment.getId(), new PropertySet(AppointmentSchema.Recurrence));
      Recurrence recurrence = appointment.getRecurrence();
      if (recurrence instanceof DailyPattern) {
        event.setRepeatType(CalendarEvent.RP_DAILY);
      } else if (recurrence instanceof WeeklyPattern) {
        event.setRepeatType(CalendarEvent.RP_WEEKLY);
        DayOfTheWeekCollection dayOfTheWeekCollection = ((WeeklyPattern) recurrence).getDaysOfTheWeek();
        if (dayOfTheWeekCollection != null && dayOfTheWeekCollection.getCount() > 0) {
          String[] days = new String[7];
          Iterator<DayOfTheWeek> iterator = dayOfTheWeekCollection.iterator();
          ITERATE_WHILE: while (iterator.hasNext()) {
            DayOfTheWeek dayOfTheWeek = (DayOfTheWeek) iterator.next();
            switch (dayOfTheWeek) {
            case Monday:
              days[0] = CalendarEvent.RP_WEEKLY_BYDAY[0];
              break;
            case Tuesday:
              days[1] = CalendarEvent.RP_WEEKLY_BYDAY[1];
              break;
            case Wednesday:
              days[2] = CalendarEvent.RP_WEEKLY_BYDAY[2];
              break;
            case Thursday:
              days[3] = CalendarEvent.RP_WEEKLY_BYDAY[3];
              break;
            case Friday:
              days[4] = CalendarEvent.RP_WEEKLY_BYDAY[4];
              break;
            case Saturday:
              days[5] = CalendarEvent.RP_WEEKLY_BYDAY[5];
              break;
            case Sunday:
              days[6] = CalendarEvent.RP_WEEKLY_BYDAY[6];
              break;
            case Weekday:
              days = Arrays.copyOfRange(CalendarEvent.RP_WEEKLY_BYDAY, 0, 4);
              event.setRepeatType(CalendarEvent.RP_WORKINGDAYS);
              break ITERATE_WHILE;
            case WeekendDay:
              days = Arrays.copyOfRange(CalendarEvent.RP_WEEKLY_BYDAY, 5, 6);
              event.setRepeatType(CalendarEvent.RP_WEEKEND);
              break ITERATE_WHILE;
            case Day:
              days = Arrays.copyOfRange(CalendarEvent.RP_WEEKLY_BYDAY, 0, 6);
              break ITERATE_WHILE;
            }
          }
          List<String> daysList = new ArrayList<String>();
          for (String day : days) {
            if (day != null) {
              daysList.add(day);
            }
          }
          event.setRepeatByDay(daysList.toArray(new String[0]));
          TimeZone userTimeZone = getUserTimeZone(username);
          Utils.adaptRepeatRule(event, userTimeZone, CalendarService.PERSISTED_TIMEZONE);
        }
      } else if (recurrence instanceof RelativeMonthlyPattern) {
        event.setRepeatType(CalendarEvent.RP_MONTHLY);
  
        DayOfTheWeekIndex dayOfTheWeekIndex = ((RelativeMonthlyPattern) recurrence).getDayOfTheWeekIndex();
        int exoIndex = (dayOfTheWeekIndex.ordinal() + 2) % 6 - 1;
        String dayPrefix = null;
  
        switch (((RelativeMonthlyPattern) recurrence).getDayOfTheWeek()) {
        case Monday:
          dayPrefix = CalendarEvent.RP_WEEKLY_BYDAY[0];
          break;
        case Tuesday:
          dayPrefix = CalendarEvent.RP_WEEKLY_BYDAY[1];
          break;
        case Wednesday:
          dayPrefix = CalendarEvent.RP_WEEKLY_BYDAY[2];
          break;
        case Thursday:
          dayPrefix = CalendarEvent.RP_WEEKLY_BYDAY[3];
          break;
        case Friday:
          dayPrefix = CalendarEvent.RP_WEEKLY_BYDAY[4];
          break;
        case Saturday:
          dayPrefix = CalendarEvent.RP_WEEKLY_BYDAY[5];
          break;
        case Sunday:
          dayPrefix = CalendarEvent.RP_WEEKLY_BYDAY[6];
          break;
        default:
          LOG.error("Uknown day of the week '" + ((RelativeMonthlyPattern) recurrence).getDayOfTheWeek() + "', for recurrence '"
              + appointment.getSubject() + "', Monday will be set.");
          dayPrefix = CalendarEvent.RP_WEEKLY_BYDAY[0];
          break;
        }
        event.setRepeatByDay(new String[] { exoIndex + dayPrefix });
        event.setRepeatByMonthDay(null);
      } else if (recurrence instanceof MonthlyPattern) {
        event.setRepeatType(CalendarEvent.RP_MONTHLY);
        event.setRepeatByDay(null);
        int dayOfMonth = 0;
        try {
          dayOfMonth = ((MonthlyPattern) recurrence).getDayOfMonth();
        } catch (Exception e) {
          dayOfMonth = recurrence.getStartDate().getDate();
        }
        event.setRepeatByMonthDay(new long[] { dayOfMonth });
        TimeZone userTimeZone = getUserTimeZone(username);
        Utils.adaptRepeatRule(event, userTimeZone, CalendarService.PERSISTED_TIMEZONE);
      } else if (recurrence instanceof YearlyPattern) {
        event.setRepeatType(CalendarEvent.RP_YEARLY);
  
        event.setRepeatInterval(1);
        Calendar tempCalendar = Calendar.getInstance();
        tempCalendar.set(Calendar.MONTH, ((YearlyPattern) recurrence).getMonth().ordinal());
        int dayOfMonth = 0;
        try {
          dayOfMonth = ((MonthlyPattern) recurrence).getDayOfMonth();
        } catch (Exception e) {
          dayOfMonth = recurrence.getStartDate().getDate();
        }
        tempCalendar.set(Calendar.DAY_OF_MONTH, dayOfMonth);
        int dayOfYear = tempCalendar.get(Calendar.DAY_OF_YEAR);
  
        event.setRepeatByYearDay(new long[] { dayOfYear });
      } else if (recurrence instanceof RelativeYearlyPattern) {
        LOG.error("Cannot manage events of type RelativeYearlyPattern.");
        event.setRepeatType(CalendarEvent.RP_YEARLY);
      }
      if (recurrence instanceof IntervalPattern) {
        if (((IntervalPattern) recurrence).getInterval() > 0) {
          event.setRepeatInterval(((IntervalPattern) recurrence).getInterval());
        }
      }
      Date endDate = recurrence.getEndDate();
      if (endDate != null) {
        Calendar calendar = getCalendarInstance(endDate);
        setEndOfDay(calendar);
        event.setRepeatUntilDate(calendar.getTime());
      }
      if (recurrence.getNumberOfOccurrences() != null) {
        event.setRepeatCount(recurrence.getNumberOfOccurrences());
      }
    }
  
    /**
     * Converts from Exchange Calendar Exceptional Occurence Event to eXo Calendar
     * Event and return the list of deleted and updated elements.
     * 
     * @param masterEvent
     * @param updatedEvents empty list that will be updated by modified occurences
     * @param occurenceAppointments
     * @param masterAppointment
     * @param username
     * @param storage
     * @param userHandler
     * @return
     * @throws Exception
     */
    public static List<CalendarEvent> convertExchangeToExoOccurenceEvent(CalendarEvent masterEvent,
                                                                         List<CalendarEvent> updatedEvents,
                                                                         List<Appointment> occurenceAppointments,
                                                                         Appointment masterAppointment,
                                                                         String username,
                                                                         JCRDataStorage storage,
                                                                         UserHandler userHandler,
                                                                         CorrespondenceService correspondenceService) throws Exception {
      masterAppointment = Appointment.bind(masterAppointment.getService(),
                                           masterAppointment.getId(),
                                           new PropertySet(AppointmentSchema.ModifiedOccurrences));
      List<CalendarEvent> calendarEvents = new ArrayList<CalendarEvent>();
      {
        OccurrenceInfoCollection occurrenceInfoCollection = masterAppointment.getModifiedOccurrences();
        if (occurrenceInfoCollection != null && occurrenceInfoCollection.getCount() > 0) {
          for (OccurrenceInfo occurrenceInfo : occurrenceInfoCollection) {
            Appointment occurenceAppointment = Appointment.bind(masterAppointment.getService(),
                                                                occurrenceInfo.getItemId(),
                                                                new PropertySet(BasePropertySet.FirstClassProperties));
  
            String exoId = correspondenceService.getCorrespondingId(username, occurenceAppointment.getId().getUniqueId());
            CalendarEvent tmpEvent = null;
            if (!StringUtils.isEmpty(exoId)) {
              tmpEvent = storage.getEvent(username, exoId);
            }
            if (tmpEvent == null) {
              tmpEvent = getOccurenceOfDate(username, storage, masterEvent, occurrenceInfo.getOriginalStart());
            }
  
            if (tmpEvent != null && verifyModifiedDatesConflict(tmpEvent, occurenceAppointment)) {
              if (LOG.isDebugEnabled()) {
                LOG.info("CONFLICT: Attempting to update eXo Event with Exchange Event for user {}, but modification date of eXo is after, ignore updating.",
                         username);
              }
              continue;
            }
            if (tmpEvent == null || tmpEvent.getIsExceptionOccurrence() == null || !tmpEvent.getIsExceptionOccurrence()) {
              CalendarEvent tmpEvent1 = new CalendarEvent();
              convertExchangeToExoEvent(tmpEvent1, occurenceAppointment, username, storage, userHandler);
              tmpEvent1.setRecurrenceId(RECURRENCE_ID_FORMAT.format(tmpEvent.getFromDateTime()));
              tmpEvent1.setRepeatType(CalendarEvent.RP_NOREPEAT);
              tmpEvent1.setId(masterEvent.getId());
              tmpEvent1.setCalendarId(masterEvent.getCalendarId());
              if (LOG.isDebugEnabled()) {
                LOG.debug("CREATE exo calendar for user {} - Occurence event: {}, with recurence id: {}",
                          username,
                          tmpEvent.getSummary(),
                          tmpEvent.getRecurrenceId());
              }
              updatedEvents.add(tmpEvent1);
              calendarEvents.add(tmpEvent);
            } else {
              if (LOG.isDebugEnabled()) {
                LOG.debug("UPDATE exo calendar for user {} - Occurence event: {}, with recurence id: {}",
                          username,
                          tmpEvent.getSummary(),
                          tmpEvent.getRecurrenceId());
              }
              convertExchangeToExoEvent(tmpEvent, occurenceAppointment, username, storage, userHandler);
              updatedEvents.add(tmpEvent);
            }
            occurenceAppointments.add(occurenceAppointment);
  
          }
        }
      }
      masterAppointment = Appointment.bind(masterAppointment.getService(),
                                           masterAppointment.getId(),
                                           new PropertySet(AppointmentSchema.DeletedOccurrences));
  
      DeletedOccurrenceInfoCollection deletedOccurrenceInfoCollection = masterAppointment.getDeletedOccurrences();
      if (deletedOccurrenceInfoCollection != null && deletedOccurrenceInfoCollection.getCount() > 0) {
        for (DeletedOccurrenceInfo occurrenceInfo : deletedOccurrenceInfoCollection) {
          CalendarEvent toDeleteEvent = getOccurenceOfDate(username, storage, masterEvent, occurrenceInfo.getOriginalStart());
          if (toDeleteEvent == null) {
            continue;
          }
  
          String appId = correspondenceService.getCorrespondingId(username, toDeleteEvent.getId());
          Appointment appointment = null;
          try {
            appointment = Appointment.bind(masterAppointment.getService(), ItemId.getItemIdFromString(appId));
          } catch (Exception e) {
          }
          if (appointment == null || toDeleteEvent.getIsExceptionOccurrence() == null
              || !toDeleteEvent.getIsExceptionOccurrence()) {
            calendarEvents.add(toDeleteEvent);
          }
        }
      }
      return calendarEvents;
    }
  
    /**
     * @param event eXo Calendar event
     * @param appointment Exchange item
     * @return
     * @throws Exception
     */
    @SuppressWarnings("deprecation")
    public static boolean verifyModifiedDatesConflict(CalendarEvent event, Appointment appointment) throws Exception {
      if (event.getLastUpdatedTime() == null) {
        return false;
      } else if (appointment.getLastModifiedTime() == null) {
        return true;
      }
      return event.getLastModified() >= appointment.getLastModifiedTime().getTime();
    }
  
    /**
     * Converts from Exchange Calendar Event to eXo Calendar Event.
     * 
     * @param appointment
     * @param calendarEvent
     * @param username
     * @param userHandler
     * @throws Exception
     */
    public static void convertExoToExchangeEvent(Appointment appointment,
                                                 CalendarEvent calendarEvent,
                                                 String username,
                                                 UserHandler userHandler) throws Exception {
      setAppointmentStatus(appointment, calendarEvent);
      setAppointmentDates(appointment, calendarEvent, username);
      setAppointmentPriority(appointment, calendarEvent);
      setAppointmentCategory(appointment, calendarEvent);
      setAppointmentAttendees(appointment, calendarEvent, userHandler, username);
      setAppointmentReminder(appointment, calendarEvent);
  
      appointment.setLocation(calendarEvent.getLocation());
      appointment.setSubject(calendarEvent.getSummary());
      if (calendarEvent.isPrivate()) {
        appointment.setSensitivity(Sensitivity.Private);
      } else {
        appointment.setSensitivity(Sensitivity.Normal);
      }
      setAppointmentAttachements(appointment, calendarEvent);
  
      // This have to be last thing to load because of BAD EWS API impl
      setApoinementSummary(appointment, calendarEvent);
    }
  
    /**
     * Converts from Exchange Calendar Recurring Master Event to eXo Calendar
     * Event.
     * 
     * @param appointment
     * @param event
     * @param username
     * @param userHandler
     * @return list of occurences to delete
     * @throws Exception
     */
    public static List<Appointment> convertExoToExchangeMasterRecurringCalendarEvent(Appointment appointment,
                                                                                     CalendarEvent event,
                                                                                     String username,
                                                                                     UserHandler userHandler) throws Exception {
      List<Appointment> toDeleteOccurences = null;
  
      convertExoToExchangeEvent(appointment, event, username, userHandler);
  
      String repeatType = event.getRepeatType();
      assert repeatType != null && !repeatType.equals(CalendarEvent.RP_NOREPEAT);
      Recurrence recurrence = null;
      if (repeatType.equals(CalendarEvent.RP_DAILY)) {
      	int repeatInterval = (int)event.getRepeatInterval();
      	if (repeatInterval == 0) {
      		repeatInterval = 1;
      	}
      	recurrence = new Recurrence.DailyPattern(event.getFromDateTime(),repeatInterval);
      } else {
        long repeatInterval = event.getRepeatInterval();
        if (repeatInterval == 0) {
          repeatInterval = 1;
        }
        if (repeatType.equals(CalendarEvent.RP_WEEKLY)) {
          TimeZone exchangeTimeZone = getExchangeTimeZone();   
          Utils.adaptRepeatRule(event, CalendarService.PERSISTED_TIMEZONE, exchangeTimeZone);
          List<DayOfTheWeek> daysOfTheWeek = new ArrayList<DayOfTheWeek>();
          String[] repeatDays = event.getRepeatByDay();
          if (repeatDays != null) {
            for (String repeatDay : repeatDays) {
              if (StringUtils.isEmpty(repeatDay)) {
                continue;
              } else if (repeatDay.equals(CalendarEvent.RP_WEEKLY_BYDAY[0])) {
                daysOfTheWeek.add(DayOfTheWeek.Monday);
              } else if (repeatDay.equals(CalendarEvent.RP_WEEKLY_BYDAY[1])) {
                daysOfTheWeek.add(DayOfTheWeek.Tuesday);
              } else if (repeatDay.equals(CalendarEvent.RP_WEEKLY_BYDAY[2])) {
                daysOfTheWeek.add(DayOfTheWeek.Wednesday);
              } else if (repeatDay.equals(CalendarEvent.RP_WEEKLY_BYDAY[3])) {
                daysOfTheWeek.add(DayOfTheWeek.Thursday);
              } else if (repeatDay.equals(CalendarEvent.RP_WEEKLY_BYDAY[4])) {
                daysOfTheWeek.add(DayOfTheWeek.Friday);
              } else if (repeatDay.equals(CalendarEvent.RP_WEEKLY_BYDAY[5])) {
                daysOfTheWeek.add(DayOfTheWeek.Saturday);
              } else if (repeatDay.equals(CalendarEvent.RP_WEEKLY_BYDAY[6])) {
                daysOfTheWeek.add(DayOfTheWeek.Sunday);
              }
            }
          }
          recurrence = new Recurrence.WeeklyPattern(event.getFromDateTime(),
                                                    (int) repeatInterval,
                                                    daysOfTheWeek.toArray(new DayOfTheWeek[0]));
        } else if (repeatType.equals(CalendarEvent.RP_MONTHLY)) {
          TimeZone exchangeTimeZone = getExchangeTimeZone();
          Utils.adaptRepeatRule(event, CalendarService.PERSISTED_TIMEZONE, exchangeTimeZone);
          long[] repeatByMonthDay = event.getRepeatByMonthDay();
  