001/* 002 * The MIT License 003 * Copyright (c) 2012 Microsoft Corporation 004 * 005 * Permission is hereby granted, free of charge, to any person obtaining a copy 006 * of this software and associated documentation files (the "Software"), to deal 007 * in the Software without restriction, including without limitation the rights 008 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 009 * copies of the Software, and to permit persons to whom the Software is 010 * furnished to do so, subject to the following conditions: 011 * 012 * The above copyright notice and this permission notice shall be included in 013 * all copies or substantial portions of the Software. 014 * 015 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 016 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 017 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 018 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 019 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 020 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 021 * THE SOFTWARE. 022 */ 023 024package microsoft.exchange.webservices.data.property.complex; 025 026import microsoft.exchange.webservices.data.core.EwsServiceXmlWriter; 027import microsoft.exchange.webservices.data.core.EwsUtilities; 028import microsoft.exchange.webservices.data.core.ICustomXmlUpdateSerializer; 029import microsoft.exchange.webservices.data.core.XmlElementNames; 030import microsoft.exchange.webservices.data.core.service.ServiceObject; 031import microsoft.exchange.webservices.data.core.service.item.Contact; 032import microsoft.exchange.webservices.data.core.service.schema.ContactGroupSchema; 033import microsoft.exchange.webservices.data.core.enumeration.property.EmailAddressKey; 034import microsoft.exchange.webservices.data.core.enumeration.property.MailboxType; 035import microsoft.exchange.webservices.data.core.enumeration.misc.XmlNamespace; 036import microsoft.exchange.webservices.data.core.exception.service.local.ServiceLocalException; 037import microsoft.exchange.webservices.data.core.exception.service.local.ServiceValidationException; 038import microsoft.exchange.webservices.data.core.exception.service.local.ServiceXmlSerializationException; 039import microsoft.exchange.webservices.data.property.definition.GroupMemberPropertyDefinition; 040import microsoft.exchange.webservices.data.property.definition.PropertyDefinition; 041 042import javax.xml.stream.XMLStreamException; 043 044import java.util.Iterator; 045import java.util.List; 046 047/** 048 * Represents a collection of members of GroupMember type. 049 */ 050public final class GroupMemberCollection extends ComplexPropertyCollection<GroupMember> implements 051 ICustomXmlUpdateSerializer { 052 /** 053 * If the collection is cleared, then store PDL members collection is 054 * updated with "SetItemField". If the collection is not cleared, then store 055 * PDL members collection is updated with "AppendToItemField". 056 */ 057 private boolean collectionIsCleared = false; 058 059 /** 060 * Initializes a new instance. 061 */ 062 public GroupMemberCollection() { 063 super(); 064 } 065 066 /** 067 * Retrieves the XML element name corresponding to the provided 068 * GroupMember object. 069 * 070 * @param member the member 071 * @return The XML element name corresponding to the provided GroupMember 072 * object 073 */ 074 @Override 075 protected String getCollectionItemXmlElementName(GroupMember member) { 076 return XmlElementNames.Member; 077 } 078 079 /** 080 * * Finds the member with the specified key in the collection.Members that 081 * have not yet been saved do not have a key. 082 * 083 * @param key the key 084 * @return The member with the specified key 085 * @throws Exception the exception 086 */ 087 public GroupMember find(String key) throws Exception { 088 EwsUtilities.validateParam(key, "key"); 089 090 for (GroupMember item : this.getItems()) { 091 if (item.getKey().equals(key)) { 092 return item; 093 } 094 } 095 096 return null; 097 } 098 099 /** 100 * Clears the collection. 101 */ 102 public void clear() { 103 // mark the whole collection for deletion 104 this.internalClear(); 105 this.collectionIsCleared = true; 106 } 107 108 /** 109 * Adds a member to the collection. 110 * 111 * @param member the member 112 * @throws Exception the exception 113 */ 114 public void add(GroupMember member) throws Exception { 115 EwsUtilities.validateParam(member, "member"); 116 EwsUtilities.ewsAssert(member.getKey() == null, "GroupMemberCollection.Add", "member.Key is not null."); 117 EwsUtilities.ewsAssert(!this.contains(member), "GroupMemberCollection.Add", 118 "The member is already in the collection"); 119 120 this.internalAdd(member); 121 } 122 123 /** 124 * Adds multiple members to the collection. 125 * 126 * @param members the members 127 * @throws Exception the exception 128 */ 129 public void addRange(Iterator<GroupMember> members) throws Exception { 130 EwsUtilities.validateParam(members, "members"); 131 while (members.hasNext()) { 132 this.add(members.next()); 133 134 } 135 } 136 137 /** 138 * Adds a member linked to a Contact Group. 139 * 140 * @param contactGroupId the contact group id 141 * @throws Exception the exception 142 */ 143 public void addContactGroup(ItemId contactGroupId) throws Exception { 144 this.add(new GroupMember(contactGroupId)); 145 } 146 147 /** 148 * Adds a member linked to a specific contact?s e-mail address. 149 * 150 * @param contactId the contact id 151 * @param addressToLink the address to link 152 * @throws Exception the exception 153 */ 154 public void addPersonalContact(ItemId contactId, String addressToLink) 155 throws Exception { 156 this.add(new GroupMember(contactId, addressToLink)); 157 } 158 159 /** 160 * Adds a member linked to a contact?s first available e-mail address. 161 * 162 * @param contactId the contact id 163 * @throws Exception the exception 164 */ 165 public void addPersonalContact(ItemId contactId) throws Exception { 166 this.addPersonalContact(contactId, null); 167 } 168 169 /** 170 * Adds a member linked to an Active Directory user. 171 * 172 * @param smtpAddress the smtp address 173 * @throws ServiceLocalException the service local exception 174 * @throws Exception the exception 175 */ 176 public void addDirectoryUser(String smtpAddress) 177 throws ServiceLocalException, Exception { 178 this.addDirectoryUser(smtpAddress, new EmailAddress() 179 .getSmtpRoutingType()); 180 } 181 182 /** 183 * Adds a member linked to an Active Directory user. 184 * 185 * @param address the address 186 * @param routingType the routing type 187 * @throws ServiceLocalException the service local exception 188 * @throws Exception the exception 189 */ 190 public void addDirectoryUser(String address, String routingType) 191 throws ServiceLocalException, Exception { 192 this.add(new GroupMember(address, routingType, MailboxType.Mailbox)); 193 } 194 195 /** 196 * Adds a member linked to an Active Directory contact. 197 * 198 * @param smtpAddress the smtp address 199 * @throws ServiceLocalException the service local exception 200 * @throws Exception the exception 201 */ 202 public void addDirectoryContact(String smtpAddress) 203 throws ServiceLocalException, Exception { 204 this.addDirectoryContact(smtpAddress, new EmailAddress() 205 .getSmtpRoutingType()); 206 } 207 208 /** 209 * Adds a member linked to an Active Directory contact. 210 * 211 * @param address the address 212 * @param routingType the routing type 213 * @throws ServiceLocalException the service local exception 214 * @throws Exception the exception 215 */ 216 public void addDirectoryContact(String address, String routingType) 217 throws ServiceLocalException, Exception { 218 this.add(new GroupMember(address, routingType, MailboxType.Contact)); 219 } 220 221 /** 222 * Adds a member linked to a Public Group. 223 * 224 * @param smtpAddress the smtp address 225 * @throws ServiceLocalException the service local exception 226 * @throws Exception the exception 227 */ 228 public void addPublicGroup(String smtpAddress) 229 throws ServiceLocalException, Exception { 230 this.add(new GroupMember(smtpAddress, new EmailAddress() 231 .getSmtpRoutingType(), MailboxType.PublicGroup)); 232 } 233 234 /** 235 * Adds a member linked to a mail-enabled Public Folder. 236 * 237 * @param smtpAddress the smtp address 238 * @throws ServiceLocalException the service local exception 239 * @throws Exception the exception 240 */ 241 public void addDirectoryPublicFolder(String smtpAddress) 242 throws ServiceLocalException, Exception { 243 this.add(new GroupMember(smtpAddress, new EmailAddress() 244 .getSmtpRoutingType(), MailboxType.PublicFolder)); 245 } 246 247 /** 248 * Adds a one-off member. 249 * 250 * @param displayName the display name 251 * @param address the address 252 * @param routingType the routing type 253 * @throws Exception the exception 254 */ 255 public void addOneOff(String displayName, 256 String address, String routingType) 257 throws Exception { 258 this.add(new GroupMember(displayName, address, routingType)); 259 } 260 261 /** 262 * Adds a one-off member. 263 * 264 * @param displayName the display name 265 * @param smtpAddress the smtp address 266 * @throws Exception the exception 267 */ 268 public void addOneOff(String displayName, String smtpAddress) 269 throws Exception { 270 this.addOneOff(displayName, smtpAddress, new EmailAddress() 271 .getSmtpRoutingType()); 272 } 273 274 /** 275 * Adds a member that is linked to a specific e-mail address of a contact. 276 * 277 * @param contact the contact 278 * @param emailAddressKey the email address key 279 * @throws Exception the exception 280 */ 281 public void addContactEmailAddress(Contact contact, 282 EmailAddressKey emailAddressKey) throws Exception { 283 this.add(new GroupMember(contact, emailAddressKey)); 284 } 285 286 /** 287 * Removes a member at the specified index. 288 * 289 * @param index the index 290 */ 291 public void removeAt(int index) { 292 if (index < 0 || index >= this.getCount()) { 293 throw new IllegalArgumentException("index", new Throwable("index is out of range.")); 294 295 } 296 297 this.internalRemoveAt(index); 298 } 299 300 /** 301 * Removes a member from the collection. 302 * 303 * @param member the member 304 * @return True if the group member was successfully removed from the 305 * collection, false otherwise. 306 */ 307 public boolean remove(GroupMember member) { 308 return this.internalRemove(member); 309 } 310 311 /** 312 * Writes the update to XML. 313 * 314 * @param writer the writer 315 * @param ownerObject the owner object 316 * @param propertyDefinition the property definition 317 * @return True if property generated serialization. 318 * @throws Exception the exception 319 */ 320 public boolean writeSetUpdateToXml(EwsServiceXmlWriter writer, 321 ServiceObject ownerObject, PropertyDefinition propertyDefinition) 322 throws Exception { 323 if (this.collectionIsCleared) { 324 325 if (!this.getAddedItems().isEmpty()) { // not visible 326 327 // Delete the whole members collection 328 this.writeDeleteMembersCollectionToXml(writer); 329 } else { 330 // The collection is cleared, so Set 331 this.writeSetOrAppendMembersToXml(writer, this.getAddedItems(), 332 true); 333 } 334 } else { 335 // The collection is not cleared, i.e. dl.Members.Clear() is not 336 // called. 337 // Append AddedItems. 338 this.writeSetOrAppendMembersToXml(writer, this.getAddedItems(), 339 false); 340 341 // Since member replacement is not supported by server 342 // Delete old ModifiedItems, then recreate new instead. 343 this.writeDeleteMembersToXml(writer, this.getModifiedItems()); 344 this.writeSetOrAppendMembersToXml(writer, this.getModifiedItems(), 345 false); 346 347 // Delete RemovedItems. 348 this.writeDeleteMembersToXml(writer, this.getRemovedItems()); 349 } 350 351 return true; 352 } 353 354 /** 355 * Writes the deletion update to XML. 356 * 357 * @param writer the writer 358 * @param ewsObject the ews object 359 * @return True if property generated serialization. 360 */ 361 public boolean writeDeleteUpdateToXml(EwsServiceXmlWriter writer, 362 ServiceObject ewsObject) { 363 return false; 364 } 365 366 /** 367 * Creates a GroupMember object from an XML element name. 368 * 369 * @param xmlElementName the xml element name 370 * @return An GroupMember object 371 */ 372 protected GroupMember createComplexProperty(String xmlElementName) { 373 return new GroupMember(); 374 } 375 376 /** 377 * Clears the change log. 378 */ 379 public void clearChangeLog() { 380 super.clearChangeLog(); 381 this.collectionIsCleared = false; 382 } 383 384 /** 385 * Delete the whole members collection. 386 * 387 * @param writer the writer 388 * @throws XMLStreamException the XML stream exception 389 * @throws ServiceXmlSerializationException the service xml serialization exception 390 */ 391 private void writeDeleteMembersCollectionToXml(EwsServiceXmlWriter writer) 392 throws XMLStreamException, ServiceXmlSerializationException { 393 writer.writeStartElement(XmlNamespace.Types, 394 XmlElementNames.DeleteItemField); 395 ContactGroupSchema.Members.writeToXml(writer); 396 writer.writeEndElement(); 397 } 398 399 /** 400 * Generate XML to delete individual members. 401 * 402 * @param writer the writer 403 * @param members the members 404 * @throws XMLStreamException the XML stream exception 405 * @throws ServiceXmlSerializationException the service xml serialization exception 406 */ 407 private void writeDeleteMembersToXml(EwsServiceXmlWriter writer, 408 List<GroupMember> members) throws XMLStreamException, 409 ServiceXmlSerializationException { 410 if (!members.isEmpty()) { 411 GroupMemberPropertyDefinition memberPropDef = 412 new GroupMemberPropertyDefinition(); 413 414 for (GroupMember member : members) { 415 writer.writeStartElement(XmlNamespace.Types, 416 XmlElementNames.DeleteItemField); 417 418 memberPropDef.setKey(member.getKey()); 419 memberPropDef.writeToXml(writer); 420 421 writer.writeEndElement(); // DeleteItemField 422 } 423 } 424 } 425 426 /** 427 * Write set or append members to xml. 428 * 429 * @param writer the writer 430 * @param members the members 431 * @param setMode the set mode 432 * @throws Exception the exception 433 */ 434 private void writeSetOrAppendMembersToXml(EwsServiceXmlWriter writer, 435 List<GroupMember> members, boolean setMode) throws Exception { 436 if (!members.isEmpty()) { 437 writer.writeStartElement(XmlNamespace.Types, 438 setMode ? XmlElementNames.SetItemField 439 : XmlElementNames.AppendToItemField); 440 441 ContactGroupSchema.Members.writeToXml(writer); 442 443 writer.writeStartElement(XmlNamespace.Types, 444 XmlElementNames.DistributionList); 445 writer.writeStartElement(XmlNamespace.Types, 446 XmlElementNames.Members); 447 448 for (GroupMember member : members) { 449 member.writeToXml(writer, XmlElementNames.Member); 450 } 451 452 writer.writeEndElement(); // Members 453 writer.writeEndElement(); // Group 454 writer.writeEndElement(); // setMode ? SetItemField : 455 // AppendItemField 456 } 457 } 458 459 /** 460 * Validates this instance. 461 * 462 * @throws Exception 463 */ 464 @Override 465 protected void internalValidate() throws Exception { 466 super.internalValidate(); 467 468 for (GroupMember groupMember : this.getModifiedItems()) { 469 if (!(groupMember.getKey() == null || groupMember.getKey().isEmpty())) { 470 throw new ServiceValidationException("The contact group's Members property must be reloaded before " 471 + "newly-added members can be updated."); 472 } 473 } 474 } 475}