Skip to content

Package: MIMEPart

MIMEPart

nameinstructionbranchcomplexitylinemethod
MIMEPart(MIMEMessage)
M: 0 C: 17
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 5
100%
M: 0 C: 1
100%
MIMEPart(MIMEMessage, String)
M: 0 C: 7
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
addBody(ByteBuffer)
M: 0 C: 5
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
close()
M: 0 C: 21
100%
M: 1 C: 3
75%
M: 1 C: 2
67%
M: 0 C: 7
100%
M: 0 C: 1
100%
doneParsing()
M: 0 C: 7
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
getAllHeaders()
M: 14 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
getContentId()
M: 2 C: 6
75%
M: 1 C: 1
50%
M: 1 C: 1
50%
M: 1 C: 2
67%
M: 0 C: 1
100%
getContentTransferEncoding()
M: 2 C: 6
75%
M: 1 C: 1
50%
M: 1 C: 1
50%
M: 1 C: 2
67%
M: 0 C: 1
100%
getContentType()
M: 8 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
getHeader(String)
M: 4 C: 11
73%
M: 1 C: 1
50%
M: 1 C: 1
50%
M: 0 C: 3
100%
M: 0 C: 1
100%
getHeaders()
M: 12 C: 4
25%
M: 5 C: 1
17%
M: 3 C: 1
25%
M: 3 C: 2
40%
M: 0 C: 1
100%
isClosed()
M: 0 C: 3
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
moveTo(File)
M: 0 C: 5
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
read()
M: 10 C: 12
55%
M: 2 C: 0
0%
M: 1 C: 1
50%
M: 3 C: 4
57%
M: 0 C: 1
100%
readOnce()
M: 10 C: 12
55%
M: 2 C: 0
0%
M: 1 C: 1
50%
M: 3 C: 4
57%
M: 0 C: 1
100%
setContentId(String)
M: 4 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
setContentTransferEncoding(String)
M: 4 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
setHeaders(InternetHeaders)
M: 0 C: 32
100%
M: 0 C: 4
100%
M: 0 C: 3
100%
M: 0 C: 6
100%
M: 0 C: 1
100%
static {...}
M: 0 C: 5
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
toString()
M: 6 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%

Coverage

1: /*
2: * Copyright (c) 1997, 2021 Oracle and/or its affiliates. All rights reserved.
3: *
4: * This program and the accompanying materials are made available under the
5: * terms of the Eclipse Distribution License v. 1.0, which is available at
6: * http://www.eclipse.org/org/documents/edl-v10.php.
7: *
8: * SPDX-License-Identifier: BSD-3-Clause
9: */
10:
11: package org.jvnet.mimepull;
12:
13: import java.io.Closeable;
14: import java.io.File;
15: import java.io.InputStream;
16: import java.nio.ByteBuffer;
17: import java.util.List;
18: import java.util.logging.Level;
19: import java.util.logging.Logger;
20:
21: /**
22: * Represents an attachment part in a MIME message. MIME message parsing is done
23: * lazily using a pull parser, so the part may not have all the data. {@link #read}
24: * and {@link #readOnce} may trigger the actual parsing the message. In fact,
25: * parsing of an attachment part may be triggered by calling {@link #read} methods
26: * on some other attachment parts. All this happens behind the scenes so the
27: * application developer need not worry about these details.
28: *
29: * @author Jitendra Kotamraju, Martin Grebac
30: */
31: public class MIMEPart implements Closeable {
32:
33: private static final Logger LOGGER = Logger.getLogger(MIMEPart.class.getName());
34:
35: private volatile boolean closed;
36: private volatile InternetHeaders headers;
37: private volatile String contentId;
38: private String contentType;
39: private String contentTransferEncoding;
40:
41: volatile boolean parsed; // part is parsed or not
42: final MIMEMessage msg;
43: private final DataHead dataHead;
44:
45: private final Object lock = new Object();
46:
47: MIMEPart(MIMEMessage msg) {
48: this.msg = msg;
49: this.dataHead = new DataHead(this);
50: }
51:
52: MIMEPart(MIMEMessage msg, String contentId) {
53: this(msg);
54: this.contentId = contentId;
55: }
56:
57: /**
58: * Can get the attachment part's content multiple times. That means
59: * the full content needs to be there in memory or on the file system.
60: * Calling this method would trigger parsing for the part's data. So
61: * do not call this unless it is required(otherwise, just wrap MIMEPart
62: * into a object that returns InputStream for e.g DataHandler)
63: *
64: * @return data for the part's content
65: */
66: public InputStream read() {
67: InputStream is = null;
68: try {
69: is = MimeUtility.decode(dataHead.read(), contentTransferEncoding);
70: } catch (DecodingException ex) { //ignore
71:• if (LOGGER.isLoggable(Level.WARNING)) {
72: LOGGER.log(Level.WARNING, null, ex);
73: }
74: }
75: return is;
76: }
77:
78: /**
79: * Cleans up any resources that are held by this part (for e.g. deletes
80: * the temp file that is used to serve this part's content). After
81: * calling this, one shouldn't call {@link #read()} or {@link #readOnce()}
82: */
83: @Override
84: public void close() {
85:• if (!closed) {
86: synchronized (lock) {
87:• if (!closed) {
88: dataHead.close();
89: closed = true;
90: }
91: }
92: }
93: }
94:
95: /**
96: * Can get the attachment part's content only once. The content
97: * will be lost after the method. Content data is not be stored
98: * on the file system or is not kept in the memory for the
99: * following case:
100: * - Attachement parts contents are accessed sequentially
101: *
102: * In general, take advantage of this when the data is used only
103: * once.
104: *
105: * @return data for the part's content
106: */
107: public InputStream readOnce() {
108: InputStream is = null;
109: try {
110: is = MimeUtility.decode(dataHead.readOnce(), contentTransferEncoding);
111: } catch (DecodingException ex) { //ignore
112:• if (LOGGER.isLoggable(Level.WARNING)) {
113: LOGGER.log(Level.WARNING, null, ex);
114: }
115: }
116: return is;
117: }
118:
119: /**
120: * Send the content to the File
121: * @param f file to store the content
122: */
123: public void moveTo(File f) {
124: dataHead.moveTo(f);
125: }
126:
127: /**
128: * Returns Content-ID MIME header for this attachment part
129: *
130: * @return Content-ID of the part
131: */
132: public String getContentId() {
133:• if (contentId == null) {
134: getHeaders();
135: }
136: return contentId;
137: }
138:
139: /**
140: * Returns Content-Transfer-Encoding MIME header for this attachment part
141: *
142: * @return Content-Transfer-Encoding of the part
143: */
144: public String getContentTransferEncoding() {
145:• if (contentTransferEncoding == null) {
146: getHeaders();
147: }
148: return contentTransferEncoding;
149: }
150:
151: /**
152: * Returns Content-Type MIME header for this attachment part
153: *
154: * @return Content-Type of the part
155: */
156: public String getContentType() {
157:• if (contentType == null) {
158: getHeaders();
159: }
160: return contentType;
161: }
162:
163: private void getHeaders() {
164: // Trigger parsing for the part headers
165:• while(headers == null) {
166:• if (!msg.makeProgress()) {
167:• if (headers == null) {
168: throw new IllegalStateException("Internal Error. Didn't get Headers even after complete parsing.");
169: }
170: }
171: }
172: }
173:
174: /**
175: * Return all the values for the specified header.
176: * Returns <code>null</code> if no headers with the
177: * specified name exist.
178: *
179: * @param        name header name
180: * @return        list of header values, or null if none
181: */
182: public List<String> getHeader(String name) {
183: getHeaders();
184:• assert headers != null;
185: return headers.getHeader(name);
186: }
187:
188: /**
189: * Return all the headers
190: *
191: * @return list of Header objects
192: */
193: public List<? extends Header> getAllHeaders() {
194: getHeaders();
195:• assert headers != null;
196: return headers.getAllHeaders();
197: }
198:
199: /**
200: * Callback to set headers
201: *
202: * @param headers MIME headers for the part
203: */
204: void setHeaders(InternetHeaders headers) {
205: this.headers = headers;
206: List<String> ct = getHeader("Content-Type");
207:• this.contentType = (ct == null) ? "application/octet-stream" : ct.get(0);
208: List<String> cte = getHeader("Content-Transfer-Encoding");
209:• this.contentTransferEncoding = (cte == null) ? "binary" : cte.get(0);
210: }
211:
212: /**
213: * Callback to notify that there is a partial content for the part
214: *
215: * @param buf content data for the part
216: */
217: void addBody(ByteBuffer buf) {
218: dataHead.addBody(buf);
219: }
220:
221: /**
222: * Callback to indicate that parsing is done for this part
223: * (no more update events for this part)
224: */
225: void doneParsing() {
226: parsed = true;
227: dataHead.doneParsing();
228: }
229:
230: /**
231: * Callback to set Content-ID for this part
232: * @param cid Content-ID of the part
233: */
234: void setContentId(String cid) {
235: this.contentId = cid;
236: }
237:
238: /**
239: * Callback to set Content-Transfer-Encoding for this part
240: * @param cte Content-Transfer-Encoding of the part
241: */
242: void setContentTransferEncoding(String cte) {
243: this.contentTransferEncoding = cte;
244: }
245:
246: /**
247: * Return {@code true} if this part has already been closed, {@code false} otherwise.
248: *
249: * @return {@code true} if this part has already been closed, {@code false} otherwise.
250: */
251: public boolean isClosed() {
252: return closed;
253: }
254:
255: @Override
256: public String toString() {
257: return "Part="+contentId+":"+contentTransferEncoding;
258: }
259:
260: }