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.XmlElementNames;
030 import microsoft.exchange.webservices.data.core.service.item.Item;
031 import microsoft.exchange.webservices.data.core.enumeration.misc.ExchangeVersion;
032 import microsoft.exchange.webservices.data.core.enumeration.misc.XmlNamespace;
033 import microsoft.exchange.webservices.data.core.exception.service.local.ServiceValidationException;
034 import microsoft.exchange.webservices.data.core.exception.service.local.ServiceVersionException;
035
036 import java.io.File;
037 import java.io.FileInputStream;
038 import java.io.FileOutputStream;
039 import java.io.InputStream;
040 import java.io.OutputStream;
041
042 /**
043 * Represents a file attachment.
044 */
045 public final class FileAttachment extends Attachment {
046
047 /**
048 * The file name.
049 */
050 private String fileName;
051
052 /**
053 * The content stream.
054 */
055 private InputStream contentStream;
056
057 /**
058 * The content.
059 */
060 private byte[] content;
061
062 /**
063 * The load to stream.
064 */
065 private OutputStream loadToStream;
066
067 /**
068 * The is contact photo.
069 */
070 private boolean isContactPhoto;
071
072 /**
073 * Initializes a new instance.
074 *
075 * @param owner the owner
076 */
077 protected FileAttachment(Item owner) {
078 super(owner);
079 }
080
081 /**
082 * Gets the name of the XML element.
083 *
084 * @return XML element name
085 */
086 public String getXmlElementName() {
087 return XmlElementNames.FileAttachment;
088 }
089
090 /**
091 * {@inheritDoc}
092 */
093 @Override
094 protected void validate(int attachmentIndex) throws ServiceValidationException {
095 if ((this.fileName == null || this.fileName.isEmpty())
096 && this.content == null && this.contentStream == null) {
097 throw new ServiceValidationException(String.format(
098 "The content of the file attachment at index %d must be set.",
099 attachmentIndex));
100 }
101 }
102
103 /**
104 * Tries to read element from XML.
105 *
106 * @param reader the reader
107 * @return True if element was read.
108 * @throws Exception the exception
109 */
110 @Override
111 public boolean tryReadElementFromXml(EwsServiceXmlReader reader)
112 throws Exception {
113 boolean result = super.tryReadElementFromXml(reader);
114
115 if (!result) {
116 if (reader.getLocalName().equals(XmlElementNames.IsContactPhoto)) {
117 this.isContactPhoto = reader.readElementValue(Boolean.class);
118 } else if (reader.getLocalName().equals(XmlElementNames.Content)) {
119 if (this.loadToStream != null) {
120 reader.readBase64ElementValue(this.loadToStream);
121 } else {
122 // If there's a file attachment content handler, use it.
123 // Otherwise
124 // load the content into a byte array.
125 // TODO: Should we mark the attachment to indicate that
126 // content is stored elsewhere?
127 if (reader.getService().getFileAttachmentContentHandler() != null) {
128 OutputStream outputStream = reader.getService()
129 .getFileAttachmentContentHandler()
130 .getOutputStream(getId());
131 if (outputStream != null) {
132 reader.readBase64ElementValue(outputStream);
133 } else {
134 this.content = reader.readBase64ElementValue();
135 }
136 } else {
137 this.content = reader.readBase64ElementValue();
138 }
139 }
140
141 result = true;
142 }
143 }
144
145 return result;
146 }
147
148
149 /**
150 * For FileAttachment, the only thing need to patch is the AttachmentId.
151 *
152 * @param reader The reader.
153 * @return true if element was read
154 */
155 @Override
156 public boolean tryReadElementFromXmlToPatch(EwsServiceXmlReader reader) throws Exception {
157 return super.tryReadElementFromXml(reader);
158 }
159
160
161 /**
162 * Writes elements and content to XML.
163 *
164 * @param writer the writer
165 * @throws Exception the exception
166 */
167 @Override
168 public void writeElementsToXml(EwsServiceXmlWriter writer)
169 throws Exception {
170 super.writeElementsToXml(writer);
171 // ExchangeVersion ev=writer.getService().getRequestedServerVersion();
172 if (writer.getService().getRequestedServerVersion().ordinal() >
173 ExchangeVersion.Exchange2007_SP1
174 .ordinal()) {
175 writer.writeElementValue(XmlNamespace.Types,
176 XmlElementNames.IsContactPhoto, this.isContactPhoto);
177 }
178
179 writer.writeStartElement(XmlNamespace.Types, XmlElementNames.Content);
180
181 if (!(this.fileName == null || this.fileName.isEmpty())) {
182 File fileStream = new File(this.fileName);
183 FileInputStream fis = null;
184 try {
185 fis = new FileInputStream(fileStream);
186 writer.writeBase64ElementValue(fis);
187 } finally {
188 if (fis != null) {
189 fis.close();
190 }
191 }
192
193 } else if (this.contentStream != null) {
194 writer.writeBase64ElementValue(this.contentStream);
195 } else if (this.content != null) {
196 writer.writeBase64ElementValue(this.content);
197 } else {
198 EwsUtilities
199 .ewsAssert(false, "FileAttachment.WriteElementsToXml", "The attachment's content is not set.");
200 }
201
202 writer.writeEndElement();
203 }
204
205 /**
206 * Loads the content of the file attachment into the specified stream.
207 * Calling this method results in a call to EWS.
208 *
209 * @param stream the stream
210 * @throws Exception the exception
211 */
212 public void load(OutputStream stream) throws Exception {
213 this.loadToStream = stream;
214
215 try {
216 this.load();
217 } finally {
218 this.loadToStream = null;
219 }
220 }
221
222 /**
223 * Loads the content of the file attachment into the specified file.
224 * Calling this method results in a call to EWS.
225 *
226 * @param fileName the file name
227 * @throws Exception the exception
228 */
229 public void load(String fileName) throws Exception {
230 File fileStream = new File(fileName);
231
232 try {
233 this.loadToStream = new FileOutputStream(fileStream);
234 this.load();
235 this.loadToStream.flush();
236 } finally {
237 try {
238 this.loadToStream.close();
239 } catch(Exception e) {
240 //ignore exception on close
241 }
242 this.loadToStream = null;
243 }
244
245 this.fileName = fileName;
246 this.content = null;
247 this.contentStream = null;
248 }
249
250 /**
251 * Gets the name of the file the attachment is linked to.
252 *
253 * @return the file name
254 */
255 public String getFileName() {
256 return this.fileName;
257 }
258
259 /**
260 * Sets the file name.
261 *
262 * @param fileName the new file name
263 */
264 protected void setFileName(String fileName) {
265 this.throwIfThisIsNotNew();
266
267 this.fileName = fileName;
268 this.content = null;
269 this.contentStream = null;
270 }
271
272 /**
273 * Gets the content stream.Gets the name of the file the attachment
274 * is linked to.
275 *
276 * @return The content stream
277 */
278 protected InputStream getContentStream() {
279 return this.contentStream;
280 }
281
282 /**
283 * Sets the content stream.
284 *
285 * @param contentStream the new content stream
286 */
287 protected void setContentStream(InputStream contentStream) {
288 this.throwIfThisIsNotNew();
289
290 this.contentStream = contentStream;
291 this.content = null;
292 this.fileName = null;
293 }
294
295 /**
296 * Gets the content of the attachment into memory. Content is set only
297 * when Load() is called.
298 *
299 * @return the content
300 */
301 public byte[] getContent() {
302 return this.content;
303 }
304
305 /**
306 * Sets the content.
307 *
308 * @param content the new content
309 */
310 protected void setContent(byte[] content) {
311 this.throwIfThisIsNotNew();
312
313 this.content = content;
314 this.fileName = null;
315 this.contentStream = null;
316 }
317
318 /**
319 * Gets a value indicating whether this attachment is a contact
320 * photo.
321 *
322 * @return true, if is contact photo
323 * @throws ServiceVersionException the service version exception
324 */
325 public boolean isContactPhoto() throws ServiceVersionException {
326 EwsUtilities.validatePropertyVersion(this.getOwner().getService(),
327 ExchangeVersion.Exchange2010, "IsContactPhoto");
328 return this.isContactPhoto;
329 }
330
331 /**
332 * Sets the checks if is contact photo.
333 *
334 * @param isContactPhoto the new checks if is contact photo
335 * @throws ServiceVersionException the service version exception
336 */
337 public void setIsContactPhoto(boolean isContactPhoto)
338 throws ServiceVersionException {
339 EwsUtilities.validatePropertyVersion(this.getOwner().getService(),
340 ExchangeVersion.Exchange2010, "IsContactPhoto");
341 this.throwIfThisIsNotNew();
342 this.isContactPhoto = isContactPhoto;
343 }
344
345 }