001package com.hfg.util.mime; 002 003import com.hfg.exception.ProgrammingException; 004import com.hfg.util.FileUtil; 005import com.hfg.util.StringBuilderPlus; 006import com.hfg.util.StringUtil; 007import com.hfg.util.io.FileBytes; 008 009import java.io.File; 010import java.io.IOException; 011import java.io.OutputStream; 012import java.util.Base64; 013 014//------------------------------------------------------------------------------ 015/** 016 MIME Entity. 017 @author J. Alex Taylor, hairyfatguy.com 018 */ 019//------------------------------------------------------------------------------ 020// com.hfg XML/HTML Coding Library 021// 022// This library is free software; you can redistribute it and/or 023// modify it under the terms of the GNU Lesser General Public 024// License as published by the Free Software Foundation; either 025// version 2.1 of the License, or (at your option) any later version. 026// 027// This library is distributed in the hope that it will be useful, 028// but WITHOUT ANY WARRANTY; without even the implied warranty of 029// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 030// Lesser General Public License for more details. 031// 032// You should have received a copy of the GNU Lesser General Public 033// License along with this library; if not, write to the Free Software 034// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 035// 036// J. Alex Taylor, President, Founder, CEO, COO, CFO, OOPS hairyfatguy.com 037// jataylor@hairyfatguy.com 038//------------------------------------------------------------------------------ 039 040public class MimeEntity 041{ 042 //########################################################################## 043 // PRIVATE FIELDS 044 //########################################################################## 045 046 private MimeContentDisposition mContentDisposition = new MimeContentDisposition().setType("form-data"); 047 private MimeType mContentType; 048 private String mContentTransferEncoding; 049 private String mContent; 050 051 // File data could take several forms. We won't convert them until actually generating the output. 052 private File mFile; 053 private FileBytes mFileBytes; 054 055 private File mCachedContentFile; 056 057 private static final int MAX_ENCODING_LINE_LENGTH = 76; 058 private static final String CRLF = "\r\n"; 059 060 private static final String CONTENT_TYPE = "Content-Type"; 061 private static final String CONTENT_TRANSFER_ENCODING = "Content-Transfer-Encoding"; 062 063 private static final MimeType DEFAULT_FILE_CONTENT_TYPE = MimeType.APPLICATION_OCTET_STREAM; 064 065 //########################################################################## 066 // CONSTRUCTORS 067 //########################################################################## 068 069 //-------------------------------------------------------------------------- 070 public MimeEntity() 071 { 072 073 } 074 075 //-------------------------------------------------------------------------- 076 public MimeEntity(String inName, File inValue) 077 { 078 getContentDisposition() 079 .setName(inName) 080 .setFilename(inValue.getName()); 081 082 mFile = inValue; 083 } 084 085 //-------------------------------------------------------------------------- 086 public MimeEntity(String inName, FileBytes inValue) 087 { 088 getContentDisposition() 089 .setName(inName) 090 .setFilename(inValue.name()); 091 092 mFileBytes = inValue; 093 } 094 095 //-------------------------------------------------------------------------- 096 public MimeEntity(String inName, Object inValue) 097 { 098 getContentDisposition() 099 .setName(inName); 100 101 if (inValue != null) 102 { 103 if (inValue instanceof File) 104 { 105 mContentDisposition.setFilename(((File)inValue).getName()); 106 mFile = (File) inValue; 107 } 108 else if (inValue instanceof FileBytes) 109 { 110 mContentDisposition.setFilename(((FileBytes)inValue).name()); 111 mFileBytes = (FileBytes) inValue; 112 } 113 else 114 { 115 mContent = inValue.toString(); 116 } 117 } 118 } 119 120 //########################################################################## 121 // PUBLIC METHODS 122 //########################################################################## 123 124 //-------------------------------------------------------------------------- 125 public MimeContentDisposition getContentDisposition() 126 { 127 return mContentDisposition; 128 } 129 130 //-------------------------------------------------------------------------- 131 public void setContentDisposition(MimeContentDisposition inValue) 132 { 133 mContentDisposition = inValue; 134 } 135 136 137 //-------------------------------------------------------------------------- 138 public MimeType getContentType() 139 { 140 if (null == mContentType 141 && (mFile != null || mFileBytes != null)) 142 { 143 setContentType(DEFAULT_FILE_CONTENT_TYPE); 144 } 145 146 return mContentType; 147 } 148 149 //-------------------------------------------------------------------------- 150 public void setContentType(MimeType inValue) 151 { 152 mContentType = inValue; 153 } 154 155 156 //-------------------------------------------------------------------------- 157 public String getContentTransferEncoding() 158 { 159 return mContentTransferEncoding; 160 } 161 162 //-------------------------------------------------------------------------- 163 public void setContentTransferEncoding(String inValue) 164 { 165 mContentTransferEncoding = inValue; 166 } 167 168 169 //-------------------------------------------------------------------------- 170 public void setContent(String inValue) 171 throws IOException 172 { 173 if (mCachedContentFile != null) 174 { 175 FileUtil.write(mCachedContentFile, inValue); 176 mContent = null; 177 } 178 else 179 { 180 mContent = inValue; 181 } 182 } 183 184 //-------------------------------------------------------------------------- 185 public String getContent() 186 { 187 return mContent; 188 } 189 190 //-------------------------------------------------------------------------- 191 public File getCachedContentFile() 192 { 193 return mCachedContentFile; 194 } 195 196 //-------------------------------------------------------------------------- 197 /** 198 Sets the file in which the entity's content will be cached. 199 */ 200 public void setCachedContentFile(File inValue) 201 throws IOException 202 { 203 mCachedContentFile = inValue; 204 if (mCachedContentFile != null) 205 { 206/* 207 if (mCachedContentFile.exists()) 208 { 209 if (!mCachedContentFile.delete()) 210 { 211 throw new IOException("The preexisting cache file '" + mCachedContentFile + "' couldn't be deleted!"); 212 } 213 } 214*/ 215 if (!mCachedContentFile.exists() 216 && !mCachedContentFile.createNewFile()) 217 { 218 throw new IOException("The cache file '" + mCachedContentFile + "' couldn't be created!"); 219 } 220 } 221 } 222 223 //-------------------------------------------------------------------------- 224 public void write(OutputStream inStream) 225 throws IOException 226 { 227 inStream.write(getContentDisposition().toString().getBytes()); 228 229 230 if (getContentType() != null) 231 { 232 inStream.write(CRLF.getBytes()); 233 inStream.write(CONTENT_TYPE.getBytes()); 234 inStream.write(": ".getBytes()); 235 inStream.write(getContentType().toString().getBytes()); 236 } 237 238 if (getContentTransferEncoding() != null) 239 { 240 inStream.write(CRLF.getBytes()); 241 inStream.write(CONTENT_TRANSFER_ENCODING.getBytes()); 242 inStream.write(": ".getBytes()); 243 inStream.write(getContentTransferEncoding().getBytes()); 244 } 245 246 inStream.write(CRLF.getBytes()); 247 inStream.write(CRLF.getBytes()); 248 249 byte[] content = generateContent(); 250 if (content != null) 251 { 252 inStream.write(content); 253 } 254 255 inStream.write(CRLF.getBytes()); 256 } 257 258 //########################################################################## 259 // PRIVATE METHODS 260 //########################################################################## 261 262 //-------------------------------------------------------------------------- 263 private byte[] generateContent() 264 throws IOException 265 { 266 byte[] content = null; 267 268 if (mFile != null) 269 { 270 content = getContentFromFile(mFile); 271 } 272 else if (mFileBytes != null) 273 { 274 content = getContentFromFileBytes(mFileBytes); 275 } 276 else if (getContent() != null) 277 { 278 content = getContent().getBytes(); 279 } 280 281 return content; 282 } 283 284 285 //-------------------------------------------------------------------------- 286 private byte[] getContentFromFileBytes(FileBytes inValue) 287 throws IOException 288 { 289 byte[] content = null; 290 if (inValue != null) 291 { 292 content = getContentFromBytes(inValue.getBytes()); 293 } 294 295 return content; 296 } 297 298 //-------------------------------------------------------------------------- 299 private byte[] getContentFromFile(File inValue) 300 throws IOException 301 { 302 byte[] content = null; 303 if (inValue != null) 304 { 305 content = getContentFromBytes(FileUtil.read(inValue).toString().getBytes()); 306 } 307 308 return content; 309 } 310 311 //-------------------------------------------------------------------------- 312 private byte[] getContentFromBytes(byte[] inValue) 313 { 314 byte[] bytes = inValue; 315 if (getContentTransferEncoding() != null) 316 { 317 if (getContentTransferEncoding().equalsIgnoreCase("base64")) 318 { 319 String encodedString = Base64.getEncoder().encodeToString(inValue); 320 StringBuilderPlus buffer = new StringBuilderPlus().setDelimiter(CRLF); 321 int i = 0; 322 while (i < encodedString.length()) 323 { 324 int limit = i + MAX_ENCODING_LINE_LENGTH; 325 if (limit > encodedString.length()) 326 { 327 limit = encodedString.length(); 328 } 329 330 buffer.delimitedAppend(encodedString.substring(i, limit)); 331 332 i = limit; 333 } 334 335 bytes = buffer.toString().getBytes(); 336 } 337 else 338 { 339 throw new ProgrammingException(StringUtil.singleQuote(getContentTransferEncoding()) 340 + " is not a currently supported transfer encoding!"); 341 } 342 } 343 344 return bytes; 345 } 346 347}