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
024 package microsoft.exchange.webservices.data.property.complex;
025
026 import microsoft.exchange.webservices.data.core.EwsServiceXmlWriter;
027 import microsoft.exchange.webservices.data.core.EwsUtilities;
028 import microsoft.exchange.webservices.data.core.ICustomXmlUpdateSerializer;
029 import microsoft.exchange.webservices.data.core.XmlElementNames;
030 import microsoft.exchange.webservices.data.core.service.ServiceObject;
031 import microsoft.exchange.webservices.data.core.service.item.Contact;
032 import microsoft.exchange.webservices.data.core.service.schema.ContactGroupSchema;
033 import microsoft.exchange.webservices.data.core.enumeration.property.EmailAddressKey;
034 import microsoft.exchange.webservices.data.core.enumeration.property.MailboxType;
035 import microsoft.exchange.webservices.data.core.enumeration.misc.XmlNamespace;
036 import microsoft.exchange.webservices.data.core.exception.service.local.ServiceLocalException;
037 import microsoft.exchange.webservices.data.core.exception.service.local.ServiceValidationException;
038 import microsoft.exchange.webservices.data.core.exception.service.local.ServiceXmlSerializationException;
039 import microsoft.exchange.webservices.data.property.definition.GroupMemberPropertyDefinition;
040 import microsoft.exchange.webservices.data.property.definition.PropertyDefinition;
041
042 import javax.xml.stream.XMLStreamException;
043
044 import java.util.Iterator;
045 import java.util.List;
046
047 /**
048 * Represents a collection of members of GroupMember type.
049 */
050 public 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 }