org.apache.james.jmap.model.MessageFactory.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.james.jmap.model.MessageFactory.java

Source

/****************************************************************
 * 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.jmap.model;

import java.io.IOException;
import java.io.InputStream;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TimeZone;
import java.util.function.Function;
import java.util.stream.Collectors;

import javax.inject.Inject;
import javax.mail.Flags;
import javax.mail.internet.SharedInputStream;

import org.apache.james.jmap.model.MessageContentExtractor.MessageContent;
import org.apache.james.mailbox.exception.MailboxException;
import org.apache.james.mailbox.model.Cid;
import org.apache.james.mailbox.model.MailboxId;
import org.apache.james.mailbox.model.MessageAttachment;
import org.apache.james.mailbox.model.MessageMetaData;
import org.apache.james.mailbox.model.MessageResult;
import org.apache.james.mime4j.dom.address.AddressList;
import org.apache.james.mime4j.dom.address.Mailbox;
import org.apache.james.mime4j.dom.address.MailboxList;
import org.apache.james.mime4j.message.MessageBuilder;
import org.apache.james.mime4j.stream.Field;

import com.github.steveash.guavate.Guavate;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Multimaps;

public class MessageFactory {

    public static final ZoneId UTC_ZONE_ID = ZoneId.of("Z");

    private final MessagePreviewGenerator messagePreview;
    private final MessageContentExtractor messageContentExtractor;

    @Inject
    public MessageFactory(MessagePreviewGenerator messagePreview, MessageContentExtractor messageContentExtractor) {
        this.messagePreview = messagePreview;
        this.messageContentExtractor = messageContentExtractor;
    }

    public Message fromMetaDataWithContent(MetaDataWithContent message) throws MailboxException {
        org.apache.james.mime4j.dom.Message mimeMessage = parse(message);
        MessageContent messageContent = extractContent(mimeMessage);

        return Message.builder().id(message.getMessageId()).blobId(BlobId.of(String.valueOf(message.getUid())))
                .threadId(message.getMessageId().serialize()).mailboxIds(ImmutableList.of(message.getMailboxId()))
                .inReplyToMessageId(getHeader(mimeMessage, "in-reply-to"))
                .isUnread(!message.getFlags().contains(Flags.Flag.SEEN))
                .isFlagged(message.getFlags().contains(Flags.Flag.FLAGGED))
                .isAnswered(message.getFlags().contains(Flags.Flag.ANSWERED))
                .isDraft(message.getFlags().contains(Flags.Flag.DRAFT))
                .subject(Strings.nullToEmpty(mimeMessage.getSubject()).trim())
                .headers(toMap(mimeMessage.getHeader().getFields()))
                .from(firstFromMailboxList(mimeMessage.getFrom())).to(fromAddressList(mimeMessage.getTo()))
                .cc(fromAddressList(mimeMessage.getCc())).bcc(fromAddressList(mimeMessage.getBcc()))
                .replyTo(fromAddressList(mimeMessage.getReplyTo())).size(message.getSize())
                .date(message.getInternalDateAsZonedDateTime()).textBody(messageContent.getTextBody().orElse(null))
                .htmlBody(messageContent.getHtmlBody().orElse(null)).preview(getPreview(messageContent))
                .attachments(getAttachments(message.getAttachments())).build();
    }

    private org.apache.james.mime4j.dom.Message parse(MetaDataWithContent message) throws MailboxException {
        try {
            return MessageBuilder.read(message.getContent())
                    .setDate(message.getInternalDate(), TimeZone.getTimeZone(UTC_ZONE_ID)).build();
        } catch (IOException e) {
            throw new MailboxException("Unable to parse message: " + e.getMessage(), e);
        }
    }

    private MessageContent extractContent(org.apache.james.mime4j.dom.Message mimeMessage) throws MailboxException {
        try {
            return messageContentExtractor.extract(mimeMessage);
        } catch (IOException e) {
            throw new MailboxException("Unable to extract content: " + e.getMessage(), e);
        }
    }

    private String getPreview(MessageContent messageContent) {
        if (messageContent.getHtmlBody().isPresent()) {
            return messagePreview.forHTMLBody(messageContent.getHtmlBody());
        }
        return messagePreview.forTextBody(messageContent.getTextBody());
    }

    private Emailer firstFromMailboxList(MailboxList list) {
        if (list == null) {
            return null;
        }
        return list.stream().map(this::fromMailbox).findFirst().orElse(null);
    }

    private ImmutableList<Emailer> fromAddressList(AddressList list) {
        if (list == null) {
            return ImmutableList.of();
        }
        return list.flatten().stream().map(this::fromMailbox).collect(Guavate.toImmutableList());
    }

    private Emailer fromMailbox(Mailbox mailbox) {
        return Emailer.builder().name(getNameOrAddress(mailbox)).email(mailbox.getAddress()).build();
    }

    private String getNameOrAddress(Mailbox mailbox) {
        if (mailbox.getName() != null) {
            return mailbox.getName();
        }
        return mailbox.getAddress();
    }

    private ImmutableMap<String, String> toMap(List<Field> fields) {
        Function<Entry<String, Collection<Field>>, String> bodyConcatenator = fieldListEntry -> fieldListEntry
                .getValue().stream().map(Field::getBody).collect(Collectors.toList()).stream()
                .collect(Collectors.joining(","));
        return Multimaps.index(fields, Field::getName).asMap().entrySet().stream()
                .collect(Guavate.toImmutableMap(Map.Entry::getKey, bodyConcatenator));
    }

    private String getHeader(org.apache.james.mime4j.dom.Message message, String header) {
        Field field = message.getHeader().getField(header);
        if (field == null) {
            return null;
        }
        return field.getBody();
    }

    private List<Attachment> getAttachments(List<MessageAttachment> attachments) {
        return attachments.stream().map(this::fromMailboxAttachment).collect(Guavate.toImmutableList());
    }

    private Attachment fromMailboxAttachment(MessageAttachment attachment) {
        return Attachment.builder().blobId(BlobId.of(attachment.getAttachmentId().getId()))
                .type(attachment.getAttachment().getType()).size(attachment.getAttachment().getSize())
                .name(attachment.getName().orNull()).cid(attachment.getCid().transform(Cid::getValue).orNull())
                .isInline(attachment.isInline()).build();
    }

    public static class MetaDataWithContent implements MessageMetaData {
        public static Builder builder() {
            return new Builder();
        }

        public static Builder builderFromMessageResult(MessageResult messageResult) throws MailboxException {
            Builder builder = builder().uid(messageResult.getUid()).modSeq(messageResult.getModSeq())
                    .flags(messageResult.getFlags()).size(messageResult.getSize())
                    .internalDate(messageResult.getInternalDate()).attachments(messageResult.getAttachments());
            try {
                return builder.content(messageResult.getFullContent().getInputStream());
            } catch (IOException e) {
                throw new MailboxException("Can't get message full content: " + e.getMessage(), e);
            }
        }

        public static class Builder {
            private Long uid;
            private Long modSeq;
            private Flags flags;
            private Long size;
            private Date internalDate;
            private InputStream content;
            private SharedInputStream sharedContent;
            private List<MessageAttachment> attachments;
            private MailboxId mailboxId;
            private MessageId messageId;

            public Builder uid(long uid) {
                this.uid = uid;
                return this;
            }

            public Builder modSeq(long modSeq) {
                this.modSeq = modSeq;
                return this;
            }

            public Builder flags(Flags flags) {
                this.flags = flags;
                return this;
            }

            public Builder size(long size) {
                this.size = size;
                return this;
            }

            public Builder internalDate(Date internalDate) {
                this.internalDate = internalDate;
                return this;
            }

            public Builder content(InputStream content) {
                this.content = content;
                return this;
            }

            public Builder sharedContent(SharedInputStream sharedContent) {
                this.sharedContent = sharedContent;
                return this;
            }

            public Builder attachments(List<MessageAttachment> attachments) {
                this.attachments = attachments;
                return this;
            }

            public Builder mailboxId(MailboxId mailboxId) {
                this.mailboxId = mailboxId;
                return this;
            }

            public Builder messageId(MessageId messageId) {
                this.messageId = messageId;
                return this;
            }

            public MetaDataWithContent build() {
                Preconditions.checkArgument(uid != null);
                if (modSeq == null) {
                    modSeq = -1L;
                }
                Preconditions.checkArgument(flags != null);
                Preconditions.checkArgument(size != null);
                Preconditions.checkArgument(internalDate != null);
                Preconditions.checkArgument(content != null ^ sharedContent != null);
                Preconditions.checkArgument(attachments != null);
                Preconditions.checkArgument(mailboxId != null);
                Preconditions.checkArgument(messageId != null);
                return new MetaDataWithContent(uid, modSeq, flags, size, internalDate, content, sharedContent,
                        attachments, mailboxId, messageId);
            }
        }

        private final long uid;
        private final long modSeq;
        private final Flags flags;
        private final long size;
        private final Date internalDate;
        private final InputStream content;
        private final SharedInputStream sharedContent;
        private final List<MessageAttachment> attachments;
        private final MailboxId mailboxId;
        private final MessageId messageId;

        private MetaDataWithContent(long uid, long modSeq, Flags flags, long size, Date internalDate,
                InputStream content, SharedInputStream sharedContent, List<MessageAttachment> attachments,
                MailboxId mailboxId, MessageId messageId) {
            this.uid = uid;
            this.modSeq = modSeq;
            this.flags = flags;
            this.size = size;
            this.internalDate = internalDate;
            this.content = content;
            this.sharedContent = sharedContent;
            this.attachments = attachments;
            this.mailboxId = mailboxId;
            this.messageId = messageId;
        }

        @Override
        public long getUid() {
            return uid;
        }

        @Override
        public long getModSeq() {
            return modSeq;
        }

        @Override
        public Flags getFlags() {
            return flags;
        }

        @Override
        public long getSize() {
            return size;
        }

        @Override
        public Date getInternalDate() {
            return internalDate;
        }

        public ZonedDateTime getInternalDateAsZonedDateTime() {
            return ZonedDateTime.ofInstant(internalDate.toInstant(), UTC_ZONE_ID);
        }

        public InputStream getContent() {
            if (sharedContent != null) {
                long begin = 0;
                long allContent = -1;
                return sharedContent.newStream(begin, allContent);
            }
            return content;
        }

        public List<MessageAttachment> getAttachments() {
            return attachments;
        }

        public MailboxId getMailboxId() {
            return mailboxId;
        }

        public MessageId getMessageId() {
            return messageId;
        }

    }
}