Repository: james-project Updated Branches: refs/heads/master bc230298b -> ef7c00f2a
JAMES-2591 Handle flags in archive format Project: http://git-wip-us.apache.org/repos/asf/james-project/repo Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/567ec556 Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/567ec556 Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/567ec556 Branch: refs/heads/master Commit: 567ec5560bbc06351177c3dcffb00909f90adfba Parents: a733ea8 Author: datph <[email protected]> Authored: Tue Nov 13 17:58:14 2018 +0700 Committer: Benoit Tellier <[email protected]> Committed: Fri Nov 16 16:57:39 2018 +0700 ---------------------------------------------------------------------- .../james/mailbox/backup/FlagsExtraField.java | 72 +++++ .../org/apache/james/mailbox/backup/Zipper.java | 2 + .../mailbox/backup/FlagExtraFieldTest.java | 303 +++++++++++++++++++ 3 files changed, 377 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/james-project/blob/567ec556/mailbox/backup/src/main/java/org/apache/james/mailbox/backup/FlagsExtraField.java ---------------------------------------------------------------------- diff --git a/mailbox/backup/src/main/java/org/apache/james/mailbox/backup/FlagsExtraField.java b/mailbox/backup/src/main/java/org/apache/james/mailbox/backup/FlagsExtraField.java new file mode 100644 index 0000000..d290472 --- /dev/null +++ b/mailbox/backup/src/main/java/org/apache/james/mailbox/backup/FlagsExtraField.java @@ -0,0 +1,72 @@ +/**************************************************************** + * 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.mailbox.backup; + +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import javax.mail.Flags; + +import org.apache.commons.compress.archivers.zip.ZipShort; +import org.apache.james.util.StreamUtils; + +public class FlagsExtraField extends StringExtraField { + + public static final ZipShort ID_AP = new ZipShort(0x7061); // "ap" in little-endian + + private static String serializeFlags(Flags flags) { + return Stream.concat( + StreamUtils.ofNullable(flags.getSystemFlags()) + .map(FlagsExtraField::systemFlagToString), + StreamUtils.ofNullable(flags.getUserFlags())) + .collect(Collectors.joining("%")); + } + + public FlagsExtraField() { + super(); + } + + public FlagsExtraField(Flags flags) { + super(Optional.of(serializeFlags(flags))); + } + + @Override + public ZipShort getHeaderId() { + return ID_AP; + } + + private static String systemFlagToString(Flags.Flag flag) throws RuntimeException { + if (flag == Flags.Flag.ANSWERED) { + return "\\ANSWERED"; + } else if (flag == Flags.Flag.DELETED) { + return "\\DELETED"; + } else if (flag == Flags.Flag.DRAFT) { + return "\\DRAFT"; + } else if (flag == Flags.Flag.FLAGGED) { + return "\\FLAGGED"; + } else if (flag == Flags.Flag.RECENT) { + return "\\RECENT"; + } else if (flag == Flags.Flag.SEEN) { + return "\\SEEN"; + } + throw new RuntimeException("Unknown system flag"); + } +} http://git-wip-us.apache.org/repos/asf/james-project/blob/567ec556/mailbox/backup/src/main/java/org/apache/james/mailbox/backup/Zipper.java ---------------------------------------------------------------------- diff --git a/mailbox/backup/src/main/java/org/apache/james/mailbox/backup/Zipper.java b/mailbox/backup/src/main/java/org/apache/james/mailbox/backup/Zipper.java index d434331..4d1de4f 100644 --- a/mailbox/backup/src/main/java/org/apache/james/mailbox/backup/Zipper.java +++ b/mailbox/backup/src/main/java/org/apache/james/mailbox/backup/Zipper.java @@ -41,6 +41,7 @@ public class Zipper implements Backup { ExtraFieldUtils.register(MailboxIdExtraField.class); ExtraFieldUtils.register(InternalDateExtraField.class); ExtraFieldUtils.register(UidValidityExtraField.class); + ExtraFieldUtils.register(FlagsExtraField.class); } @Override @@ -84,6 +85,7 @@ public class Zipper implements Backup { archiveEntry.addExtraField(new MessageIdExtraField(message.getMessageId().serialize())); archiveEntry.addExtraField(new MailboxIdExtraField(message.getMailboxId().serialize())); archiveEntry.addExtraField(new InternalDateExtraField(message.getInternalDate())); + archiveEntry.addExtraField(new FlagsExtraField(message.createFlags())); archiveOutputStream.putArchiveEntry(archiveEntry); IOUtils.copy(message.getFullContent(), archiveOutputStream); http://git-wip-us.apache.org/repos/asf/james-project/blob/567ec556/mailbox/backup/src/test/java/org/apache/james/mailbox/backup/FlagExtraFieldTest.java ---------------------------------------------------------------------- diff --git a/mailbox/backup/src/test/java/org/apache/james/mailbox/backup/FlagExtraFieldTest.java b/mailbox/backup/src/test/java/org/apache/james/mailbox/backup/FlagExtraFieldTest.java new file mode 100644 index 0000000..2210438 --- /dev/null +++ b/mailbox/backup/src/test/java/org/apache/james/mailbox/backup/FlagExtraFieldTest.java @@ -0,0 +1,303 @@ +/**************************************************************** + * 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.mailbox.backup; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.charset.StandardCharsets; + +import javax.mail.Flags; + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import com.google.common.base.Charsets; + +import nl.jqno.equalsverifier.EqualsVerifier; +import nl.jqno.equalsverifier.Warning; + +public class FlagExtraFieldTest { + + @Test + public void shouldMatchBeanContract() { + EqualsVerifier.forClass(FlagsExtraField.class) + .suppress(Warning.NONFINAL_FIELDS) + .verify(); + } + + @Nested + class GetHeaderId { + + @Test + void getHeaderIdShouldReturnSpecificStringInLittleEndian() { + FlagsExtraField testee = new FlagsExtraField(); + ByteBuffer byteBuffer = ByteBuffer.wrap(testee.getHeaderId().getBytes()) + .order(ByteOrder.LITTLE_ENDIAN); + + assertThat(Charsets.US_ASCII.decode(byteBuffer).toString()) + .isEqualTo("ap"); + } + } + + @Nested + class GetLocalFileDataLength { + + @Test + void getLocalFileDataLengthShouldThrowWhenNoValue() { + FlagsExtraField testee = new FlagsExtraField(); + + assertThatThrownBy(() -> testee.getLocalFileDataLength().getValue()) + .isInstanceOf(RuntimeException.class); + } + + @Test + void getLocalFileDataLengthShouldReturnIntegerSize() { + FlagsExtraField testee = new FlagsExtraField(new Flags()); + + assertThat(testee.getLocalFileDataLength().getValue()) + .isEqualTo(0); + } + + @Test + void getLocalFileDataLengthShouldReturnIntegerSizeWhenSystemFlagSet() { + Flags flags = new Flags(); + flags.add(Flags.Flag.SEEN); + FlagsExtraField testee = new FlagsExtraField(flags); + + assertThat(testee.getLocalFileDataLength().getValue()) + .isEqualTo(5); + } + + @Test + void getLocalFileDataLengthShouldReturnIntegerSizeWhenUserFlagSet() { + Flags flags = new Flags("myFlags"); + FlagsExtraField testee = new FlagsExtraField(flags); + + assertThat(testee.getLocalFileDataLength().getValue()) + .isEqualTo(7); + } + + @Test + void getLocalFileDataLengthShouldReturnIntegerSizeWhenSystemAndUserFlagSet() { + Flags flags = new Flags("myFlags"); + flags.add(Flags.Flag.ANSWERED); + FlagsExtraField testee = new FlagsExtraField(flags); + + assertThat(testee.getLocalFileDataLength().getValue()) + .isEqualTo(17); + } + } + + @Nested + class GetCentralDirectoryLength { + + @Test + void getCentralDirectoryLengthShouldThrowWhenNoValue() { + FlagsExtraField testee = new FlagsExtraField(); + + assertThatThrownBy(() -> testee.getCentralDirectoryLength().getValue()) + .isInstanceOf(RuntimeException.class); + } + + @Test + void getCentralDirectoryLengthShouldReturnIntegerSize() { + FlagsExtraField testee = new FlagsExtraField(new Flags()); + + assertThat(testee.getCentralDirectoryLength().getValue()) + .isEqualTo(0); + } + + @Test + void getCentralDirectoryLengthShouldReturnIntegerSizeWhenSystemFlagSet() { + Flags flags = new Flags(); + flags.add(Flags.Flag.SEEN); + FlagsExtraField testee = new FlagsExtraField(flags); + + assertThat(testee.getCentralDirectoryLength().getValue()) + .isEqualTo(5); + } + + @Test + void getCentralDirectoryLengthShouldReturnIntegerSizeWhenUserFlagSet() { + Flags flags = new Flags("myFlags"); + flags.add("newFlag"); + FlagsExtraField testee = new FlagsExtraField(flags); + + assertThat(testee.getCentralDirectoryLength().getValue()) + .isEqualTo(15); + } + + @Test + void getLocalFileDataLengthShouldReturnIntegerSizeWhenSystemAndUserFlagSet() { + Flags flags = new Flags("myFlags"); + flags.add(Flags.Flag.ANSWERED); + flags.add(Flags.Flag.SEEN); + FlagsExtraField testee = new FlagsExtraField(flags); + + assertThat(testee.getCentralDirectoryLength().getValue()) + .isEqualTo(23); + } + } + + @Nested + class GetLocalFileData { + + @Test + void getLocalFileDataDataShouldThrowWhenNoValue() { + FlagsExtraField testee = new FlagsExtraField(); + + assertThatThrownBy(() -> testee.getLocalFileDataData()) + .isInstanceOf(RuntimeException.class); + } + + @Test + void getLocalFileDataDataShouldReturnByteArraysOfSystemFlagSet() { + Flags flags = new Flags(); + flags.add(Flags.Flag.SEEN); + FlagsExtraField testee = new FlagsExtraField(flags); + + assertThat(testee.getLocalFileDataData()) + .isEqualTo("\\SEEN".getBytes(StandardCharsets.UTF_8)); + } + + @Test + void getLocalFileDataDataShouldReturnByteArrayOfUserFlagSet() { + Flags flags = new Flags("myFlags"); + FlagsExtraField testee = new FlagsExtraField(flags); + + assertThat(testee.getLocalFileDataData()) + .isEqualTo("myFlags".getBytes(StandardCharsets.UTF_8)); + } + + @Test + void getLocalFileDataDataShouldReturnByteArrayOfSystemAndUserFlagSet() { + Flags flags = new Flags("myFlags"); + flags.add(Flags.Flag.ANSWERED); + flags.add(Flags.Flag.SEEN); + FlagsExtraField testee = new FlagsExtraField(flags); + + assertThat(testee.getLocalFileDataData()) + .isEqualTo("\\ANSWERED%\\SEEN%myFlags".getBytes(StandardCharsets.UTF_8)); + } + } + + @Nested + class GetCentralDirectoryData { + + @Test + void getCentralDirectoryDataShouldThrowWhenNoValue() { + FlagsExtraField testee = new FlagsExtraField(); + + assertThatThrownBy(() -> testee.getCentralDirectoryData()) + .isInstanceOf(RuntimeException.class); + } + + @Test + void getCentralDirectoryDataShouldReturnByteArraysOfSystemFlagSet() { + Flags flags = new Flags(); + flags.add(Flags.Flag.SEEN); + FlagsExtraField testee = new FlagsExtraField(flags); + + assertThat(testee.getCentralDirectoryData()) + .isEqualTo("\\SEEN".getBytes(StandardCharsets.UTF_8)); + } + + @Test + void getCentralDirectoryDataShouldReturnByteArrayOfUserFlagSet() { + Flags flags = new Flags("myFlags"); + FlagsExtraField testee = new FlagsExtraField(flags); + + assertThat(testee.getCentralDirectoryData()) + .isEqualTo("myFlags".getBytes(StandardCharsets.UTF_8)); + } + + @Test + void getCentralDirectoryDataShouldReturnByteArrayOfSystemAndUserFlagSet() { + Flags flags = new Flags("myFlags"); + flags.add(Flags.Flag.ANSWERED); + flags.add(Flags.Flag.SEEN); + FlagsExtraField testee = new FlagsExtraField(flags); + + assertThat(testee.getCentralDirectoryData()) + .isEqualTo("\\ANSWERED%\\SEEN%myFlags".getBytes(StandardCharsets.UTF_8)); + } + } + + @Nested + class ParseFromLocalFileData { + + @Test + void parseFromLocalFileDataShouldParseByteData() { + String bufferContent = "\\ANSWERED%\\SEEN%myFlags"; + Flags flags = new Flags("myFlags"); + flags.add(Flags.Flag.ANSWERED); + flags.add(Flags.Flag.SEEN); + + FlagsExtraField testee = new FlagsExtraField(new Flags()); + testee.parseFromLocalFileData(bufferContent + .getBytes(StandardCharsets.UTF_8), 0, 23); + assertThat(testee.getValue()).contains(bufferContent); + } + + @Test + void parseFromLocalFileDataShouldParseByteDataWhenOffsetSet() { + String bufferContent = "\\ANSWERED%\\SEEN%myFlags"; + Flags flags = new Flags("myFlags"); + flags.add(Flags.Flag.SEEN); + + FlagsExtraField testee = new FlagsExtraField(new Flags()); + testee.parseFromLocalFileData(bufferContent + .getBytes(StandardCharsets.UTF_8), 10, 13); + assertThat(testee.getValue()).contains("\\SEEN%myFlags"); + } + } + + @Nested + class ParseFromCentralDirectoryData { + + @Test + void parseFromCentralDirectoryDataShouldParseByteData() { + String bufferContent = "\\ANSWERED%\\SEEN%myFlags"; + Flags flags = new Flags("myFlags"); + flags.add(Flags.Flag.ANSWERED); + flags.add(Flags.Flag.SEEN); + + FlagsExtraField testee = new FlagsExtraField(new Flags()); + testee.parseFromCentralDirectoryData(bufferContent + .getBytes(StandardCharsets.UTF_8), 0, 23); + assertThat(testee.getValue()).contains(bufferContent); + } + + @Test + void parseFromCentralDirectoryDataShouldParseByteDataWhenOffsetSet() { + String bufferContent = "\\ANSWERED%\\SEEN%myFlags"; + Flags flags = new Flags("myFlags"); + flags.add(Flags.Flag.SEEN); + + FlagsExtraField testee = new FlagsExtraField(new Flags()); + testee.parseFromCentralDirectoryData(bufferContent + .getBytes(StandardCharsets.UTF_8), 10, 13); + assertThat(testee.getValue()).contains("\\SEEN%myFlags"); + } + } +} --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
