You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@james.apache.org by rc...@apache.org on 2024/11/06 03:44:01 UTC
(james-project) 02/07: JAMES-4082 Introduce LuceneIndexableDocument
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 <vt...@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-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org