microsoft.exchange.webservices.data.property.complex.AttachmentCollection Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ews-java-api Show documentation
Show all versions of ews-java-api Show documentation
Exchange Web Services (EWS) Java API
/*
* The MIT License
* Copyright (c) 2012 Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package microsoft.exchange.webservices.data.property.complex;
import microsoft.exchange.webservices.data.attribute.EditorBrowsable;
import microsoft.exchange.webservices.data.core.EwsUtilities;
import microsoft.exchange.webservices.data.core.XmlElementNames;
import microsoft.exchange.webservices.data.core.response.CreateAttachmentResponse;
import microsoft.exchange.webservices.data.core.response.DeleteAttachmentResponse;
import microsoft.exchange.webservices.data.core.response.ServiceResponseCollection;
import microsoft.exchange.webservices.data.core.service.ServiceObject;
import microsoft.exchange.webservices.data.core.service.item.Item;
import microsoft.exchange.webservices.data.core.enumeration.attribute.EditorBrowsableState;
import microsoft.exchange.webservices.data.core.enumeration.misc.ExchangeVersion;
import microsoft.exchange.webservices.data.core.enumeration.service.ServiceResult;
import microsoft.exchange.webservices.data.core.exception.service.remote.CreateAttachmentException;
import microsoft.exchange.webservices.data.core.exception.service.remote.DeleteAttachmentException;
import microsoft.exchange.webservices.data.core.exception.misc.InvalidOperationException;
import microsoft.exchange.webservices.data.core.exception.service.local.ServiceLocalException;
import microsoft.exchange.webservices.data.core.exception.service.local.ServiceValidationException;
import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
/**
* Represents an item's attachment collection.
*/
@EditorBrowsable(state = EditorBrowsableState.Never)
public final class AttachmentCollection extends ComplexPropertyCollection
implements IOwnedProperty {
// The item owner that owns this attachment collection
/**
* The owner.
*/
private Item owner;
/**
* Initializes a new instance of AttachmentCollection.
*/
public AttachmentCollection() {
super();
}
/**
* The owner of this attachment collection.
*
* @return the owner
*/
public ServiceObject getOwner() {
return this.owner;
}
/**
* The owner of this attachment collection.
*
* @param value accepts ServiceObject
*/
public void setOwner(ServiceObject value) {
Item item = (Item) value;
EwsUtilities.ewsAssert(item != null, "AttachmentCollection.IOwnedProperty.set_Owner",
"value is not a descendant of ItemBase");
this.owner = item;
}
/**
* Adds a file attachment to the collection.
*
* @param fileName the file name
* @return A FileAttachment instance.
*/
public FileAttachment addFileAttachment(String fileName) {
return this.addFileAttachment(new File(fileName).getName(), fileName);
}
/**
* Adds a file attachment to the collection.
*
* @param name accepts String display name of the new attachment.
* @param fileName accepts String name of the file representing the content of
* the attachment.
* @return A FileAttachment instance.
*/
public FileAttachment addFileAttachment(String name, String fileName) {
FileAttachment fileAttachment = new FileAttachment(this.owner);
fileAttachment.setName(name);
fileAttachment.setFileName(fileName);
this.internalAdd(fileAttachment);
return fileAttachment;
}
/**
* Adds a file attachment to the collection.
*
* @param name accepts String display name of the new attachment.
* @param contentStream accepts InputStream stream from which to read the content of
* the attachment.
* @return A FileAttachment instance.
*/
public FileAttachment addFileAttachment(String name,
InputStream contentStream) {
FileAttachment fileAttachment = new FileAttachment(this.owner);
fileAttachment.setName(name);
fileAttachment.setContentStream(contentStream);
this.internalAdd(fileAttachment);
return fileAttachment;
}
/**
* Adds a file attachment to the collection.
*
* @param name the name
* @param content accepts byte byte arrays representing the content of the
* attachment.
* @return FileAttachment
*/
public FileAttachment addFileAttachment(String name, byte[] content) {
FileAttachment fileAttachment = new FileAttachment(this.owner);
fileAttachment.setName(name);
fileAttachment.setContent(content);
this.internalAdd(fileAttachment);
return fileAttachment;
}
/**
* Adds an item attachment to the collection.
*
* @param the generic type
* @param cls the cls
* @return An ItemAttachment instance.
* @throws Exception the exception
*/
public GenericItemAttachment addItemAttachment(
Class cls) throws Exception {
if (cls.getDeclaredFields().length == 0) {
throw new InvalidOperationException(String.format(
"Items of type %s are not supported as attachments.", cls
.getName()));
}
GenericItemAttachment itemAttachment =
new GenericItemAttachment(
this.owner);
itemAttachment.setTItem((TItem) EwsUtilities.createItemFromItemClass(
itemAttachment, cls, true));
this.internalAdd(itemAttachment);
return itemAttachment;
}
/**
* Removes all attachments from this collection.
*/
public void clear() {
this.internalClear();
}
/**
* Removes the attachment at the specified index.
*
* @param index Index of the attachment to remove.
*/
public void removeAt(int index) {
if (index < 0 || index >= this.getCount()) {
throw new IllegalArgumentException("parameter \'index\' : " + "index is out of range.");
}
this.internalRemoveAt(index);
}
/**
* Removes the specified attachment.
*
* @param attachment The attachment to remove.
* @return True if the attachment was successfully removed from the
* collection, false otherwise.
* @throws Exception the exception
*/
public boolean remove(Attachment attachment) throws Exception {
EwsUtilities.validateParam(attachment, "attachment");
return this.internalRemove(attachment);
}
/**
* Instantiate the appropriate attachment type depending on the current XML
* element name.
*
* @param xmlElementName The XML element name from which to determine the type of
* attachment to create.
* @return An Attachment instance.
*/
@Override
protected Attachment createComplexProperty(String xmlElementName) {
if (xmlElementName.equals(XmlElementNames.FileAttachment)) {
return new FileAttachment(this.owner);
} else if (xmlElementName.equals(XmlElementNames.ItemAttachment)) {
return new ItemAttachment(this.owner);
} else {
return null;
}
}
/**
* Determines the name of the XML element associated with the
* complexProperty parameter.
*
* @param complexProperty The attachment object for which to determine the XML element
* name with.
* @return The XML element name associated with the complexProperty
* parameter.
*/
@Override
protected String getCollectionItemXmlElementName(Attachment
complexProperty) {
if (complexProperty instanceof FileAttachment) {
return XmlElementNames.FileAttachment;
} else {
return XmlElementNames.ItemAttachment;
}
}
/**
* Saves this collection by creating new attachment and deleting removed
* ones.
*
* @throws Exception the exception
*/
public void save() throws Exception {
ArrayList attachments =
new ArrayList();
for (Attachment attachment : this.getRemovedItems()) {
if (!attachment.isNew()) {
attachments.add(attachment);
}
}
// If any, delete them by calling the DeleteAttachment web method.
if (attachments.size() > 0) {
this.internalDeleteAttachments(attachments);
}
attachments.clear();
// Retrieve a list of attachments that have to be created.
for (Attachment attachment : this) {
if (attachment.isNew()) {
attachments.add(attachment);
}
}
// If there are any, create them by calling the CreateAttachment web
// method.
if (attachments.size() > 0) {
if (this.owner.isAttachment()) {
this.internalCreateAttachments(this.owner.getParentAttachment()
.getId(), attachments);
} else {
this.internalCreateAttachments(
this.owner.getId().getUniqueId(), attachments);
}
}
// Process all of the item attachments in this collection.
for (Attachment attachment : this) {
ItemAttachment itemAttachment = (ItemAttachment)
((attachment instanceof
ItemAttachment) ? attachment :
null);
if (itemAttachment != null) {
// Bug E14:80864: Make sure item was created/loaded before
// trying to create/delete sub-attachments
if (itemAttachment.getItem() != null) {
// Create/delete any sub-attachments
itemAttachment.getItem().getAttachments().save();
// Clear the item's change log
itemAttachment.getItem().clearChangeLog();
}
}
}
super.clearChangeLog();
}
/**
* Determines whether there are any unsaved attachment collection changes.
*
* @return True if attachment adds or deletes haven't been processed yet.
* @throws ServiceLocalException
*/
public boolean hasUnprocessedChanges() throws ServiceLocalException {
// Any new attachments?
for (Attachment attachment : this) {
if (attachment.isNew()) {
return true;
}
}
// Any pending deletions?
for (Attachment attachment : this.getRemovedItems()) {
if (!attachment.isNew()) {
return true;
}
}
Collection itemAttachments =
new ArrayList();
for (Object event : this.getItems()) {
if (event instanceof ItemAttachment) {
itemAttachments.add((ItemAttachment) event);
}
}
// Recurse: process item attachments to check
// for new or deleted sub-attachments.
for (ItemAttachment itemAttachment : itemAttachments) {
if (itemAttachment.getItem() != null) {
if (itemAttachment.getItem().getAttachments().hasUnprocessedChanges()) {
return true;
}
}
}
return false;
}
/**
* Disables the change log clearing mechanism. Attachment collections are
* saved separately from the item they belong to.
*/
@Override public void clearChangeLog() {
// Do nothing
}
/**
* Validates this instance.
*
* @throws Exception the exception
*/
public void validate() throws Exception {
// Validate all added attachments
if (this.owner.isNew()
&& this.owner.getService().getRequestedServerVersion()
.ordinal() >= ExchangeVersion.Exchange2010_SP2
.ordinal()) {
boolean contactPhotoFound = false;
for (int attachmentIndex = 0; attachmentIndex < this.getAddedItems()
.size(); attachmentIndex++) {
final Attachment attachment = this.getAddedItems().get(attachmentIndex);
if (attachment != null) {
if (attachment.isNew() && attachment instanceof FileAttachment) {
// At the server side, only the last attachment with
// IsContactPhoto is kept, all other IsContactPhoto
// attachments are removed. CreateAttachment will generate
// AttachmentId for each of such attachments (although
// only the last one is valid).
//
// With E14 SP2 CreateItemWithAttachment, such request will only
// return 1 AttachmentId; but the client
// expects to see all, so let us prevent such "invalid" request
// in the first place.
//
// The IsNew check is to still let CreateAttachmentRequest allow
// multiple IsContactPhoto attachments.
//
if (((FileAttachment) attachment).isContactPhoto()) {
if (contactPhotoFound) {
throw new ServiceValidationException("Multiple contact photos in attachment.");
}
contactPhotoFound = true;
}
}
attachment.validate(attachmentIndex);
}
}
}
}
/**
* Calls the DeleteAttachment web method to delete a list of attachments.
*
* @param attachments the attachments
* @throws Exception the exception
*/
private void internalDeleteAttachments(Iterable attachments)
throws Exception {
ServiceResponseCollection responses =
this.owner
.getService().deleteAttachments(attachments);
Enumeration enumerator = responses
.getEnumerator();
while (enumerator.hasMoreElements()) {
DeleteAttachmentResponse response = enumerator.nextElement();
// We remove all attachments that were successfully deleted from the
// change log. We should never
// receive a warning from EWS, so we ignore them.
if (response.getResult() != ServiceResult.Error) {
this.removeFromChangeLog(response.getAttachment());
}
}
// TODO : Should we throw for warnings as well?
if (responses.getOverallResult() == ServiceResult.Error) {
throw new DeleteAttachmentException(responses, "At least one attachment couldn't be deleted.");
}
}
/**
* Calls the CreateAttachment web method to create a list of attachments.
*
* @param parentItemId the parent item id
* @param attachments the attachments
* @throws Exception the exception
*/
private void internalCreateAttachments(String parentItemId,
Iterable attachments) throws Exception {
ServiceResponseCollection responses =
this.owner
.getService().createAttachments(parentItemId, attachments);
Enumeration enumerator = responses
.getEnumerator();
while (enumerator.hasMoreElements()) {
CreateAttachmentResponse response = enumerator.nextElement();
// We remove all attachments that were successfully created from the
// change log. We should never
// receive a warning from EWS, so we ignore them.
if (response.getResult() != ServiceResult.Error) {
this.removeFromChangeLog(response.getAttachment());
}
}
// TODO : Should we throw for warnings as well?
if (responses.getOverallResult() == ServiceResult.Error) {
throw new CreateAttachmentException(responses, "At least one attachment couldn't be created.");
}
}
}