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 a4191571ef6ae83eee08b3d51778db80f7c3984d
Author: TungTV <vtt...@linagora.com>
AuthorDate: Mon Nov 4 08:29:24 2024 +0700

    JAMES-4082 Introduce LuceneIndexableDocument
---
 .../lucene/search/DocumentFieldConstants.java      | 253 ++++++++++++++++++
 .../lucene/search/LuceneIndexableDocument.java     | 289 +++++++++++++++++++++
 2 files changed, 542 insertions(+)

diff --git 
a/mailbox/lucene/src/main/java/org/apache/james/mailbox/lucene/search/DocumentFieldConstants.java
 
b/mailbox/lucene/src/main/java/org/apache/james/mailbox/lucene/search/DocumentFieldConstants.java
new file mode 100644
index 0000000000..f9bce07851
--- /dev/null
+++ 
b/mailbox/lucene/src/main/java/org/apache/james/mailbox/lucene/search/DocumentFieldConstants.java
@@ -0,0 +1,253 @@
+/****************************************************************
+ * 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.lucene.search;
+
+import java.util.function.Function;
+
+import jakarta.mail.Flags;
+
+import org.apache.james.mailbox.MailboxSession;
+import org.apache.james.mailbox.model.Mailbox;
+import org.apache.james.mailbox.model.MessageId;
+import org.apache.james.mailbox.store.mail.model.MailboxMessage;
+import org.apache.lucene.document.Document;
+import org.apache.lucene.document.Field;
+
+public interface DocumentFieldConstants {
+
+    /**
+     * {@link Field} which will contain the unique index of the {@link 
Document}
+     */
+    String ID_FIELD = "id";
+
+
+    /**
+     * {@link Field} which will contain uid of the {@link MailboxMessage}
+     */
+    String UID_FIELD = "uid";
+
+    /**
+     * {@link Field} boolean field that say if the message as an attachment or 
not
+     */
+    String HAS_ATTACHMENT_FIELD = "hasAttachment";
+
+    /**
+     * {@link Field} which will contain the {@link Flags} of the {@link 
MailboxMessage}
+     */
+    String FLAGS_FIELD = "flags";
+
+    /**
+     * {@link Field} which will contain the size of the {@link MailboxMessage}
+     */
+    String SIZE_FIELD = "size";
+
+    /**
+     * {@link Field} which will contain the body of the {@link MailboxMessage}
+     */
+    String BODY_FIELD = "body";
+
+    /**
+     * Prefix which will be used for each message header to store it also in a 
seperate {@link Field}
+     */
+    String PREFIX_HEADER_FIELD = "header_";
+
+    /**
+     * {@link Field} which will contain the whole message header of the {@link 
MailboxMessage}
+     */
+    String HEADERS_FIELD = "headers";
+
+    /**
+     * {@link Field} which will contain the mod-sequence of the message
+     */
+    String MODSEQ_FIELD = "modSeq";
+
+    /**
+     * {@link Field} which will contain the threadId of the message
+     */
+    String THREAD_ID_FIELD = "threadId";
+
+    /**
+     * {@link Field} which will contain the TO-Address of the message
+     */
+    String TO_FIELD = "to";
+
+    String FIRST_TO_MAILBOX_NAME_FIELD = "firstToMailboxName";
+
+    /**
+     * {@link Field} which will contain the CC-Address of the message
+     */
+    String CC_FIELD = "cc";
+
+    String FIRST_CC_MAILBOX_NAME_FIELD = "firstCcMailboxName";
+
+
+    /**
+     * {@link Field} which will contain the FROM-Address of the message
+     */
+    String FROM_FIELD = "from";
+
+    String FIRST_FROM_MAILBOX_NAME_FIELD = "firstFromMailboxName";
+
+    /**
+     * {@link Field} which will contain the BCC-Address of the message
+     */
+    String BCC_FIELD = "bcc";
+
+
+    String BASE_SUBJECT_FIELD = "baseSubject";
+    String SUBJECT_FIELD = "subject";
+
+    /**
+     * {@link Field} which contain the internalDate of the message with 
YEAR-Resolution
+     */
+    String INTERNAL_DATE_FIELD_YEAR_RESOLUTION = "internaldateYearResolution";
+
+
+    /**
+     * {@link Field} which contain the internalDate of the message with 
MONTH-Resolution
+     */
+    String INTERNAL_DATE_FIELD_MONTH_RESOLUTION = 
"internaldateMonthResolution";
+
+    /**
+     * {@link Field} which contain the internalDate of the message with 
DAY-Resolution
+     */
+    String INTERNAL_DATE_FIELD_DAY_RESOLUTION = "internaldateDayResolution";
+
+    /**
+     * {@link Field} which contain the internalDate of the message with 
HOUR-Resolution
+     */
+    String INTERNAL_DATE_FIELD_HOUR_RESOLUTION = "internaldateHourResolution";
+
+    /**
+     * {@link Field} which contain the internalDate of the message with 
MINUTE-Resolution
+     */
+    String INTERNAL_DATE_FIELD_MINUTE_RESOLUTION = 
"internaldateMinuteResolution";
+
+    /**
+     * {@link Field} which contain the internalDate of the message with 
SECOND-Resolution
+     */
+    String INTERNAL_DATE_FIELD_SECOND_RESOLUTION = 
"internaldateSecondResolution";
+
+
+    /**
+     * {@link Field} which contain the internalDate of the message with 
MILLISECOND-Resolution
+     */
+    String INTERNAL_DATE_FIELD_MILLISECOND_RESOLUTION = 
"internaldateMillisecondResolution";
+
+    /**
+     * {@link Field} which contain the saveDate of the message with 
YEAR-Resolution
+     */
+    String SAVE_DATE_FIELD_YEAR_RESOLUTION = "saveDateYearResolution";
+
+    /**
+     * {@link Field} which contain the saveDate of the message with 
MONTH-Resolution
+     */
+    String SAVE_DATE_FIELD_MONTH_RESOLUTION = "saveDateMonthResolution";
+
+    /**
+     * {@link Field} which contain the saveDate of the message with 
DAY-Resolution
+     */
+    String SAVE_DATE_FIELD_DAY_RESOLUTION = "saveDateDayResolution";
+
+    /**
+     * {@link Field} which contain the saveDate of the message with 
HOUR-Resolution
+     */
+    String SAVE_DATE_FIELD_HOUR_RESOLUTION = "saveDateHourResolution";
+
+    /**
+     * {@link Field} which contain the saveDate of the message with 
MINUTE-Resolution
+     */
+    String SAVE_DATE_FIELD_MINUTE_RESOLUTION = "saveDateMinuteResolution";
+
+    /**
+     * {@link Field} which contain the saveDate of the message with 
SECOND-Resolution
+     */
+    String SAVE_DATE_FIELD_SECOND_RESOLUTION = "saveDateSecondResolution";
+
+    /**
+     * {@link Field} which will contain the id of the {@link Mailbox}
+     */
+    String MAILBOX_ID_FIELD = "mailboxid";
+
+    /**
+     * {@link Field} which will contain the user of the {@link MailboxSession}
+     */
+    String USERS = "userSession";
+    /**
+     * {@link Field} which will contain the id of the {@link MessageId}
+     */
+    String MESSAGE_ID_FIELD = "messageid";
+
+    /**
+     * {@link Field} which contain the Date header of the message with 
YEAR-Resolution
+     */
+    String SENT_DATE_FIELD_YEAR_RESOLUTION = "sentdateYearResolution";
+
+
+    /**
+     * {@link Field} which contain the Date header of the message with 
MONTH-Resolution
+     */
+    String SENT_DATE_FIELD_MONTH_RESOLUTION = "sentdateMonthResolution";
+
+    /**
+     * {@link Field} which contain the Date header of the message with 
DAY-Resolution
+     */
+    String SENT_DATE_FIELD_DAY_RESOLUTION = "sentdateDayResolution";
+
+    /**
+     * {@link Field} which contain the Date header of the message with 
HOUR-Resolution
+     */
+    String SENT_DATE_FIELD_HOUR_RESOLUTION = "sentdateHourResolution";
+
+    /**
+     * {@link Field} which contain the Date header of the message with 
MINUTE-Resolution
+     */
+    String SENT_DATE_FIELD_MINUTE_RESOLUTION = "sentdateMinuteResolution";
+
+    /**
+     * {@link Field} which contain the Date header of the message with 
SECOND-Resolution
+     */
+    String SENT_DATE_FIELD_SECOND_RESOLUTION = "sentdateSecondResolution";
+
+
+    /**
+     * {@link Field} which contain the Date header of the message with 
MILLISECOND-Resolution
+     */
+    String SENT_DATE_FIELD_MILLISECOND_RESOLUTION = 
"sentdateMillisecondResolution";
+
+    String SENT_DATE_SORT_FIELD_MILLISECOND_RESOLUTION = "sentdateSort";
+
+    String ATTACHMENTS = "attachments";
+
+    interface Attachment {
+        String TEXT_CONTENT = "textContent";
+        String MEDIA_TYPE = "mediaType";
+        String SUBTYPE = "subtype";
+        String CONTENT_DISPOSITION = "contentDisposition";
+        String FILENAME = "fileName";
+        String FILE_EXTENSION = "fileExtension";
+    }
+
+    Function<String, String> ATTACHMENT_FIELD_FUNCTION = (fieldName) -> 
ATTACHMENTS + "." + fieldName;
+
+    String ATTACHMENT_TEXT_CONTENT_FIELD = 
ATTACHMENT_FIELD_FUNCTION.apply(Attachment.TEXT_CONTENT);
+    String ATTACHMENT_FILE_NAME_FIELD = 
ATTACHMENT_FIELD_FUNCTION.apply(Attachment.FILENAME);
+
+}
diff --git 
a/mailbox/lucene/src/main/java/org/apache/james/mailbox/lucene/search/LuceneIndexableDocument.java
 
b/mailbox/lucene/src/main/java/org/apache/james/mailbox/lucene/search/LuceneIndexableDocument.java
new file mode 100644
index 0000000000..1cb006783b
--- /dev/null
+++ 
b/mailbox/lucene/src/main/java/org/apache/james/mailbox/lucene/search/LuceneIndexableDocument.java
@@ -0,0 +1,289 @@
+/****************************************************************
+ * 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.lucene.search;
+
+import static 
org.apache.james.mailbox.lucene.search.DocumentFieldConstants.ATTACHMENT_FILE_NAME_FIELD;
+import static 
org.apache.james.mailbox.lucene.search.DocumentFieldConstants.ATTACHMENT_TEXT_CONTENT_FIELD;
+import static 
org.apache.james.mailbox.lucene.search.DocumentFieldConstants.BASE_SUBJECT_FIELD;
+import static 
org.apache.james.mailbox.lucene.search.DocumentFieldConstants.BCC_FIELD;
+import static 
org.apache.james.mailbox.lucene.search.DocumentFieldConstants.BODY_FIELD;
+import static 
org.apache.james.mailbox.lucene.search.DocumentFieldConstants.CC_FIELD;
+import static 
org.apache.james.mailbox.lucene.search.DocumentFieldConstants.FIRST_CC_MAILBOX_NAME_FIELD;
+import static 
org.apache.james.mailbox.lucene.search.DocumentFieldConstants.FIRST_FROM_MAILBOX_NAME_FIELD;
+import static 
org.apache.james.mailbox.lucene.search.DocumentFieldConstants.FIRST_TO_MAILBOX_NAME_FIELD;
+import static 
org.apache.james.mailbox.lucene.search.DocumentFieldConstants.FLAGS_FIELD;
+import static 
org.apache.james.mailbox.lucene.search.DocumentFieldConstants.FROM_FIELD;
+import static 
org.apache.james.mailbox.lucene.search.DocumentFieldConstants.HAS_ATTACHMENT_FIELD;
+import static 
org.apache.james.mailbox.lucene.search.DocumentFieldConstants.HEADERS_FIELD;
+import static 
org.apache.james.mailbox.lucene.search.DocumentFieldConstants.ID_FIELD;
+import static 
org.apache.james.mailbox.lucene.search.DocumentFieldConstants.INTERNAL_DATE_FIELD_DAY_RESOLUTION;
+import static 
org.apache.james.mailbox.lucene.search.DocumentFieldConstants.INTERNAL_DATE_FIELD_HOUR_RESOLUTION;
+import static 
org.apache.james.mailbox.lucene.search.DocumentFieldConstants.INTERNAL_DATE_FIELD_MILLISECOND_RESOLUTION;
+import static 
org.apache.james.mailbox.lucene.search.DocumentFieldConstants.INTERNAL_DATE_FIELD_MINUTE_RESOLUTION;
+import static 
org.apache.james.mailbox.lucene.search.DocumentFieldConstants.INTERNAL_DATE_FIELD_MONTH_RESOLUTION;
+import static 
org.apache.james.mailbox.lucene.search.DocumentFieldConstants.INTERNAL_DATE_FIELD_SECOND_RESOLUTION;
+import static 
org.apache.james.mailbox.lucene.search.DocumentFieldConstants.INTERNAL_DATE_FIELD_YEAR_RESOLUTION;
+import static 
org.apache.james.mailbox.lucene.search.DocumentFieldConstants.MAILBOX_ID_FIELD;
+import static 
org.apache.james.mailbox.lucene.search.DocumentFieldConstants.MESSAGE_ID_FIELD;
+import static 
org.apache.james.mailbox.lucene.search.DocumentFieldConstants.PREFIX_HEADER_FIELD;
+import static 
org.apache.james.mailbox.lucene.search.DocumentFieldConstants.SAVE_DATE_FIELD_DAY_RESOLUTION;
+import static 
org.apache.james.mailbox.lucene.search.DocumentFieldConstants.SAVE_DATE_FIELD_HOUR_RESOLUTION;
+import static 
org.apache.james.mailbox.lucene.search.DocumentFieldConstants.SAVE_DATE_FIELD_MINUTE_RESOLUTION;
+import static 
org.apache.james.mailbox.lucene.search.DocumentFieldConstants.SAVE_DATE_FIELD_MONTH_RESOLUTION;
+import static 
org.apache.james.mailbox.lucene.search.DocumentFieldConstants.SAVE_DATE_FIELD_SECOND_RESOLUTION;
+import static 
org.apache.james.mailbox.lucene.search.DocumentFieldConstants.SAVE_DATE_FIELD_YEAR_RESOLUTION;
+import static 
org.apache.james.mailbox.lucene.search.DocumentFieldConstants.SENT_DATE_FIELD_DAY_RESOLUTION;
+import static 
org.apache.james.mailbox.lucene.search.DocumentFieldConstants.SENT_DATE_FIELD_HOUR_RESOLUTION;
+import static 
org.apache.james.mailbox.lucene.search.DocumentFieldConstants.SENT_DATE_FIELD_MILLISECOND_RESOLUTION;
+import static 
org.apache.james.mailbox.lucene.search.DocumentFieldConstants.SENT_DATE_FIELD_MINUTE_RESOLUTION;
+import static 
org.apache.james.mailbox.lucene.search.DocumentFieldConstants.SENT_DATE_FIELD_MONTH_RESOLUTION;
+import static 
org.apache.james.mailbox.lucene.search.DocumentFieldConstants.SENT_DATE_FIELD_SECOND_RESOLUTION;
+import static 
org.apache.james.mailbox.lucene.search.DocumentFieldConstants.SENT_DATE_FIELD_YEAR_RESOLUTION;
+import static 
org.apache.james.mailbox.lucene.search.DocumentFieldConstants.SENT_DATE_SORT_FIELD_MILLISECOND_RESOLUTION;
+import static 
org.apache.james.mailbox.lucene.search.DocumentFieldConstants.SIZE_FIELD;
+import static 
org.apache.james.mailbox.lucene.search.DocumentFieldConstants.SUBJECT_FIELD;
+import static 
org.apache.james.mailbox.lucene.search.DocumentFieldConstants.THREAD_ID_FIELD;
+import static 
org.apache.james.mailbox.lucene.search.DocumentFieldConstants.TO_FIELD;
+import static 
org.apache.james.mailbox.lucene.search.DocumentFieldConstants.UID_FIELD;
+import static 
org.apache.james.mailbox.lucene.search.DocumentFieldConstants.USERS;
+
+import java.util.Arrays;
+import java.util.Date;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Optional;
+
+import jakarta.mail.Flags;
+
+import org.apache.james.mailbox.MailboxSession;
+import org.apache.james.mailbox.MessageUid;
+import org.apache.james.mailbox.extractor.TextExtractor;
+import org.apache.james.mailbox.model.MailboxId;
+import org.apache.james.mailbox.model.MessageAttachmentMetadata;
+import org.apache.james.mailbox.store.mail.model.MailboxMessage;
+import org.apache.james.mailbox.store.search.SearchUtil;
+import org.apache.james.mailbox.store.search.mime.EMailers;
+import org.apache.james.mailbox.store.search.mime.HeaderCollection;
+import org.apache.james.mailbox.store.search.mime.MimePart;
+import org.apache.james.mailbox.store.search.mime.MimePartParser;
+import org.apache.lucene.document.DateTools;
+import org.apache.lucene.document.Document;
+import org.apache.lucene.document.Field;
+import org.apache.lucene.document.LongPoint;
+import org.apache.lucene.document.NumericDocValuesField;
+import org.apache.lucene.document.SortedSetDocValuesField;
+import org.apache.lucene.document.StoredField;
+import org.apache.lucene.document.StringField;
+import org.apache.lucene.document.TextField;
+import org.apache.lucene.util.BytesRef;
+
+import com.github.fge.lambdas.Throwing;
+import com.google.common.collect.ImmutableMap;
+
+import reactor.core.publisher.Mono;
+
+public class LuceneIndexableDocument {
+    public static final Map<Flags.Flag, String> SYSTEM_FLAG_STRING_MAP = 
ImmutableMap.<Flags.Flag, String>builder()
+        .put(Flags.Flag.ANSWERED, "\\ANSWERED")
+        .put(Flags.Flag.DELETED, "\\DELETED")
+        .put(Flags.Flag.DRAFT, "\\DRAFT")
+        .put(Flags.Flag.FLAGGED, "\\FLAGGED")
+        .put(Flags.Flag.RECENT, "\\RECENT")
+        .put(Flags.Flag.SEEN, "\\FLAG")
+        .build();
+
+    private final TextExtractor textExtractor;
+
+    public LuceneIndexableDocument(TextExtractor textExtractor) {
+        this.textExtractor = textExtractor;
+    }
+
+    public Mono<Document> createMessageDocument(MailboxMessage message, 
MailboxSession session) {
+        return Throwing.supplier(() -> new 
MimePartParser(textExtractor).parse(message.getFullContent())).get()
+            .asMimePart(textExtractor)
+            .map(parsingResult -> createMessageDocument(message, session, 
parsingResult));
+    }
+
+    /**
+     * Create a new {@link Document} for the given {@link MailboxMessage}. 
This Document does not contain any flags data. The {@link Flags} are stored in 
a seperate Document.
+     * <p>
+     * See {@link #createFlagsDocument(MailboxMessage)}
+     */
+    public Document createMessageDocument(MailboxMessage message, 
MailboxSession session, MimePart mimePartExtracted) {
+        Document doc = new Document();
+        doc.add(new StringField(USERS, 
session.getUser().asString().toUpperCase(Locale.US), Field.Store.YES));
+        doc.add(new StringField(MAILBOX_ID_FIELD, 
message.getMailboxId().serialize().toUpperCase(Locale.US), Field.Store.YES));
+        doc.add(new NumericDocValuesField(UID_FIELD, 
message.getUid().asLong()));
+        doc.add(new LongPoint(UID_FIELD, message.getUid().asLong()));
+        doc.add(new StoredField(UID_FIELD, message.getUid().asLong()));
+        doc.add(new StringField(HAS_ATTACHMENT_FIELD, 
Boolean.toString(MessageAttachmentMetadata.hasNonInlinedAttachment(message.getAttachments())),
 Field.Store.YES));
+        doc.add(new LongPoint(SIZE_FIELD, message.getFullContentOctets()));
+        doc.add(new NumericDocValuesField(SIZE_FIELD, 
message.getFullContentOctets()));
+
+        // create a unique key for the document which can be used later on 
updates to find the document
+        doc.add(new StringField(ID_FIELD, 
message.getMailboxId().serialize().toUpperCase(Locale.US) + "-" + 
message.getUid().asLong(), Field.Store.YES));
+
+        
Optional.ofNullable(SearchUtil.getSerializedMessageIdIfSupportedByUnderlyingStorageOrNull(message))
+            .ifPresent(serializedMessageId -> doc.add(new 
StringField(MESSAGE_ID_FIELD, serializedMessageId, Field.Store.YES)));
+        
Optional.ofNullable(SearchUtil.getSerializedThreadIdIfSupportedByUnderlyingStorageOrNull(message))
+            .ifPresent(serializedThreadId -> doc.add(new 
StringField(THREAD_ID_FIELD, serializedThreadId, Field.Store.YES)));
+
+        HeaderCollection headerCollection = 
mimePartExtracted.getHeaderCollection();
+
+        // index date fields
+        indexInternalDateFields(message.getInternalDate(), doc);
+        message.getSaveDate().ifPresent(saveDate -> 
indexSaveDateFields(saveDate, doc));
+        headerCollection.getSentDate()
+            .map(zonedDateTime -> Date.from(zonedDateTime.toInstant()))
+            .or(() -> Optional.ofNullable(message.getInternalDate()))
+            .ifPresent(sentDate -> indexSentDateFields(sentDate, doc));
+
+        // index header
+        headerCollection.getHeaders()
+            .forEach(header -> {
+                String headerName = uppercase(header.getHeaderName());
+                String headerValue = uppercase(header.getValue());
+                doc.add(new TextField(HEADERS_FIELD, String.format("%s: %s", 
headerName, headerValue), Field.Store.NO));
+                doc.add(new TextField(PREFIX_HEADER_FIELD + headerName, 
headerValue, Field.Store.NO));
+
+                switch (headerName) {
+                    case "TO":
+                        doc.add(new TextField(TO_FIELD, headerValue, 
Field.Store.NO));
+                        doc.add(new 
SortedSetDocValuesField(FIRST_TO_MAILBOX_NAME_FIELD, new 
BytesRef(SearchUtil.getMailboxAddress(header.getValue()))));
+                        break;
+                    case "FROM":
+                        doc.add(new TextField(FROM_FIELD, headerValue, 
Field.Store.NO));
+                        doc.add(new 
SortedSetDocValuesField(FIRST_FROM_MAILBOX_NAME_FIELD, new 
BytesRef(SearchUtil.getMailboxAddress(header.getValue()))));
+                        break;
+                    case "CC":
+                        doc.add(new TextField(CC_FIELD, headerValue, 
Field.Store.NO));
+                        doc.add(new 
SortedSetDocValuesField(FIRST_CC_MAILBOX_NAME_FIELD, new 
BytesRef(SearchUtil.getMailboxAddress(header.getValue()))));
+                        break;
+                    case "BCC":
+                        doc.add(new TextField(BCC_FIELD, headerValue, 
Field.Store.NO));
+                        break;
+                    case "SUBJECT":
+                        doc.add(new StringField(SUBJECT_FIELD, 
header.getValue(), Field.Store.YES));
+                        doc.add(new StringField(BASE_SUBJECT_FIELD, 
headerValue, Field.Store.NO));
+                        doc.add(new 
SortedSetDocValuesField(BASE_SUBJECT_FIELD, new 
BytesRef(SearchUtil.getBaseSubject(headerValue))));
+                        break;
+                    default:
+                        break;
+                }
+            });
+
+        doc.add(new TextField(FROM_FIELD, 
uppercase(EMailers.from(headerCollection.getFromAddressSet()).serialize()), 
Field.Store.YES));
+        doc.add(new TextField(TO_FIELD, 
uppercase(EMailers.from(headerCollection.getToAddressSet()).serialize()), 
Field.Store.YES));
+        doc.add(new TextField(CC_FIELD, 
uppercase(EMailers.from(headerCollection.getCcAddressSet()).serialize()), 
Field.Store.YES));
+        doc.add(new TextField(BCC_FIELD, 
uppercase(EMailers.from(headerCollection.getBccAddressSet()).serialize()), 
Field.Store.YES));
+
+        // index body
+        Optional<String> bodyText = mimePartExtracted.locateFirstTextBody();
+        Optional<String> bodyHtml = mimePartExtracted.locateFirstHtmlBody();
+
+        bodyText.or(() -> bodyHtml)
+            .ifPresent(bodyContent -> doc.add(new TextField(BODY_FIELD, 
bodyContent, Field.Store.YES)));
+
+        // index attachment
+        mimePartExtracted.getAttachmentsStream().forEach(attachmentFields -> {
+            attachmentFields.getTextualBody().ifPresent(textualBody -> 
doc.add(new TextField(ATTACHMENT_TEXT_CONTENT_FIELD, textualBody, 
Field.Store.YES)));
+            attachmentFields.getFileName().ifPresent(fileName -> doc.add(new 
StringField(ATTACHMENT_FILE_NAME_FIELD, uppercase(fileName), Field.Store.YES)));
+        });
+        return doc;
+    }
+
+    /**
+     * Index the {@link Flags} and add it to the {@link Document}
+     */
+    public Document createFlagsDocument(MailboxMessage message) {
+        return createFlagsDocument(message.getMailboxId(), message.getUid(), 
message.createFlags());
+    }
+
+    public Document createFlagsDocument(MailboxId mailboxId, final MessageUid 
messageUid, Flags messageFlags) {
+        Document doc = new Document();
+        doc.add(new StringField(ID_FIELD, createFlagsIdField(mailboxId, 
messageUid), Field.Store.YES));
+        doc.add(new StringField(MAILBOX_ID_FIELD, mailboxId.serialize(), 
Field.Store.YES));
+
+        Optional.of(messageUid.asLong())
+            .ifPresent(uidAsLong -> {
+                doc.add(new NumericDocValuesField(UID_FIELD, uidAsLong));
+                doc.add(new LongPoint(UID_FIELD, uidAsLong));
+                doc.add(new StoredField(UID_FIELD, uidAsLong));
+            });
+
+        Arrays.stream(messageFlags.getSystemFlags())
+            .forEach(sysFlag ->
+                doc.add(new StringField(FLAGS_FIELD, 
Optional.ofNullable(SYSTEM_FLAG_STRING_MAP.get(sysFlag))
+                    .orElse(sysFlag.toString()), Field.Store.YES)));
+
+        Arrays.stream(messageFlags.getUserFlags())
+            .forEach(userFlag -> doc.add(new StringField(FLAGS_FIELD, 
userFlag, Field.Store.YES)));
+
+        // if no flags are there we just use a empty field
+        if (messageFlags.getSystemFlags().length == 0 && 
messageFlags.getUserFlags().length == 0) {
+            doc.add(new StringField(FLAGS_FIELD, "", Field.Store.NO));
+        }
+
+        return doc;
+    }
+
+    public static String createFlagsIdField(MailboxId mailboxId, MessageUid 
messageUid) {
+        return "flags-" + mailboxId.serialize() + "-" + messageUid.asLong();
+    }
+
+    private static void indexSaveDateFields(Date saveDate, Document doc) {
+        doc.add(new StringField(SAVE_DATE_FIELD_YEAR_RESOLUTION, 
DateTools.dateToString(saveDate, DateTools.Resolution.YEAR), Field.Store.NO));
+        doc.add(new StringField(SAVE_DATE_FIELD_MONTH_RESOLUTION, 
DateTools.dateToString(saveDate, DateTools.Resolution.MONTH), Field.Store.NO));
+        doc.add(new StringField(SAVE_DATE_FIELD_DAY_RESOLUTION, 
DateTools.dateToString(saveDate, DateTools.Resolution.DAY), Field.Store.NO));
+        doc.add(new StringField(SAVE_DATE_FIELD_HOUR_RESOLUTION, 
DateTools.dateToString(saveDate, DateTools.Resolution.HOUR), Field.Store.NO));
+        doc.add(new StringField(SAVE_DATE_FIELD_MINUTE_RESOLUTION, 
DateTools.dateToString(saveDate, DateTools.Resolution.MINUTE), Field.Store.NO));
+        doc.add(new StringField(SAVE_DATE_FIELD_SECOND_RESOLUTION, 
DateTools.dateToString(saveDate, DateTools.Resolution.SECOND), Field.Store.NO));
+    }
+
+    private static void indexInternalDateFields(Date date, Document doc) {
+        doc.add(new StringField(INTERNAL_DATE_FIELD_YEAR_RESOLUTION, 
DateTools.dateToString(date, DateTools.Resolution.YEAR), Field.Store.NO));
+        doc.add(new StringField(INTERNAL_DATE_FIELD_MONTH_RESOLUTION, 
DateTools.dateToString(date, DateTools.Resolution.MONTH), Field.Store.NO));
+        doc.add(new StringField(INTERNAL_DATE_FIELD_DAY_RESOLUTION, 
DateTools.dateToString(date, DateTools.Resolution.DAY), Field.Store.NO));
+        doc.add(new StringField(INTERNAL_DATE_FIELD_HOUR_RESOLUTION, 
DateTools.dateToString(date, DateTools.Resolution.HOUR), Field.Store.NO));
+        doc.add(new StringField(INTERNAL_DATE_FIELD_MINUTE_RESOLUTION, 
DateTools.dateToString(date, DateTools.Resolution.MINUTE), Field.Store.NO));
+        doc.add(new StringField(INTERNAL_DATE_FIELD_SECOND_RESOLUTION, 
DateTools.dateToString(date, DateTools.Resolution.SECOND), Field.Store.NO));
+        doc.add(new 
NumericDocValuesField(INTERNAL_DATE_FIELD_MILLISECOND_RESOLUTION, 
Long.parseLong(DateTools.dateToString(date, 
DateTools.Resolution.MILLISECOND))));
+    }
+
+    private static void indexSentDateFields(Date sentDate, Document doc) {
+        doc.add(new StringField(SENT_DATE_FIELD_YEAR_RESOLUTION, 
DateTools.dateToString(sentDate, DateTools.Resolution.YEAR), Field.Store.NO));
+        doc.add(new StringField(SENT_DATE_FIELD_MONTH_RESOLUTION, 
DateTools.dateToString(sentDate, DateTools.Resolution.MONTH), Field.Store.NO));
+        doc.add(new StringField(SENT_DATE_FIELD_DAY_RESOLUTION, 
DateTools.dateToString(sentDate, DateTools.Resolution.DAY), Field.Store.NO));
+        doc.add(new StringField(SENT_DATE_FIELD_HOUR_RESOLUTION, 
DateTools.dateToString(sentDate, DateTools.Resolution.HOUR), Field.Store.NO));
+        doc.add(new StringField(SENT_DATE_FIELD_MINUTE_RESOLUTION, 
DateTools.dateToString(sentDate, DateTools.Resolution.MINUTE), Field.Store.NO));
+        doc.add(new StringField(SENT_DATE_FIELD_SECOND_RESOLUTION, 
DateTools.dateToString(sentDate, DateTools.Resolution.SECOND), Field.Store.NO));
+        doc.add(new StringField(SENT_DATE_FIELD_MILLISECOND_RESOLUTION, 
DateTools.dateToString(sentDate, DateTools.Resolution.MILLISECOND), 
Field.Store.NO));
+        doc.add(new 
NumericDocValuesField(SENT_DATE_SORT_FIELD_MILLISECOND_RESOLUTION, 
Long.parseLong(DateTools.dateToString(sentDate, 
DateTools.Resolution.MILLISECOND))));
+    }
+
+    public static String uppercase(String value) {
+        return value.toUpperCase(Locale.US);
+    }
+
+    public static String lowercase(String value) {
+        return value.toLowerCase(Locale.US);
+    }
+
+}


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

Reply via email to