You are viewing a plain text version of this content. The canonical link for it is here.
Posted to mime4j-dev@james.apache.org by ol...@apache.org on 2011/06/28 16:11:41 UTC

svn commit: r1140633 - in /james/mime4j/trunk: core/src/main/java/org/apache/james/mime4j/parser/ core/src/main/java/org/apache/james/mime4j/stream/ core/src/test/java/org/apache/james/mime4j/stream/ dom/src/main/java/org/apache/james/mime4j/message/ d...

Author: olegk
Date: Tue Jun 28 14:11:40 2011
New Revision: 1140633

URL: http://svn.apache.org/viewvc?rev=1140633&view=rev
Log:
MutableBodyDescriptor and MutableBodyDescriptorFactory replaced with BodyDescriptorBuilder; MinimalBodyDescriptor is no longer needed

Added:
    james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/stream/BasicBodyDescriptor.java   (with props)
    james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/stream/BodyDescriptorBuilder.java   (with props)
    james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/stream/FallbackBodyDescriptorBuilder.java
      - copied, changed from r1139766, james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/stream/DefaultBodyDescriptor.java
    james/mime4j/trunk/core/src/test/java/org/apache/james/mime4j/stream/FallbackBodyDescriptorBuilderTest.java
      - copied, changed from r1139766, james/mime4j/trunk/core/src/test/java/org/apache/james/mime4j/stream/BaseTestForBodyDescriptors.java
    james/mime4j/trunk/dom/src/main/java/org/apache/james/mime4j/message/DefaultBodyDescriptorBuilder.java   (with props)
Removed:
    james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/stream/DefaultBodyDescriptor.java
    james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/stream/MutableBodyDescriptor.java
    james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/stream/MutableBodyDescriptorFactory.java
    james/mime4j/trunk/core/src/test/java/org/apache/james/mime4j/stream/BaseTestForBodyDescriptors.java
    james/mime4j/trunk/dom/src/main/java/org/apache/james/mime4j/message/MaximalBodyDescriptorFactory.java
    james/mime4j/trunk/dom/src/main/java/org/apache/james/mime4j/message/MinimalBodyDescriptor.java
    james/mime4j/trunk/dom/src/main/java/org/apache/james/mime4j/message/MinimalBodyDescriptorFactory.java
Modified:
    james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/parser/MimeStreamParser.java
    james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/stream/ContentDescriptor.java
    james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/stream/MimeEntity.java
    james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/stream/MimeTokenStream.java
    james/mime4j/trunk/core/src/test/java/org/apache/james/mime4j/stream/MimeEntityTest.java
    james/mime4j/trunk/dom/src/main/java/org/apache/james/mime4j/message/DefaultMessageBuilder.java
    james/mime4j/trunk/dom/src/main/java/org/apache/james/mime4j/message/MaximalBodyDescriptor.java
    james/mime4j/trunk/dom/src/main/java/org/apache/james/mime4j/message/MessageServiceFactoryImpl.java
    james/mime4j/trunk/dom/src/test/java/org/apache/james/mime4j/message/MaximalBodyDescriptorTest.java

Modified: james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/parser/MimeStreamParser.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/parser/MimeStreamParser.java?rev=1140633&r1=1140632&r2=1140633&view=diff
==============================================================================
--- james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/parser/MimeStreamParser.java (original)
+++ james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/parser/MimeStreamParser.java Tue Jun 28 14:11:40 2011
@@ -25,11 +25,11 @@ import java.io.InputStream;
 import org.apache.james.mime4j.MimeException;
 import org.apache.james.mime4j.codec.DecodeMonitor;
 import org.apache.james.mime4j.stream.BodyDescriptor;
+import org.apache.james.mime4j.stream.BodyDescriptorBuilder;
 import org.apache.james.mime4j.stream.EntityState;
 import org.apache.james.mime4j.stream.Field;
 import org.apache.james.mime4j.stream.MimeEntityConfig;
 import org.apache.james.mime4j.stream.MimeTokenStream;
-import org.apache.james.mime4j.stream.MutableBodyDescriptorFactory;
 import org.apache.james.mime4j.stream.RecursionMode;
 
 /**
@@ -65,8 +65,8 @@ public class MimeStreamParser {
             final MimeEntityConfig config, 
             boolean clone,
             final DecodeMonitor monitor,
-            final MutableBodyDescriptorFactory bodyDescFactory) {
-        this(new MimeTokenStream(clone ? config.clone() : config, monitor, bodyDescFactory));
+            final BodyDescriptorBuilder bodyDescBuilder) {
+        this(new MimeTokenStream(clone ? config.clone() : config, monitor, bodyDescBuilder));
     }
 
     public MimeStreamParser(final MimeEntityConfig config, boolean clone) {
@@ -76,9 +76,9 @@ public class MimeStreamParser {
     public MimeStreamParser(
             final MimeEntityConfig config,
             final DecodeMonitor monitor,
-            final MutableBodyDescriptorFactory bodyDescFactory) {
+            final BodyDescriptorBuilder bodyDescBuilder) {
         this(config != null ? config : new MimeEntityConfig(), config != null, 
-                monitor, bodyDescFactory);
+                monitor, bodyDescBuilder);
     }
 
     public MimeStreamParser(final MimeEntityConfig config) {

Added: james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/stream/BasicBodyDescriptor.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/stream/BasicBodyDescriptor.java?rev=1140633&view=auto
==============================================================================
--- james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/stream/BasicBodyDescriptor.java (added)
+++ james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/stream/BasicBodyDescriptor.java Tue Jun 28 14:11:40 2011
@@ -0,0 +1,95 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.stream;
+
+class BasicBodyDescriptor implements BodyDescriptor {
+
+    private final String mimeType;
+    private final String mediaType;
+    private final String subType;
+    private final String boundary;
+    private final String charset;
+    private final String transferEncoding;
+    private final long contentLength;
+
+    BasicBodyDescriptor(
+            final String mimeType,
+            final String mediaType,
+            final String subType,
+            final String boundary,
+            final String charset,
+            final String transferEncoding,
+            final long contentLength) {
+        super();
+        this.mimeType = mimeType;
+        this.mediaType = mediaType;
+        this.subType = subType;
+        this.boundary = boundary;
+        this.charset = charset;
+        this.transferEncoding = transferEncoding;
+        this.contentLength = contentLength;
+    }
+
+    public String getMimeType() {
+        return mimeType;
+    }
+
+    public String getMediaType() {
+        return mediaType;
+    }
+
+    public String getSubType() {
+        return subType;
+    }
+
+    public String getBoundary() {
+        return boundary;
+    }
+
+    public String getCharset() {
+        return charset;
+    }
+
+    public String getTransferEncoding() {
+        return transferEncoding;
+    }
+
+    public long getContentLength() {
+        return contentLength;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("[mimeType=");
+        sb.append(mimeType);
+        sb.append(", mediaType=");
+        sb.append(mediaType);
+        sb.append(", subType=");
+        sb.append(subType);
+        sb.append(", boundary=");
+        sb.append(boundary);
+        sb.append(", charset=");
+        sb.append(charset);
+        sb.append("]");
+        return sb.toString();
+    }
+
+}

Propchange: james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/stream/BasicBodyDescriptor.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/stream/BasicBodyDescriptor.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/stream/BasicBodyDescriptor.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/stream/BodyDescriptorBuilder.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/stream/BodyDescriptorBuilder.java?rev=1140633&view=auto
==============================================================================
--- james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/stream/BodyDescriptorBuilder.java (added)
+++ james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/stream/BodyDescriptorBuilder.java Tue Jun 28 14:11:40 2011
@@ -0,0 +1,50 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.stream;
+
+import org.apache.james.mime4j.MimeException;
+
+public interface BodyDescriptorBuilder {
+
+    /**
+     * Resets the internal state.
+     */
+    void reset();
+
+    /**
+     * Adds a field to the builder updating its internal state. The field
+     * can be transformed as a result of this operation.
+     * @param field the MIME field.
+     *
+     * @return null or an elaborated field representing the same data.
+     */
+    Field addField(RawField field) throws MimeException;
+
+    /**
+     * Builds an instance of {@link BodyDescriptor} based on the internal
+     * state.
+     *
+     * @return body descriptor
+     */
+    BodyDescriptor build();
+
+    BodyDescriptorBuilder newChild();
+
+}

Propchange: james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/stream/BodyDescriptorBuilder.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/stream/BodyDescriptorBuilder.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/stream/BodyDescriptorBuilder.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/stream/ContentDescriptor.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/stream/ContentDescriptor.java?rev=1140633&r1=1140632&r2=1140633&view=diff
==============================================================================
--- james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/stream/ContentDescriptor.java (original)
+++ james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/stream/ContentDescriptor.java Tue Jun 28 14:11:40 2011
@@ -19,8 +19,6 @@
 
 package org.apache.james.mime4j.stream;
 
-import java.util.Map;
-
 /**
  * Represents common content properties. 
  */
@@ -74,11 +72,6 @@ public interface ContentDescriptor {
     String getTransferEncoding();
 
     /**
-     * Returns the map of parameters of the content-type header.
-     */
-    Map<String, String> getContentTypeParameters();
-
-    /**
      * Returns the body descriptors content-length.
      * @return Content length, if known, or -1, to indicate the absence of a
      *   content-length header.

Copied: james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/stream/FallbackBodyDescriptorBuilder.java (from r1139766, james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/stream/DefaultBodyDescriptor.java)
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/stream/FallbackBodyDescriptorBuilder.java?p2=james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/stream/FallbackBodyDescriptorBuilder.java&p1=james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/stream/DefaultBodyDescriptor.java&r1=1139766&r2=1140633&rev=1140633&view=diff
==============================================================================
--- james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/stream/DefaultBodyDescriptor.java (original)
+++ james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/stream/FallbackBodyDescriptorBuilder.java Tue Jun 28 14:11:40 2011
@@ -31,40 +31,32 @@ import org.apache.james.mime4j.util.Mime
  * Encapsulates the values of the MIME-specific header fields 
  * (which starts with <code>Content-</code>). 
  */
-class DefaultBodyDescriptor implements MutableBodyDescriptor {
+class FallbackBodyDescriptorBuilder implements BodyDescriptorBuilder {
+    
     private static final String US_ASCII = "us-ascii";
-
     private static final String SUB_TYPE_EMAIL = "rfc822";
-
     private static final String MEDIA_TYPE_TEXT = "text";
-
     private static final String MEDIA_TYPE_MESSAGE = "message";
-
     private static final String EMAIL_MESSAGE_MIME_TYPE = MEDIA_TYPE_MESSAGE + "/" + SUB_TYPE_EMAIL;
-
     private static final String DEFAULT_SUB_TYPE = "plain";
-
     private static final String DEFAULT_MEDIA_TYPE = MEDIA_TYPE_TEXT;
-
     private static final String DEFAULT_MIME_TYPE = DEFAULT_MEDIA_TYPE + "/" + DEFAULT_SUB_TYPE;
 
+    private final String parentMimeType;
     private final DecodeMonitor monitor;
     
-    private String mediaType = DEFAULT_MEDIA_TYPE;
-    private String subType = DEFAULT_SUB_TYPE;
-    private String mimeType = DEFAULT_MIME_TYPE;
-    private String boundary = null;
-    private String charset = US_ASCII;
-    private String transferEncoding = "7bit";
-    private Map<String, String> parameters = new HashMap<String, String>();
-    private boolean contentTypeSet;
-    private boolean contentTransferEncSet;
-    private long contentLength = -1;
+    private String mediaType;
+    private String subType;
+    private String mimeType;
+    private String boundary;
+    private String charset;
+    private String transferEncoding;
+    private long contentLength;
     
     /**
      * Creates a new root <code>BodyDescriptor</code> instance.
      */
-    public DefaultBodyDescriptor() {
+    public FallbackBodyDescriptorBuilder() {
         this(null, null);
     }
 
@@ -74,27 +66,52 @@ class DefaultBodyDescriptor implements M
      * @param parent the descriptor of the parent or <code>null</code> if this
      *        is the root descriptor.
      */
-    public DefaultBodyDescriptor(final BodyDescriptor parent, final DecodeMonitor monitor) {
-        if (parent != null && MimeUtil.isSameMimeType("multipart/digest", parent.getMimeType())) {
-            this.mimeType = EMAIL_MESSAGE_MIME_TYPE;
-            this.subType = SUB_TYPE_EMAIL;
-            this.mediaType = MEDIA_TYPE_MESSAGE;
-        } else {
-            this.mimeType = DEFAULT_MIME_TYPE;
-            this.subType = DEFAULT_SUB_TYPE;
-            this.mediaType = DEFAULT_MEDIA_TYPE;
-        }
+    public FallbackBodyDescriptorBuilder(final String parentMimeType, final DecodeMonitor monitor) {
+        super();
+        this.parentMimeType = parentMimeType;
         this.monitor = monitor != null ? monitor : DecodeMonitor.SILENT;
+        reset();
     }
     
-    protected DecodeMonitor getDecodeMonitor() {
-        return monitor;
-    }
-    
-    public MutableBodyDescriptor newChild() {
-		return new DefaultBodyDescriptor(this, getDecodeMonitor());
+    public void reset() {
+        mimeType = null;
+        subType = null;
+        mediaType = null;
+        boundary = null;        
+        charset = null;   
+        transferEncoding = null;
+        contentLength = -1;
+    }
+
+    public BodyDescriptorBuilder newChild() {
+		return new FallbackBodyDescriptorBuilder(mimeType, monitor);
+    }
+    
+    public BodyDescriptor build() {
+        String actualMimeType = mimeType;
+        String actualMediaType = mediaType;
+        String actualSubType = subType;
+        String actualCharset = charset;
+        if (actualMimeType == null) {
+            if (MimeUtil.isSameMimeType("multipart/digest", parentMimeType)) {
+                actualMimeType = EMAIL_MESSAGE_MIME_TYPE;
+                actualMediaType = MEDIA_TYPE_MESSAGE;
+                actualSubType = SUB_TYPE_EMAIL;
+            } else {
+                actualMimeType = DEFAULT_MIME_TYPE;
+                actualMediaType = DEFAULT_MEDIA_TYPE;
+                actualSubType = DEFAULT_SUB_TYPE;
+            }
+        } 
+        if (actualCharset == null && MEDIA_TYPE_TEXT.equals(actualMediaType)) {
+            actualCharset = US_ASCII;
+        }
+        return new BasicBodyDescriptor(actualMimeType, actualMediaType, actualSubType, 
+                boundary, actualCharset, 
+                transferEncoding != null ? transferEncoding : "7bit", 
+                contentLength);
     }
-    
+
     /**
      * Should be called for each <code>Content-</code> header field of 
      * a MIME message or part.
@@ -104,8 +121,7 @@ class DefaultBodyDescriptor implements M
     public Field addField(RawField field) throws MimeException {
         String name = field.getName().toLowerCase(Locale.US);
         
-        if (name.equals("content-transfer-encoding") && !contentTransferEncSet) {
-            contentTransferEncSet = true;
+        if (name.equals("content-transfer-encoding") && transferEncoding == null) {
             String value = field.getBody();
             if (value != null) {
                 value = value.trim().toLowerCase(Locale.US);
@@ -126,14 +142,13 @@ class DefaultBodyDescriptor implements M
                     }
                 }
             }
-        } else if (name.equals("content-type") && !contentTypeSet) {
+        } else if (name.equals("content-type") && mimeType == null) {
             parseContentType(field);
         }
         return null;
     }
 
     private void parseContentType(Field field) throws MimeException {
-        contentTypeSet = true;
         RawField rawfield;
         if (field instanceof RawField) {
             rawfield = ((RawField) field);
@@ -175,8 +190,8 @@ class DefaultBodyDescriptor implements M
                 && ((main.startsWith("multipart/") && b != null) 
                         || !main.startsWith("multipart/"))) {
             mimeType = main;
-            this.subType = subtype;
-            this.mediaType = type;
+            mediaType = type;
+            subType = subtype;
         }
         
         if (MimeUtil.isMultipart(mimeType)) {
@@ -188,81 +203,9 @@ class DefaultBodyDescriptor implements M
         if (c != null) {
             c = c.trim();
             if (c.length() > 0) {
-                charset = c.toLowerCase();
+                charset = c;
             }
         }
-        if (charset == null && MEDIA_TYPE_TEXT.equals(mediaType)) {
-            charset = US_ASCII;
-        }
-        
-        /*
-         * Add all other parameters to parameters.
-         */
-        parameters.putAll(params);
-        parameters.remove("boundary");
-        parameters.remove("charset");
-    }
-
-    /**
-     * Return the MimeType 
-     * 
-     * @return mimeType
-     */
-    public String getMimeType() {
-        return mimeType;
-    }
-    
-    /**
-     * Return the boundary
-     * 
-     * @return boundary
-     */
-    public String getBoundary() {
-        return boundary;
-    }
-    
-    /**
-     * Return the charset
-     * 
-     * @return charset
-     */
-    public String getCharset() {
-        return charset;
-    }
-    
-    /**
-     * Return all parameters for the BodyDescriptor
-     * 
-     * @return parameters
-     */
-    public Map<String, String> getContentTypeParameters() {
-        return parameters;
-    }
-    
-    /**
-     * Return the TransferEncoding
-     * 
-     * @return transferEncoding
-     */
-    public String getTransferEncoding() {
-        return transferEncoding;
-    }
-    
-    @Override
-    public String toString() {
-        return mimeType;
-    }
-
-    public long getContentLength() {
-        return contentLength;
-    }
-
-    public String getMediaType() {
-        return mediaType;
-    }
-
-    public String getSubType() {
-        return subType;
     }
 
 }

Modified: james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/stream/MimeEntity.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/stream/MimeEntity.java?rev=1140633&r1=1140632&r2=1140633&view=diff
==============================================================================
--- james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/stream/MimeEntity.java (original)
+++ james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/stream/MimeEntity.java Tue Jun 28 14:11:40 2011
@@ -44,7 +44,7 @@ class MimeEntity implements EntityStateM
     private final MimeEntityConfig config;
     private final DecodeMonitor monitor;
     private final FieldBuilder fieldBuilder;
-    private final MutableBodyDescriptor body;
+    private final BodyDescriptorBuilder bodyDescBuilder;
 
     private final ByteArrayBuffer linebuf;
     private final LineNumberSource lineSource;
@@ -55,6 +55,7 @@ class MimeEntity implements EntityStateM
     private boolean endOfHeader;
     private int headerCount;
     private Field field;
+    private BodyDescriptor body;
 
     private RecursionMode recursionMode;
     private MimeBoundaryInputStream currentMimePartStream;
@@ -70,14 +71,14 @@ class MimeEntity implements EntityStateM
             EntityState endState,
             DecodeMonitor monitor,
             FieldBuilder fieldBuilder,
-            MutableBodyDescriptor body) {
+            BodyDescriptorBuilder bodyDescBuilder) {
         super();
         this.config = config;
         this.state = startState;
         this.endState = endState;
         this.monitor = monitor;
         this.fieldBuilder = fieldBuilder;
-        this.body = body;
+        this.bodyDescBuilder = bodyDescBuilder;
         this.linebuf = new ByteArrayBuffer(64);
         this.lineCount = 0;
         this.endOfHeader = false;
@@ -98,42 +99,46 @@ class MimeEntity implements EntityStateM
             MimeEntityConfig config,
             EntityState startState,
             EntityState endState,
-            MutableBodyDescriptor body) {
+            BodyDescriptorBuilder bodyDescBuilder) {
         this(lineSource, instream, config, startState, endState,
                 config.isStrictParsing() ? DecodeMonitor.STRICT : DecodeMonitor.SILENT,
-                new DefaultFieldBuilder(config.getMaxHeaderLen()), body);
+                new DefaultFieldBuilder(config.getMaxHeaderLen()), 
+                bodyDescBuilder);
     }
 
     MimeEntity(
             LineNumberSource lineSource,
             InputStream instream,
             MimeEntityConfig config,
-            MutableBodyDescriptor body) {
+            BodyDescriptorBuilder bodyDescBuilder) {
         this(lineSource, instream, config,
                 EntityState.T_START_MESSAGE, EntityState.T_END_MESSAGE,
                 config.isStrictParsing() ? DecodeMonitor.STRICT : DecodeMonitor.SILENT,
-                new DefaultFieldBuilder(config.getMaxHeaderLen()), body);
+                new DefaultFieldBuilder(config.getMaxHeaderLen()), 
+                bodyDescBuilder);
     }
 
     MimeEntity(
             LineNumberSource lineSource,
             InputStream instream,
             FieldBuilder fieldBuilder,
-            MutableBodyDescriptor body) {
+            BodyDescriptorBuilder bodyDescBuilder) {
         this(lineSource, instream, new MimeEntityConfig(),
                 EntityState.T_START_MESSAGE, EntityState.T_END_MESSAGE,
                 DecodeMonitor.SILENT,
-                fieldBuilder, body);
+                fieldBuilder, 
+                bodyDescBuilder);
     }
 
     MimeEntity(
             LineNumberSource lineSource,
             InputStream instream,
-            MutableBodyDescriptor body) {
+            BodyDescriptorBuilder bodyDescBuilder) {
         this(lineSource, instream, new MimeEntityConfig(),
                 EntityState.T_START_MESSAGE, EntityState.T_END_MESSAGE,
                 DecodeMonitor.SILENT,
-                new DefaultFieldBuilder(-1), body);
+                new DefaultFieldBuilder(-1), 
+                bodyDescBuilder);
     }
 
     public EntityState getState() {
@@ -259,9 +264,8 @@ class MimeEntity implements EntityStateM
                 if (rawfield.getDelimiterIdx() != rawfield.getName().length()) {
                     monitor(Event.OBSOLETE_HEADER);
                 }
-                Field newfield = body.addField(rawfield);
-                if (newfield != null) field = newfield;
-                else field = rawfield;
+                Field parsedField = bodyDescBuilder.addField(rawfield);
+                field = parsedField != null ? parsedField : rawfield;
                 return true;
             } catch (MimeException e) {
                 monitor(Event.INVALID_HEADER);
@@ -287,10 +291,12 @@ class MimeEntity implements EntityStateM
             state = EntityState.T_START_HEADER;
             break;
         case T_START_HEADER:
+            bodyDescBuilder.reset();
         case T_FIELD:
             state = nextField() ? EntityState.T_FIELD : EntityState.T_END_HEADER;
             break;
         case T_END_HEADER:
+            body = bodyDescBuilder.build();
             String mimeType = body.getMimeType();
             if (recursionMode == RecursionMode.M_FLAT) {
                 state = EntityState.T_BODY;
@@ -421,7 +427,7 @@ class MimeEntity implements EntityStateM
                     endState,
                     monitor,
                     fieldBuilder,
-                    body.newChild());
+                    bodyDescBuilder.newChild());
             mimeentity.setRecursionMode(recursionMode);
             return mimeentity;
         }

Modified: james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/stream/MimeTokenStream.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/stream/MimeTokenStream.java?rev=1140633&r1=1140632&r2=1140633&view=diff
==============================================================================
--- james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/stream/MimeTokenStream.java (original)
+++ james/mime4j/trunk/core/src/main/java/org/apache/james/mime4j/stream/MimeTokenStream.java Tue Jun 28 14:11:40 2011
@@ -75,7 +75,7 @@ public class MimeTokenStream {
     private final MimeEntityConfig config;
     private final DecodeMonitor monitor;
     private final FieldBuilder fieldBuilder;
-    private final MutableBodyDescriptorFactory bodyDescFactory;
+    private final BodyDescriptorBuilder bodyDescBuilder;
     private final LinkedList<EntityStateMachine> entities = new LinkedList<EntityStateMachine>();
     
     private EntityState state = EntityState.T_END_OF_STREAM;
@@ -92,7 +92,7 @@ public class MimeTokenStream {
      * a stream that strictly validates the input.
      */
     public MimeTokenStream() {
-        this(new MimeEntityConfig());
+        this(null);
     }
 
     public MimeTokenStream(final MimeEntityConfig config) {
@@ -101,29 +101,30 @@ public class MimeTokenStream {
         
     public MimeTokenStream(
             final MimeEntityConfig config, 
-            final MutableBodyDescriptorFactory bodyDescFactory) {
-        this(config, null, null, bodyDescFactory);
+            final BodyDescriptorBuilder bodyDescBuilder) {
+        this(config, null, null, bodyDescBuilder);
     }
 
     public MimeTokenStream(
             final MimeEntityConfig config, 
             final DecodeMonitor monitor,
-            final MutableBodyDescriptorFactory bodyDescFactory) {
-        this(config, monitor, null, bodyDescFactory);
+            final BodyDescriptorBuilder bodyDescBuilder) {
+        this(config, monitor, null, bodyDescBuilder);
     }
 
     public MimeTokenStream(
             final MimeEntityConfig config, 
             final DecodeMonitor monitor,
             final FieldBuilder fieldBuilder,
-            final MutableBodyDescriptorFactory bodyDescFactory) {
+            final BodyDescriptorBuilder bodyDescBuilder) {
         super();
-        this.config = config;
+        this.config = config != null ? config : new MimeEntityConfig();
         this.fieldBuilder = fieldBuilder != null ? fieldBuilder : 
-            new DefaultFieldBuilder(config.getMaxHeaderLen());
+            new DefaultFieldBuilder(this.config.getMaxHeaderLen());
         this.monitor = monitor != null ? monitor : 
-            (config.isStrictParsing() ? DecodeMonitor.STRICT : DecodeMonitor.SILENT);
-        this.bodyDescFactory = bodyDescFactory;
+            (this.config.isStrictParsing() ? DecodeMonitor.STRICT : DecodeMonitor.SILENT);
+        this.bodyDescBuilder = bodyDescBuilder != null ? bodyDescBuilder : 
+            new FallbackBodyDescriptorBuilder();
     }
 
     /** Instructs the {@code MimeTokenStream} to parse the given streams contents.
@@ -131,7 +132,7 @@ public class MimeTokenStream {
      * internal state.
      */
     public void parse(InputStream stream) {
-        doParse(stream, newBodyDescriptor(), EntityState.T_START_MESSAGE);
+        doParse(stream, EntityState.T_START_MESSAGE);
     }
 
     /** 
@@ -149,17 +150,16 @@ public class MimeTokenStream {
             throw new IllegalArgumentException("Content type may not be null");
         }
         Field newContentType;
-        MutableBodyDescriptor newBodyDescriptor = newBodyDescriptor();
         try {
             RawField rawContentType = new RawField("Content-Type", contentType);
-            newContentType = newBodyDescriptor.addField(rawContentType);
+            newContentType = bodyDescBuilder.addField(rawContentType);
             if (newContentType == null) newContentType = rawContentType;
         } catch (MimeException ex) {
             // should never happen
             throw new IllegalArgumentException(ex.getMessage());
         }
         
-        doParse(stream, newBodyDescriptor, EntityState.T_END_HEADER);
+        doParse(stream, EntityState.T_END_HEADER);
         try {
             next();
         } catch (IOException e) {
@@ -172,23 +172,7 @@ public class MimeTokenStream {
         return newContentType;
     }
 
-    /**
-     * Creates a new instance of {@link BodyDescriptor}. Subclasses may override
-     * this in order to create body descriptors, that provide more specific
-     * information.
-     */
-    protected MutableBodyDescriptor newBodyDescriptor() {
-        final MutableBodyDescriptor result;
-        if (bodyDescFactory != null) {
-            result = bodyDescFactory.newInstance(monitor);
-        } else {
-            result = new DefaultBodyDescriptor(null, monitor);
-        }
-        return result;
-    }
-
-    public void doParse(InputStream stream,
-            MutableBodyDescriptor newBodyDescriptor, EntityState start) {
+    private void doParse(InputStream stream, EntityState start) {
         LineNumberSource lineSource = null;
         if (config.isCountLineNumbers()) {
             LineNumberInputStream lineInput = new LineNumberInputStream(stream);
@@ -204,7 +188,7 @@ public class MimeTokenStream {
                 EntityState.T_END_MESSAGE,
                 monitor,
                 fieldBuilder,
-                newBodyDescriptor);
+                bodyDescBuilder);
 
         rootentity.setRecursionMode(recursionMode);
         currentStateMachine = rootentity;

Copied: james/mime4j/trunk/core/src/test/java/org/apache/james/mime4j/stream/FallbackBodyDescriptorBuilderTest.java (from r1139766, james/mime4j/trunk/core/src/test/java/org/apache/james/mime4j/stream/BaseTestForBodyDescriptors.java)
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/core/src/test/java/org/apache/james/mime4j/stream/FallbackBodyDescriptorBuilderTest.java?p2=james/mime4j/trunk/core/src/test/java/org/apache/james/mime4j/stream/FallbackBodyDescriptorBuilderTest.java&p1=james/mime4j/trunk/core/src/test/java/org/apache/james/mime4j/stream/BaseTestForBodyDescriptors.java&r1=1139766&r2=1140633&rev=1140633&view=diff
==============================================================================
--- james/mime4j/trunk/core/src/test/java/org/apache/james/mime4j/stream/BaseTestForBodyDescriptors.java (original)
+++ james/mime4j/trunk/core/src/test/java/org/apache/james/mime4j/stream/FallbackBodyDescriptorBuilderTest.java Tue Jun 28 14:11:40 2011
@@ -21,170 +21,146 @@ package org.apache.james.mime4j.stream;
 
 import junit.framework.TestCase;
 
-public abstract class BaseTestForBodyDescriptors extends TestCase {
+public class FallbackBodyDescriptorBuilderTest extends TestCase {
 
-    protected abstract MutableBodyDescriptor newBodyDescriptor();
-
-    protected abstract MutableBodyDescriptor newBodyDescriptor(BodyDescriptor parent);
-    
-    public void testGetParameters() throws Exception {
-        MutableBodyDescriptor bd = null;
-        
-        bd = newBodyDescriptor();
-        bd.addField(new RawField("Content-Type ", "text/plain; charset=ISO-8859-1; "
-                + "boundary=foo; param1=value1; param2=value2; param3=value3"));
-        assertEquals(3, bd.getContentTypeParameters().size());
-        assertEquals("value1", bd.getContentTypeParameters().get("param1"));
-        assertEquals("value2", bd.getContentTypeParameters().get("param2"));
-        assertEquals("value3", bd.getContentTypeParameters().get("param3"));
-        
-        bd = newBodyDescriptor();
-        bd.addField(new RawField("Content-Type ", "text/plain; param1=value1; param2=value2;"
-                     + " param3=value3"));
-        assertEquals(3, bd.getContentTypeParameters().size());
-        assertEquals("value1", bd.getContentTypeParameters().get("param1"));
-        assertEquals("value2", bd.getContentTypeParameters().get("param2"));
-        assertEquals("value3", bd.getContentTypeParameters().get("param3"));
-        
-        bd = newBodyDescriptor();
-        bd.addField(new RawField("Content-Type ", "text/plain; "
-                + "param1= \" value with\tspaces \" ; "
-                + "param2=\"\\\"value4 with escaped \\\" \\\"\";"));
-        assertEquals(2, bd.getContentTypeParameters().size());
-        assertEquals(" value with\tspaces ", bd.getContentTypeParameters().get("param1"));
-        assertEquals("\"value4 with escaped \" \"", bd.getContentTypeParameters().get("param2"));
-    }
-    
     public void testAddField() throws Exception {
-        MutableBodyDescriptor bd = null;
-        
         /*
          * Make sure that only the first Content-Type header added is used.
          */
-        bd = newBodyDescriptor();
-        bd.addField(new RawField("Content-Type ", "text/plain; charset=ISO-8859-1"));
+        BodyDescriptorBuilder builder = new FallbackBodyDescriptorBuilder(); 
+        builder.addField(new RawField("Content-Type ", "text/plain; charset=ISO-8859-1"));
+        BodyDescriptor bd = builder.build();
         assertEquals("text/plain", bd.getMimeType());
         assertEquals("ISO-8859-1", bd.getCharset());
-        bd.addField(new RawField("Content-Type ", "text/html; charset=us-ascii"));
+        builder.addField(new RawField("Content-Type ", "text/html; charset=us-ascii"));
+        bd = builder.build();
         assertEquals("text/plain", bd.getMimeType());
         assertEquals("ISO-8859-1", bd.getCharset());
     }
     
     public void testGetMimeType() throws Exception {
-        MutableBodyDescriptor bd = null;
-        
-        bd = newBodyDescriptor();
-        bd.addField(new RawField("Content-Type ", "text/PLAIN"));
+        BodyDescriptorBuilder builder = new FallbackBodyDescriptorBuilder(); 
+        builder.addField(new RawField("Content-Type ", "text/PLAIN"));
+        BodyDescriptor bd = builder.build();
         assertEquals("text/plain", bd.getMimeType());
         
-        bd = newBodyDescriptor();
-        bd.addField(new RawField("Content-Type ", "text/PLAIN;"));
-        assertEquals("text/plain", bd.getMimeType());
-        
-        bd = newBodyDescriptor();
-        bd.addField(new RawField("content-type", "   TeXt / html   "));
+        builder.reset();
+        builder.addField(new RawField("content-type", "   TeXt / html   "));
+        bd = builder.build();
         assertEquals("text/html", bd.getMimeType());
         
-        bd = newBodyDescriptor();
-        bd.addField(new RawField("CONTENT-TYPE", "   x-app/yada ;  param = yada"));
+        builder.reset();
+        builder.addField(new RawField("CONTENT-TYPE", "   x-app/yada ;  param = yada"));
+        bd = builder.build();
         assertEquals("x-app/yada", bd.getMimeType());
         
-        bd = newBodyDescriptor();
-        bd.addField(new RawField("CONTENT-TYPE", "   yada"));
+        builder.reset();
+        builder.addField(new RawField("CONTENT-TYPE", "   yada"));
+        bd = builder.build();
         assertEquals("text/plain", bd.getMimeType());
         
         /*
          * Make sure that only the first Content-Type header added is used.
          */
-        bd = newBodyDescriptor();
-        bd.addField(new RawField("Content-Type ", "text/plain"));
+        builder.reset();
+        builder.addField(new RawField("Content-Type ", "text/plain"));
+        bd = builder.build();
         assertEquals("text/plain", bd.getMimeType());
-        bd.addField(new RawField("Content-Type ", "text/html"));
+        builder.addField(new RawField("Content-Type ", "text/html"));
+        bd = builder.build();
         assertEquals("text/plain", bd.getMimeType());
         
         /*
          * Implicit mime types.
          */
-        MutableBodyDescriptor child = null;
-        MutableBodyDescriptor parent = null;
-        
-        parent = newBodyDescriptor();
+        BodyDescriptorBuilder parent = new FallbackBodyDescriptorBuilder();
         parent.addField(new RawField("Content-Type", "mutlipart/alternative; boundary=foo"));
-        
-        child = newBodyDescriptor(parent);
-        assertEquals("text/plain", child.getMimeType());
+        BodyDescriptorBuilder child = parent.newChild();
+        bd = child.build();
+        assertEquals("text/plain", bd.getMimeType());
         child.addField(new RawField("Content-Type", " child/type"));
-        assertEquals("child/type", child.getMimeType());
+        bd = child.build();
+        assertEquals("child/type", bd.getMimeType());
         
-        parent = newBodyDescriptor();
+        parent.reset();
         parent.addField(new RawField("Content-Type", "multipart/digest; boundary=foo"));
         
-        child = newBodyDescriptor(parent);
-        assertEquals("message/rfc822", child.getMimeType());
+        child = parent.newChild();
+        bd = child.build();
+        assertEquals("message/rfc822", bd.getMimeType());
         child.addField(new RawField("Content-Type", " child/type"));
-        assertEquals("child/type", child.getMimeType());
+        bd = child.build();
+        assertEquals("child/type", bd.getMimeType());
         
     }
     
     public void testParameters() throws Exception {
-        MutableBodyDescriptor bd = null;
-
+        BodyDescriptorBuilder builder = new FallbackBodyDescriptorBuilder(); 
         /*
          * Test charset.
          */
-        bd = newBodyDescriptor();
+        BodyDescriptor bd = builder.build();
         assertEquals("us-ascii", bd.getCharset());
-        bd.addField(new RawField("Content-Type ", "text/type; charset=ISO-8859-1"));
+        builder.addField(new RawField("Content-Type ", "text/type; charset=ISO-8859-1"));
+        bd = builder.build();
         assertEquals("ISO-8859-1", bd.getCharset());
         
-        bd = newBodyDescriptor();
+        builder.reset();
+        bd = builder.build();
         assertEquals("us-ascii", bd.getCharset());
-        bd.addField(new RawField("Content-Type ", "text/type"));
+        builder.addField(new RawField("Content-Type ", "text/type"));
+        bd = builder.build();
         assertEquals("us-ascii", bd.getCharset());
         
         /*
          * Test boundary.
          */
-        bd = newBodyDescriptor();
-        bd.addField(new RawField("Content-Type", "text/html; boundary=yada yada"));
+        builder.reset();
+        builder.addField(new RawField("Content-Type", "text/html; boundary=yada yada"));
+        bd = builder.build();
         assertNull(bd.getBoundary());
 
-        bd = newBodyDescriptor();
-        bd.addField(new RawField("Content-Type", "multipart/yada; boundary=yada"));
+        builder.reset();
+        builder.addField(new RawField("Content-Type", "multipart/yada; boundary=yada"));
+        bd = builder.build();
         assertEquals("yada", bd.getBoundary());
 
-        bd = newBodyDescriptor();
-        bd.addField(new RawField("Content-Type", "multipart/yada; boUNdarY= \"ya \\\"\\\"\tda \\\"\"; "
+        builder.reset();
+        builder.addField(new RawField("Content-Type", "multipart/yada; boUNdarY= \"ya \\\"\\\"\tda \\\"\"; "
                             + "\tcharset\t =  \"\\\"hepp\\\"  =us\t-ascii\""));
+        bd = builder.build();
         assertEquals("ya \"\"\tda \"", bd.getBoundary());
         assertEquals("\"hepp\"  =us\t-ascii", bd.getCharset());
         
     }
     
     public void testGetContentLength() throws Exception {
-        MutableBodyDescriptor bd = null;
-
-        bd = newBodyDescriptor();
+        BodyDescriptorBuilder builder = new FallbackBodyDescriptorBuilder(); 
+        BodyDescriptor bd = builder.build();
         assertEquals(-1, bd.getContentLength());
 
-        bd.addField(new RawField("Content-Length", "9901"));
+        builder.addField(new RawField("Content-Length", "9901"));
+        bd = builder.build();
         assertEquals(9901, bd.getContentLength());
 
         // only the first content-length counts
-        bd.addField(new RawField("Content-Length", "1239901"));
+        builder.addField(new RawField("Content-Length", "1239901"));
+        bd = builder.build();
         assertEquals(9901, bd.getContentLength());
     }
     
     public void testDoDefaultToUsAsciiWhenUntyped() throws Exception {
-        MutableBodyDescriptor descriptor = newBodyDescriptor();
-        descriptor.addField(new RawField("To", "me@example.org"));
-        assertEquals("us-ascii", descriptor.getCharset());
+        BodyDescriptorBuilder builder = new FallbackBodyDescriptorBuilder(); 
+        builder.addField(new RawField("To", "me@example.org"));
+        BodyDescriptor bd = builder.build();
+        assertEquals("us-ascii", bd.getCharset());
     }
 
     public void testDoNotDefaultToUsAsciiForNonTextTypes() throws Exception {
-        MutableBodyDescriptor descriptor = newBodyDescriptor();
-        descriptor.addField(new RawField("Content-Type", "image/png; name=blob.png"));
-        assertNull(descriptor.getCharset());
+        BodyDescriptorBuilder builder = new FallbackBodyDescriptorBuilder(); 
+        builder.addField(new RawField("Content-Type", "image/png; name=blob.png"));
+        BodyDescriptor bd = builder.build();
+        assertNull(bd.getCharset());
     }
     
 }

Modified: james/mime4j/trunk/core/src/test/java/org/apache/james/mime4j/stream/MimeEntityTest.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/core/src/test/java/org/apache/james/mime4j/stream/MimeEntityTest.java?rev=1140633&r1=1140632&r2=1140633&view=diff
==============================================================================
--- james/mime4j/trunk/core/src/test/java/org/apache/james/mime4j/stream/MimeEntityTest.java (original)
+++ james/mime4j/trunk/core/src/test/java/org/apache/james/mime4j/stream/MimeEntityTest.java Tue Jun 28 14:11:40 2011
@@ -51,7 +51,7 @@ public class MimeEntityTest extends Test
 
         MimeEntity entity = new MimeEntity(
                 lineInput,
-                rawstream, new DefaultBodyDescriptor());
+                rawstream, new FallbackBodyDescriptorBuilder());
 
 
         assertEquals(EntityState.T_START_MESSAGE, entity.getState());
@@ -127,7 +127,7 @@ public class MimeEntityTest extends Test
 
         MimeEntity entity = new MimeEntity(
                 lineInput,
-                rawstream, new DefaultBodyDescriptor());
+                rawstream, new FallbackBodyDescriptorBuilder());
 
 
         assertEquals(EntityState.T_START_MESSAGE, entity.getState());
@@ -211,7 +211,7 @@ public class MimeEntityTest extends Test
 
         MimeEntity entity = new MimeEntity(
                 lineInput,
-                rawstream, new DefaultBodyDescriptor());
+                rawstream, new FallbackBodyDescriptorBuilder());
 
         assertEquals(EntityState.T_START_MESSAGE, entity.getState());
         entity.advance();
@@ -321,7 +321,7 @@ public class MimeEntityTest extends Test
 
         MimeEntity entity = new MimeEntity(
                 lineInput,
-                rawstream, new DefaultBodyDescriptor());
+                rawstream, new FallbackBodyDescriptorBuilder());
 
         entity.setRecursionMode(RecursionMode.M_RAW);
 
@@ -416,7 +416,7 @@ public class MimeEntityTest extends Test
                 lineInput,
                 rawstream,
                 config,
-                new DefaultBodyDescriptor());
+                new FallbackBodyDescriptorBuilder());
 
         assertEquals(EntityState.T_START_MESSAGE, entity.getState());
         entity.advance(); // advances to T_START_HEADER
@@ -468,7 +468,7 @@ public class MimeEntityTest extends Test
                 lineInput,
                 rawstream,
                 config,
-                new DefaultBodyDescriptor());
+                new FallbackBodyDescriptorBuilder());
 
         assertEquals(EntityState.T_START_MESSAGE, entity.getState());
         entity.advance();
@@ -514,7 +514,7 @@ public class MimeEntityTest extends Test
                 lineInput,
                 rawstream,
                 config,
-                new DefaultBodyDescriptor());
+                new FallbackBodyDescriptorBuilder());
 
         assertEquals(EntityState.T_START_MESSAGE, entity.getState());
         entity.advance();
@@ -563,7 +563,7 @@ public class MimeEntityTest extends Test
                 lineInput,
                 rawstream,
                 config,
-                new DefaultBodyDescriptor());
+                new FallbackBodyDescriptorBuilder());
 
         assertEquals(EntityState.T_START_MESSAGE, entity.getState());
         entity.advance();
@@ -609,7 +609,7 @@ public class MimeEntityTest extends Test
                 lineInput,
                 rawstream,
                 config,
-                new DefaultBodyDescriptor());
+                new FallbackBodyDescriptorBuilder());
 
         assertEquals(EntityState.T_START_MESSAGE, entity.getState());
         entity.advance();
@@ -666,7 +666,7 @@ public class MimeEntityTest extends Test
 
         MimeEntity entity = new MimeEntity(
                 lineInput,
-                rawstream, fieldBuilder, new DefaultBodyDescriptor());
+                rawstream, fieldBuilder, new FallbackBodyDescriptorBuilder());
 
 
         assertEquals(EntityState.T_START_MESSAGE, entity.getState());

Added: james/mime4j/trunk/dom/src/main/java/org/apache/james/mime4j/message/DefaultBodyDescriptorBuilder.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/dom/src/main/java/org/apache/james/mime4j/message/DefaultBodyDescriptorBuilder.java?rev=1140633&view=auto
==============================================================================
--- james/mime4j/trunk/dom/src/main/java/org/apache/james/mime4j/message/DefaultBodyDescriptorBuilder.java (added)
+++ james/mime4j/trunk/dom/src/main/java/org/apache/james/mime4j/message/DefaultBodyDescriptorBuilder.java Tue Jun 28 14:11:40 2011
@@ -0,0 +1,149 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.mime4j.message;
+
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import org.apache.james.mime4j.MimeException;
+import org.apache.james.mime4j.codec.DecodeMonitor;
+import org.apache.james.mime4j.dom.FieldParser;
+import org.apache.james.mime4j.dom.field.ContentTypeField;
+import org.apache.james.mime4j.dom.field.FieldName;
+import org.apache.james.mime4j.dom.field.ParsedField;
+import org.apache.james.mime4j.field.DefaultFieldParser;
+import org.apache.james.mime4j.stream.BodyDescriptor;
+import org.apache.james.mime4j.stream.BodyDescriptorBuilder;
+import org.apache.james.mime4j.stream.Field;
+import org.apache.james.mime4j.stream.RawField;
+import org.apache.james.mime4j.util.MimeUtil;
+
+public class DefaultBodyDescriptorBuilder implements BodyDescriptorBuilder {
+
+    private static final String CONTENT_TYPE = FieldName.CONTENT_TYPE.toLowerCase(Locale.US);
+
+    private static final String US_ASCII = "us-ascii";
+    private static final String SUB_TYPE_EMAIL = "rfc822";
+    private static final String MEDIA_TYPE_TEXT = "text";
+    private static final String MEDIA_TYPE_MESSAGE = "message";
+    private static final String EMAIL_MESSAGE_MIME_TYPE = MEDIA_TYPE_MESSAGE + "/" + SUB_TYPE_EMAIL;
+    private static final String DEFAULT_SUB_TYPE = "plain";
+    private static final String DEFAULT_MEDIA_TYPE = MEDIA_TYPE_TEXT;
+    private static final String DEFAULT_MIME_TYPE = DEFAULT_MEDIA_TYPE + "/" + DEFAULT_SUB_TYPE;
+
+    private final String parentMimeType;
+    private final DecodeMonitor monitor;
+    private final FieldParser<? extends ParsedField> fieldParser;
+    private final Map<String, ParsedField> fields;
+
+    /**
+     * Creates a new root <code>BodyDescriptor</code> instance.
+     */
+    public DefaultBodyDescriptorBuilder() {
+        this(null);
+    }
+
+    public DefaultBodyDescriptorBuilder(final String parentMimeType) {
+        this(parentMimeType, null, null);
+    }
+
+    /**
+     * Creates a new <code>BodyDescriptor</code> instance.
+     *
+     * @param parent the descriptor of the parent or <code>null</code> if this
+     *        is the root descriptor.
+     */
+    public DefaultBodyDescriptorBuilder(
+            final String parentMimeType,
+            final FieldParser<? extends ParsedField> fieldParser,
+            final DecodeMonitor monitor) {
+        super();
+        this.parentMimeType = parentMimeType;
+        this.fieldParser = fieldParser != null ? fieldParser : DefaultFieldParser.getParser();
+        this.monitor = monitor != null ? monitor : DecodeMonitor.SILENT;
+        this.fields = new HashMap<String, ParsedField>();
+    }
+
+    public void reset() {
+        fields.clear();
+    }
+
+    public Field addField(final RawField rawfield) throws MimeException {
+        ParsedField field = fieldParser.parse(rawfield, monitor);
+        String name = field.getName().toLowerCase(Locale.US);
+        if (!fields.containsKey(name)) {
+            fields.put(name, field);
+        }
+        return field;
+    }
+
+    public BodyDescriptor build() {
+        String actualMimeType = null;
+        String actualMediaType = null;
+        String actualSubType = null;
+        String actualCharset = null;
+        String actualBoundary = null;
+        ContentTypeField contentTypeField = (ContentTypeField) fields.get(CONTENT_TYPE);
+        if (contentTypeField != null) {
+            actualMimeType = contentTypeField.getMimeType();
+            actualMediaType = contentTypeField.getMediaType();
+            actualSubType = contentTypeField.getSubType();
+            actualCharset = contentTypeField.getCharset();
+            actualBoundary = contentTypeField.getBoundary();
+        }
+        if (actualMimeType == null) {
+            if (MimeUtil.isSameMimeType("multipart/digest", parentMimeType)) {
+                actualMimeType = EMAIL_MESSAGE_MIME_TYPE;
+                actualMediaType = MEDIA_TYPE_MESSAGE;
+                actualSubType = SUB_TYPE_EMAIL;
+            } else {
+                actualMimeType = DEFAULT_MIME_TYPE;
+                actualMediaType = DEFAULT_MEDIA_TYPE;
+                actualSubType = DEFAULT_SUB_TYPE;
+            }
+        }
+        if (actualCharset == null && MEDIA_TYPE_TEXT.equals(actualMediaType)) {
+            actualCharset = US_ASCII;
+        }
+        if (!MimeUtil.isMultipart(actualMimeType)) {
+            actualBoundary = null;
+        }
+        return new MaximalBodyDescriptor(
+                actualMimeType, actualMediaType, actualSubType, actualBoundary, actualCharset,
+                fields);
+    }
+
+    public BodyDescriptorBuilder newChild() {
+        String actualMimeType;
+        ContentTypeField contentTypeField = (ContentTypeField) fields.get(CONTENT_TYPE);
+        if (contentTypeField != null) {
+            actualMimeType = contentTypeField.getMimeType();
+        } else {
+            if (MimeUtil.isSameMimeType("multipart/digest", parentMimeType)) {
+                actualMimeType = EMAIL_MESSAGE_MIME_TYPE;
+            } else {
+                actualMimeType = DEFAULT_MIME_TYPE;
+            }
+        }
+        return new DefaultBodyDescriptorBuilder(actualMimeType, fieldParser, monitor);
+    }
+
+}

Propchange: james/mime4j/trunk/dom/src/main/java/org/apache/james/mime4j/message/DefaultBodyDescriptorBuilder.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: james/mime4j/trunk/dom/src/main/java/org/apache/james/mime4j/message/DefaultBodyDescriptorBuilder.java
------------------------------------------------------------------------------
    svn:keywords = Date Revision

Propchange: james/mime4j/trunk/dom/src/main/java/org/apache/james/mime4j/message/DefaultBodyDescriptorBuilder.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: james/mime4j/trunk/dom/src/main/java/org/apache/james/mime4j/message/DefaultMessageBuilder.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/dom/src/main/java/org/apache/james/mime4j/message/DefaultMessageBuilder.java?rev=1140633&r1=1140632&r2=1140633&view=diff
==============================================================================
--- james/mime4j/trunk/dom/src/main/java/org/apache/james/mime4j/message/DefaultMessageBuilder.java (original)
+++ james/mime4j/trunk/dom/src/main/java/org/apache/james/mime4j/message/DefaultMessageBuilder.java Tue Jun 28 14:11:40 2011
@@ -39,9 +39,9 @@ import org.apache.james.mime4j.field.Def
 import org.apache.james.mime4j.field.LenientFieldParser;
 import org.apache.james.mime4j.parser.AbstractContentHandler;
 import org.apache.james.mime4j.parser.MimeStreamParser;
+import org.apache.james.mime4j.stream.BodyDescriptorBuilder;
 import org.apache.james.mime4j.stream.Field;
 import org.apache.james.mime4j.stream.MimeEntityConfig;
-import org.apache.james.mime4j.stream.MutableBodyDescriptorFactory;
 
 /**
  * Utility class for copying message and parsing message elements.
@@ -51,7 +51,7 @@ public class DefaultMessageBuilder imple
     private FieldParser<? extends ParsedField> fieldParser = null;
     private BodyFactory bodyFactory = null;
     private MimeEntityConfig config = null;
-    private MutableBodyDescriptorFactory bodyDescFactory = null;
+    private BodyDescriptorBuilder bodyDescBuilder = null;
     private boolean contentDecoding = true;
     private boolean flatMode = false;
     private DecodeMonitor monitor = null;
@@ -72,9 +72,8 @@ public class DefaultMessageBuilder imple
         this.config = config;
     }
 
-    public void setMutableBodyDescriptorFactory(
-            final MutableBodyDescriptorFactory bodyDescFactory) {
-        this.bodyDescFactory  = bodyDescFactory;
+    public void setBodyDescriptorBuilder(final BodyDescriptorBuilder bodyDescBuilder) {
+        this.bodyDescBuilder  = bodyDescBuilder;
     }
 
     public void setDecodeMonitor(final DecodeMonitor monitor) {
@@ -295,12 +294,11 @@ public class DefaultMessageBuilder imple
             boolean strict = cfg.isStrictParsing();
             DecodeMonitor mon = monitor != null ? monitor : 
                 strict ? DecodeMonitor.STRICT : DecodeMonitor.SILENT;
-            FieldParser<? extends ParsedField> fp = fieldParser != null ? fieldParser : 
-                strict ? DefaultFieldParser.getParser() : LenientFieldParser.getParser();
-            MutableBodyDescriptorFactory bdf = bodyDescFactory != null ? bodyDescFactory :
-                new MinimalBodyDescriptorFactory(fp);
+            BodyDescriptorBuilder bdb = bodyDescBuilder != null ? bodyDescBuilder :
+                new DefaultBodyDescriptorBuilder(null, fieldParser != null ? fieldParser : 
+                    strict ? DefaultFieldParser.getParser() : LenientFieldParser.getParser(), mon);
             BodyFactory bf = bodyFactory != null ? bodyFactory : new BasicBodyFactory();
-            MimeStreamParser parser = new MimeStreamParser(cfg, mon, bdf);
+            MimeStreamParser parser = new MimeStreamParser(cfg, mon, bdb);
             // EntityBuilder expect the parser will send ParserFields for the well known fields
             // It will throw exceptions, otherwise.
             parser.setContentHandler(new EntityBuilder(message, bf));

Modified: james/mime4j/trunk/dom/src/main/java/org/apache/james/mime4j/message/MaximalBodyDescriptor.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/dom/src/main/java/org/apache/james/mime4j/message/MaximalBodyDescriptor.java?rev=1140633&r1=1140632&r2=1140633&view=diff
==============================================================================
--- james/mime4j/trunk/dom/src/main/java/org/apache/james/mime4j/message/MaximalBodyDescriptor.java (original)
+++ james/mime4j/trunk/dom/src/main/java/org/apache/james/mime4j/message/MaximalBodyDescriptor.java Tue Jun 28 14:11:40 2011
@@ -21,115 +21,106 @@ package org.apache.james.mime4j.message;
 
 import java.util.Collections;
 import java.util.Date;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 
-import org.apache.james.mime4j.MimeException;
-import org.apache.james.mime4j.codec.DecodeMonitor;
-import org.apache.james.mime4j.dom.FieldParser;
 import org.apache.james.mime4j.dom.field.ContentDescriptionField;
 import org.apache.james.mime4j.dom.field.ContentDispositionField;
 import org.apache.james.mime4j.dom.field.ContentIdField;
 import org.apache.james.mime4j.dom.field.ContentLanguageField;
+import org.apache.james.mime4j.dom.field.ContentLengthField;
 import org.apache.james.mime4j.dom.field.ContentLocationField;
 import org.apache.james.mime4j.dom.field.ContentMD5Field;
+import org.apache.james.mime4j.dom.field.ContentTransferEncodingField;
+import org.apache.james.mime4j.dom.field.ContentTypeField;
 import org.apache.james.mime4j.dom.field.FieldName;
 import org.apache.james.mime4j.dom.field.MimeVersionField;
 import org.apache.james.mime4j.dom.field.ParsedField;
 import org.apache.james.mime4j.field.MimeVersionFieldImpl;
 import org.apache.james.mime4j.stream.BodyDescriptor;
-import org.apache.james.mime4j.stream.Field;
-import org.apache.james.mime4j.stream.MutableBodyDescriptor;
-import org.apache.james.mime4j.stream.RawField;
+import org.apache.james.mime4j.util.MimeUtil;
 
 /**
  * Parses and stores values for standard MIME header values.
  * 
  */
-public class MaximalBodyDescriptor extends MinimalBodyDescriptor {
+public class MaximalBodyDescriptor implements BodyDescriptor {
 
-    private MimeVersionField mimeVersionField;
-    private ContentIdField contentIdField;
-    private ContentDescriptionField contentDescriptionField;
-    private ContentDispositionField contentDispositionField;
-    private ContentLanguageField contentLanguageField;
-    private ContentLocationField contentLocationField;
-    private ContentMD5Field contentMD5Field;
-    
-    protected MaximalBodyDescriptor() {
-        this(null);
+    private static final String CONTENT_TYPE = FieldName.CONTENT_TYPE.toLowerCase(Locale.US);
+    private static final String CONTENT_LENGTH = FieldName.CONTENT_LENGTH.toLowerCase(Locale.US);
+    private static final String CONTENT_TRANSFER_ENCODING = FieldName.CONTENT_TRANSFER_ENCODING.toLowerCase(Locale.US);
+    private static final String CONTENT_DISPOSITION = FieldName.CONTENT_DISPOSITION.toLowerCase(Locale.US);
+    private static final String CONTENT_ID = FieldName.CONTENT_ID.toLowerCase(Locale.US);
+    private static final String CONTENT_MD5 = FieldName.CONTENT_MD5.toLowerCase(Locale.US);
+    private static final String CONTENT_DESCRIPTION = FieldName.CONTENT_DESCRIPTION.toLowerCase(Locale.US);
+    private static final String CONTENT_LANGUAGE = FieldName.CONTENT_LANGUAGE.toLowerCase(Locale.US);
+    private static final String CONTENT_LOCATION = FieldName.CONTENT_LOCATION.toLowerCase(Locale.US);
+    private static final String MIME_VERSION = FieldName.MIME_VERSION.toLowerCase(Locale.US);
+    
+    private final String mediaType;
+    private final String subType;
+    private final String mimeType;
+    private final String boundary;
+    private final String charset;
+    private final Map<String, ParsedField> fields;
+    
+    MaximalBodyDescriptor(
+            final String mimeType,
+            final String mediaType,
+            final String subType,
+            final String boundary,
+            final String charset,
+            final Map<String, ParsedField> fields) {
+        super();
+        this.mimeType = mimeType;
+        this.mediaType = mediaType;
+        this.subType = subType;
+        this.boundary = boundary;
+        this.charset = charset;
+        this.fields = fields != null ? new HashMap<String, ParsedField>(fields) : 
+            Collections.<String, ParsedField>emptyMap();
+    }
+    
+    public String getMimeType() {
+        return mimeType;
+    }
+    
+    public String getBoundary() {
+        return boundary;
+    }
+    
+    public String getCharset() {
+        return charset;
+    }
+    
+    public String getMediaType() {
+        return mediaType;
+    }
+
+    public String getSubType() {
+        return subType;
+    }
+
+    public Map<String, String> getContentTypeParameters() {
+        ContentTypeField contentTypeField = (ContentTypeField) fields.get(CONTENT_TYPE);
+        return contentTypeField != null ? contentTypeField.getParameters() : 
+            Collections.<String, String>emptyMap();
     }
     
-    protected MaximalBodyDescriptor(final BodyDescriptor parent) {
-        this(parent, null, null);
-    }
-
-    public MaximalBodyDescriptor(final BodyDescriptor parent, final FieldParser<?> fieldParser, final DecodeMonitor monitor) {
-        super(parent, fieldParser, monitor);
-    }
-
-    @Override
-    public MutableBodyDescriptor newChild() {
-        return new MaximalBodyDescriptor(this, getFieldParser(), getDecodeMonitor());
-    }
-
-    @Override
-    public Field addField(RawField field) throws MimeException {
-        String name = field.getName();
-        if (name.equalsIgnoreCase(FieldName.MIME_VERSION) && mimeVersionField == null) {
-            return parseMimeVersion(field);
-        } else if (name.equalsIgnoreCase(FieldName.CONTENT_ID) && contentIdField == null) {
-            return parseContentId(field);
-        } else if (name.equalsIgnoreCase(FieldName.CONTENT_DESCRIPTION) && contentDescriptionField == null) {
-            return parseContentDescription(field);
-        } else if (name.equalsIgnoreCase(FieldName.CONTENT_DISPOSITION) && contentDispositionField == null) {
-            return parseContentDisposition(field);
-        } else if (name.equalsIgnoreCase(FieldName.CONTENT_LANGUAGE) && contentLanguageField == null) {
-            return parseLanguage(field);
-        } else if (name.equalsIgnoreCase(FieldName.CONTENT_LOCATION) && contentLocationField == null) {
-            return parseLocation(field);
-        } else if (name.equalsIgnoreCase(FieldName.CONTENT_MD5) && contentMD5Field == null) {
-            return parseMD5(field);
-        } else {
-            return super.addField(field);
-        }
-    }
-    
-    private ContentMD5Field parseMD5(final Field field) {
-        contentMD5Field = (ContentMD5Field) getFieldParser().parse(field, getDecodeMonitor());
-        return contentMD5Field;
-    }
-
-    private ContentLocationField parseLocation(final Field field) {
-        contentLocationField = (ContentLocationField) getFieldParser().parse(field, getDecodeMonitor());
-        return contentLocationField;
+    public String getTransferEncoding() {
+        ContentTransferEncodingField contentTransferEncodingField = 
+            (ContentTransferEncodingField) fields.get(CONTENT_TRANSFER_ENCODING);
+        return contentTransferEncodingField != null ? contentTransferEncodingField.getEncoding() : 
+            MimeUtil.ENC_7BIT;
     }
     
-    private ParsedField parseLanguage(final Field field) {
-        contentLanguageField = (ContentLanguageField) getFieldParser().parse(field, getDecodeMonitor());
-        return contentLanguageField;
+    public long getContentLength() {
+        ContentLengthField contentLengthField = (ContentLengthField) fields.get(CONTENT_LENGTH);
+        return contentLengthField != null ? contentLengthField.getContentLength() : -1;
     }
 
-    private ParsedField parseContentDisposition(final Field field) throws MimeException {
-        contentDispositionField = (ContentDispositionField) getFieldParser().parse(field, getDecodeMonitor());
-        return contentDispositionField;
-    }
-
-    private ParsedField parseContentDescription(final Field field) {
-        contentDescriptionField = (ContentDescriptionField) getFieldParser().parse(field, getDecodeMonitor());
-        return contentDescriptionField;
-    }
-
-    private ContentIdField parseContentId(final Field field) {
-        contentIdField = (ContentIdField) getFieldParser().parse(field, getDecodeMonitor());
-        return contentIdField;
-    }
-
-    private MimeVersionField parseMimeVersion(final Field field) {
-        mimeVersionField = (MimeVersionField) getFieldParser().parse(field, getDecodeMonitor());
-        return mimeVersionField;
-    }
-    
     /**
      * Gets the MIME major version
      * as specified by the <code>MIME-Version</code>
@@ -138,6 +129,7 @@ public class MaximalBodyDescriptor exten
      * @return positive integer
      */
     public int getMimeMajorVersion() {
+        MimeVersionField mimeVersionField = (MimeVersionField) fields.get(MIME_VERSION);
         return mimeVersionField != null ? mimeVersionField.getMajorVersion() : 
             MimeVersionFieldImpl.DEFAULT_MAJOR_VERSION;
     }
@@ -150,6 +142,7 @@ public class MaximalBodyDescriptor exten
      * @return positive integer
      */
     public int getMimeMinorVersion() {
+        MimeVersionField mimeVersionField = (MimeVersionField) fields.get(MIME_VERSION);
         return mimeVersionField != null ? mimeVersionField.getMinorVersion() : 
             MimeVersionFieldImpl.DEFAULT_MINOR_VERSION;
     }
@@ -162,6 +155,8 @@ public class MaximalBodyDescriptor exten
      * null otherwise
      */
     public String getContentDescription() {
+        ContentDescriptionField contentDescriptionField = 
+            (ContentDescriptionField) fields.get(CONTENT_DESCRIPTION);
         return contentDescriptionField != null ? contentDescriptionField.getDescription() : null;
     }
     
@@ -172,6 +167,7 @@ public class MaximalBodyDescriptor exten
      * null otherwise
      */
     public String getContentId() {
+        ContentIdField contentIdField = (ContentIdField) fields.get(CONTENT_ID);
         return contentIdField != null ? contentIdField.getId() : null;
     }
     
@@ -183,6 +179,8 @@ public class MaximalBodyDescriptor exten
      * or null when this has not been set
      */
     public String getContentDispositionType() {
+        ContentDispositionField contentDispositionField = 
+            (ContentDispositionField) fields.get(CONTENT_DISPOSITION);
         return contentDispositionField != null ? contentDispositionField.getDispositionType() : null;
     }
     
@@ -193,6 +191,8 @@ public class MaximalBodyDescriptor exten
      * not null
      */
     public Map<String, String> getContentDispositionParameters() {
+        ContentDispositionField contentDispositionField = 
+            (ContentDispositionField) fields.get(CONTENT_DISPOSITION);
         return contentDispositionField != null ? contentDispositionField.getParameters() : 
             Collections.<String, String>emptyMap();
     }
@@ -204,6 +204,8 @@ public class MaximalBodyDescriptor exten
      * or null when it is not present
      */
     public String getContentDispositionFilename() {
+        ContentDispositionField contentDispositionField = 
+            (ContentDispositionField) fields.get(CONTENT_DISPOSITION);
         return contentDispositionField != null ? contentDispositionField.getFilename() : null;
     }
     
@@ -214,6 +216,8 @@ public class MaximalBodyDescriptor exten
      * or null when this is not present
      */
     public Date getContentDispositionModificationDate() {
+        ContentDispositionField contentDispositionField = 
+            (ContentDispositionField) fields.get(CONTENT_DISPOSITION);
         return contentDispositionField != null ? contentDispositionField.getModificationDate() : null;
     }
     
@@ -224,6 +228,8 @@ public class MaximalBodyDescriptor exten
      * or null when this is not present
      */
     public Date getContentDispositionCreationDate() {
+        ContentDispositionField contentDispositionField = 
+            (ContentDispositionField) fields.get(CONTENT_DISPOSITION);
         return contentDispositionField != null ? contentDispositionField.getCreationDate() : null;
     }
     
@@ -234,6 +240,8 @@ public class MaximalBodyDescriptor exten
      * or null when this is not present
      */
     public Date getContentDispositionReadDate() {
+        ContentDispositionField contentDispositionField = 
+            (ContentDispositionField) fields.get(CONTENT_DISPOSITION);
         return contentDispositionField != null ? contentDispositionField.getReadDate() : null;
     }
     
@@ -244,6 +252,8 @@ public class MaximalBodyDescriptor exten
      * or -1 if this size has not been set
      */
     public long getContentDispositionSize() {
+        ContentDispositionField contentDispositionField = 
+            (ContentDispositionField) fields.get(CONTENT_DISPOSITION);
         return contentDispositionField != null ? contentDispositionField.getSize() : -1;
     }
     
@@ -256,6 +266,8 @@ public class MaximalBodyDescriptor exten
      * or null if no header exists
      */
     public List<String> getContentLanguage() {
+        ContentLanguageField contentLanguageField = 
+            (ContentLanguageField) fields.get(CONTENT_LANGUAGE);
         return contentLanguageField != null ? contentLanguageField.getLanguages() : 
             Collections.<String>emptyList();
     }
@@ -267,6 +279,8 @@ public class MaximalBodyDescriptor exten
      * or null if no header exists
      */
     public String getContentLocation() {
+        ContentLocationField contentLocationField = 
+            (ContentLocationField) fields.get(CONTENT_LOCATION);
         return contentLocationField != null ? contentLocationField.getLocation() : null;
     }
     
@@ -278,7 +292,25 @@ public class MaximalBodyDescriptor exten
      * or null if no header exists
      */
     public String getContentMD5Raw() {
+        ContentMD5Field contentMD5Field = (ContentMD5Field) fields.get(CONTENT_MD5);
         return contentMD5Field != null ? contentMD5Field.getMD5Raw() : null;
     }
     
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("[mimeType=");
+        sb.append(mimeType);
+        sb.append(", mediaType=");
+        sb.append(mediaType);
+        sb.append(", subType=");
+        sb.append(subType);
+        sb.append(", boundary=");
+        sb.append(boundary);
+        sb.append(", charset=");
+        sb.append(charset);
+        sb.append("]");
+        return sb.toString();
+    }
+
 } 

Modified: james/mime4j/trunk/dom/src/main/java/org/apache/james/mime4j/message/MessageServiceFactoryImpl.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/dom/src/main/java/org/apache/james/mime4j/message/MessageServiceFactoryImpl.java?rev=1140633&r1=1140632&r2=1140633&view=diff
==============================================================================
--- james/mime4j/trunk/dom/src/main/java/org/apache/james/mime4j/message/MessageServiceFactoryImpl.java (original)
+++ james/mime4j/trunk/dom/src/main/java/org/apache/james/mime4j/message/MessageServiceFactoryImpl.java Tue Jun 28 14:11:40 2011
@@ -21,8 +21,8 @@ package org.apache.james.mime4j.message;
 import org.apache.james.mime4j.dom.MessageBuilder;
 import org.apache.james.mime4j.dom.MessageServiceFactory;
 import org.apache.james.mime4j.dom.MessageWriter;
+import org.apache.james.mime4j.stream.BodyDescriptorBuilder;
 import org.apache.james.mime4j.stream.MimeEntityConfig;
-import org.apache.james.mime4j.stream.MutableBodyDescriptorFactory;
 
 /**
  * The default MessageBuilderFactory bundled with Mime4j.
@@ -34,7 +34,7 @@ public class MessageServiceFactoryImpl e
 
     private BodyFactory bodyFactory = null;
     private MimeEntityConfig mimeEntityConfig = null;
-    private MutableBodyDescriptorFactory mutableBodyDescriptorFactory = null;
+    private BodyDescriptorBuilder bodyDescriptorBuilder = null;
     private Boolean flatMode = null;
     private Boolean contentDecoding = null;
 
@@ -43,7 +43,7 @@ public class MessageServiceFactoryImpl e
         DefaultMessageBuilder m = new DefaultMessageBuilder();
         if (bodyFactory != null) m.setBodyFactory(bodyFactory);
         if (mimeEntityConfig != null) m.setMimeEntityConfig(mimeEntityConfig);
-        if (mutableBodyDescriptorFactory != null) m.setMutableBodyDescriptorFactory(mutableBodyDescriptorFactory);
+        if (bodyDescriptorBuilder != null) m.setBodyDescriptorBuilder(bodyDescriptorBuilder);
         if (flatMode != null) m.setFlatMode(flatMode.booleanValue());
         if (contentDecoding != null) m.setContentDecoding(contentDecoding.booleanValue());
         return m;
@@ -68,8 +68,8 @@ public class MessageServiceFactoryImpl e
                 return;
             } else throw new IllegalArgumentException("Unsupported attribute value type for "+name+", expected a MimeEntityConfig");
         } else if ("MutableBodyDescriptorFactory".equals(name)) {
-            if (value instanceof MutableBodyDescriptorFactory) {
-                this.mutableBodyDescriptorFactory  = (MutableBodyDescriptorFactory) value;
+            if (value instanceof BodyDescriptorBuilder) {
+                this.bodyDescriptorBuilder  = (BodyDescriptorBuilder) value;
                 return;
             } else throw new IllegalArgumentException("Unsupported attribute value type for "+name+", expected a MutableBodyDescriptorFactory");
         } else if ("FlatMode".equals(name)) {

Modified: james/mime4j/trunk/dom/src/test/java/org/apache/james/mime4j/message/MaximalBodyDescriptorTest.java
URL: http://svn.apache.org/viewvc/james/mime4j/trunk/dom/src/test/java/org/apache/james/mime4j/message/MaximalBodyDescriptorTest.java?rev=1140633&r1=1140632&r2=1140633&view=diff
==============================================================================
--- james/mime4j/trunk/dom/src/test/java/org/apache/james/mime4j/message/MaximalBodyDescriptorTest.java (original)
+++ james/mime4j/trunk/dom/src/test/java/org/apache/james/mime4j/message/MaximalBodyDescriptorTest.java Tue Jun 28 14:11:40 2011
@@ -23,15 +23,17 @@ import java.io.ByteArrayInputStream;
 import java.text.SimpleDateFormat;
 import java.util.TimeZone;
 
+import junit.framework.TestCase;
+
 import org.apache.james.mime4j.ExampleMail;
-import org.apache.james.mime4j.stream.BaseTestForBodyDescriptors;
 import org.apache.james.mime4j.stream.BodyDescriptor;
+import org.apache.james.mime4j.stream.BodyDescriptorBuilder;
 import org.apache.james.mime4j.stream.EntityState;
 import org.apache.james.mime4j.stream.MimeEntityConfig;
 import org.apache.james.mime4j.stream.MimeTokenStream;
-import org.apache.james.mime4j.stream.MutableBodyDescriptor;
+import org.apache.james.mime4j.stream.RawField;
 
-public class MaximalBodyDescriptorTest extends BaseTestForBodyDescriptors {
+public class MaximalBodyDescriptorTest extends TestCase {
 
     MimeTokenStream parser;
     
@@ -40,13 +42,147 @@ public class MaximalBodyDescriptorTest e
         super.setUp();
         MimeEntityConfig config = new MimeEntityConfig();
         config.setStrictParsing(true);
-        parser = new MimeTokenStream(config, 
-                new MaximalBodyDescriptorFactory(null));
+        parser = new MimeTokenStream(config, new DefaultBodyDescriptorBuilder(null));
     }
 
-    @Override
-    protected void tearDown() throws Exception {
-        super.tearDown();
+    public void testAddField() throws Exception {
+        /*
+         * Make sure that only the first Content-Type header added is used.
+         */
+        BodyDescriptorBuilder builder = new DefaultBodyDescriptorBuilder(); 
+        builder.addField(new RawField("Content-Type ", "text/plain; charset=ISO-8859-1"));
+        BodyDescriptor bd = builder.build();
+        assertEquals("text/plain", bd.getMimeType());
+        assertEquals("ISO-8859-1", bd.getCharset());
+        builder.addField(new RawField("Content-Type ", "text/html; charset=us-ascii"));
+        bd = builder.build();
+        assertEquals("text/plain", bd.getMimeType());
+        assertEquals("ISO-8859-1", bd.getCharset());
+    }
+    
+    public void testGetMimeType() throws Exception {
+        BodyDescriptorBuilder builder = new DefaultBodyDescriptorBuilder(); 
+        builder.addField(new RawField("Content-Type ", "text/PLAIN"));
+        BodyDescriptor bd = builder.build();
+        assertEquals("text/plain", bd.getMimeType());
+        
+        builder.reset();
+        builder.addField(new RawField("content-type", "   TeXt / html   "));
+        bd = builder.build();
+        assertEquals("text/html", bd.getMimeType());
+        
+        builder.reset();
+        builder.addField(new RawField("CONTENT-TYPE", "   x-app/yada ;  param = yada"));
+        bd = builder.build();
+        assertEquals("x-app/yada", bd.getMimeType());
+        
+        builder.reset();
+        builder.addField(new RawField("CONTENT-TYPE", "   yada"));
+        bd = builder.build();
+        assertEquals("text/plain", bd.getMimeType());
+        
+        /*
+         * Make sure that only the first Content-Type header added is used.
+         */
+        builder.reset();
+        builder.addField(new RawField("Content-Type ", "text/plain"));
+        bd = builder.build();
+        assertEquals("text/plain", bd.getMimeType());
+        builder.addField(new RawField("Content-Type ", "text/html"));
+        bd = builder.build();
+        assertEquals("text/plain", bd.getMimeType());
+        
+        /*
+         * Implicit mime types.
+         */
+        BodyDescriptorBuilder parent = new DefaultBodyDescriptorBuilder();
+        parent.addField(new RawField("Content-Type", "mutlipart/alternative; boundary=foo"));
+        BodyDescriptorBuilder child = parent.newChild();
+        bd = child.build();
+        assertEquals("text/plain", bd.getMimeType());
+        child.addField(new RawField("Content-Type", " child/type"));
+        bd = child.build();
+        assertEquals("child/type", bd.getMimeType());
+        
+        parent.reset();
+        parent.addField(new RawField("Content-Type", "multipart/digest; boundary=foo"));
+        
+        child = parent.newChild();
+        bd = child.build();
+        assertEquals("message/rfc822", bd.getMimeType());
+        child.addField(new RawField("Content-Type", " child/type"));
+        bd = child.build();
+        assertEquals("child/type", bd.getMimeType());
+        
+    }
+    
+    public void testParameters() throws Exception {
+        BodyDescriptorBuilder builder = new DefaultBodyDescriptorBuilder(); 
+        /*
+         * Test charset.
+         */
+        BodyDescriptor bd = builder.build();
+        assertEquals("us-ascii", bd.getCharset());
+        builder.addField(new RawField("Content-Type ", "text/type; charset=ISO-8859-1"));
+        bd = builder.build();
+        assertEquals("ISO-8859-1", bd.getCharset());
+        
+        builder.reset();
+        bd = builder.build();
+        assertEquals("us-ascii", bd.getCharset());
+        builder.addField(new RawField("Content-Type ", "text/type"));
+        bd = builder.build();
+        assertEquals("us-ascii", bd.getCharset());
+        
+        /*
+         * Test boundary.
+         */
+        builder.reset();
+        builder.addField(new RawField("Content-Type", "text/html; boundary=yada yada"));
+        bd = builder.build();
+        assertNull(bd.getBoundary());
+
+        builder.reset();
+        builder.addField(new RawField("Content-Type", "multipart/yada; boundary=yada"));
+        bd = builder.build();
+        assertEquals("yada", bd.getBoundary());
+
+        builder.reset();
+        builder.addField(new RawField("Content-Type", "multipart/yada; boUNdarY= \"ya \\\"\\\"\tda \\\"\"; "
+                            + "\tcharset\t =  \"\\\"hepp\\\"  =us\t-ascii\""));
+        bd = builder.build();
+        assertEquals("ya \"\"\tda \"", bd.getBoundary());
+        assertEquals("\"hepp\"  =us\t-ascii", bd.getCharset());
+        
+    }
+    
+    public void testGetContentLength() throws Exception {
+        BodyDescriptorBuilder builder = new DefaultBodyDescriptorBuilder(); 
+        BodyDescriptor bd = builder.build();
+        assertEquals(-1, bd.getContentLength());
+
+        builder.addField(new RawField("Content-Length", "9901"));
+        bd = builder.build();
+        assertEquals(9901, bd.getContentLength());
+
+        // only the first content-length counts
+        builder.addField(new RawField("Content-Length", "1239901"));
+        bd = builder.build();
+        assertEquals(9901, bd.getContentLength());
+    }
+    
+    public void testDoDefaultToUsAsciiWhenUntyped() throws Exception {
+        BodyDescriptorBuilder builder = new DefaultBodyDescriptorBuilder(); 
+        builder.addField(new RawField("To", "me@example.org"));
+        BodyDescriptor bd = builder.build();
+        assertEquals("us-ascii", bd.getCharset());
+    }
+
+    public void testDoNotDefaultToUsAsciiForNonTextTypes() throws Exception {
+        BodyDescriptorBuilder builder = new DefaultBodyDescriptorBuilder(); 
+        builder.addField(new RawField("Content-Type", "image/png; name=blob.png"));
+        BodyDescriptor bd = builder.build();
+        assertNull(bd.getCharset());
     }
 
     public void testMimeVersionDefault() throws Exception {
@@ -185,13 +321,4 @@ public class MaximalBodyDescriptorTest e
         return (MaximalBodyDescriptor) descriptor;
     }
 
-    @Override
-    protected MutableBodyDescriptor newBodyDescriptor() {
-        return new MaximalBodyDescriptor();
-    }
-
-    @Override
-    protected MutableBodyDescriptor newBodyDescriptor(BodyDescriptor parent) {
-        return new MaximalBodyDescriptor(parent);
-    }
 }