You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by ad...@apache.org on 2017/01/18 13:43:34 UTC
[2/3] james-project git commit: MAILET-148 Create mailet to transform
map of ICAL to list of JSONs
MAILET-148 Create mailet to transform map of ICAL to list of JSONs
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/cb844422
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/cb844422
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/cb844422
Branch: refs/heads/master
Commit: cb844422302e735d43bff0d9ab51aedf39ce7d97
Parents: 3bdeb52
Author: Benoit Tellier <bt...@linagora.com>
Authored: Mon Jan 16 10:00:40 2017 +0700
Committer: Benoit Tellier <bt...@linagora.com>
Committed: Wed Jan 18 17:39:45 2017 +0700
----------------------------------------------------------------------
mailet/icalendar/pom.xml | 33 ++
.../transport/mailets/ICALToJsonAttribute.java | 174 ++++++++
.../james/transport/mailets/model/ICAL.java | 163 ++++++++
.../mailets/ICALToJsonAttributeTest.java | 414 +++++++++++++++++++
.../james/transport/mailets/model/ICALTest.java | 196 +++++++++
.../resources/ics/meeting_without_method.ics | 30 ++
.../resources/ics/meeting_without_sequence.ics | 30 ++
.../test/resources/ics/meeting_without_uid.ics | 29 ++
mailet/pom.xml | 17 +
9 files changed, 1086 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/cb844422/mailet/icalendar/pom.xml
----------------------------------------------------------------------
diff --git a/mailet/icalendar/pom.xml b/mailet/icalendar/pom.xml
index e64a33b..c66123e 100644
--- a/mailet/icalendar/pom.xml
+++ b/mailet/icalendar/pom.xml
@@ -168,6 +168,21 @@
<version>0.5.0</version>
</dependency>
<dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-databind</artifactId>
+ <version>${jackson-data.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.fasterxml.jackson.datatype</groupId>
+ <artifactId>jackson-datatype-jdk8</artifactId>
+ <version>${jackson-data.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.github.steveash.guavate</groupId>
+ <artifactId>guavate</artifactId>
+ <version>${guavate.version}</version>
+ </dependency>
+ <dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
@@ -177,6 +192,24 @@
<scope>test</scope>
</dependency>
<dependency>
+ <groupId>net.javacrumbs.json-unit</groupId>
+ <artifactId>json-unit</artifactId>
+ <version>1.5.5</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>net.javacrumbs.json-unit</groupId>
+ <artifactId>json-unit-fluent</artifactId>
+ <version>1.5.5</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>nl.jqno.equalsverifier</groupId>
+ <artifactId>equalsverifier</artifactId>
+ <version>1.7.5</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>${assertj-3.version}</version>
http://git-wip-us.apache.org/repos/asf/james-project/blob/cb844422/mailet/icalendar/src/main/java/org/apache/james/transport/mailets/ICALToJsonAttribute.java
----------------------------------------------------------------------
diff --git a/mailet/icalendar/src/main/java/org/apache/james/transport/mailets/ICALToJsonAttribute.java b/mailet/icalendar/src/main/java/org/apache/james/transport/mailets/ICALToJsonAttribute.java
new file mode 100644
index 0000000..1e314af
--- /dev/null
+++ b/mailet/icalendar/src/main/java/org/apache/james/transport/mailets/ICALToJsonAttribute.java
@@ -0,0 +1,174 @@
+/****************************************************************
+ * 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.transport.mailets;
+
+import java.io.Serializable;
+import java.util.Map;
+import java.util.UUID;
+import java.util.stream.Stream;
+
+import javax.mail.MessagingException;
+
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.james.transport.mailets.model.ICAL;
+import org.apache.mailet.Mail;
+import org.apache.mailet.MailAddress;
+import org.apache.mailet.base.GenericMailet;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
+import com.github.steveash.guavate.Guavate;
+import com.google.common.base.Charsets;
+import com.google.common.base.Strings;
+
+import net.fortuna.ical4j.model.Calendar;
+
+/**
+ * ICALToJsonAttribute takes a map of ICAL4J objects attached as attribute, and output the map of corresponding json bytes as
+ * an other attribute, with unique String keys.
+ *
+ * The JSON contains the following fields :
+ *
+ * <ul>
+ * <li><b>ical</b> : the raw ical string, in UTF-8</li>
+ * <li><b>sender</b> : the sender of the mail (compulsory, mail without sender will be discarded)</li>
+ * <li><b>recipient</b> : the recipient of the mail. If the mail have several recipients, each recipient will have
+ * its own JSON.</li>
+ * <li><b>uid</b> : the UID of the ical (optional)</li>
+ * <li><b>sequence</b> : the sequence of the ical (optional)</li>
+ * <li><b>dtstamp</b> : the date stamp of the ical (optional)</li>
+ * <li><b>method</b> : the method of the ical (optional)</li>
+ * <li><b>recurrence-id</b> : the recurrence-id of the ical (optional)</li>
+ * </ul>
+ *
+ * Example are included in test call ICalToJsonAttributeTest.
+ *
+ * Configuration example :
+ *
+ * <pre>
+ * <code>
+ * <mailet matcher=??? class=ICALToJsonAttribute>
+ * <sourceAttribute>icalendars</sourceAttribute>
+ * <destinationAttribute>icalendarJson</destinationAttribute>
+ * </mailet>
+ * </code>
+ * </pre>
+ */
+public class ICALToJsonAttribute extends GenericMailet {
+
+ public static final String SOURCE_ATTRIBUTE_NAME = "source";
+ public static final String DESTINATION_ATTRIBUTE_NAME = "destination";
+ public static final String DEFAULT_SOURCE_ATTRIBUTE_NAME = "icalendar";
+ public static final String DEFAULT_DESTINATION_ATTRIBUTE_NAME = "icalendarJson";
+
+ private final ObjectMapper objectMapper;
+ private String sourceAttributeName;
+ private String destinationAttributeName;
+
+ public ICALToJsonAttribute() {
+ this.objectMapper = new ObjectMapper()
+ .registerModule(new Jdk8Module());
+ }
+
+ public String getSourceAttributeName() {
+ return sourceAttributeName;
+ }
+
+ public String getDestinationAttributeName() {
+ return destinationAttributeName;
+ }
+
+ @Override
+ public String getMailetInfo() {
+ return "ICALToJson Mailet";
+ }
+
+ @Override
+ public void init() throws MessagingException {
+ sourceAttributeName = getInitParameter(SOURCE_ATTRIBUTE_NAME, DEFAULT_SOURCE_ATTRIBUTE_NAME);
+ destinationAttributeName = getInitParameter(DESTINATION_ATTRIBUTE_NAME, DEFAULT_DESTINATION_ATTRIBUTE_NAME);
+ if (Strings.isNullOrEmpty(sourceAttributeName)) {
+ throw new MessagingException(SOURCE_ATTRIBUTE_NAME + " configuration parameter can not be null or empty");
+ }
+ if (Strings.isNullOrEmpty(destinationAttributeName)) {
+ throw new MessagingException(DESTINATION_ATTRIBUTE_NAME + " configuration parameter can not be null or empty");
+ }
+ }
+
+ @Override
+ public void service(Mail mail) throws MessagingException {
+ if (mail.getAttribute(sourceAttributeName) == null) {
+ return;
+ }
+ if (mail.getSender() == null) {
+ log("Skipping " + mail.getName() + " because no sender");
+ return;
+ }
+ try {
+ Map<String, Calendar> calendars = getCalendarMap(mail);
+ Map<String, byte[]> jsonsInByteForm = calendars.entrySet()
+ .stream()
+ .flatMap(calendar -> toJson(calendar, mail))
+ .collect(Guavate.toImmutableMap(Pair::getKey, Pair::getValue));
+ mail.setAttribute(destinationAttributeName, (Serializable) jsonsInByteForm);
+ } catch (ClassCastException e) {
+ log("Received a mail with " + sourceAttributeName + " not being an ICAL object for mail " + mail.getName(), e);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private Map<String, Calendar> getCalendarMap(Mail mail) {
+ return (Map<String, Calendar>) mail.getAttribute(sourceAttributeName);
+ }
+
+ private Stream<Pair<String, byte[]>> toJson(Map.Entry<String, Calendar> entry, Mail mail) {
+ return mail.getRecipients()
+ .stream()
+ .flatMap(recipient -> toICAL(entry.getValue(), recipient, mail.getSender()))
+ .flatMap(ical -> toJson(ical, mail.getName()))
+ .map(json -> Pair.of(UUID.randomUUID().toString(), json.getBytes(Charsets.UTF_8)));
+ }
+
+ private Stream<String> toJson(ICAL ical, String mailName) {
+ try {
+ return Stream.of(objectMapper.writeValueAsString(ical));
+ } catch (JsonProcessingException e) {
+ log("Error while serializing Calendar for mail " + mailName, e);
+ return Stream.of();
+ } catch (Exception e) {
+ log("Exception caught while attaching ICAL to the email as JSON for mail " + mailName, e);
+ return Stream.of();
+ }
+ }
+
+ private Stream<ICAL> toICAL(Calendar calendar, MailAddress recipient, MailAddress sender) {
+ try {
+ return Stream.of(ICAL.builder()
+ .from(calendar)
+ .recipient(recipient)
+ .sender(sender)
+ .build());
+ } catch (Exception e) {
+ log("Exception while converting calendar to ICAL", e);
+ return Stream.of();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/cb844422/mailet/icalendar/src/main/java/org/apache/james/transport/mailets/model/ICAL.java
----------------------------------------------------------------------
diff --git a/mailet/icalendar/src/main/java/org/apache/james/transport/mailets/model/ICAL.java b/mailet/icalendar/src/main/java/org/apache/james/transport/mailets/model/ICAL.java
new file mode 100644
index 0000000..b873a93
--- /dev/null
+++ b/mailet/icalendar/src/main/java/org/apache/james/transport/mailets/model/ICAL.java
@@ -0,0 +1,163 @@
+/****************************************************************
+ * 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.transport.mailets.model;
+
+import java.util.Objects;
+import java.util.Optional;
+
+import org.apache.mailet.MailAddress;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.Preconditions;
+
+import net.fortuna.ical4j.model.Calendar;
+import net.fortuna.ical4j.model.Property;
+import net.fortuna.ical4j.model.component.VEvent;
+
+public class ICAL {
+
+ public static final String DEFAULT_SEQUENCE_VALUE = "0";
+
+ public static class Builder {
+ private String ical;
+ private String sender;
+ private String recipient;
+ private Optional<String> uid = Optional.empty();
+ private Optional<String> sequence = Optional.empty();
+ private Optional<String> dtstamp = Optional.empty();
+ private Optional<String> method = Optional.empty();
+ private Optional<String> recurrenceId = Optional.empty();
+
+ public Builder from(Calendar calendar) {
+ this.ical = calendar.toString();
+ VEvent vevent = (VEvent) calendar.getComponent("VEVENT");
+ this.uid = optionalOf(vevent.getUid());
+ this.method = optionalOf(calendar.getMethod());
+ this.recurrenceId = optionalOf(vevent.getRecurrenceId());
+ this.sequence = optionalOf(vevent.getSequence());
+ this.dtstamp = optionalOf(vevent.getDateStamp());
+ return this;
+ }
+
+ private Optional<String> optionalOf(Property property) {
+ return Optional.ofNullable(property).map(Property::getValue);
+ }
+
+ public Builder sender(MailAddress sender) {
+ this.sender = sender.asString();
+ return this;
+ }
+
+
+ public Builder recipient(MailAddress recipient) {
+ this.recipient = recipient.asString();
+ return this;
+ }
+
+ public ICAL build() {
+ Preconditions.checkNotNull(recipient);
+ Preconditions.checkNotNull(sender);
+ Preconditions.checkNotNull(ical);
+ Preconditions.checkState(uid.isPresent(), "uid is a compulsary property of an ICAL object");
+ Preconditions.checkState(method.isPresent(), "method is a compulsary property of an ICAL object");
+ Preconditions.checkState(dtstamp.isPresent(), "dtstamp is a compulsary property of an ICAL object");
+ return new ICAL(ical, sender, recipient, uid, sequence, dtstamp, method, recurrenceId);
+ }
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ private final String ical;
+ private final String sender;
+ private final String recipient;
+ private final Optional<String> uid;
+ private final Optional<String> sequence;
+ private final Optional<String> dtstamp;
+ private final Optional<String> method;
+ private final Optional<String> recurrenceId;
+
+ private ICAL(String ical, String sender, String recipient, Optional<String> uid, Optional<String> sequence, Optional<String> dtstamp,
+ Optional<String> method, Optional<String> recurrenceId) {
+ this.ical = ical;
+ this.sender = sender;
+ this.recipient = recipient;
+ this.uid = uid;
+ this.sequence = sequence;
+ this.dtstamp = dtstamp;
+ this.method = method;
+ this.recurrenceId = recurrenceId;
+ }
+
+ public String getIcal() {
+ return ical;
+ }
+
+ public String getSender() {
+ return sender;
+ }
+
+ public String getRecipient() {
+ return recipient;
+ }
+
+ public Optional<String> getUid() {
+ return uid;
+ }
+
+ public String getSequence() {
+ return sequence.orElse(DEFAULT_SEQUENCE_VALUE);
+ }
+
+ public Optional<String> getDtstamp() {
+ return dtstamp;
+ }
+
+ public Optional<String> getMethod() {
+ return method;
+ }
+
+ @JsonProperty("recurrence-id")
+ public Optional<String> getRecurrenceId() {
+ return recurrenceId;
+ }
+
+ @Override
+ public final boolean equals(Object o) {
+ if (o instanceof ICAL) {
+ ICAL that = (ICAL) o;
+ return Objects.equals(that.ical, this.ical)
+ && Objects.equals(that.sender, this.sender)
+ && Objects.equals(that.recipient, this.recipient)
+ && Objects.equals(that.uid, this.uid)
+ && Objects.equals(that.sequence, this.sequence)
+ && Objects.equals(that.dtstamp, this.dtstamp)
+ && Objects.equals(that.method, this.method)
+ && Objects.equals(that.recurrenceId, this.recurrenceId);
+ }
+ return false;
+ }
+
+ @Override
+ public final int hashCode() {
+ return Objects.hash(ical, sender, recipient, uid, sequence, dtstamp, method, recurrenceId);
+ }
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/cb844422/mailet/icalendar/src/test/java/org/apache/james/transport/mailets/ICALToJsonAttributeTest.java
----------------------------------------------------------------------
diff --git a/mailet/icalendar/src/test/java/org/apache/james/transport/mailets/ICALToJsonAttributeTest.java b/mailet/icalendar/src/test/java/org/apache/james/transport/mailets/ICALToJsonAttributeTest.java
new file mode 100644
index 0000000..f100584
--- /dev/null
+++ b/mailet/icalendar/src/test/java/org/apache/james/transport/mailets/ICALToJsonAttributeTest.java
@@ -0,0 +1,414 @@
+/****************************************************************
+ * 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.transport.mailets;
+
+import static net.javacrumbs.jsonunit.fluent.JsonFluentAssert.assertThatJson;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import javax.mail.MessagingException;
+
+import org.apache.mailet.Mail;
+import org.apache.mailet.MailAddress;
+import org.apache.mailet.base.MailAddressFixture;
+import org.apache.mailet.base.test.FakeMail;
+import org.apache.mailet.base.test.FakeMailetConfig;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import com.google.common.base.Charsets;
+import com.google.common.collect.ImmutableMap;
+
+import net.fortuna.ical4j.data.CalendarBuilder;
+import net.fortuna.ical4j.model.Calendar;
+
+public class ICALToJsonAttributeTest {
+ public static final MailAddress SENDER = MailAddressFixture.ANY_AT_JAMES;
+ public static final String MEETING_ICS = "\"BEGIN:VCALENDAR\\r\\n" +
+ "PRODID:-//Aliasource Groupe LINAGORA//OBM Calendar 3.2.1-rc2//FR\\r\\n" +
+ "CALSCALE:GREGORIAN\\r\\n" +
+ "X-OBM-TIME:1483703436\\r\\n" +
+ "VERSION:2.0\\r\\n" +
+ "METHOD:REQUEST\\r\\n" +
+ "BEGIN:VEVENT\\r\\n" +
+ "CREATED:20170106T115035Z\\r\\n" +
+ "LAST-MODIFIED:20170106T115036Z\\r\\n" +
+ "DTSTAMP:20170106T115036Z\\r\\n" +
+ "DTSTART:20170111T090000Z\\r\\n" +
+ "DURATION:PT1H30M\\r\\n" +
+ "TRANSP:OPAQUE\\r\\n" +
+ "SEQUENCE:0\\r\\n" +
+ "SUMMARY:Sprint planning #23\\r\\n" +
+ "DESCRIPTION:\\r\\n" +
+ "CLASS:PUBLIC\\r\\n" +
+ "PRIORITY:5\\r\\n" +
+ "ORGANIZER;X-OBM-ID=128;CN=Raphael OUAZANA:MAILTO:ouazana@linagora.com\\r\\n" +
+ "X-OBM-DOMAIN:linagora.com\\r\\n" +
+ "X-OBM-DOMAIN-UUID:02874f7c-d10e-102f-acda-0015176f7922\\r\\n" +
+ "LOCATION:Hangout\\r\\n" +
+ "CATEGORIES:\\r\\n" +
+ "X-OBM-COLOR:\\r\\n" +
+ "UID:f1514f44bf39311568d640727cff54e819573448d09d2e5677987ff29caa01a9e047feb2aab16e43439a608f28671ab7c10e754ce92be513f8e04ae9ff15e65a9819cf285a6962bc\\r\\n" +
+ "ATTENDEE;CUTYPE=INDIVIDUAL;RSVP=TRUE;CN=Matthieu EXT_BAECHLER;PARTSTAT=NEEDS-ACTION;X-OBM-ID=302:MAILTO:baechler@linagora.com\\r\\n" +
+ "ATTENDEE;CUTYPE=INDIVIDUAL;RSVP=TRUE;CN=Laura ROYET;PARTSTAT=NEEDS-ACTION;X-OBM-ID=723:MAILTO:royet@linagora.com\\r\\n" +
+ "ATTENDEE;CUTYPE=INDIVIDUAL;RSVP=TRUE;CN=Raphael OUAZANA;PARTSTAT=ACCEPTED;X-OBM-ID=128:MAILTO:ouazana@linagora.com\\r\\n" +
+ "ATTENDEE;CUTYPE=INDIVIDUAL;RSVP=TRUE;CN=Luc DUZAN;PARTSTAT=NEEDS-ACTION;X-OBM-ID=715:MAILTO:duzan@linagora.com\\r\\n" +
+ "ATTENDEE;CUTYPE=RESOURCE;CN=Salle de reunion Lyon;PARTSTAT=ACCEPTED;X-OBM-ID=66:MAILTO:noreply@linagora.com\\r\\n" +
+ "ATTENDEE;CUTYPE=INDIVIDUAL;RSVP=TRUE;CN=Antoine DUPRAT;PARTSTAT=NEEDS-ACTION;X-OBM-ID=453:MAILTO:duprat@linagora.com\\r\\n" +
+ "ATTENDEE;CUTYPE=INDIVIDUAL;RSVP=TRUE;CN=\\\"Beno�t TELLIER\\\";PARTSTAT=NEEDS-ACTION;X-OBM-ID=623:MAILTO:tellier@linagora.com\\r\\n" +
+ "ATTENDEE;CUTYPE=INDIVIDUAL;RSVP=TRUE;CN=Quynh Quynh N NGUYEN;PARTSTAT=NEEDS-ACTION;X-OBM-ID=769:MAILTO:nguyen@linagora.com\\r\\n" +
+ "END:VEVENT\\r\\n" +
+ "END:VCALENDAR\\r\\n" +
+ "\"";
+ public static final String SMALL_ICS = "\"BEGIN:VCALENDAR\\r\\n" +
+ "PRODID:-//Aliasource Groupe LINAGORA//OBM Calendar 3.2.1-rc2//FR\\r\\n" +
+ "CALSCALE:GREGORIAN\\r\\n" +
+ "X-OBM-TIME:1483439571\\r\\n" +
+ "VERSION:2.0\\r\\n" +
+ "METHOD:REQUEST\\r\\n" +
+ "BEGIN:VEVENT\\r\\n" +
+ "CREATED:20170103T103250Z\\r\\n" +
+ "LAST-MODIFIED:20170103T103250Z\\r\\n" +
+ "DTSTAMP:20170103T103250Z\\r\\n" +
+ "DTSTART:20170120T100000Z\\r\\n" +
+ "DURATION:PT30M\\r\\n" +
+ "TRANSP:OPAQUE\\r\\n" +
+ "SEQUENCE:0\\r\\n" +
+ "SUMMARY:Sprint Social #3 Demo\\r\\n" +
+ "DESCRIPTION:\\r\\n" +
+ "CLASS:PUBLIC\\r\\n" +
+ "PRIORITY:5\\r\\n" +
+ "ORGANIZER;X-OBM-ID=468;CN=Attendee 1:MAILTO:attendee1@linagora.com\\r\\n" +
+ "X-OBM-DOMAIN:linagora.com\\r\\n" +
+ "X-OBM-DOMAIN-UUID:02874f7c-d10e-102f-acda-0015176f7922\\r\\n" +
+ "LOCATION:hangout\\r\\n" +
+ "CATEGORIES:\\r\\n" +
+ "X-OBM-COLOR:\\r\\n" +
+ "UID:f1514f44bf39311568d64072ac247c17656ceafde3b4b3eba961c8c5184cdc6ee047feb2aab16e43439a608f28671ab7c10e754c301b1e32001ad51dd20eac2fc7af20abf4093bbe\\r\\n" +
+ "ATTENDEE;CUTYPE=INDIVIDUAL;RSVP=TRUE;CN=Attendee 2;PARTSTAT=NEEDS-ACTION;X-OBM-ID=348:MAILTO:attendee2@linagora.com\\r\\n" +
+ "END:VEVENT\\r\\n" +
+ "END:VCALENDAR\\r\\n" +
+ "\"";
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ private ICALToJsonAttribute testee;
+
+ @Before
+ public void setUp() {
+ testee = new ICALToJsonAttribute();
+ }
+
+ @Test
+ public void getMailetInfoShouldReturnExpectedValue() throws Exception {
+ assertThat(testee.getMailetInfo()).isEqualTo("ICALToJson Mailet");
+ }
+
+ @Test
+ public void initShouldSetAttributesWhenAbsent() throws Exception {
+ testee.init(FakeMailetConfig.builder().build());
+
+ assertThat(testee.getSourceAttributeName()).isEqualTo(ICALToJsonAttribute.DEFAULT_SOURCE_ATTRIBUTE_NAME);
+ assertThat(testee.getDestinationAttributeName()).isEqualTo(ICALToJsonAttribute.DEFAULT_DESTINATION_ATTRIBUTE_NAME);
+ }
+
+ @Test
+ public void initShouldThrowOnEmptySourceAttribute() throws Exception {
+ expectedException.expect(MessagingException.class);
+
+ testee.init(FakeMailetConfig.builder()
+ .setProperty(ICALToJsonAttribute.SOURCE_ATTRIBUTE_NAME, "")
+ .build());
+ }
+
+ @Test
+ public void initShouldThrowOnEmptyDestinationAttribute() throws Exception {
+ expectedException.expect(MessagingException.class);
+
+ testee.init(FakeMailetConfig.builder()
+ .setProperty(ICALToJsonAttribute.DESTINATION_ATTRIBUTE_NAME, "")
+ .build());
+ }
+
+ @Test
+ public void initShouldSetAttributesWhenPresent() throws Exception {
+ String destination = "myDestination";
+ String source = "mySource";
+ testee.init(FakeMailetConfig.builder()
+ .setProperty(ICALToJsonAttribute.SOURCE_ATTRIBUTE_NAME, source)
+ .setProperty(ICALToJsonAttribute.DESTINATION_ATTRIBUTE_NAME, destination)
+ .build());
+
+ assertThat(testee.getSourceAttributeName()).isEqualTo(source);
+ assertThat(testee.getDestinationAttributeName()).isEqualTo(destination);
+ }
+
+ @Test
+ public void serviceShouldFilterMailsWithoutICALs() throws Exception {
+ testee.init(FakeMailetConfig.builder().build());
+
+ Mail mail = FakeMail.builder()
+ .sender(SENDER)
+ .recipient(MailAddressFixture.OTHER_AT_JAMES)
+ .build();
+ testee.service(mail);
+
+ assertThat(mail.getAttribute(ICALToJsonAttribute.DEFAULT_DESTINATION_ATTRIBUTE_NAME))
+ .isNull();
+ }
+
+ @Test
+ public void serviceShouldNotFailOnWrongAttributeType() throws Exception {
+ testee.init(FakeMailetConfig.builder().build());
+
+ Mail mail = FakeMail.builder()
+ .sender(SENDER)
+ .recipient(MailAddressFixture.OTHER_AT_JAMES)
+ .attribute(ICALToJsonAttribute.DEFAULT_SOURCE_ATTRIBUTE_NAME, "wrong type")
+ .build();
+ testee.service(mail);
+
+ assertThat(mail.getAttribute(ICALToJsonAttribute.DEFAULT_DESTINATION_ATTRIBUTE_NAME))
+ .isNull();
+ }
+
+ @Test
+ public void serviceShouldNotFailOnWrongAttributeParameter() throws Exception {
+ testee.init(FakeMailetConfig.builder().build());
+
+ ImmutableMap<String, String> wrongParametrizedMap = ImmutableMap.<String, String>builder()
+ .put("key", "value")
+ .build();
+ Mail mail = FakeMail.builder()
+ .sender(SENDER)
+ .recipient(MailAddressFixture.OTHER_AT_JAMES)
+ .attribute(ICALToJsonAttribute.DEFAULT_SOURCE_ATTRIBUTE_NAME, wrongParametrizedMap)
+ .build();
+ testee.service(mail);
+
+ assertThat(mail.getAttribute(ICALToJsonAttribute.DEFAULT_DESTINATION_ATTRIBUTE_NAME))
+ .isNull();
+ }
+
+ @Test
+ public void serviceShouldFilterMailsWithoutSender() throws Exception {
+ testee.init(FakeMailetConfig.builder().build());
+
+ Calendar calendar = new CalendarBuilder().build(ClassLoader.getSystemResourceAsStream("ics/meeting.ics"));
+ ImmutableMap<String, Calendar> icals = ImmutableMap.<String, Calendar>builder()
+ .put("key", calendar)
+ .build();
+ Mail mail = FakeMail.builder()
+ .recipient(MailAddressFixture.OTHER_AT_JAMES)
+ .attribute(ICALToJsonAttribute.DEFAULT_SOURCE_ATTRIBUTE_NAME, icals)
+ .build();
+ testee.service(mail);
+
+ assertThat(mail.getAttribute(ICALToJsonAttribute.DEFAULT_DESTINATION_ATTRIBUTE_NAME))
+ .isNull();
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void serviceShouldAttachEmptyListWhenNoRecipient() throws Exception {
+ testee.init(FakeMailetConfig.builder().build());
+
+ Calendar calendar = new CalendarBuilder().build(ClassLoader.getSystemResourceAsStream("ics/meeting.ics"));
+ ImmutableMap<String, Calendar> icals = ImmutableMap.<String, Calendar>builder()
+ .put("key", calendar)
+ .build();
+ Mail mail = FakeMail.builder()
+ .sender(SENDER)
+ .attribute(ICALToJsonAttribute.DEFAULT_SOURCE_ATTRIBUTE_NAME, icals)
+ .build();
+ testee.service(mail);
+
+ assertThat((Map) mail.getAttribute(ICALToJsonAttribute.DEFAULT_DESTINATION_ATTRIBUTE_NAME))
+ .isEmpty();
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void serviceShouldAttachJson() throws Exception {
+ testee.init(FakeMailetConfig.builder().build());
+
+ Calendar calendar = new CalendarBuilder().build(ClassLoader.getSystemResourceAsStream("ics/meeting.ics"));
+ ImmutableMap<String, Calendar> icals = ImmutableMap.<String, Calendar>builder()
+ .put("key", calendar)
+ .build();
+ MailAddress recipient = MailAddressFixture.ANY_AT_JAMES2;
+ Mail mail = FakeMail.builder()
+ .sender(SENDER)
+ .recipient(recipient)
+ .attribute(ICALToJsonAttribute.DEFAULT_SOURCE_ATTRIBUTE_NAME, icals)
+ .build();
+ testee.service(mail);
+
+ Map<String, byte[]> jsons = (Map<String, byte[]>) mail.getAttribute(ICALToJsonAttribute.DEFAULT_DESTINATION_ATTRIBUTE_NAME);
+ assertThat(jsons).hasSize(1);
+ assertThatJson(new String(jsons.values().iterator().next(), Charsets.UTF_8))
+ .isEqualTo("{" +
+ "\"ical\": " + MEETING_ICS +"," +
+ "\"sender\": \"" + SENDER.asString() + "\"," +
+ "\"recipient\": \"" + recipient.asString() + "\"," +
+ "\"uid\": \"f1514f44bf39311568d640727cff54e819573448d09d2e5677987ff29caa01a9e047feb2aab16e43439a608f28671ab7c10e754ce92be513f8e04ae9ff15e65a9819cf285a6962bc\"," +
+ "\"sequence\": \"0\"," +
+ "\"dtstamp\": \"20170106T115036Z\"," +
+ "\"method\": \"REQUEST\"," +
+ "\"recurrence-id\": null" +
+ "}");
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void serviceShouldAttachJsonForSeveralRecipient() throws Exception {
+ testee.init(FakeMailetConfig.builder().build());
+
+ Calendar calendar = new CalendarBuilder().build(ClassLoader.getSystemResourceAsStream("ics/meeting.ics"));
+ ImmutableMap<String, Calendar> icals = ImmutableMap.<String, Calendar>builder()
+ .put("key", calendar)
+ .build();
+ Mail mail = FakeMail.builder()
+ .sender(SENDER)
+ .recipients(MailAddressFixture.OTHER_AT_JAMES, MailAddressFixture.ANY_AT_JAMES2)
+ .attribute(ICALToJsonAttribute.DEFAULT_SOURCE_ATTRIBUTE_NAME, icals)
+ .build();
+ testee.service(mail);
+
+ Map<String, byte[]> jsons = (Map<String, byte[]>) mail.getAttribute(ICALToJsonAttribute.DEFAULT_DESTINATION_ATTRIBUTE_NAME);
+ assertThat(jsons).hasSize(2);
+ List<String> actual = toSortedValueList(jsons);
+
+ assertThatJson(actual.get(0)).isEqualTo("{" +
+ "\"ical\": " + MEETING_ICS +"," +
+ "\"sender\": \"" + SENDER.asString() + "\"," +
+ "\"recipient\": \"" + MailAddressFixture.ANY_AT_JAMES2.asString() + "\"," +
+ "\"uid\": \"f1514f44bf39311568d640727cff54e819573448d09d2e5677987ff29caa01a9e047feb2aab16e43439a608f28671ab7c10e754ce92be513f8e04ae9ff15e65a9819cf285a6962bc\"," +
+ "\"sequence\": \"0\"," +
+ "\"dtstamp\": \"20170106T115036Z\"," +
+ "\"method\": \"REQUEST\"," +
+ "\"recurrence-id\": null" +
+ "}");
+ assertThatJson(actual.get(1)).isEqualTo("{" +
+ "\"ical\": " + MEETING_ICS +"," +
+ "\"sender\": \"" + SENDER.asString() + "\"," +
+ "\"recipient\": \"" + MailAddressFixture.OTHER_AT_JAMES.asString() + "\"," +
+ "\"uid\": \"f1514f44bf39311568d640727cff54e819573448d09d2e5677987ff29caa01a9e047feb2aab16e43439a608f28671ab7c10e754ce92be513f8e04ae9ff15e65a9819cf285a6962bc\"," +
+ "\"sequence\": \"0\"," +
+ "\"dtstamp\": \"20170106T115036Z\"," +
+ "\"method\": \"REQUEST\"," +
+ "\"recurrence-id\": null" +
+ "}");
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void serviceShouldAttachJsonForSeveralICALs() throws Exception {
+ testee.init(FakeMailetConfig.builder().build());
+
+ Calendar calendar = new CalendarBuilder().build(ClassLoader.getSystemResourceAsStream("ics/meeting.ics"));
+ Calendar calendar2 = new CalendarBuilder().build(ClassLoader.getSystemResourceAsStream("ics/meeting_2.ics"));
+ ImmutableMap<String, Calendar> icals = ImmutableMap.<String, Calendar>builder()
+ .put("key", calendar)
+ .put("key2", calendar2)
+ .build();
+ MailAddress recipient = MailAddressFixture.OTHER_AT_JAMES;
+ Mail mail = FakeMail.builder()
+ .sender(SENDER)
+ .recipient(recipient)
+ .attribute(ICALToJsonAttribute.DEFAULT_SOURCE_ATTRIBUTE_NAME, icals)
+ .build();
+ testee.service(mail);
+
+ Map<String, byte[]> jsons = (Map<String, byte[]>) mail.getAttribute(ICALToJsonAttribute.DEFAULT_DESTINATION_ATTRIBUTE_NAME);
+ assertThat(jsons).hasSize(2);
+ List<String> actual = toSortedValueList(jsons);
+
+ assertThatJson(actual.get(0)).isEqualTo("{" +
+ "\"ical\": " + SMALL_ICS +"," +
+ "\"sender\": \"" + SENDER.asString() + "\"," +
+ "\"recipient\": \"" + recipient.asString() + "\"," +
+ "\"uid\": \"f1514f44bf39311568d64072ac247c17656ceafde3b4b3eba961c8c5184cdc6ee047feb2aab16e43439a608f28671ab7c10e754c301b1e32001ad51dd20eac2fc7af20abf4093bbe\"," +
+ "\"sequence\": \"0\"," +
+ "\"dtstamp\": \"20170103T103250Z\"," +
+ "\"method\": \"REQUEST\"," +
+ "\"recurrence-id\": null" +
+ "}");
+ assertThatJson(actual.get(1)).isEqualTo("{" +
+ "\"ical\": " + MEETING_ICS +"," +
+ "\"sender\": \"" + SENDER.asString() + "\"," +
+ "\"recipient\": \"" + recipient.asString() + "\"," +
+ "\"uid\": \"f1514f44bf39311568d640727cff54e819573448d09d2e5677987ff29caa01a9e047feb2aab16e43439a608f28671ab7c10e754ce92be513f8e04ae9ff15e65a9819cf285a6962bc\"," +
+ "\"sequence\": \"0\"," +
+ "\"dtstamp\": \"20170106T115036Z\"," +
+ "\"method\": \"REQUEST\"," +
+ "\"recurrence-id\": null" +
+ "}");
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void serviceShouldFilterInvalidICS() throws Exception {
+ testee.init(FakeMailetConfig.builder().build());
+
+ Calendar calendar = new CalendarBuilder().build(ClassLoader.getSystemResourceAsStream("ics/meeting.ics"));
+ Calendar calendar2 = new CalendarBuilder().build(ClassLoader.getSystemResourceAsStream("ics/meeting_without_uid.ics"));
+ ImmutableMap<String, Calendar> icals = ImmutableMap.<String, Calendar>builder()
+ .put("key", calendar)
+ .put("key2", calendar2)
+ .build();
+ MailAddress recipient = MailAddressFixture.OTHER_AT_JAMES;
+ Mail mail = FakeMail.builder()
+ .sender(SENDER)
+ .recipient(recipient)
+ .attribute(ICALToJsonAttribute.DEFAULT_SOURCE_ATTRIBUTE_NAME, icals)
+ .build();
+ testee.service(mail);
+
+ Map<String, byte[]> jsons = (Map<String, byte[]>) mail.getAttribute(ICALToJsonAttribute.DEFAULT_DESTINATION_ATTRIBUTE_NAME);
+ assertThat(jsons).hasSize(1);
+ List<String> actual = toSortedValueList(jsons);
+
+ assertThatJson(actual.get(0)).isEqualTo("{" +
+ "\"ical\": " + MEETING_ICS + "," +
+ "\"sender\": \"" + SENDER.asString() + "\"," +
+ "\"recipient\": \"" + recipient.asString() + "\"," +
+ "\"uid\": \"f1514f44bf39311568d640727cff54e819573448d09d2e5677987ff29caa01a9e047feb2aab16e43439a608f28671ab7c10e754ce92be513f8e04ae9ff15e65a9819cf285a6962bc\"," +
+ "\"sequence\": \"0\"," +
+ "\"dtstamp\": \"20170106T115036Z\"," +
+ "\"method\": \"REQUEST\"," +
+ "\"recurrence-id\": null" +
+ "}");
+ }
+
+ private List<String> toSortedValueList(Map<String, byte[]> jsons) {
+ return jsons.values()
+ .stream()
+ .map(bytes -> new String(bytes, Charsets.UTF_8))
+ .sorted()
+ .collect(Collectors.toList());
+ }
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/cb844422/mailet/icalendar/src/test/java/org/apache/james/transport/mailets/model/ICALTest.java
----------------------------------------------------------------------
diff --git a/mailet/icalendar/src/test/java/org/apache/james/transport/mailets/model/ICALTest.java b/mailet/icalendar/src/test/java/org/apache/james/transport/mailets/model/ICALTest.java
new file mode 100644
index 0000000..f8ab4ab
--- /dev/null
+++ b/mailet/icalendar/src/test/java/org/apache/james/transport/mailets/model/ICALTest.java
@@ -0,0 +1,196 @@
+/****************************************************************
+ * 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.transport.mailets.model;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.apache.mailet.MailAddress;
+import org.apache.mailet.base.MailAddressFixture;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import net.fortuna.ical4j.data.CalendarBuilder;
+import net.fortuna.ical4j.model.Calendar;
+import nl.jqno.equalsverifier.EqualsVerifier;
+
+public class ICALTest {
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ @Test
+ public void buildShouldFailWhenNoCalendar() throws Exception {
+ expectedException.expect(NullPointerException.class);
+
+ ICAL.builder()
+ .recipient(MailAddressFixture.ANY_AT_JAMES)
+ .sender(MailAddressFixture.OTHER_AT_JAMES)
+ .build();
+ }
+
+ @Test
+ public void buildShouldFailWhenNoSender() throws Exception {
+ expectedException.expect(NullPointerException.class);
+
+ Calendar calendar = new CalendarBuilder().build(ClassLoader.getSystemResourceAsStream("ics/meeting.ics"));
+
+ ICAL.builder()
+ .recipient(MailAddressFixture.ANY_AT_JAMES)
+ .from(calendar)
+ .build();
+ }
+
+ @Test
+ public void buildShouldFailWhenNoRecipient() throws Exception {
+ expectedException.expect(NullPointerException.class);
+
+ Calendar calendar = new CalendarBuilder().build(ClassLoader.getSystemResourceAsStream("ics/meeting.ics"));
+
+ ICAL.builder()
+ .sender(MailAddressFixture.OTHER_AT_JAMES)
+ .from(calendar)
+ .build();
+ }
+
+
+ @Test
+ public void buildShouldWork() throws Exception {
+ Calendar calendar = new CalendarBuilder().build(ClassLoader.getSystemResourceAsStream("ics/meeting.ics"));
+
+ MailAddress recipient = MailAddressFixture.ANY_AT_JAMES;
+ MailAddress sender = MailAddressFixture.OTHER_AT_JAMES;
+ ICAL ical = ICAL.builder()
+ .recipient(recipient)
+ .sender(sender)
+ .from(calendar)
+ .build();
+
+ assertThat(ical.getRecipient()).isEqualTo(recipient.asString());
+ assertThat(ical.getSender()).isEqualTo(sender.asString());
+ assertThat(ical.getUid())
+ .contains("f1514f44bf39311568d640727cff54e819573448d09d2e5677987ff29caa01a9e047feb2aab16e43439a608f28671ab7" +
+ "c10e754ce92be513f8e04ae9ff15e65a9819cf285a6962bc");
+ assertThat(ical.getMethod()).contains("REQUEST");
+ assertThat(ical.getRecurrenceId()).isEmpty();
+ assertThat(ical.getDtstamp()).contains("20170106T115036Z");
+ assertThat(ical.getSequence()).isEqualTo("0");
+ assertThat(ical.getIcal()).isEqualTo("BEGIN:VCALENDAR\r\n" +
+ "PRODID:-//Aliasource Groupe LINAGORA//OBM Calendar 3.2.1-rc2//FR\r\n" +
+ "CALSCALE:GREGORIAN\r\n" +
+ "X-OBM-TIME:1483703436\r\n" +
+ "VERSION:2.0\r\n" +
+ "METHOD:REQUEST\r\n" +
+ "BEGIN:VEVENT\r\n" +
+ "CREATED:20170106T115035Z\r\n" +
+ "LAST-MODIFIED:20170106T115036Z\r\n" +
+ "DTSTAMP:20170106T115036Z\r\n" +
+ "DTSTART:20170111T090000Z\r\n" +
+ "DURATION:PT1H30M\r\n" +
+ "TRANSP:OPAQUE\r\n" +
+ "SEQUENCE:0\r\n" +
+ "SUMMARY:Sprint planning #23\r\n" +
+ "DESCRIPTION:\r\n" +
+ "CLASS:PUBLIC\r\n" +
+ "PRIORITY:5\r\n" +
+ "ORGANIZER;X-OBM-ID=128;CN=Raphael OUAZANA:MAILTO:ouazana@linagora.com\r\n" +
+ "X-OBM-DOMAIN:linagora.com\r\n" +
+ "X-OBM-DOMAIN-UUID:02874f7c-d10e-102f-acda-0015176f7922\r\n" +
+ "LOCATION:Hangout\r\n" +
+ "CATEGORIES:\r\n" +
+ "X-OBM-COLOR:\r\n" +
+ "UID:f1514f44bf39311568d640727cff54e819573448d09d2e5677987ff29caa01a9e047feb2aab16e43439a608f28671ab7c10e754ce92be513f8e04ae9ff15e65a9819cf285a6962bc\r\n" +
+ "ATTENDEE;CUTYPE=INDIVIDUAL;RSVP=TRUE;CN=Matthieu EXT_BAECHLER;PARTSTAT=NEEDS-ACTION;X-OBM-ID=302:MAILTO:baechler@linagora.com\r\n" +
+ "ATTENDEE;CUTYPE=INDIVIDUAL;RSVP=TRUE;CN=Laura ROYET;PARTSTAT=NEEDS-ACTION;X-OBM-ID=723:MAILTO:royet@linagora.com\r\n" +
+ "ATTENDEE;CUTYPE=INDIVIDUAL;RSVP=TRUE;CN=Raphael OUAZANA;PARTSTAT=ACCEPTED;X-OBM-ID=128:MAILTO:ouazana@linagora.com\r\n" +
+ "ATTENDEE;CUTYPE=INDIVIDUAL;RSVP=TRUE;CN=Luc DUZAN;PARTSTAT=NEEDS-ACTION;X-OBM-ID=715:MAILTO:duzan@linagora.com\r\n" +
+ "ATTENDEE;CUTYPE=RESOURCE;CN=Salle de reunion Lyon;PARTSTAT=ACCEPTED;X-OBM-ID=66:MAILTO:noreply@linagora.com\r\n" +
+ "ATTENDEE;CUTYPE=INDIVIDUAL;RSVP=TRUE;CN=Antoine DUPRAT;PARTSTAT=NEEDS-ACTION;X-OBM-ID=453:MAILTO:duprat@linagora.com\r\n" +
+ "ATTENDEE;CUTYPE=INDIVIDUAL;RSVP=TRUE;CN=\"Beno�t TELLIER\";PARTSTAT=NEEDS-ACTION;X-OBM-ID=623:MAILTO:tellier@linagora.com\r\n" +
+ "ATTENDEE;CUTYPE=INDIVIDUAL;RSVP=TRUE;CN=Quynh Quynh N NGUYEN;PARTSTAT=NEEDS-ACTION;X-OBM-ID=769:MAILTO:nguyen@linagora.com\r\n" +
+ "END:VEVENT\r\n" +
+ "END:VCALENDAR\r\n");
+ }
+
+ @Test
+ public void equalsAndHashCodeShouldBeWellImplemented() {
+ EqualsVerifier.forClass(ICAL.class).verify();
+ }
+
+ @Test
+ public void buildShouldThrowOnCalendarWithoutDtstamp() throws Exception {
+ Calendar calendar = new CalendarBuilder().build(ClassLoader.getSystemResourceAsStream("ics/meeting_without_dtstamp.ics"));
+
+ expectedException.expect(IllegalStateException.class);
+
+ MailAddress recipient = MailAddressFixture.ANY_AT_JAMES;
+ MailAddress sender = MailAddressFixture.OTHER_AT_JAMES;
+ ICAL.builder()
+ .recipient(recipient)
+ .sender(sender)
+ .from(calendar)
+ .build();
+ }
+
+ @Test
+ public void buildShouldThrowOnCalendarWithoutUid() throws Exception {
+ Calendar calendar = new CalendarBuilder().build(ClassLoader.getSystemResourceAsStream("ics/meeting_without_uid.ics"));
+
+ expectedException.expect(IllegalStateException.class);
+
+ MailAddress recipient = MailAddressFixture.ANY_AT_JAMES;
+ MailAddress sender = MailAddressFixture.OTHER_AT_JAMES;
+ ICAL.builder()
+ .recipient(recipient)
+ .sender(sender)
+ .from(calendar)
+ .build();
+ }
+
+ @Test
+ public void buildShouldThrowOnCalendarWithoutMethod() throws Exception {
+ Calendar calendar = new CalendarBuilder().build(ClassLoader.getSystemResourceAsStream("ics/meeting_without_method.ics"));
+
+ expectedException.expect(IllegalStateException.class);
+
+ MailAddress recipient = MailAddressFixture.ANY_AT_JAMES;
+ MailAddress sender = MailAddressFixture.OTHER_AT_JAMES;
+ ICAL.builder()
+ .recipient(recipient)
+ .sender(sender)
+ .from(calendar)
+ .build();
+ }
+
+ @Test
+ public void buildShouldSetDefaultValueWhenCalendarWithoutSequence() throws Exception {
+ Calendar calendar = new CalendarBuilder().build(ClassLoader.getSystemResourceAsStream("ics/meeting_without_sequence.ics"));
+
+ MailAddress recipient = MailAddressFixture.ANY_AT_JAMES;
+ MailAddress sender = MailAddressFixture.OTHER_AT_JAMES;
+ ICAL ical = ICAL.builder()
+ .recipient(recipient)
+ .sender(sender)
+ .from(calendar)
+ .build();
+
+ assertThat(ical.getSequence()).isEqualTo(ICAL.DEFAULT_SEQUENCE_VALUE);
+ }
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/cb844422/mailet/icalendar/src/test/resources/ics/meeting_without_method.ics
----------------------------------------------------------------------
diff --git a/mailet/icalendar/src/test/resources/ics/meeting_without_method.ics b/mailet/icalendar/src/test/resources/ics/meeting_without_method.ics
new file mode 100644
index 0000000..2d628f6
--- /dev/null
+++ b/mailet/icalendar/src/test/resources/ics/meeting_without_method.ics
@@ -0,0 +1,30 @@
+BEGIN:VCALENDAR
+PRODID:-//Aliasource Groupe LINAGORA//OBM Calendar 3.2.1-rc2//FR
+CALSCALE:GREGORIAN
+X-OBM-TIME:1483439571
+VERSION:2.0
+BEGIN:VEVENT
+CREATED:20170103T103250Z
+LAST-MODIFIED:20170103T103250Z
+DTSTAMP:20170103T103250Z
+DTSTART:20170120T100000Z
+DURATION:PT30M
+TRANSP:OPAQUE
+SEQUENCE:0
+SUMMARY:Sprint Social #3 Demo
+DESCRIPTION:
+CLASS:PUBLIC
+PRIORITY:5
+ORGANIZER;X-OBM-ID=468;CN=Attendee 1:MAILTO:attendee1@linagora.
+ com
+X-OBM-DOMAIN:linagora.com
+X-OBM-DOMAIN-UUID:02874f7c-d10e-102f-acda-0015176f7922
+LOCATION:hangout
+CATEGORIES:
+X-OBM-COLOR:
+UID:f1514f44bf39311568d64072ac247c17656ceafde3b4b3eba961c8c5184cdc6ee047fe
+ b2aab16e43439a608f28671ab7c10e754c301b1e32001ad51dd20eac2fc7af20abf4093bbe
+ATTENDEE;CUTYPE=INDIVIDUAL;RSVP=TRUE;CN=Attendee 2;PARTSTAT=NEEDS-ACTI
+ ON;X-OBM-ID=348:MAILTO:attendee2@linagora.com
+END:VEVENT
+END:VCALENDAR
http://git-wip-us.apache.org/repos/asf/james-project/blob/cb844422/mailet/icalendar/src/test/resources/ics/meeting_without_sequence.ics
----------------------------------------------------------------------
diff --git a/mailet/icalendar/src/test/resources/ics/meeting_without_sequence.ics b/mailet/icalendar/src/test/resources/ics/meeting_without_sequence.ics
new file mode 100644
index 0000000..ad57338
--- /dev/null
+++ b/mailet/icalendar/src/test/resources/ics/meeting_without_sequence.ics
@@ -0,0 +1,30 @@
+BEGIN:VCALENDAR
+PRODID:-//Aliasource Groupe LINAGORA//OBM Calendar 3.2.1-rc2//FR
+CALSCALE:GREGORIAN
+X-OBM-TIME:1483439571
+VERSION:2.0
+METHOD:REQUEST
+BEGIN:VEVENT
+CREATED:20170103T103250Z
+LAST-MODIFIED:20170103T103250Z
+DTSTAMP:20170103T103250Z
+DTSTART:20170120T100000Z
+DURATION:PT30M
+TRANSP:OPAQUE
+SUMMARY:Sprint Social #3 Demo
+DESCRIPTION:
+CLASS:PUBLIC
+PRIORITY:5
+ORGANIZER;X-OBM-ID=468;CN=Attendee 1:MAILTO:attendee1@linagora.
+ com
+X-OBM-DOMAIN:linagora.com
+X-OBM-DOMAIN-UUID:02874f7c-d10e-102f-acda-0015176f7922
+LOCATION:hangout
+CATEGORIES:
+X-OBM-COLOR:
+UID:f1514f44bf39311568d64072ac247c17656ceafde3b4b3eba961c8c5184cdc6ee047fe
+ b2aab16e43439a608f28671ab7c10e754c301b1e32001ad51dd20eac2fc7af20abf4093bbe
+ATTENDEE;CUTYPE=INDIVIDUAL;RSVP=TRUE;CN=Attendee 2;PARTSTAT=NEEDS-ACTI
+ ON;X-OBM-ID=348:MAILTO:attendee2@linagora.com
+END:VEVENT
+END:VCALENDAR
http://git-wip-us.apache.org/repos/asf/james-project/blob/cb844422/mailet/icalendar/src/test/resources/ics/meeting_without_uid.ics
----------------------------------------------------------------------
diff --git a/mailet/icalendar/src/test/resources/ics/meeting_without_uid.ics b/mailet/icalendar/src/test/resources/ics/meeting_without_uid.ics
new file mode 100644
index 0000000..f7e0c2d
--- /dev/null
+++ b/mailet/icalendar/src/test/resources/ics/meeting_without_uid.ics
@@ -0,0 +1,29 @@
+BEGIN:VCALENDAR
+PRODID:-//Aliasource Groupe LINAGORA//OBM Calendar 3.2.1-rc2//FR
+CALSCALE:GREGORIAN
+X-OBM-TIME:1483439571
+VERSION:2.0
+METHOD:REQUEST
+BEGIN:VEVENT
+CREATED:20170103T103250Z
+LAST-MODIFIED:20170103T103250Z
+DTSTAMP:20170103T103250Z
+DTSTART:20170120T100000Z
+DURATION:PT30M
+TRANSP:OPAQUE
+SEQUENCE:0
+SUMMARY:Sprint Social #3 Demo
+DESCRIPTION:
+CLASS:PUBLIC
+PRIORITY:5
+ORGANIZER;X-OBM-ID=468;CN=Attendee 1:MAILTO:attendee1@linagora.
+ com
+X-OBM-DOMAIN:linagora.com
+X-OBM-DOMAIN-UUID:02874f7c-d10e-102f-acda-0015176f7922
+LOCATION:hangout
+CATEGORIES:
+X-OBM-COLOR:
+ATTENDEE;CUTYPE=INDIVIDUAL;RSVP=TRUE;CN=Attendee 2;PARTSTAT=NEEDS-ACTI
+ ON;X-OBM-ID=348:MAILTO:attendee2@linagora.com
+END:VEVENT
+END:VCALENDAR
http://git-wip-us.apache.org/repos/asf/james-project/blob/cb844422/mailet/pom.xml
----------------------------------------------------------------------
diff --git a/mailet/pom.xml b/mailet/pom.xml
index 1c68cad..fa203b2 100644
--- a/mailet/pom.xml
+++ b/mailet/pom.xml
@@ -59,6 +59,8 @@
<assertj-3.version>3.3.0</assertj-3.version>
<assertj-1-guava.version>1.3.1</assertj-1-guava.version>
<slf4j.version>1.7.7</slf4j.version>
+ <jackson-data.version>2.6.3</jackson-data.version>
+ <guavate.version>1.0.0</guavate.version>
</properties>
@@ -197,6 +199,21 @@
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
+ <dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-databind</artifactId>
+ <version>${jackson-data.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.fasterxml.jackson.datatype</groupId>
+ <artifactId>jackson-datatype-jdk8</artifactId>
+ <version>${jackson-data.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.github.steveash.guavate</groupId>
+ <artifactId>guavate</artifactId>
+ <version>${guavate.version}</version>
+ </dependency>
</dependencies>
</dependencyManagement>
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org