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 *
10
* http://www.apache.org/licenses/LICENSE-2.0 *
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
****************************************************************/
20
package org.apache.james.mime4j.message;
22
import java.io.IOException;
23
import java.io.InputStream;
24
import java.util.Collections;
25
import java.util.HashMap;
26
import java.util.Iterator;
27
import java.util.LinkedList;
28
import java.util.List;
31
import org.apache.james.mime4j.MimeException;
32
import org.apache.james.mime4j.MimeIOException;
33
import org.apache.james.mime4j.parser.AbstractContentHandler;
34
import org.apache.james.mime4j.parser.Field;
35
import org.apache.james.mime4j.parser.MimeStreamParser;
38
* The header of an entity (see RFC 2045).
40
public class Header implements Iterable<Field> {
42
private List<Field> fields = new LinkedList<Field>();
43
private Map<String, List<Field>> fieldMap = new HashMap<String, List<Field>>();
46
* Creates a new empty <code>Header</code>.
52
* Creates a new <code>Header</code> from the specified
53
* <code>Header</code>. The <code>Header</code> instance is initialized
54
* with a copy of the list of {@link Field}s of the specified
55
* <code>Header</code>. The <code>Field</code> objects are not copied
56
* because they are immutable and can safely be shared between headers.
61
public Header(Header other) {
62
for (Field otherField : other.fields) {
68
* Creates a new <code>Header</code> from the specified stream.
70
* @param is the stream to read the header from.
72
* @throws IOException on I/O errors.
73
* @throws MimeIOException on MIME protocol violations.
75
public Header(InputStream is)
76
throws IOException, MimeIOException {
77
final MimeStreamParser parser = new MimeStreamParser();
78
parser.setContentHandler(new AbstractContentHandler() {
80
public void endHeader() {
84
public void field(Field field) throws MimeException {
90
} catch (MimeException ex) {
91
throw new MimeIOException(ex);
96
* Adds a field to the end of the list of fields.
98
* @param field the field to add.
100
public void addField(Field field) {
101
List<Field> values = fieldMap.get(field.getName().toLowerCase());
102
if (values == null) {
103
values = new LinkedList<Field>();
104
fieldMap.put(field.getName().toLowerCase(), values);
111
* Gets the fields of this header. The returned list will not be
114
* @return the list of <code>Field</code> objects.
116
public List<Field> getFields() {
117
return Collections.unmodifiableList(fields);
121
* Gets a <code>Field</code> given a field name. If there are multiple
122
* such fields defined in this header the first one will be returned.
124
* @param name the field name (e.g. From, Subject).
125
* @return the field or <code>null</code> if none found.
127
public Field getField(String name) {
128
List<Field> l = fieldMap.get(name.toLowerCase());
129
if (l != null && !l.isEmpty()) {
136
* Gets all <code>Field</code>s having the specified field name.
138
* @param name the field name (e.g. From, Subject).
139
* @return the list of fields.
141
public List<Field> getFields(final String name) {
142
final String lowerCaseName = name.toLowerCase();
143
final List<Field> l = fieldMap.get(lowerCaseName);
144
final List<Field> results;
145
if (l == null || l.isEmpty()) {
146
results = Collections.emptyList();
148
results = Collections.unmodifiableList(l);
154
* Returns an iterator over the list of fields of this header.
156
* @return an iterator.
158
public Iterator<Field> iterator() {
159
return Collections.unmodifiableList(fields).iterator();
163
* Removes all <code>Field</code>s having the specified field name.
166
* the field name (e.g. From, Subject).
167
* @return number of fields removed.
169
public int removeFields(String name) {
170
final String lowerCaseName = name.toLowerCase();
171
List<Field> removed = fieldMap.remove(lowerCaseName);
172
if (removed == null || removed.isEmpty())
175
for (Iterator<Field> iterator = fields.iterator(); iterator.hasNext();) {
176
Field field = iterator.next();
177
if (field.getName().equalsIgnoreCase(name))
181
return removed.size();
185
* Sets or replaces a field. This method is useful for header fields such as
186
* Subject or Message-ID that should not occur more than once in a message.
188
* If this <code>Header</code> does not already contain a header field of
189
* the same name as the given field then it is added to the end of the list
190
* of fields (same behavior as {@link #addField(Field)}). Otherwise the
191
* first occurrence of a field with the same name is replaced by the given
192
* field and all further occurrences are removed.
194
* @param field the field to set.
196
public void setField(Field field) {
197
final String lowerCaseName = field.getName().toLowerCase();
198
List<Field> l = fieldMap.get(lowerCaseName);
199
if (l == null || l.isEmpty()) {
207
int firstOccurrence = -1;
209
for (Iterator<Field> iterator = fields.iterator(); iterator.hasNext(); index++) {
210
Field f = iterator.next();
211
if (f.getName().equalsIgnoreCase(field.getName())) {
214
if (firstOccurrence == -1)
215
firstOccurrence = index;
219
fields.add(firstOccurrence, field);
223
* Return Header Object as String representation. Each headerline is
224
* seperated by "\r\n"
229
public String toString() {
230
StringBuilder str = new StringBuilder(128);
231
for (Field field : fields) {
232
str.append(field.toString());
235
return str.toString();