1 /* 2 * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.xml.internal.org.jvnet.mimepull; 27 28 import java.io.File; 29 import java.io.InputStream; 30 import java.nio.ByteBuffer; 31 import java.util.List; 32 33 /** 34 * Represents an attachment part in a MIME message. MIME message parsing is done 35 * lazily using a pull parser, so the part may not have all the data. {@link #read} 36 * and {@link #readOnce} may trigger the actual parsing the message. In fact, 37 * parsing of an attachment part may be triggered by calling {@link #read} methods 38 * on some other attachemnt parts. All this happens behind the scenes so the 39 * application developer need not worry about these details. 40 * 41 * @author Jitendra Kotamraju 42 */ 43 public class MIMEPart { 44 45 private volatile InternetHeaders headers; 46 private volatile String contentId; 47 private String contentType; 48 volatile boolean parsed; // part is parsed or not 49 final MIMEMessage msg; 50 private final DataHead dataHead; 51 52 MIMEPart(MIMEMessage msg) { 53 this.msg = msg; 54 this.dataHead = new DataHead(this); 55 } 56 57 MIMEPart(MIMEMessage msg, String contentId) { 58 this(msg); 59 this.contentId = contentId; 60 } 61 62 /** 63 * Can get the attachment part's content multiple times. That means 64 * the full content needs to be there in memory or on the file system. 65 * Calling this method would trigger parsing for the part's data. So 66 * do not call this unless it is required(otherwise, just wrap MIMEPart 67 * into a object that returns InputStream for e.g DataHandler) 68 * 69 * @return data for the part's content 70 */ 71 public InputStream read() { 72 return dataHead.read(); 73 } 74 75 /** 76 * Cleans up any resources that are held by this part (for e.g. deletes 77 * the temp file that is used to serve this part's content). After 78 * calling this, one shouldn't call {@link #read()} or {@link #readOnce()} 79 */ 80 public void close() { 81 dataHead.close(); 82 } 83 84 85 /** 86 * Can get the attachment part's content only once. The content 87 * will be lost after the method. Content data is not be stored 88 * on the file system or is not kept in the memory for the 89 * following case: 90 * - Attachement parts contents are accessed sequentially 91 * 92 * In general, take advantage of this when the data is used only 93 * once. 94 * 95 * @return data for the part's content 96 */ 97 public InputStream readOnce() { 98 return dataHead.readOnce(); 99 } 100 101 public void moveTo(File f) { 102 dataHead.moveTo(f); 103 } 104 105 /** 106 * Returns Content-ID MIME header for this attachment part 107 * 108 * @return Content-ID of the part 109 */ 110 public String getContentId() { 111 if (contentId == null) { 112 getHeaders(); 113 } 114 return contentId; 115 } 116 117 /** 118 * Returns Content-Type MIME header for this attachment part 119 * 120 * @return Content-Type of the part 121 */ 122 public String getContentType() { 123 if (contentType == null) { 124 getHeaders(); 125 } 126 return contentType; 127 } 128 129 private void getHeaders() { 130 // Trigger parsing for the part headers 131 while(headers == null) { 132 if (!msg.makeProgress()) { 133 if (headers == null) { 134 throw new IllegalStateException("Internal Error. Didn't get Headers even after complete parsing."); 135 } 136 } 137 } 138 } 139 140 /** 141 * Return all the values for the specified header. 142 * Returns <code>null</code> if no headers with the 143 * specified name exist. 144 * 145 * @param name header name 146 * @return list of header values, or null if none 147 */ 148 public List<String> getHeader(String name) { 149 getHeaders(); 150 assert headers != null; 151 return headers.getHeader(name); 152 } 153 154 /** 155 * Return all the headers 156 * 157 * @return list of Header objects 158 */ 159 public List<? extends Header> getAllHeaders() { 160 getHeaders(); 161 assert headers != null; 162 return headers.getAllHeaders(); 163 } 164 165 /** 166 * Callback to set headers 167 * 168 * @param headers MIME headers for the part 169 */ 170 void setHeaders(InternetHeaders headers) { 171 this.headers = headers; 172 List<String> ct = getHeader("Content-Type"); 173 this.contentType = (ct == null) ? "application/octet-stream" : ct.get(0); 174 } 175 176 /** 177 * Callback to notify that there is a partial content for the part 178 * 179 * @param buf content data for the part 180 */ 181 void addBody(ByteBuffer buf) { 182 dataHead.addBody(buf); 183 } 184 185 /** 186 * Callback to indicate that parsing is done for this part 187 * (no more update events for this part) 188 */ 189 void doneParsing() { 190 parsed = true; 191 dataHead.doneParsing(); 192 } 193 194 /** 195 * Callback to set Content-ID for this part 196 * @param cid Content-ID of the part 197 */ 198 void setContentId(String cid) { 199 this.contentId = cid; 200 } 201 202 @Override 203 public String toString() { 204 return "Part="+contentId; 205 } 206 207 }