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.XmlElementNames; 030import microsoft.exchange.webservices.data.core.service.item.Item; 031import microsoft.exchange.webservices.data.core.enumeration.misc.ExchangeVersion; 032import microsoft.exchange.webservices.data.core.enumeration.misc.XmlNamespace; 033import microsoft.exchange.webservices.data.core.exception.service.local.ServiceValidationException; 034import microsoft.exchange.webservices.data.core.exception.service.local.ServiceVersionException; 035 036import java.io.File; 037import java.io.FileInputStream; 038import java.io.FileOutputStream; 039import java.io.InputStream; 040import java.io.OutputStream; 041 042/** 043 * Represents a file attachment. 044 */ 045public 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}