JAMES-2578 Add new Mailet API
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/9ebeaf05 Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/9ebeaf05 Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/9ebeaf05 Branch: refs/heads/master Commit: 9ebeaf05e796ed7cddd80802bc5893ab6a126662 Parents: 719e254 Author: Gautier DI FOLCO <[email protected]> Authored: Tue Oct 30 18:39:09 2018 +0100 Committer: Gautier DI FOLCO <[email protected]> Committed: Mon Nov 5 11:34:33 2018 +0100 ---------------------------------------------------------------------- .../src/main/java/org/apache/mailet/Mail.java | 81 +++++++++++++++++++- mailet/test/pom.xml | 6 ++ .../org/apache/mailet/base/test/FakeMail.java | 39 +++++++++- .../org/apache/james/server/core/MailImpl.java | 53 +++++++++++-- 4 files changed, 167 insertions(+), 12 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/james-project/blob/9ebeaf05/mailet/api/src/main/java/org/apache/mailet/Mail.java ---------------------------------------------------------------------- diff --git a/mailet/api/src/main/java/org/apache/mailet/Mail.java b/mailet/api/src/main/java/org/apache/mailet/Mail.java index c1bccd0..5508b82 100644 --- a/mailet/api/src/main/java/org/apache/mailet/Mail.java +++ b/mailet/api/src/main/java/org/apache/mailet/Mail.java @@ -24,14 +24,20 @@ import java.io.Serializable; import java.util.Collection; import java.util.Date; import java.util.Iterator; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Stream; import javax.mail.MessagingException; import javax.mail.internet.MimeMessage; +import org.apache.commons.lang3.tuple.Pair; import org.apache.james.core.MailAddress; import org.apache.james.core.MaybeSender; import org.apache.mailet.PerRecipientHeaders.Header; +import com.google.common.collect.ImmutableMap; + /** * <p>Wraps a MimeMessage with additional routing and processing information. * <p>This includes @@ -212,7 +218,12 @@ public interface Mail extends Serializable, Cloneable { * @param state the new state of this message */ void setState(String state); - + + /** + * Get the stream of all attributes + */ + Stream<Attribute> attributes(); + /** * Returns the value of the named Mail instance attribute, * or null if the attribute does not exist. @@ -220,9 +231,18 @@ public interface Mail extends Serializable, Cloneable { * @param name the attribute name * @return the attribute value, or null if the attribute does not exist * @since Mailet API v2.1 + * @deprecated see {@link #getAttribute(AttributeName)} */ + @Deprecated Serializable getAttribute(String name); - + + /** + * Returns the attribute corresponding to an attribute name + * + * @since Mailet API v3.2 + */ + Optional<Attribute> getAttribute(AttributeName name); + /** * Returns an Iterator over the names of all attributes which are set * in this Mail instance. @@ -232,10 +252,23 @@ public interface Mail extends Serializable, Cloneable { * * @return an Iterator (of Strings) over all attribute names * @since Mailet API v2.1 + * @deprecated see {@link #attributeNames()} */ + @Deprecated Iterator<String> getAttributeNames(); /** + * Returns a Stream over the names of all attributes which are set + * in this Mail instance. + * <p> + * The {@link #getAttribute} method can be called to + * retrieve an attribute's value given its name. + * + * @since Mailet API v3.2 + */ + Stream<AttributeName> attributeNames(); + + /** * Returns whether this Mail instance has any attributes set. * * @return true if this Mail instance has any attributes set, false if not @@ -251,8 +284,20 @@ public interface Mail extends Serializable, Cloneable { * if there was no such attribute (or if the attribute existed * and its value was null) * @since Mailet API v2.1 + * @deprecated see {@link #removeAttribute(AttributeName) */ + @Deprecated Serializable removeAttribute(String name); + + /** + * Removes the attribute with the given attribute name from this Mail instance. + * + * @return the removed attribute, or null + * if there was no such attribute (or if the attribute existed + * and its value was null) + * @since Mailet API v3.2 + */ + Optional<Attribute> removeAttribute(AttributeName attributeName); /** * Removes all attributes associated with this Mail instance. @@ -276,10 +321,29 @@ public interface Mail extends Serializable, Cloneable { * or null if there was no such attribute (or if the attribute existed * and its value was null) * @since Mailet API v2.1 + * @deprecated see {@link #setAttribute(Attribute) */ + @Deprecated Serializable setAttribute(String name, Serializable object); /** + * Associates an attribute with the given name and value with this Mail instance. + * If an attribute with a given name already exists, it is replaced, and the + * previous value is returned. + * <p> + * Conventionally, attribute names should follow the namespacing guidelines + * for Java packages. + * The Mailet API specification reserves names matching + * <i>org.apache.james.*</i> and <i>org.apache.mailet.*</i>. + * + * @return the previously existing attribute with the same name, + * or null if there was no such attribute (or if the attribute existed + * and its value was null) + * @since Mailet API v3.2 + */ + Optional<Attribute> setAttribute(Attribute attribute); + + /** * Store a header (and its specific values) for a recipient * This header will be stored only for this recipient at delivery time * @@ -324,4 +388,17 @@ public interface Mail extends Serializable, Cloneable { * @since Mailet API v2.3 */ void setLastUpdated(Date lastUpdated); + + /** + * Returns a map of AttribeName Attribute for the currently registered attributes + * + * @since Mailet API v3.2 + */ + default Map<AttributeName, Attribute> attributesMap() { + return attributeNames() + .map(name -> getAttribute(name).map(attribute -> Pair.of(name, attribute))) + .filter(Optional::isPresent) + .map(Optional::get) + .collect(ImmutableMap.toImmutableMap(Pair::getKey, Pair::getValue)); + } } http://git-wip-us.apache.org/repos/asf/james-project/blob/9ebeaf05/mailet/test/pom.xml ---------------------------------------------------------------------- diff --git a/mailet/test/pom.xml b/mailet/test/pom.xml index 80f5e64..a0a8627 100644 --- a/mailet/test/pom.xml +++ b/mailet/test/pom.xml @@ -40,6 +40,12 @@ </dependency> <dependency> <groupId>${james.groupId}</groupId> + <artifactId>apache-mailet-api</artifactId> + <type>test-jar</type> + <scope>test</scope> + </dependency> + <dependency> + <groupId>${james.groupId}</groupId> <artifactId>apache-mime4j-core</artifactId> </dependency> <dependency> http://git-wip-us.apache.org/repos/asf/james-project/blob/9ebeaf05/mailet/test/src/main/java/org/apache/mailet/base/test/FakeMail.java ---------------------------------------------------------------------- diff --git a/mailet/test/src/main/java/org/apache/mailet/base/test/FakeMail.java b/mailet/test/src/main/java/org/apache/mailet/base/test/FakeMail.java index 02cb868..9d5a188 100644 --- a/mailet/test/src/main/java/org/apache/mailet/base/test/FakeMail.java +++ b/mailet/test/src/main/java/org/apache/mailet/base/test/FakeMail.java @@ -30,6 +30,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Properties; +import java.util.stream.Stream; import javax.mail.MessagingException; import javax.mail.internet.AddressException; @@ -40,6 +41,9 @@ import org.apache.james.core.MailAddress; import org.apache.james.core.MaybeSender; import org.apache.james.core.builder.MimeMessageBuilder; import org.apache.james.util.MimeMessageUtil; +import org.apache.mailet.Attribute; +import org.apache.mailet.AttributeName; +import org.apache.mailet.AttributeValue; import org.apache.mailet.Mail; import org.apache.mailet.PerRecipientHeaders; import org.apache.mailet.PerRecipientHeaders.Header; @@ -119,6 +123,11 @@ public class FakeMail implements Mail, Serializable { perRecipientHeaders = new PerRecipientHeaders(); } + public Builder attribute(Attribute attribute) { + this.attributes.put(attribute.getName().asString(), (Serializable) attribute.getValue().value()); + return this; + } + public Builder size(long size) { this.size = Optional.of(size); return this; @@ -399,8 +408,18 @@ public class FakeMail implements Mail, Serializable { } @Override + public Stream<Attribute> attributes() { + return attributes.entrySet().stream().map(entry -> new Attribute(AttributeName.of(entry.getKey()), AttributeValue.ofAny(entry.getValue()))); + } + + @Override public Serializable getAttribute(String name) { - return attributes.get(name); + return (Serializable) attributes.get(name); + } + + @Override + public Optional<Attribute> getAttribute(AttributeName name) { + return Optional.ofNullable(attributes.get(name.asString())).map(value -> new Attribute(name, AttributeValue.ofAny(value))); } @Override @@ -409,14 +428,24 @@ public class FakeMail implements Mail, Serializable { } @Override + public Stream<AttributeName> attributeNames() { + return attributes.keySet().stream().map(AttributeName::of); + } + + @Override public boolean hasAttributes() { return !attributes.isEmpty(); } @Override public Serializable removeAttribute(String name) { - return attributes.remove(name); + return (Serializable) attributes.remove(name); + } + @Override + public Optional<Attribute> removeAttribute(AttributeName attributeName) { + AttributeValue<?> previous = AttributeValue.ofAny(attributes.remove(attributeName.asString())); + return Optional.ofNullable(previous).map(value -> new Attribute(attributeName, value)); } @Override @@ -430,6 +459,12 @@ public class FakeMail implements Mail, Serializable { } @Override + public Optional<Attribute> setAttribute(Attribute attribute) { + Serializable previous = this.attributes.put(attribute.getName().asString(), (Serializable) attribute.getValue().value()); + return Optional.ofNullable(previous).map(value -> new Attribute(attribute.getName(), AttributeValue.ofAny(value))); + } + + @Override public long getMessageSize() throws MessagingException { return size; } http://git-wip-us.apache.org/repos/asf/james-project/blob/9ebeaf05/server/container/core/src/main/java/org/apache/james/server/core/MailImpl.java ---------------------------------------------------------------------- diff --git a/server/container/core/src/main/java/org/apache/james/server/core/MailImpl.java b/server/container/core/src/main/java/org/apache/james/server/core/MailImpl.java index cd0fc57..3bcaeb6 100644 --- a/server/container/core/src/main/java/org/apache/james/server/core/MailImpl.java +++ b/server/container/core/src/main/java/org/apache/james/server/core/MailImpl.java @@ -37,6 +37,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; import java.util.UUID; +import java.util.stream.Stream; import javax.mail.Address; import javax.mail.MessagingException; @@ -51,6 +52,9 @@ import org.apache.james.core.MaybeSender; import org.apache.james.core.builder.MimeMessageBuilder; import org.apache.james.lifecycle.api.Disposable; import org.apache.james.lifecycle.api.LifecycleUtil; +import org.apache.mailet.Attribute; +import org.apache.mailet.AttributeName; +import org.apache.mailet.AttributeValue; import org.apache.mailet.Mail; import org.apache.mailet.PerRecipientHeaders; import org.apache.mailet.PerRecipientHeaders.Header; @@ -58,7 +62,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.github.fge.lambdas.Throwing; -import com.github.steveash.guavate.Guavate; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; @@ -160,7 +163,7 @@ public class MailImpl implements Disposable, Mail { public Builder recipients(String... recipients) { return recipients(Arrays.stream(recipients) .map(Throwing.function(MailAddress::new)) - .collect(Guavate.toImmutableList())); + .collect(ImmutableList.toImmutableList())); } public Builder recipient(MailAddress recipient) { @@ -249,7 +252,7 @@ public class MailImpl implements Disposable, Mail { state.ifPresent(mail::setState); errorMessage.ifPresent(mail::setErrorMessage); lastUpdated.ifPresent(mail::setLastUpdated); - mail.setAttributesRaw(new HashMap<>(attributes)); + mail.setAttributes(new HashMap<>(attributes)); remoteAddr.ifPresent(mail::setRemoteAddr); remoteHost.ifPresent(mail::setRemoteHost); mail.perRecipientSpecificHeaders.addAll(perRecipientHeaders); @@ -260,7 +263,7 @@ public class MailImpl implements Disposable, Mail { private static ImmutableList<MailAddress> getRecipients(MimeMessage mimeMessage) throws MessagingException { return Arrays.stream(mimeMessage.getAllRecipients()) .map(Throwing.function(MailImpl::castToMailAddress).sneakyThrow()) - .collect(Guavate.toImmutableList()); + .collect(ImmutableList.toImmutableList()); } private static MailAddress getSender(MimeMessage mimeMessage) throws MessagingException { @@ -703,7 +706,12 @@ public class MailImpl implements Disposable, Mail { * @since 2.2.0 */ public Map<String, Object> getAttributesRaw() { - return attributes; + return Maps.newHashMap(attributes); + } + + public void setAttributes(Map<String, Object> attr) { + Preconditions.checkNotNull(attr); + this.attributes = attr; } /** @@ -719,8 +727,13 @@ public class MailImpl implements Disposable, Mail { * @param attr Serializable of the entire attributes collection * @since 2.2.0 */ - public void setAttributesRaw(HashMap<String, Object> attr) { - this.attributes = (attr == null) ? new HashMap<>() : attr; + public void setAttributesRaw(Map<String, Object> attr) { + this.attributes = Optional.ofNullable(attr).orElse(new HashMap<>()); + } + + @Override + public Stream<Attribute> attributes() { + return this.attributes.entrySet().stream().map(entry -> new Attribute(AttributeName.of(entry.getKey()), AttributeValue.ofAny(entry.getValue()))); } @Override @@ -729,9 +742,22 @@ public class MailImpl implements Disposable, Mail { } @Override + public Optional<Attribute> getAttribute(AttributeName name) { + return Optional.ofNullable(attributes.get(name.asString())).map(value -> new Attribute(name, AttributeValue.ofAny(value))); + } + + @Override public Serializable setAttribute(String key, Serializable object) { Preconditions.checkNotNull(key, "Key of an attribute should not be null"); - return (Serializable) attributes.put(key, object); + Serializable previous = (Serializable) attributes.put(key, object); + return previous; + } + + @Override + public Optional<Attribute> setAttribute(Attribute attribute) { + Preconditions.checkNotNull(attribute.getName().asString(), "AttributeName should not be null"); + Object previous = this.attributes.put(attribute.getName().asString(), attribute.getValue().value()); + return Optional.ofNullable(previous).map(value -> new Attribute(attribute.getName(), AttributeValue.ofAny(value))); } @Override @@ -740,6 +766,12 @@ public class MailImpl implements Disposable, Mail { } @Override + public Optional<Attribute> removeAttribute(AttributeName attributeName) { + Object previous = attributes.remove(attributeName.asString()); + return Optional.ofNullable(previous).map(value -> new Attribute(attributeName, AttributeValue.ofAny(value))); + } + + @Override public void removeAllAttributes() { attributes.clear(); } @@ -750,6 +782,11 @@ public class MailImpl implements Disposable, Mail { } @Override + public Stream<AttributeName> attributeNames() { + return attributes.keySet().stream().map(AttributeName::of); + } + + @Override public boolean hasAttributes() { return !attributes.isEmpty(); } --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
