This is an automated email from the ASF dual-hosted git repository.

Arsnael pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-mime4j.git

commit 3cb6297d5ebbdae4ba2327281c87534d21a86fff
Author: Benoit TELLIER <[email protected]>
AuthorDate: Fri Sep 11 11:19:41 2026 +0200

    [PERF] ParserStreamContentHandler Stack -> Deque
---
 .../internal/ParserStreamContentHandler.java       | 131 +++++++++++++--------
 1 file changed, 83 insertions(+), 48 deletions(-)

diff --git 
a/dom/src/main/java/org/apache/james/mime4j/internal/ParserStreamContentHandler.java
 
b/dom/src/main/java/org/apache/james/mime4j/internal/ParserStreamContentHandler.java
index d251ba7a..fa9be441 100644
--- 
a/dom/src/main/java/org/apache/james/mime4j/internal/ParserStreamContentHandler.java
+++ 
b/dom/src/main/java/org/apache/james/mime4j/internal/ParserStreamContentHandler.java
@@ -34,12 +34,15 @@ import org.apache.james.mime4j.message.MultipartImpl;
 import org.apache.james.mime4j.parser.ContentHandler;
 import org.apache.james.mime4j.stream.BodyDescriptor;
 import org.apache.james.mime4j.stream.Field;
+import org.apache.james.mime4j.util.BufferRecycler;
 import org.apache.james.mime4j.util.ByteArrayBuffer;
 import org.apache.james.mime4j.util.ByteSequence;
+import org.apache.james.mime4j.util.ContentUtil;
 
 import java.io.IOException;
 import java.io.InputStream;
-import java.util.Stack;
+import java.util.ArrayDeque;
+import java.util.Deque;
 
 /**
  * A <code>ContentHandler</code> for building an <code>Entity</code> to be
@@ -47,18 +50,17 @@ import java.util.Stack;
  */
 public class ParserStreamContentHandler implements ContentHandler {
 
+    private static final int COPY_BUFFER_SIZE = 4096;
+
     private final Entity entity;
     private final MessageImplFactory messageImplFactory;
     private final BodyFactory bodyFactory;
-    private final Stack<Object> stack;
+    private final Deque<Object> stack;
 
     public ParserStreamContentHandler(
             final Entity entity,
             final BodyFactory bodyFactory) {
-        this.entity = entity;
-        this.messageImplFactory = new DefaultMessageImplFactory();
-        this.bodyFactory = bodyFactory;
-        this.stack = new Stack<Object>();
+        this(entity, new DefaultMessageImplFactory(), bodyFactory);
     }
 
     public ParserStreamContentHandler(
@@ -68,14 +70,58 @@ public class ParserStreamContentHandler implements 
ContentHandler {
         this.entity = entity;
         this.messageImplFactory = messageImplFactory;
         this.bodyFactory = bodyFactory;
-        this.stack = new Stack<Object>();
+        this.stack = new ArrayDeque<Object>();
+    }
+
+    private static IllegalStateException unexpected(final Class<?> expected, 
final Object found) {
+        return new IllegalStateException("Internal stack error: "
+                + "Expected '" + expected.getName() + "' found '"
+                + found.getClass().getName() + "'");
+    }
+
+    private Entity peekEntity() {
+        Object top = stack.peek();
+        if (top instanceof Entity) {
+            return (Entity) top;
+        }
+        throw unexpected(Entity.class, top);
+    }
+
+    private Header peekHeader() {
+        Object top = stack.peek();
+        if (top instanceof Header) {
+            return (Header) top;
+        }
+        throw unexpected(Header.class, top);
+    }
+
+    private Multipart peekMultipart() {
+        Object top = stack.peek();
+        if (top instanceof Multipart) {
+            return (Multipart) top;
+        }
+        throw unexpected(Multipart.class, top);
     }
 
-    private void expect(Class<?> c) {
-        if (!c.isInstance(stack.peek())) {
-            throw new IllegalStateException("Internal stack error: "
-                    + "Expected '" + c.getName() + "' found '"
-                    + stack.peek().getClass().getName() + "'");
+    private MultipartImpl peekMultipartImpl() {
+        Object top = stack.peek();
+        if (top instanceof MultipartImpl) {
+            return (MultipartImpl) top;
+        }
+        throw unexpected(MultipartImpl.class, top);
+    }
+
+    private void expectMessage() {
+        Object top = stack.peek();
+        if (!(top instanceof Message)) {
+            throw unexpected(Message.class, top);
+        }
+    }
+
+    private void expectBodyPart() {
+        Object top = stack.peek();
+        if (!(top instanceof BodyPart)) {
+            throw unexpected(BodyPart.class, top);
         }
     }
 
@@ -83,15 +129,14 @@ public class ParserStreamContentHandler implements 
ContentHandler {
         if (stack.isEmpty()) {
             stack.push(this.entity);
         } else {
-            expect(Entity.class);
             Message m = messageImplFactory.messageImpl();
-            ((Entity) stack.peek()).setBody(m);
+            peekEntity().setBody(m);
             stack.push(m);
         }
     }
 
     public void endMessage() throws MimeException {
-        expect(Message.class);
+        expectMessage();
         stack.pop();
     }
 
@@ -100,39 +145,31 @@ public class ParserStreamContentHandler implements 
ContentHandler {
     }
 
     public void field(Field field) throws MimeException {
-        expect(Header.class);
-        ((Header) stack.peek()).addField(field);
+        peekHeader().addField(field);
     }
 
     public void endHeader() throws MimeException {
-        expect(Header.class);
-        Header h = (Header) stack.pop();
-        expect(Entity.class);
-        ((Entity) stack.peek()).setHeader(h);
+        Header h = peekHeader();
+        stack.pop();
+        peekEntity().setHeader(h);
     }
 
     public void startMultipart(final BodyDescriptor bd) throws MimeException {
-        expect(Entity.class);
-
-        final Entity e = (Entity) stack.peek();
-        final String subType = bd.getSubType();
-        final Multipart multiPart = new MultipartImpl(subType);
+        final Entity e = peekEntity();
+        final Multipart multiPart = new MultipartImpl(bd.getSubType());
         e.setBody(multiPart);
         stack.push(multiPart);
     }
 
     public void body(BodyDescriptor bd, final InputStream is) throws 
MimeException, IOException {
-        expect(Entity.class);
-
+        final Entity e = peekEntity();
         final Body body;
         if (bd.getMimeType().startsWith("text/")) {
             body = bodyFactory.textBody(is, bd.getCharset());
         } else {
             body = bodyFactory.binaryBody(is);
         }
-
-        Entity entity = ((Entity) stack.peek());
-        entity.setBody(body);
+        e.setBody(body);
     }
 
     public void endMultipart() throws MimeException {
@@ -140,28 +177,22 @@ public class ParserStreamContentHandler implements 
ContentHandler {
     }
 
     public void startBodyPart() throws MimeException {
-        expect(Multipart.class);
-
         BodyPart bodyPart = new BodyPart();
-        ((Multipart) stack.peek()).addBodyPart(bodyPart);
+        peekMultipart().addBodyPart(bodyPart);
         stack.push(bodyPart);
     }
 
     public void endBodyPart() throws MimeException {
-        expect(BodyPart.class);
+        expectBodyPart();
         stack.pop();
     }
 
     public void epilogue(InputStream is) throws MimeException, IOException {
-        expect(MultipartImpl.class);
-        ByteSequence bytes = loadStream(is);
-        ((MultipartImpl) stack.peek()).setEpilogueRaw(bytes);
+        peekMultipartImpl().setEpilogueRaw(loadStream(is));
     }
 
     public void preamble(InputStream is) throws MimeException, IOException {
-        expect(MultipartImpl.class);
-        ByteSequence bytes = loadStream(is);
-        ((MultipartImpl) stack.peek()).setPreambleRaw(bytes);
+        peekMultipartImpl().setPreambleRaw(loadStream(is));
     }
 
     /**
@@ -175,14 +206,18 @@ public class ParserStreamContentHandler implements 
ContentHandler {
     }
 
     private static ByteSequence loadStream(InputStream in) throws IOException {
-        ByteArrayBuffer bab = new ByteArrayBuffer(64);
-
-        int b;
-        while ((b = in.read()) != -1) {
-            bab.append(b);
+        BufferRecycler recycler = ContentUtil.getBufferRecycler();
+        byte[] chunk = recycler.allocByteBuffer(0, COPY_BUFFER_SIZE);
+        try {
+            ByteArrayBuffer bab = new ByteArrayBuffer(64);
+            int len;
+            while ((len = in.read(chunk)) != -1) {
+                bab.append(chunk, 0, len);
+            }
+            return bab;
+        } finally {
+            recycler.releaseByteBuffer(0, chunk);
         }
-
-        return bab;
     }
 
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to