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.EwsServiceXmlReader;
027import microsoft.exchange.webservices.data.core.EwsServiceXmlWriter;
028import microsoft.exchange.webservices.data.core.EwsUtilities;
029import microsoft.exchange.webservices.data.core.XmlAttributeNames;
030import microsoft.exchange.webservices.data.core.XmlElementNames;
031import microsoft.exchange.webservices.data.core.exception.service.local.ServiceValidationException;
032import microsoft.exchange.webservices.data.core.service.item.Item;
033import microsoft.exchange.webservices.data.core.enumeration.property.BodyType;
034import microsoft.exchange.webservices.data.core.enumeration.misc.ExchangeVersion;
035import microsoft.exchange.webservices.data.core.enumeration.misc.XmlNamespace;
036import microsoft.exchange.webservices.data.core.exception.service.local.ServiceVersionException;
037import microsoft.exchange.webservices.data.property.definition.PropertyDefinitionBase;
038import org.apache.commons.logging.Log;
039import org.apache.commons.logging.LogFactory;
040
041import java.util.Date;
042
043/**
044 * Represents an attachment to an item.
045 */
046public abstract class Attachment extends ComplexProperty {
047
048  private static final Log LOG = LogFactory.getLog(Attachment.class);
049
050  /**
051   * The owner.
052   */
053  private Item owner;
054
055  /**
056   * The id.
057   */
058  private String id;
059
060  /**
061   * The name.
062   */
063  private String name;
064
065  /**
066   * The content type.
067   */
068  private String contentType;
069
070  /**
071   * The content id.
072   */
073  private String contentId;
074
075  /**
076   * The content location.
077   */
078  private String contentLocation;
079
080  /**
081   * The size.
082   */
083  private int size;
084
085  /**
086   * The last modified time.
087   */
088  private Date lastModifiedTime;
089
090  /**
091   * The is inline.
092   */
093  private boolean isInline;
094
095  /**
096   * Initializes a new instance.
097   *
098   * @param owner The owner.
099   */
100  protected Attachment(Item owner) {
101    this.owner = owner;
102  }
103
104  /**
105   * Throws exception if this is not a new service object.
106   */
107  protected void throwIfThisIsNotNew() {
108    if (!this.isNew()) {
109      throw new UnsupportedOperationException("Attachments can't be updated.");
110    }
111  }
112
113  /**
114   * Sets value of field.
115   * <p/>
116   * We override the base implementation. Attachments cannot be modified so
117   * any attempts the change a property on an existing attachment is an error.
118   *
119   * @param <T>   the generic type
120   * @param field The field
121   * @param value The value.
122   * @return true, if successful
123   */
124  public <T> boolean canSetFieldValue(T field, T value) {
125    this.throwIfThisIsNotNew();
126    return super.canSetFieldValue(field, value);
127  }
128
129  /**
130   * Gets the Id of the attachment.
131   *
132   * @return the id
133   */
134  public String getId() {
135    return this.id;
136  }
137
138  /**
139   * Gets the name of the attachment.
140   *
141   * @return the name
142   */
143  public String getName() {
144    return this.name;
145  }
146
147  /**
148   * Sets the name.
149   *
150   * @param value the new name
151   */
152  public void setName(String value) {
153    if (this.canSetFieldValue(this.name, value)) {
154      this.name = value;
155      this.changed();
156    }
157  }
158
159  /**
160   * Gets  the content type of the attachment.
161   *
162   * @return the content type
163   */
164  public String getContentType() {
165    return this.contentType;
166  }
167
168  /**
169   * Sets the content type.
170   *
171   * @param value the new content type
172   */
173  public void setContentType(String value) {
174    if (this.canSetFieldValue(this.contentType, value)) {
175      this.contentType = value;
176      this.changed();
177    }
178  }
179
180  /**
181   * Gets  the content Id of the attachment. ContentId can be used as a
182   * custom way to identify an attachment in order to reference it from within
183   * the body of the item the attachment belongs to.
184   *
185   * @return the content id
186   */
187  public String getContentId() {
188    return this.contentId;
189  }
190
191  /**
192   * Sets the content id.
193   *
194   * @param value the new content id
195   */
196  public void setContentId(String value) {
197    if (this.canSetFieldValue(this.contentId, value)) {
198      this.contentId = value;
199      this.changed();
200    }
201  }
202
203  /**
204   * Gets  the content location of the attachment. ContentLocation can
205   * be used to associate an attachment with a Url defining its location on
206   * the Web.
207   *
208   * @return the content location
209   */
210  public String getContentLocation() {
211    return this.contentLocation;
212  }
213
214  /**
215   * Sets the content location.
216   *
217   * @param value the new content location
218   */
219  public void setContentLocation(String value) {
220    if (this.canSetFieldValue(this.contentLocation, value)) {
221      this.contentLocation = value;
222      this.changed();
223    }
224  }
225
226  /**
227   * Gets the size of the attachment.
228   *
229   * @return the size
230   * @throws ServiceVersionException throws ServiceVersionException
231   */
232  public int getSize() throws ServiceVersionException {
233    EwsUtilities.validatePropertyVersion(this.getOwner().getService(), ExchangeVersion.Exchange2010, "Size");
234    return this.size;
235  }
236
237  /**
238   * Gets the date and time when this attachment was last modified.
239   *
240   * @return the last modified time
241   * @throws ServiceVersionException the service version exception
242   */
243  public Date getLastModifiedTime() throws ServiceVersionException {
244
245    EwsUtilities.validatePropertyVersion(this.getOwner().getService(),
246        ExchangeVersion.Exchange2010, "LastModifiedTime");
247
248    return this.lastModifiedTime;
249
250  }
251
252  /**
253   * Gets  a value indicating whether this is an inline attachment.
254   * Inline attachments are not visible to end users.
255   *
256   * @return the checks if is inline
257   * @throws ServiceVersionException the service version exception
258   */
259  public boolean getIsInline() throws ServiceVersionException {
260    EwsUtilities.validatePropertyVersion(this.getOwner().getService(),
261        ExchangeVersion.Exchange2010, "IsInline");
262    return this.isInline;
263
264  }
265
266  /**
267   * Sets the checks if is inline.
268   *
269   * @param value the new checks if is inline
270   * @throws ServiceVersionException the service version exception
271   */
272  public void setIsInline(boolean value) throws ServiceVersionException {
273    EwsUtilities.validatePropertyVersion(this.getOwner().getService(),
274        ExchangeVersion.Exchange2010, "IsInline");
275    if (this.canSetFieldValue(this.isInline, value)) {
276      this.isInline = value;
277      this.changed();
278    }
279  }
280
281  /**
282   * True if the attachment has not yet been saved, false otherwise.
283   *
284   * @return true, if is new
285   */
286  public boolean isNew() {
287    return (this.getId() == null || this.getId().isEmpty());
288  }
289
290  /**
291   * Gets the owner of the attachment.
292   *
293   * @return the owner
294   */
295  public Item getOwner() {
296    return this.owner;
297  }
298
299  /**
300   * Gets the name of the XML element.
301   *
302   * @return XML element name.
303   */
304  public abstract String getXmlElementName();
305
306  /**
307   * Tries to read element from XML.
308   *
309   * @param reader The reader.
310   * @return True if element was read.
311   * @throws Exception the exception
312   */
313  @Override
314  public boolean tryReadElementFromXml(EwsServiceXmlReader reader)
315      throws Exception {
316
317    try {
318      if (reader.getLocalName().equalsIgnoreCase(
319          XmlElementNames.AttachmentId)) {
320        try {
321          this.id = reader.readAttributeValue(XmlAttributeNames.Id);
322        } catch (Exception e) {
323          LOG.error(e);
324          return false;
325        }
326        if (this.getOwner() != null) {
327          String rootItemChangeKey = reader
328              .readAttributeValue(XmlAttributeNames.
329                  RootItemChangeKey);
330          if (null != rootItemChangeKey &&
331              !rootItemChangeKey.isEmpty()) {
332            this.getOwner().getRootItemId().setChangeKey(
333                rootItemChangeKey);
334          }
335        }
336        reader.readEndElementIfNecessary(XmlNamespace.Types,
337            XmlElementNames.AttachmentId);
338        return true;
339      } else if (reader.getLocalName().equalsIgnoreCase(
340          XmlElementNames.Name)) {
341        this.name = reader.readElementValue();
342        return true;
343      } else if (reader.getLocalName().equalsIgnoreCase(
344          XmlElementNames.ContentType)) {
345        this.contentType = reader.readElementValue();
346        return true;
347      } else if (reader.getLocalName().equalsIgnoreCase(
348          XmlElementNames.ContentId)) {
349        this.contentId = reader.readElementValue();
350        return true;
351      } else if (reader.getLocalName().equalsIgnoreCase(
352          XmlElementNames.ContentLocation)) {
353        this.contentLocation = reader.readElementValue();
354        return true;
355      } else if (reader.getLocalName().equalsIgnoreCase(
356          XmlElementNames.Size)) {
357        this.size = reader.readElementValue(Integer.class);
358        return true;
359      } else if (reader.getLocalName().equalsIgnoreCase(
360          XmlElementNames.LastModifiedTime)) {
361        this.lastModifiedTime = reader.readElementValueAsDateTime();
362        return true;
363      } else if (reader.getLocalName().equalsIgnoreCase(
364          XmlElementNames.IsInline)) {
365        this.isInline = reader.readElementValue(Boolean.class);
366        return true;
367      } else {
368        return false;
369      }
370    } catch (Exception e) {
371      LOG.error(e);
372      return false;
373    }
374  }
375
376  /**
377   * Writes elements to XML.
378   *
379   * @param writer the writer
380   * @throws Exception the exception
381   */
382  @Override
383  public void writeElementsToXml(EwsServiceXmlWriter writer)
384      throws Exception {
385    writer.writeElementValue(XmlNamespace.Types, XmlElementNames.Name, this
386        .getName());
387    writer.writeElementValue(XmlNamespace.Types,
388        XmlElementNames.ContentType, this.getContentType());
389    writer.writeElementValue(XmlNamespace.Types, XmlElementNames.ContentId,
390        this.getContentId());
391    writer.writeElementValue(XmlNamespace.Types,
392        XmlElementNames.ContentLocation, this.getContentLocation());
393    if (writer.getService().getRequestedServerVersion().ordinal() >
394        ExchangeVersion.Exchange2007_SP1
395            .ordinal()) {
396      writer.writeElementValue(XmlNamespace.Types,
397          XmlElementNames.IsInline, this.getIsInline());
398    }
399  }
400
401  /**
402   * Load the attachment.
403   *
404   * @param bodyType             Type of the body.
405   * @param additionalProperties The additional property.
406   * @throws Exception the exception
407   */
408  protected void internalLoad(BodyType bodyType,
409      Iterable<PropertyDefinitionBase> additionalProperties)
410      throws Exception {
411    this.getOwner().getService().getAttachment(this, bodyType,
412        additionalProperties);
413  }
414
415  /**
416   * Validates this instance.
417   *
418   * @param attachmentIndex Index of this attachment.
419   * @throws ServiceValidationException the service validation exception
420   * @throws Exception                  the exception
421   */
422  abstract void validate(int attachmentIndex) throws Exception;
423
424  /**
425   * Loads the attachment. Calling this method results in a call to EWS.
426   *
427   * @throws Exception the exception
428   */
429  public void load() throws Exception {
430    this.internalLoad(null, null);
431  }
432
433}