Java tutorial
/** * See the NOTICE file distributed with this work * for additional information regarding copyright ownership. * Board of Regents of the University of Wisconsin System * licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a * copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package com.microsoft.exchange.impl; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import javax.xml.datatype.XMLGregorianCalendar; import net.fortuna.ical4j.model.Calendar; import net.fortuna.ical4j.model.Date; import net.fortuna.ical4j.model.DateTime; import net.fortuna.ical4j.model.Dur; import net.fortuna.ical4j.model.Parameter; import net.fortuna.ical4j.model.ParameterList; import net.fortuna.ical4j.model.TextList; import net.fortuna.ical4j.model.component.VEvent; import net.fortuna.ical4j.model.component.VTimeZone; import net.fortuna.ical4j.model.component.VToDo; import net.fortuna.ical4j.model.parameter.Cn; import net.fortuna.ical4j.model.parameter.CuType; import net.fortuna.ical4j.model.parameter.PartStat; import net.fortuna.ical4j.model.parameter.Role; import net.fortuna.ical4j.model.property.Attendee; import net.fortuna.ical4j.model.property.Categories; import net.fortuna.ical4j.model.property.Clazz; import net.fortuna.ical4j.model.property.DtEnd; import net.fortuna.ical4j.model.property.DtStamp; import net.fortuna.ical4j.model.property.DtStart; import net.fortuna.ical4j.model.property.Duration; import net.fortuna.ical4j.model.property.Location; import net.fortuna.ical4j.model.property.Organizer; import net.fortuna.ical4j.model.property.Priority; import net.fortuna.ical4j.model.property.Status; import net.fortuna.ical4j.model.property.Summary; import net.fortuna.ical4j.model.property.Transp; import net.fortuna.ical4j.model.property.Uid; import net.fortuna.ical4j.model.property.XProperty; import org.apache.commons.lang.BooleanUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.Validate; import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.util.CollectionUtils; import com.microsoft.exchange.ExchangeEventConverter; import com.microsoft.exchange.exception.ExchangeEventConverterException; import com.microsoft.exchange.ical.model.EmailAddressMailboxType; import com.microsoft.exchange.ical.model.EmailAddressRoutingType; import com.microsoft.exchange.ical.model.ExchangeEndTimeZoneProperty; import com.microsoft.exchange.ical.model.ExchangeStartTimeZoneProperty; import com.microsoft.exchange.ical.model.ExchangeTimeZoneProperty; import com.microsoft.exchange.ical.model.ItemTypeChangeKey; import com.microsoft.exchange.ical.model.ItemTypeItemId; import com.microsoft.exchange.ical.model.ItemTypeParentFolderChangeKey; import com.microsoft.exchange.ical.model.ItemTypeParentFolderId; import com.microsoft.exchange.ical.model.PathToExtendedFieldTypePropertyId; import com.microsoft.exchange.ical.model.PathToExtendedFieldTypePropertySetId; import com.microsoft.exchange.ical.model.PathToExtendedFieldTypePropertyTag; import com.microsoft.exchange.ical.model.PathToExtendedFieldTypePropertyType; import com.microsoft.exchange.types.ArrayOfStringsType; import com.microsoft.exchange.types.AttendeeType; import com.microsoft.exchange.types.CalendarItemType; import com.microsoft.exchange.types.CalendarItemTypeType; import com.microsoft.exchange.types.DistinguishedPropertySetType; import com.microsoft.exchange.types.EmailAddressType; import com.microsoft.exchange.types.ExtendedPropertyType; import com.microsoft.exchange.types.FolderIdType; import com.microsoft.exchange.types.ImportanceChoicesType; import com.microsoft.exchange.types.ItemIdType; import com.microsoft.exchange.types.ItemType; import com.microsoft.exchange.types.LegacyFreeBusyType; import com.microsoft.exchange.types.MailboxTypeType; import com.microsoft.exchange.types.MapiPropertyTypeType; import com.microsoft.exchange.types.NonEmptyArrayOfAttendeesType; import com.microsoft.exchange.types.NonEmptyArrayOfPropertyValuesType; import com.microsoft.exchange.types.PathToExtendedFieldType; import com.microsoft.exchange.types.ResponseTypeType; import com.microsoft.exchange.types.SensitivityChoicesType; import com.microsoft.exchange.types.SingleRecipientType; import com.microsoft.exchange.types.TaskType; import com.microsoft.exchange.types.TimeZoneDefinitionType; public class ExchangeEventConverterImpl implements ExchangeEventConverter { protected Log log = LogFactory.getLog(this.getClass()); @Override public Calendar convertToCalendar(Collection<ItemType> items, String upn) { Calendar result = new Calendar(); result.getProperties().add(PROD_ID); result.getProperties().add(VERSION); int size = CollectionUtils.isEmpty(items) ? 0 : items.size(); log.debug("attempting to convert " + size + " items"); if (!CollectionUtils.isEmpty(items)) { for (ItemType item : items) { if (item instanceof CalendarItemType) { CalendarItemType calendarItem = (CalendarItemType) item; Pair<VEvent, ArrayList<VTimeZone>> pair = null; try { pair = convertCalendarItemType(calendarItem, upn); } catch (ExchangeEventConverterException e) { log.error("Failed to convert calendarItem:" + e.getMessage()); } if (null != pair) { if (null != pair.getLeft()) { result.getComponents().add(pair.getLeft()); } else { log.warn("Failed to generate VEvent for CalendarItemType=" + calendarItem); } if (!CollectionUtils.isEmpty(pair.getRight())) { log.debug("Generated " + pair.getRight().size() + " VTimeZone components for CalendarItemType=" + calendarItem); for (VTimeZone timeZone : pair.getRight()) { result.getComponents().add(timeZone); } } else { log.warn("Failed to generate VTimeZone for CalendarItemType=" + calendarItem); } } } else if (item instanceof TaskType) { TaskType taskItem = (TaskType) item; Pair<VToDo, ArrayList<VTimeZone>> pair = convertTaskType(taskItem, upn); //TODO handle tasks } else { log.warn("Not an instanceof CalendarItemType | TaskType. Cannot convert item: " + item); } } } return result; } protected Pair<VToDo, ArrayList<VTimeZone>> convertTaskType(TaskType taskItem, String upn) { VToDo task = new VToDo(); ArrayList<VTimeZone> timeZones = new ArrayList<VTimeZone>(); Pair<VToDo, ArrayList<VTimeZone>> pair = Pair.of(task, timeZones); return pair; } /** * * TimeZones. * * @param calendarItem * @param upn * @return * @throws ExchangeEventConverterException */ protected Pair<VEvent, ArrayList<VTimeZone>> convertCalendarItemType(CalendarItemType calendarItem, String upn) throws ExchangeEventConverterException { VEvent event = new VEvent(); ArrayList<VTimeZone> timeZones = new ArrayList<VTimeZone>(); if (calendarItem.getStart() == null) { throw new ExchangeEventConverterException("calendarItem must have a valid start time."); } if (calendarItem.getEnd() == null && calendarItem.getDuration() == null) { throw new ExchangeEventConverterException("calendarItem must have a valid end time or duration."); } //does this element have a timezone? XMLGregorianCalendar start = calendarItem.getStart(); DtStart dtStart = new DtStart(new DateTime(start.toGregorianCalendar().getTime())); DtEnd dtEnd = null; if (null != calendarItem.getEnd()) { dtEnd = new DtEnd(new DateTime(calendarItem.getEnd().toGregorianCalendar().getTime())); } //if all day event, must use Date if (null != calendarItem.isIsAllDayEvent() && calendarItem.isIsAllDayEvent()) { dtStart = new DtStart(new Date(start.toGregorianCalendar().getTime()), true); dtEnd = new DtEnd(new Date(calendarItem.getEnd().toGregorianCalendar().getTime()), true); log.debug("set to all day event"); } //this way no vtimezone is needed dtStart.setUtc(true); event.getProperties().add(dtStart); log.debug("added dtStart=" + dtStart); if (null != dtEnd) { dtEnd.setUtc(true); event.getProperties().add(dtEnd); log.debug("added dtEnd=" + dtEnd); } //in case dtEnd is not present but duration is. String duration = calendarItem.getDuration(); if (StringUtils.isNotBlank(duration) && event.getProperty(DtEnd.DTEND) == null) { Dur dur = new Dur(duration); Duration durationProperty = new Duration(dur); event.getProperties().add(durationProperty); event.getProperties().remove(DtEnd.DTEND); log.debug("dtend overridden with duration=" + durationProperty); } String uid = calendarItem.getUID(); if (StringUtils.isNotBlank(uid)) { Uid uidProperty = new Uid(uid); event.getProperties().add(uidProperty); log.debug("added Uid=" + uidProperty); } else { log.debug("could not generate Uid property."); } //should always set dtstamp, otherwise it's auto-generated and !veventCreatedNow.equals(veventCreatedLater); if (null != calendarItem.getDateTimeCreated()) { DtStamp dtstamp = new DtStamp( new DateTime(calendarItem.getDateTimeCreated().toGregorianCalendar().getTime())); dtstamp.setUtc(true); event.getProperties().remove(event.getProperty(DtStamp.DTSTAMP)); event.getProperties().add(dtstamp); log.debug("overide DtStamp=" + dtstamp); } else { log.debug("could not generate DtStamp, property will be autogenerated."); } String subject = calendarItem.getSubject(); if (StringUtils.isNotBlank(subject)) { Summary summaryProperty = new Summary(subject); event.getProperties().add(summaryProperty); log.debug("add summary=" + summaryProperty); } else { log.debug("could not generate Summary property"); } String location = calendarItem.getLocation(); if (StringUtils.isNotBlank(location)) { event.getProperties().add(new Location(location)); } else { log.debug("could not generate location property"); } LegacyFreeBusyType freeBusy = calendarItem.getLegacyFreeBusyStatus(); Transp transpProperty = Transp.OPAQUE; if (LegacyFreeBusyType.FREE.equals(freeBusy)) { transpProperty = Transp.TRANSPARENT; } event.getProperties().add(transpProperty); log.debug("added Transp=" + transpProperty); Status status = Status.VEVENT_CONFIRMED; if (BooleanUtils.isTrue(calendarItem.isIsCancelled())) { status = Status.VEVENT_CANCELLED; } event.getProperties().add(status); log.debug("added Status=" + status); boolean organizerIsSet = false; SingleRecipientType calendarItemOrganizer = calendarItem.getOrganizer(); if (null != calendarItemOrganizer) { Organizer organizer = convertToOrganizer(calendarItemOrganizer); if (null != organizer) { event.getProperties().add(organizer); organizerIsSet = true; log.debug("added Organizer=" + organizer); } else { log.debug("could not gernate Organizer. As a result, attendees will not be added."); } } else { log.debug("could not gernate Organizer. As a result, attendees will not be added."); } //only add RequiredAttendees, OptionalAttendees and Resources if and only if organizer present. if (organizerIsSet) { ResponseTypeType myResponseType = calendarItem.getMyResponseType(); //add RequiredAttendees NonEmptyArrayOfAttendeesType requiredAttendees = calendarItem.getRequiredAttendees(); if (null != requiredAttendees) { Set<Attendee> attendees = convertRequiredAttendees(requiredAttendees, myResponseType); for (Attendee attendee : attendees) { event.getProperties().add(attendee); } } else { log.debug("no required attendees."); } //add OptionalAttendees NonEmptyArrayOfAttendeesType optionalAttendees = calendarItem.getOptionalAttendees(); if (null != optionalAttendees) { Set<Attendee> attendees = convertOptionalAttendees(optionalAttendees, myResponseType); for (Attendee attendee : attendees) { event.getProperties().add(attendee); } } else { log.debug("no optional attendees"); } //add Resources NonEmptyArrayOfAttendeesType resourceAttendees = calendarItem.getResources(); if (null != resourceAttendees) { Set<Attendee> attendees = convertResourceAttendees(resourceAttendees, myResponseType); for (Attendee attendee : attendees) { event.getProperties().add(attendee); } } } CalendarItemTypeType calendarItemType = calendarItem.getCalendarItemType(); if (null != calendarItemType) { if (CalendarItemTypeType.EXCEPTION.equals(calendarItemType) || CalendarItemTypeType.RECURRING_MASTER.equals(calendarItemType)) { log.warn( "Recurring Event Detected! This implementation of ExchangeEventConverter does not expand recurrance. You should use a CalendarView to expand recurrence on the Exchagne server. --http://msdn.microsoft.com/en-us/library/office/aa564515(v=exchg.150).aspx"); } } //generate xproperties for standard item properties Collection<XProperty> itemXProperties = generateItemTypeXProperties(calendarItem); for (XProperty xp : itemXProperties) { event.getProperties().add(xp); } //generate XProperty's for ExtendedProperties... List<ExtendedPropertyType> extendedProperties = calendarItem.getExtendedProperties(); if (!CollectionUtils.isEmpty(extendedProperties)) { for (ExtendedPropertyType extendedProperty : extendedProperties) { Collection<XProperty> xProperties = convertExtendedPropertyType(extendedProperty); for (XProperty xp : xProperties) { event.getProperties().add(xp); } } } Pair<VEvent, ArrayList<VTimeZone>> pair = Pair.of(event, timeZones); return pair; } private Collection<XProperty> generateCalendarItemTypeXProperties(CalendarItemType calendarItem) { Collection<XProperty> xprops = new LinkedHashSet<XProperty>(); String timeZone = calendarItem.getTimeZone(); if (StringUtils.isNotBlank(timeZone)) { xprops.add(new ExchangeTimeZoneProperty(timeZone)); } else { log.warn("unable to generate ExchangeTimeZoneProperty, timeZone is blank"); } TimeZoneDefinitionType startTimeZone = calendarItem.getStartTimeZone(); if (null != startTimeZone && StringUtils.isNotBlank(startTimeZone.getId())) { xprops.add(new ExchangeStartTimeZoneProperty(startTimeZone.getId())); } else { log.debug("unable to generate ExchangeStartTimeZoneProperty, startTimeZone is blank"); } TimeZoneDefinitionType endTimeZone = calendarItem.getEndTimeZone(); if (null != endTimeZone && StringUtils.isNotBlank(endTimeZone.getId())) { xprops.add(new ExchangeEndTimeZoneProperty(endTimeZone.getId())); } else { log.debug("unable to generate ExchangeEndTimeZoneProperty, endTimeZone is blank"); } return xprops; } /** * Return a never null but possibly empty {@link Collection} of {@link XProperty} * * Returned {@link XProperty}s may include: * {@link ItemTypeParentFolderId}, * * @param item * @return */ private Collection<XProperty> generateItemTypeXProperties(ItemType item) { Collection<XProperty> xprops = new LinkedHashSet<XProperty>(); FolderIdType parentFolderId = item.getParentFolderId(); if (null != parentFolderId) { String p_id = parentFolderId.getId(); String p_ck = parentFolderId.getChangeKey(); if (StringUtils.isNotBlank(p_id)) { xprops.add(new ItemTypeParentFolderId(parentFolderId)); } else { log.warn("unable to generate X_EWS_PARENT_FOLDER_ID, parentFolderId is blank"); } if (StringUtils.isNotBlank(p_ck)) { xprops.add(new ItemTypeParentFolderChangeKey(parentFolderId)); } else { log.warn("unable to generate X_EWS_PARENT_FOLDER_CHANGEKEY, parentFolderChangeKey is blank"); } } ItemIdType itemId = item.getItemId(); if (null != itemId) { String i_id = itemId.getId(); String i_ck = itemId.getChangeKey(); if (StringUtils.isNotBlank(i_id)) { xprops.add(new ItemTypeItemId(itemId)); } else { log.warn("unable to generate X_EWS_ITEM_ID, itemId is blank"); } if (StringUtils.isNotBlank(i_ck)) { xprops.add(new ItemTypeChangeKey(itemId)); } else { log.warn("unable to generate X_EWS_ITEM_CHANGEKEY, itemChangeKey is blank"); } } if (item instanceof CalendarItemType) { CalendarItemType calendarItem = (CalendarItemType) item; Collection<XProperty> calendarXProps = generateCalendarItemTypeXProperties(calendarItem); if (!CollectionUtils.isEmpty(calendarXProps)) { xprops.addAll(calendarXProps); } } else { log.warn("item is not a CalendarItemType, X_EWS...TIMEZONE properties will not be generated."); } return xprops; } /** * return a never null but possibly empty {@link Collection} of {@link XProperty} * * if an {@link ExtendedPropertyType} contains multiple values this method will return multiple {@link XProperty}'s. * * @param extendedProperty * @return */ private Collection<XProperty> convertExtendedPropertyType(ExtendedPropertyType extendedProperty) { Collection<XProperty> xprops = new LinkedHashSet<XProperty>(); PathToExtendedFieldType extendedFieldURI = extendedProperty.getExtendedFieldURI(); if (null != extendedFieldURI) { String propertyName = extendedFieldURI.getPropertyName(); if (StringUtils.isBlank(propertyName)) { DistinguishedPropertySetType distinguishedPropertySetId = extendedFieldURI .getDistinguishedPropertySetId(); if (null != distinguishedPropertySetId) { propertyName = distinguishedPropertySetId.value(); } } ParameterList params = new ParameterList(); String exPropSetId = extendedFieldURI.getPropertySetId(); if (StringUtils.isNotBlank(exPropSetId)) { params.add(new PathToExtendedFieldTypePropertySetId(extendedFieldURI)); } Integer exPropId = extendedFieldURI.getPropertyId(); if (StringUtils.isNotBlank(exPropId.toString())) { params.add(new PathToExtendedFieldTypePropertyId(extendedFieldURI)); } MapiPropertyTypeType propertyType = extendedFieldURI.getPropertyType(); if (null != propertyType && StringUtils.isNotBlank(propertyType.value())) { params.add(new PathToExtendedFieldTypePropertyType(extendedFieldURI)); } String propertyTag = extendedFieldURI.getPropertyTag(); if (StringUtils.isNotBlank(propertyTag)) { params.add(new PathToExtendedFieldTypePropertyTag(extendedFieldURI)); } Set<String> xPropertyValues = new HashSet<String>(); if (StringUtils.isNotBlank(propertyName)) { NonEmptyArrayOfPropertyValuesType values = extendedProperty.getValues(); if (null != values && !CollectionUtils.isEmpty(values.getValues())) { xPropertyValues.addAll(values.getValues()); } else if (null != extendedProperty.getValue()) { xPropertyValues.add(extendedProperty.getValue()); } } else { log.error("Unable to generate XProperty(s). propertyName not found for ExtendedPropertyType=" + extendedProperty); } if (!CollectionUtils.isEmpty(xPropertyValues)) { Integer count = 0; for (String xValue : xPropertyValues) { xprops.add(new XProperty(propertyName, params, xValue)); propertyName += "_" + count; count++; } } else { log.error("Unable to generate XProperty(s). propertyValue(s) not found for ExtendedPropertyType=" + extendedProperty); } } return xprops; } /** * Convert the {@link String} argument to a mailto {@link URI} if possible. * * @param emailAddress * @return the email as a URI * @throws IllegalArgumentException * if conversion failed, or if the argument was empty * * <strong>WARNING</strong >A {@link CalendarItemType} may contain attendees that no longer have a valid email address. * If an event contains an attendee that has been deleted, the email address field takes the value of <legacyDn> example: <t:EmailAddress>/O=EXCHANGELABS/OU=EXCHANGE ADMINISTRATIVE GROUP (FYDIBOHF23SPDLT)/CN=RECIPIENTS/CN=F450764bd9384fd3b7a38722504c8815-Documentati</t:EmailAddress> */ public URI emailToURI(final String emailAddress) { Validate.notEmpty(emailAddress, "emailAddress cannot be null"); URI uri = null; try { uri = new URI("mailto:" + emailAddress); } catch (URISyntaxException e) { log.debug("caught URISyntaxException trying to construct mailto URI for " + emailAddress + "\n" + e.getMessage()); } return uri; } /** * This method will return a never null a {@link Pair}<{@link ParameterList},{@link URI}> for a given {@link EmailAddressType} * This method will return a null URI element if the {@link EmailAddressType} does not contain a valid EmailAddress property * This method will return a never null but possibly empty {@link ParameterList}. * * ParamaterList may contain the following {@link Parameter}s: * {@link Cn}, {@link EmailAddressRoutingType}, {@link EmailAddressMailboxType} * * @param recipient * @return */ protected Pair<ParameterList, URI> convertEmailAddressType(EmailAddressType emailAddressType, Role role) { URI uri = null; ParameterList params = new ParameterList(); if (null != emailAddressType) { String emailAddress = emailAddressType.getEmailAddress(); if (StringUtils.isNotBlank(emailAddress)) { uri = emailToURI(emailAddress); } else { log.warn("convertEmailAddressType: could not generate URI."); } if (null != role) { params.add(role); } String name = emailAddressType.getName(); if (StringUtils.isNotBlank(name)) { params.add(new Cn(name)); } else { log.debug("convertEmailAddressType: could not generate Cn"); } String routingType = emailAddressType.getRoutingType(); if (StringUtils.isNotBlank(routingType)) { params.add(new EmailAddressRoutingType(routingType)); } else { log.debug("convertEmailAddressType: could not generate EmailAddressRoutingType"); } MailboxTypeType mailboxType = emailAddressType.getMailboxType(); if (null != mailboxType) { params.add(new EmailAddressMailboxType(mailboxType)); CuType cuType = convertMailboxTypeTypeToCuType(mailboxType, role); params.add(cuType); } else { log.debug("convertEmailAddressType: could not generate EmailAddressMailboxType"); } } else { log.debug("convertEmailAddressType: EmailAddressType = null"); } Pair<ParameterList, URI> pair = Pair.of(params, uri); return pair; } /** * This method will attempt to generate a {@link Organizer} from a {@link SingleRecipientType} * * * This method will add {@link PartStat.ACCEPTED} and {@link net.fortuna.ical4j.model.parameter.Role.CHAIR} when an organizer is found. * {@link com.microsoft.exchange.impl.ExchangeEventConverterImpl.convertEmailAddressType(EmailAddressType)} for a list of other paramaters that may be included in the response * * This method will return null if the {@link SingleRecipientType} EmailAddress field is missing or invalid. * * @param calendarItemOrganizer * @return */ public Organizer convertToOrganizer(SingleRecipientType calendarItemOrganizer) { Organizer organizer = null; if (null != calendarItemOrganizer) { Pair<ParameterList, URI> pair = convertEmailAddressType(calendarItemOrganizer.getMailbox(), Role.CHAIR); URI organizerURI = pair.getRight(); ParameterList organizerParams = pair.getLeft(); if (null != organizerURI) { organizer = new Organizer(organizerParams, organizerURI); //organizer is always ACCEPTED organizer.getParameters().add(PartStat.ACCEPTED); } else { log.debug("convertToOrganizer: organizerURI = null, Organizer = null "); } } else { log.debug("convertToOrganizer: calendarItemOrganizer = null, Organizer = null "); } return organizer; } /** * This method returns a never null but possibly empty {@link HashSet} of {@link Attendee}s. * This method will attempt to generate a {@link Attendee} for each {@link AttendeeType} contained within @link {@link NonEmptyArrayOfAttendeesType}. * An a {@link Attendee} will not be generated for any {@link AttendeeType} with a missing or invalid {@link EmailAddressType} * * Attendee Responses are only present if you obtained CalendarItem from Exchange as organizer. @see <a href="http://office.microsoft.com/en-us/outlook-help/organize-meetings-with-outlook-RZ001166003.aspx?section=20">Attendees do not see responses</a> * * {@link com.microsoft.exchange.impl.ExchangeEventConverterImpl.convertEmailAddressType(EmailAddressType)} for details on how recipient EmailAddressType properties are mapped to {@link Parameter}s. * * @param attendees * @param myResponseType - a {@link PartStat} parameter will be added to every {@link Attendee} if and only if myResponseType.eqals( {@link ResponseTypeType}.ORGANIZER and the corresponding {@link AttendeeType} contains a valid {@link ResponseTypeType} ) * @param requiredAttendees - Indicates which {@link Role} parameter to add to attendees. True indicates that the {@link NonEmptyArrayOfAttendeesType} represent Role.REQ_PARTICIPANT, false indicates the {@link NonEmptyArrayOfAttendeesType} are optional attendees * @return */ protected Set<Attendee> convertAttendees(NonEmptyArrayOfAttendeesType attendees, ResponseTypeType myResponseType, Role role) { Set<Attendee> attendeeSet = new HashSet<Attendee>(); if (null != attendees && !CollectionUtils.isEmpty(attendees.getAttendees())) { for (AttendeeType attendeeType : attendees.getAttendees()) { if (null != attendeeType) { EmailAddressType mailbox = attendeeType.getMailbox(); Pair<ParameterList, URI> attendeePair = convertEmailAddressType(mailbox, role); URI attendeeURI = attendeePair.getRight(); ParameterList attendeeParams = attendeePair.getLeft(); if (null != attendeeURI) { Attendee attendee = new Attendee(attendeeParams, attendeeURI); if (null != myResponseType && myResponseType.equals(ResponseTypeType.ORGANIZER)) { //responseType should be present ResponseTypeType responseType = attendeeType.getResponseType(); if (null != responseType) { //go ahead and add a partstat attendee.getParameters().add(convertResponseTypeTypeToPartStat(responseType)); } } if (attendeeSet.add(attendee)) { log.debug("added Attendee=" + attendee); } } } } } else { log.debug("no attendees"); } return attendeeSet; } public Set<Attendee> convertRequiredAttendees(NonEmptyArrayOfAttendeesType attendees, ResponseTypeType myResponseType) { return convertAttendees(attendees, myResponseType, Role.REQ_PARTICIPANT); } public Set<Attendee> convertOptionalAttendees(NonEmptyArrayOfAttendeesType attendees, ResponseTypeType myResponseType) { return convertAttendees(attendees, myResponseType, Role.OPT_PARTICIPANT); } public Set<Attendee> convertResourceAttendees(NonEmptyArrayOfAttendeesType attendees, ResponseTypeType myResponseType) { return convertAttendees(attendees, myResponseType, Role.NON_PARTICIPANT); } /** * Returns a never null {@link PartStat} for a given {@link ResponseTypeType} * * ResponseTypeType.ORGANIZER => PartStat.ACCEPTED * ResponseTypeType.ACCEPT => PartStat.ACCEPTED * ResponseTypeType.DECLINE => PartStat.DECLINED * ResponseTypeType.TENTATIVE => PartStat.TENTATIVE * All other ResponseTypeTypes => PartStat.NEEDS_ACTION * * @param responseType * @return */ public static PartStat convertResponseTypeTypeToPartStat(ResponseTypeType responseType) { if (null != responseType) { if (responseType.equals(ResponseTypeType.ACCEPT) || responseType.equals(ResponseTypeType.ORGANIZER)) { return PartStat.ACCEPTED; } else if (responseType.equals(ResponseTypeType.DECLINE)) { return PartStat.DECLINED; } else if (responseType.equals(ResponseTypeType.TENTATIVE)) { return PartStat.TENTATIVE; } } return PartStat.NEEDS_ACTION; } /** * Returns a never null {@link ResponseTypeType} for a given {@link PartStat} * * PartStat.ACCEPTED => ResponseTypeType.ACCEPT * PartStat.DECLINED => ResponseTypeType.DECLINE * PartStat.TENTATIVE => ResponseTypeType.TENTATIVE * PartStat.NEEDS_ACTION => ResponseTypeType.NO_RESPONSE_RECEIVED * All other PartStats => ResponseTypeType.UNKNOWN * * @param partStat * @return */ public static ResponseTypeType convertPartStatToResponseTypeType(PartStat partStat) { if (null != partStat) { if (partStat.equals(PartStat.ACCEPTED)) { return ResponseTypeType.ACCEPT; } else if (partStat.equals(PartStat.DECLINED)) { return ResponseTypeType.DECLINE; } else if (partStat.equals(PartStat.TENTATIVE)) { return ResponseTypeType.TENTATIVE; } else if (partStat.equals(PartStat.NEEDS_ACTION)) { return ResponseTypeType.NO_RESPONSE_RECEIVED; } } return ResponseTypeType.UNKNOWN; } /** * Return a never null {@link Clazz} for a given {@link SensitivityChoicesType} * * @see <a href="http://windowsitpro.com/outlook/outlook-using-sensitivity-levels-appointments">Using Sensitivity Levels with Appointments</a> * * SensitivityChoicesType.CONFIDENTIAL => Clazz.CONFIDENTIAL * SensitivityChoicesType.NORMAL => Clazz.PUBLIC * All other SensitivityChoicesType => Clazz.PRIVATE * * @param sensitivity * @return */ public static Clazz convertSensitivityToClazz(SensitivityChoicesType sensitivity) { Clazz clazz = Clazz.PRIVATE; if (null != sensitivity) { if (sensitivity.equals(SensitivityChoicesType.CONFIDENTIAL)) { clazz = Clazz.CONFIDENTIAL; } else if (sensitivity.equals(SensitivityChoicesType.NORMAL)) { clazz = Clazz.PUBLIC; } } return clazz; } /** * Return a never null {@link SensitivityChoicesType} for a given {@link Clazz} * * Clazz.CONFIDENTIAL => SensitivityChoicesType.CONFIDENTIAL * Clazz.PUBLIC => SensitivityChoicesType.NORMAL * All other Clazz => SensitivityChoicesType.PRIVATE * * @param clazz * @return */ public static SensitivityChoicesType convertClazzToSensitivityChoicesType(Clazz clazz) { SensitivityChoicesType sensitivity = SensitivityChoicesType.PRIVATE; if (null != clazz) { if (clazz.equals(Clazz.CONFIDENTIAL)) { sensitivity = SensitivityChoicesType.CONFIDENTIAL; } else if (clazz.equals(Clazz.PUBLIC)) { sensitivity = SensitivityChoicesType.NORMAL; } } return sensitivity; } /** * Returns a never null {@link Priority} for a given {@link ImportanceChoicesType} * * Defaults to Priority.MEDIUM; * * @param importance * @return */ public static Priority convertImportanceChoicesTypeToPriority(ImportanceChoicesType importance) { Priority priority = Priority.MEDIUM; if (null != importance) { if (importance.equals(ImportanceChoicesType.HIGH)) { priority = Priority.HIGH; } else if (importance.equals(ImportanceChoicesType.LOW)) priority = Priority.LOW; } return priority; } /** * Returns a never null {@link ImportanceChoicesType} for a given {@link Priority} * * Defaults to ImportanceChoicesType.NORMAL * * Priority (HIGH => 1, NORMAL => 5, LOW => 9) * * @param priority * @return */ public static ImportanceChoicesType convertPriorityToImportanceChoicesType(Priority priority) { ImportanceChoicesType importance = ImportanceChoicesType.NORMAL; if (null != priority) { if (priority.equals(Priority.HIGH)) { importance = ImportanceChoicesType.HIGH; } else if (priority.equals(Priority.LOW)) { importance = ImportanceChoicesType.LOW; } } return importance; } /** * Return a never null {@link CuType} for a given {@link MailboxTypeType} * * Defaults to CuType.INDIVIDUAL * * @see <a href="http://www.kanzaki.com/docs/ical/cutype.html">Calendar User Type</a> * @see <a href="http://msdn.microsoft.com/en-us/library/office/aa563493(v=exchg.140).aspx">MailboxType</a> * * @param mailboxType * @return */ public static CuType convertMailboxTypeTypeToCuType(MailboxTypeType mailboxType, Role role) { //If not specified on a property that allows this parameter, the default is INDIVIDUAL. CuType cuType = CuType.INDIVIDUAL; if (null != mailboxType) { if (MailboxTypeType.PRIVATE_DL.equals(mailboxType) || MailboxTypeType.PUBLIC_DL.equals(mailboxType)) { cuType = CuType.GROUP; } //TODO this is bad hack if (Role.NON_PARTICIPANT.equals(role)) { cuType = CuType.RESOURCE; } } return cuType; } /** * Returns a never null but possibly empty TextList * * @param strings * @return */ public static TextList convertArrayOfStringsTypeToTextList(ArrayOfStringsType strings) { TextList textList = new TextList(); if (strings != null) { List<String> stringList = strings.getStrings(); if (!CollectionUtils.isEmpty(stringList)) { for (String s : stringList) { textList.add(s); } } } return textList; } /** * Returns a never null {@link Categories} containing one entry for each entry string contained in {@link ArrayOfStringsType} * * @param categories * @return */ public static Categories convertCategories(ArrayOfStringsType arrayOfCategories) { TextList textList = convertArrayOfStringsTypeToTextList(arrayOfCategories); return new Categories(textList); } }