You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@james.apache.org by rc...@apache.org on 2020/12/11 10:44:08 UTC

[james-project] 04/15: JAMES-2578 PerRecipientHeaders: No longer rely on Java serialization for JMS and ActiveMQ

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

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

commit 56e7f67f83d2d196c1f6209727f14911c9fb9e17
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Mon Dec 7 14:19:47 2020 +0700

    JAMES-2578 PerRecipientHeaders: No longer rely on Java serialization for JMS and ActiveMQ
---
 .../org/apache/mailet/PerRecipientHeaders.java     | 36 +++++++++++++++++---
 .../james/queue/jms/JMSCacheableMailQueue.java     | 39 +++++++++++++++++-----
 2 files changed, 61 insertions(+), 14 deletions(-)

diff --git a/mailet/api/src/main/java/org/apache/mailet/PerRecipientHeaders.java b/mailet/api/src/main/java/org/apache/mailet/PerRecipientHeaders.java
index 4e0a434..0f70335 100644
--- a/mailet/api/src/main/java/org/apache/mailet/PerRecipientHeaders.java
+++ b/mailet/api/src/main/java/org/apache/mailet/PerRecipientHeaders.java
@@ -21,14 +21,17 @@ package org.apache.mailet;
 
 import java.io.Serializable;
 import java.util.Collection;
+import java.util.List;
 
 import org.apache.james.core.MailAddress;
 
 import com.github.steveash.guavate.Guavate;
 import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Joiner;
 import com.google.common.base.MoreObjects;
 import com.google.common.base.Objects;
 import com.google.common.base.Preconditions;
+import com.google.common.base.Splitter;
 import com.google.common.collect.ArrayListMultimap;
 import com.google.common.collect.Multimap;
 
@@ -74,12 +77,8 @@ public class PerRecipientHeaders implements Serializable {
     }
 
     public static class Header implements Serializable {
-        private final String name;
-        private final String value;
 
-        public static Builder builder() {
-            return new Builder();
-        }
+        public static final String SEPARATOR = ": ";
 
         public static class Builder {
             private String name;
@@ -102,8 +101,31 @@ public class PerRecipientHeaders implements Serializable {
             }
         }
 
+        public static Builder builder() {
+            return new Builder();
+        }
+
+        public static Header fromString(String value) {
+            Preconditions.checkArgument(value.contains(SEPARATOR), "Header is string form needs to contain ': ' separator");
+
+            List<String> parts = Splitter.on(SEPARATOR).splitToList(value);
+
+            return new Header(
+                parts.get(0),
+                Joiner.on(SEPARATOR)
+                    .join(parts.stream()
+                        .skip(1)
+                        .collect(Guavate.toImmutableList())));
+        }
+
+        private final String name;
+        private final String value;
+
         @VisibleForTesting
         Header(String name, String value) {
+            Preconditions.checkArgument(!name.contains(":"), "Header name should not contain separator");
+            Preconditions.checkArgument(!name.contains("\n"), "Header name should not contain line break");
+
             this.name = name;
             this.value = value;
         }
@@ -116,6 +138,10 @@ public class PerRecipientHeaders implements Serializable {
             return value;
         }
 
+        public String asString() {
+            return name + SEPARATOR + value;
+        }
+
         @Override
         public final boolean equals(Object o) {
             if (o instanceof Header) {
diff --git a/server/queue/queue-jms/src/main/java/org/apache/james/queue/jms/JMSCacheableMailQueue.java b/server/queue/queue-jms/src/main/java/org/apache/james/queue/jms/JMSCacheableMailQueue.java
index e6950c7..a680e2c 100644
--- a/server/queue/queue-jms/src/main/java/org/apache/james/queue/jms/JMSCacheableMailQueue.java
+++ b/server/queue/queue-jms/src/main/java/org/apache/james/queue/jms/JMSCacheableMailQueue.java
@@ -32,7 +32,6 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.NoSuchElementException;
-import java.util.Optional;
 import java.util.StringTokenizer;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Stream;
@@ -53,6 +52,7 @@ import javax.mail.internet.AddressException;
 import javax.mail.internet.MimeMessage;
 
 import org.apache.commons.collections.iterators.EnumerationIterator;
+import org.apache.commons.lang3.tuple.Pair;
 import org.apache.james.core.MailAddress;
 import org.apache.james.core.MaybeSender;
 import org.apache.james.lifecycle.api.Disposable;
@@ -68,7 +68,6 @@ import org.apache.james.queue.api.MailQueueName;
 import org.apache.james.queue.api.ManageableMailQueue;
 import org.apache.james.server.core.MailImpl;
 import org.apache.james.server.core.MimeMessageCopyOnWriteProxy;
-import org.apache.james.util.SerializationUtil;
 import org.apache.mailet.Attribute;
 import org.apache.mailet.AttributeName;
 import org.apache.mailet.AttributeUtils;
@@ -341,11 +340,13 @@ public class JMSCacheableMailQueue implements ManageableMailQueue, JMSSupport, M
         props.put(JAMES_MAIL_MESSAGE_SIZE, mail.getMessageSize());
         props.put(JAMES_MAIL_NAME, mail.getName());
 
-        // won't serialize the empty headers so it is mandatory
-        // to handle nulls when reconstructing mail from message
-        if (!mail.getPerRecipientSpecificHeaders().getHeadersByRecipient().isEmpty()) {
-            props.put(JAMES_MAIL_PER_RECIPIENT_HEADERS, SerializationUtil.serialize(mail.getPerRecipientSpecificHeaders()));
-        }
+        mail.getPerRecipientSpecificHeaders().getHeadersByRecipient()
+            .asMap()
+            .forEach((recipient, headers) -> props.put(JAMES_MAIL_PER_RECIPIENT_HEADERS + "-" + recipient.asString(),
+                Joiner.on('\n')
+                    .join(headers.stream()
+                        .map(PerRecipientHeaders.Header::asString)
+                        .collect(Guavate.toImmutableList()))));
 
         String recipientsAsString = joiner.join(mail.getRecipients());
 
@@ -413,9 +414,29 @@ public class JMSCacheableMailQueue implements ManageableMailQueue, JMSSupport, M
         MailImpl.Builder builder = MailImpl.builder().name(name);
         builder.errorMessage(message.getStringProperty(JAMES_MAIL_ERROR_MESSAGE));
         builder.lastUpdated(new Date(message.getLongProperty(JAMES_MAIL_LAST_UPDATED)));
+        Enumeration<String> properties = message.getPropertyNames();
 
-        Optional.ofNullable(SerializationUtil.<PerRecipientHeaders>deserialize(message.getStringProperty(JAMES_MAIL_PER_RECIPIENT_HEADERS)))
-                .ifPresent(builder::addAllHeadersForRecipients);
+        PerRecipientHeaders perRecipientHeaders = new PerRecipientHeaders();
+        ImmutableList.copyOf(properties.asIterator())
+            .stream()
+            .filter(property -> property.startsWith(JAMES_MAIL_PER_RECIPIENT_HEADERS + "-"))
+            .flatMap(property -> {
+                try {
+                    MailAddress address = new MailAddress(property.substring(JAMES_MAIL_PER_RECIPIENT_HEADERS.length() + 1));
+                    String headers = message.getStringProperty(property);
+                    return Splitter.on('\n').splitToList(headers)
+                        .stream()
+                        .map(PerRecipientHeaders.Header::fromString)
+                        .map(header -> Pair.of(address, header));
+                } catch (AddressException | JMSException e) {
+                    LOGGER.error("Error deserializing per-recipient header", e);
+                    return Stream.empty();
+                }
+            })
+            .forEach(pair -> perRecipientHeaders.addHeaderForRecipient(pair.getValue(), pair.getKey()));
+        if (!perRecipientHeaders.getHeadersByRecipient().isEmpty()) {
+            builder.addAllHeadersForRecipients(perRecipientHeaders);
+        }
 
         String recipients = message.getStringProperty(JAMES_MAIL_RECIPIENTS);
         StringTokenizer recipientTokenizer = new StringTokenizer(recipients, JAMES_MAIL_SEPARATOR);


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org