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.EwsServiceXmlReader;
027    import microsoft.exchange.webservices.data.core.EwsServiceXmlWriter;
028    import microsoft.exchange.webservices.data.core.EwsUtilities;
029    import microsoft.exchange.webservices.data.core.XmlAttributeNames;
030    import microsoft.exchange.webservices.data.core.XmlElementNames;
031    import microsoft.exchange.webservices.data.core.exception.service.local.ServiceValidationException;
032    import microsoft.exchange.webservices.data.core.service.item.Item;
033    import microsoft.exchange.webservices.data.core.enumeration.property.BodyType;
034    import microsoft.exchange.webservices.data.core.enumeration.misc.ExchangeVersion;
035    import microsoft.exchange.webservices.data.core.enumeration.misc.XmlNamespace;
036    import microsoft.exchange.webservices.data.core.exception.service.local.ServiceVersionException;
037    import microsoft.exchange.webservices.data.property.definition.PropertyDefinitionBase;
038    import org.apache.commons.logging.Log;
039    import org.apache.commons.logging.LogFactory;
040    
041    import java.util.Date;
042    
043    /**
044     * Represents an attachment to an item.
045     */
046    public 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    }