source: contrib/MailArchiver/sources/vendor/mime4j/apache-mime4j-0.7-SNAPSHOT-20110327.010440-17/dom/src/main/java/org/apache/james/mime4j/message/AbstractEntity.java @ 6785

Revision 6785, 19.3 KB checked in by rafaelraymundo, 12 years ago (diff)

Ticket #2946 - Liberado codigo do MailArchiver?. Documentação na subpasta DOCS.

Line 
1/****************************************************************
2 * Licensed to the Apache Software Foundation (ASF) under one   *
3 * or more contributor license agreements.  See the NOTICE file *
4 * distributed with this work for additional information        *
5 * regarding copyright ownership.  The ASF licenses this file   *
6 * to you under the Apache License, Version 2.0 (the            *
7 * "License"); you may not use this file except in compliance   *
8 * with the License.  You may obtain a copy of the License at   *
9 *                                                              *
10 *   http://www.apache.org/licenses/LICENSE-2.0                 *
11 *                                                              *
12 * Unless required by applicable law or agreed to in writing,   *
13 * software distributed under the License is distributed on an  *
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
15 * KIND, either express or implied.  See the License for the    *
16 * specific language governing permissions and limitations      *
17 * under the License.                                           *
18 ****************************************************************/
19
20package org.apache.james.mime4j.message;
21
22import java.util.Collections;
23import java.util.Date;
24import java.util.HashMap;
25import java.util.Map;
26
27import org.apache.james.mime4j.dom.Body;
28import org.apache.james.mime4j.dom.Disposable;
29import org.apache.james.mime4j.dom.Entity;
30import org.apache.james.mime4j.dom.Header;
31import org.apache.james.mime4j.dom.Message;
32import org.apache.james.mime4j.dom.Multipart;
33import org.apache.james.mime4j.dom.TextBody;
34import org.apache.james.mime4j.dom.field.ContentDispositionField;
35import org.apache.james.mime4j.dom.field.ContentTransferEncodingField;
36import org.apache.james.mime4j.dom.field.ContentTypeField;
37import org.apache.james.mime4j.dom.field.Field;
38import org.apache.james.mime4j.dom.field.FieldName;
39
40/**
41 * MIME entity. An entity has a header and a body (see RFC 2045).
42 */
43public abstract class AbstractEntity implements Entity {
44    private Header header = null;
45    private Body body = null;
46    private Entity parent = null;
47
48    /**
49     * Creates a new <code>Entity</code>. Typically invoked implicitly by a
50     * subclass constructor.
51     */
52    protected AbstractEntity() {
53    }
54
55    /**
56     * Gets the parent entity of this entity.
57     * Returns <code>null</code> if this is the root entity.
58     *
59     * @return the parent or <code>null</code>.
60     */
61    public Entity getParent() {
62        return parent;
63    }
64   
65    /**
66     * Sets the parent entity of this entity.
67     *
68     * @param parent the parent entity or <code>null</code> if
69     *        this will be the root entity.
70     */
71    public void setParent(Entity parent) {
72        this.parent = parent;
73    }
74   
75    /**
76     * Gets the entity header.
77     *
78     * @return the header.
79     */
80    public Header getHeader() {
81        return header;
82    }
83   
84    /**
85     * Sets the entity header.
86     *
87     * @param header the header.
88     */
89    public void setHeader(Header header) {
90        this.header = header;
91    }
92   
93    /**
94     * Gets the body of this entity.
95     *
96     * @return the body,
97     */
98    public Body getBody() {
99        return body;
100    }
101
102    /**
103     * Sets the body of this entity.
104     *
105     * @param body the body.
106     * @throws IllegalStateException if the body has already been set.
107     */
108    public void setBody(Body body) {
109        if (this.body != null)
110            throw new IllegalStateException("body already set");
111
112        this.body = body;
113        body.setParent(this);
114    }
115
116    /**
117     * Removes and returns the body of this entity. The removed body may be
118     * attached to another entity. If it is no longer needed it should be
119     * {@link Disposable#dispose() disposed} of.
120     *
121     * @return the removed body or <code>null</code> if no body was set.
122     */
123    public Body removeBody() {
124        if (body == null)
125            return null;
126
127        Body body = this.body;
128        this.body = null;
129        body.setParent(null);
130
131        return body;
132    }
133
134    /**
135     * Sets the specified message as body of this entity and the content type to
136     * &quot;message/rfc822&quot;. A <code>Header</code> is created if this
137     * entity does not already have one.
138     *
139     * @param message
140     *            the message to set as body.
141     */
142    public void setMessage(Message message) {
143        setBody(message, "message/rfc822", null);
144    }
145
146    /**
147     * Sets the specified multipart as body of this entity. Also sets the
148     * content type accordingly and creates a message boundary string. A
149     * <code>Header</code> is created if this entity does not already have
150     * one.
151     *
152     * @param multipart
153     *            the multipart to set as body.
154     */
155    public void setMultipart(Multipart multipart) {
156        String mimeType = "multipart/" + multipart.getSubType();
157        Map<String, String> parameters = Collections.singletonMap("boundary",
158                newUniqueBoundary());
159
160        setBody(multipart, mimeType, parameters);
161    }
162
163    /**
164     * Sets the specified multipart as body of this entity. Also sets the
165     * content type accordingly and creates a message boundary string. A
166     * <code>Header</code> is created if this entity does not already have
167     * one.
168     *
169     * @param multipart
170     *            the multipart to set as body.
171     * @param parameters
172     *            additional parameters for the Content-Type header field.
173     */
174    public void setMultipart(Multipart multipart, Map<String, String> parameters) {
175        String mimeType = "multipart/" + multipart.getSubType();
176        if (!parameters.containsKey("boundary")) {
177            parameters = new HashMap<String, String>(parameters);
178            parameters.put("boundary", newUniqueBoundary());
179        }
180
181        setBody(multipart, mimeType, parameters);
182    }
183
184    /**
185     * Sets the specified <code>TextBody</code> as body of this entity and the
186     * content type to &quot;text/plain&quot;. A <code>Header</code> is
187     * created if this entity does not already have one.
188     *
189     * @param textBody
190     *            the <code>TextBody</code> to set as body.
191     * @see org.apache.james.mime4j.message.BodyFactory#textBody(String)
192     */
193    public void setText(TextBody textBody) {
194        setText(textBody, "plain");
195    }
196
197    /**
198     * Sets the specified <code>TextBody</code> as body of this entity. Also
199     * sets the content type according to the specified sub-type. A
200     * <code>Header</code> is created if this entity does not already have
201     * one.
202     *
203     * @param textBody
204     *            the <code>TextBody</code> to set as body.
205     * @param subtype
206     *            the text subtype (e.g. &quot;plain&quot;, &quot;html&quot; or
207     *            &quot;xml&quot;).
208     * @see org.apache.james.mime4j.message.BodyFactory#textBody(String)
209     */
210    public void setText(TextBody textBody, String subtype) {
211        String mimeType = "text/" + subtype;
212
213        Map<String, String> parameters = null;
214        String mimeCharset = textBody.getMimeCharset();
215        if (mimeCharset != null && !mimeCharset.equalsIgnoreCase("us-ascii")) {
216            parameters = Collections.singletonMap("charset", mimeCharset);
217        }
218
219        setBody(textBody, mimeType, parameters);
220    }
221
222    /**
223     * Sets the body of this entity and sets the content-type to the specified
224     * value. A <code>Header</code> is created if this entity does not already
225     * have one.
226     *
227     * @param body
228     *            the body.
229     * @param mimeType
230     *            the MIME media type of the specified body
231     *            (&quot;type/subtype&quot;).
232     */
233    public void setBody(Body body, String mimeType) {
234        setBody(body, mimeType, null);
235    }
236
237    /**
238     * Sets the body of this entity and sets the content-type to the specified
239     * value. A <code>Header</code> is created if this entity does not already
240     * have one.
241     *
242     * @param body
243     *            the body.
244     * @param mimeType
245     *            the MIME media type of the specified body
246     *            (&quot;type/subtype&quot;).
247     * @param parameters
248     *            additional parameters for the Content-Type header field.
249     */
250    public void setBody(Body body, String mimeType,
251            Map<String, String> parameters) {
252        setBody(body);
253
254        Header header = obtainHeader();
255        header.setField(newContentType(mimeType, parameters));
256    }
257
258    /**
259     * Determines the MIME type of this <code>Entity</code>. The MIME type
260     * is derived by looking at the parent's Content-Type field if no
261     * Content-Type field is set for this <code>Entity</code>.
262     *
263     * @return the MIME type.
264     */
265    public String getMimeType() {
266        ContentTypeField child =
267            getContentTypeField();
268        ContentTypeField parent = getParent() != null
269            ? (ContentTypeField) getParent().getHeader().
270                                                getField(FieldName.CONTENT_TYPE)
271            : null;
272       
273        return calcMimeType(child, parent);
274    }
275
276    private ContentTypeField getContentTypeField() {
277        return (ContentTypeField) getHeader().getField(FieldName.CONTENT_TYPE);
278    }
279   
280    /**
281     * Determines the MIME character set encoding of this <code>Entity</code>.
282     *
283     * @return the MIME character set encoding.
284     */
285    public String getCharset() {
286        return calcCharset((ContentTypeField) getHeader().getField(FieldName.CONTENT_TYPE));
287    }
288   
289    /**
290     * Determines the transfer encoding of this <code>Entity</code>.
291     *
292     * @return the transfer encoding.
293     */
294    public String getContentTransferEncoding() {
295        ContentTransferEncodingField f = (ContentTransferEncodingField)
296                        getHeader().getField(FieldName.CONTENT_TRANSFER_ENCODING);
297       
298        return calcTransferEncoding(f);
299    }
300
301    /**
302     * Sets the transfer encoding of this <code>Entity</code> to the specified
303     * value.
304     *
305     * @param contentTransferEncoding
306     *            transfer encoding to use.
307     */
308    public void setContentTransferEncoding(String contentTransferEncoding) {
309        Header header = obtainHeader();
310        header.setField(newContentTransferEncoding(contentTransferEncoding));
311    }
312
313    /**
314     * Return the disposition type of the content disposition of this
315     * <code>Entity</code>.
316     *
317     * @return the disposition type or <code>null</code> if no disposition
318     *         type has been set.
319     */
320    public String getDispositionType() {
321        ContentDispositionField field = obtainField(FieldName.CONTENT_DISPOSITION);
322        if (field == null)
323            return null;
324
325        return field.getDispositionType();
326    }
327
328    /**
329     * Sets the content disposition of this <code>Entity</code> to the
330     * specified disposition type. No filename, size or date parameters
331     * are included in the content disposition.
332     *
333     * @param dispositionType
334     *            disposition type value (usually <code>inline</code> or
335     *            <code>attachment</code>).
336     */
337    public void setContentDisposition(String dispositionType) {
338        Header header = obtainHeader();
339        header.setField(newContentDisposition(dispositionType, null, -1, null,
340                null, null));
341    }
342
343    /**
344     * Sets the content disposition of this <code>Entity</code> to the
345     * specified disposition type and filename. No size or date parameters are
346     * included in the content disposition.
347     *
348     * @param dispositionType
349     *            disposition type value (usually <code>inline</code> or
350     *            <code>attachment</code>).
351     * @param filename
352     *            filename parameter value or <code>null</code> if the
353     *            parameter should not be included.
354     */
355    public void setContentDisposition(String dispositionType, String filename) {
356        Header header = obtainHeader();
357        header.setField(newContentDisposition(dispositionType, filename, -1,
358                null, null, null));
359    }
360
361    /**
362     * Sets the content disposition of this <code>Entity</code> to the
363     * specified values. No date parameters are included in the content
364     * disposition.
365     *
366     * @param dispositionType
367     *            disposition type value (usually <code>inline</code> or
368     *            <code>attachment</code>).
369     * @param filename
370     *            filename parameter value or <code>null</code> if the
371     *            parameter should not be included.
372     * @param size
373     *            size parameter value or <code>-1</code> if the parameter
374     *            should not be included.
375     */
376    public void setContentDisposition(String dispositionType, String filename,
377            long size) {
378        Header header = obtainHeader();
379        header.setField(newContentDisposition(dispositionType, filename, size,
380                null, null, null));
381    }
382
383    /**
384     * Sets the content disposition of this <code>Entity</code> to the
385     * specified values.
386     *
387     * @param dispositionType
388     *            disposition type value (usually <code>inline</code> or
389     *            <code>attachment</code>).
390     * @param filename
391     *            filename parameter value or <code>null</code> if the
392     *            parameter should not be included.
393     * @param size
394     *            size parameter value or <code>-1</code> if the parameter
395     *            should not be included.
396     * @param creationDate
397     *            creation-date parameter value or <code>null</code> if the
398     *            parameter should not be included.
399     * @param modificationDate
400     *            modification-date parameter value or <code>null</code> if
401     *            the parameter should not be included.
402     * @param readDate
403     *            read-date parameter value or <code>null</code> if the
404     *            parameter should not be included.
405     */
406    public void setContentDisposition(String dispositionType, String filename,
407            long size, Date creationDate, Date modificationDate, Date readDate) {
408        Header header = obtainHeader();
409        header.setField(newContentDisposition(dispositionType, filename, size,
410                creationDate, modificationDate, readDate));
411    }
412
413    /**
414     * Returns the filename parameter of the content disposition of this
415     * <code>Entity</code>.
416     *
417     * @return the filename parameter of the content disposition or
418     *         <code>null</code> if the filename has not been set.
419     */
420    public String getFilename() {
421        ContentDispositionField field = obtainField(FieldName.CONTENT_DISPOSITION);
422        if (field == null)
423            return null;
424
425        return field.getFilename();
426    }
427   
428    /**
429     * Sets the filename parameter of the content disposition of this
430     * <code>Entity</code> to the specified value. If this entity does not
431     * have a content disposition header field a new one with disposition type
432     * <code>attachment</code> is created.
433     *
434     * @param filename
435     *            filename parameter value or <code>null</code> if the
436     *            parameter should be removed.
437     */
438    public void setFilename(String filename) {
439        Header header = obtainHeader();
440        ContentDispositionField field = (ContentDispositionField) header
441                .getField(FieldName.CONTENT_DISPOSITION);
442        if (field == null) {
443            if (filename != null) {
444                header.setField(newContentDisposition(
445                        ContentDispositionField.DISPOSITION_TYPE_ATTACHMENT,
446                        filename, -1, null, null, null));
447            }
448        } else {
449            String dispositionType = field.getDispositionType();
450            Map<String, String> parameters = new HashMap<String, String>(field
451                    .getParameters());
452            if (filename == null) {
453                parameters.remove(ContentDispositionField.PARAM_FILENAME);
454            } else {
455                parameters
456                        .put(ContentDispositionField.PARAM_FILENAME, filename);
457            }
458            header.setField(newContentDisposition(dispositionType, parameters));
459        }
460    }
461
462    /**
463     * Determines if the MIME type of this <code>Entity</code> matches the
464     * given one. MIME types are case-insensitive.
465     *
466     * @param type the MIME type to match against.
467     * @return <code>true</code> on match, <code>false</code> otherwise.
468     */
469    public boolean isMimeType(String type) {
470        return getMimeType().equalsIgnoreCase(type);
471    }
472   
473    /**
474     * Determines if the MIME type of this <code>Entity</code> is
475     * <code>multipart/*</code>. Since multipart-entities must have
476     * a boundary parameter in the <code>Content-Type</code> field this
477     * method returns <code>false</code> if no boundary exists.
478     *
479     * @return <code>true</code> on match, <code>false</code> otherwise.
480     */
481    public boolean isMultipart() {
482        ContentTypeField f = getContentTypeField();
483        return f != null
484                && f.getBoundary() != null
485                && getMimeType().startsWith(
486                        ContentTypeField.TYPE_MULTIPART_PREFIX);
487    }
488
489    /**
490     * Disposes of the body of this entity. Note that the dispose call does not
491     * get forwarded to the parent entity of this Entity.
492     *
493     * Subclasses that need to free resources should override this method and
494     * invoke super.dispose().
495     *
496     * @see org.apache.james.mime4j.dom.Disposable#dispose()
497     */
498    public void dispose() {
499        if (body != null) {
500            body.dispose();
501        }
502    }
503
504    /**
505     * Obtains the header of this entity. Creates and sets a new header if this
506     * entity's header is currently <code>null</code>.
507     *
508     * @return the header of this entity; never <code>null</code>.
509     */
510    Header obtainHeader() {
511        if (header == null) {
512            header = new HeaderImpl();
513        }
514        return header;
515    }
516
517    /**
518     * Obtains the header field with the specified name.
519     *
520     * @param <F>
521     *            concrete field type.
522     * @param fieldName
523     *            name of the field to retrieve.
524     * @return the header field or <code>null</code> if this entity has no
525     *         header or the header contains no such field.
526     */
527    <F extends Field> F obtainField(String fieldName) {
528        Header header = getHeader();
529        if (header == null)
530            return null;
531
532        @SuppressWarnings("unchecked")
533        F field = (F) header.getField(fieldName);
534        return field;
535    }
536
537    protected abstract String newUniqueBoundary();
538
539    protected abstract ContentDispositionField newContentDisposition(
540            String dispositionType, String filename, long size,
541            Date creationDate, Date modificationDate, Date readDate);
542
543    protected abstract ContentDispositionField newContentDisposition(
544            String dispositionType, Map<String, String> parameters);
545
546    protected abstract ContentTypeField newContentType(String mimeType,
547            Map<String, String> parameters);
548
549    protected abstract ContentTransferEncodingField newContentTransferEncoding(
550            String contentTransferEncoding);
551
552    protected abstract String calcMimeType(ContentTypeField child, ContentTypeField parent);
553
554    protected abstract String calcTransferEncoding(ContentTransferEncodingField f);
555
556    protected abstract String calcCharset(ContentTypeField contentType);
557}
Note: See TracBrowser for help on using the repository browser.