Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/****************************************************************
* 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;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.EnumSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import javax.mail.Flags;
import javax.mail.internet.SharedInputStream;
import org.apache.commons.io.IOUtils;
import org.apache.james.mailbox.MailboxManager.MessageCapabilities;
import org.apache.james.mailbox.exception.MailboxException;
import org.apache.james.mailbox.exception.UnsupportedCriteriaException;
import org.apache.james.mailbox.exception.UnsupportedRightException;
import org.apache.james.mailbox.model.ByteContent;
import org.apache.james.mailbox.model.ComposedMessageId;
import org.apache.james.mailbox.model.ComposedMessageIdWithMetaData;
import org.apache.james.mailbox.model.Content;
import org.apache.james.mailbox.model.FetchGroup;
import org.apache.james.mailbox.model.Mailbox;
import org.apache.james.mailbox.model.MailboxACL;
import org.apache.james.mailbox.model.MailboxCounters;
import org.apache.james.mailbox.model.MailboxId;
import org.apache.james.mailbox.model.MailboxPath;
import org.apache.james.mailbox.model.MessageAttachmentMetadata;
import org.apache.james.mailbox.model.MessageRange;
import org.apache.james.mailbox.model.MessageResult;
import org.apache.james.mailbox.model.MessageResultIterator;
import org.apache.james.mailbox.model.SearchQuery;
import org.apache.james.mailbox.model.ThreadId;
import org.apache.james.mailbox.model.UidValidity;
import org.apache.james.mime4j.dom.Message;
import org.apache.james.mime4j.message.DefaultMessageWriter;
import org.reactivestreams.Publisher;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
/**
* Interface which represent a Mailbox
*
* A {@link MessageManager} should be valid for the whole {@link MailboxSession}
*/
public interface MessageManager {
enum FlagsUpdateMode {
ADD,
REMOVE,
REPLACE
}
/**
* Return the count of messages in the mailbox
*/
long getMessageCount(MailboxSession mailboxSession) throws MailboxException;
/**
* Return the count of unseen messages in the mailbox
*/
MailboxCounters getMailboxCounters(MailboxSession mailboxSession) throws MailboxException;
Publisher getMailboxCountersReactive(MailboxSession mailboxSession);
/**
* Return if the Mailbox is writable
* @deprecated use
* {@link #getMetaData(boolean, MailboxSession, MailboxMetaData.FetchGroup)}
*/
@Deprecated
boolean isWriteable(MailboxSession session) throws MailboxException;
/**
* Return true if {@link MessageResult#getModSeq()} is stored in a permanent
* way.
*
* @deprecated use
* {@link #getMetaData(boolean, MailboxSession, MailboxMetaData.FetchGroup)}
*/
@Deprecated
boolean isModSeqPermanent(MailboxSession session);
/**
* Searches for messages matching the given query. The result must be
* ordered
*
* @param mailboxSession
* not null
* @return uid iterator
* @throws UnsupportedCriteriaException
* when any of the search parameters are not supported by this
* mailbox
* @throws MailboxException
* when search fails for other reasons
*/
Publisher search(SearchQuery searchQuery, MailboxSession mailboxSession) throws MailboxException;
/**
* Expunges messages in the given range from this mailbox by first retrieving the messages to be deleted
* and then deleting them.
*
* @param set
* not null
* @param mailboxSession
* not null
* @return uid iterator
* @throws MailboxException
* if anything went wrong
*/
Iterator expunge(MessageRange set, MailboxSession mailboxSession) throws MailboxException;
/**
* Deletes a list of messages given their uids in the mailbox.
*/
void delete(List uids, MailboxSession mailboxSession) throws MailboxException;
/**
* Sets flags on messages within the given range. The new flags are returned
* for each message altered.
*
* @param flags Flags to be taken into account for transformation of stored flags
* @param flagsUpdateMode Mode of the transformation of stored flags
* @param set the range of messages
* @param mailboxSession not null
* @return new flags indexed by UID
*/
Map setFlags(Flags flags, FlagsUpdateMode flagsUpdateMode, MessageRange set, MailboxSession mailboxSession) throws MailboxException;
class AppendResult {
private final ComposedMessageId id;
private final Long size;
private final Optional> messageAttachments;
private final ThreadId threadId;
public AppendResult(ComposedMessageId id, Long size, Optional> messageAttachments, ThreadId threadId) {
this.id = id;
this.size = size;
this.messageAttachments = messageAttachments;
this.threadId = threadId;
}
public ComposedMessageId getId() {
return id;
}
public Long getSize() {
return size;
}
public List getMessageAttachments() {
Preconditions.checkState(messageAttachments.isPresent(), "'attachment storage' not supported by the implementation");
return messageAttachments.get();
}
public ThreadId getThreadId() {
return threadId;
}
@Override
public final boolean equals(Object o) {
if (o instanceof AppendResult) {
AppendResult that = (AppendResult) o;
return Objects.equals(this.id, that.id)
&& Objects.equals(this.messageAttachments, that.messageAttachments)
&& Objects.equals(this.size, that.size)
&& Objects.equals(this.threadId, that.threadId);
}
return false;
}
@Override
public final int hashCode() {
return Objects.hash(id, messageAttachments, size, threadId);
}
}
/**
* Appends a message to this mailbox. This method must return a higher UID
* as the last call in every case which also needs to be unique for the
* lifetime of the mailbox.
*
*
* @param internalDate
* the time of addition to be set, not null
* @param mailboxSession
* not null
* @param isRecent
* true when the message should be marked recent, false otherwise
* @param flags
* optionally set these flags on created message, or null when no
* additional flags should be set
* @return uid for the newly added message
* @throws MailboxException
* when message cannot be appended
*/
AppendResult appendMessage(InputStream msgIn, Date internalDate, MailboxSession mailboxSession, boolean isRecent, Flags flags) throws MailboxException;
class AppendCommand {
public static AppendCommand from(Message.Builder builder) throws IOException {
return builder().build(builder);
}
public static AppendCommand from(Message message) throws IOException {
return builder().build(message);
}
public static AppendCommand from(Content message) {
return builder().build(message);
}
public static AppendCommand from(SharedInputStream message) {
return builder().build(message);
}
public static class Builder {
private Optional internalDate;
private Optional isRecent;
private Optional flags;
private Optional maybeParsedMessage;
private Builder() {
this.internalDate = Optional.empty();
this.isRecent = Optional.empty();
this.flags = Optional.empty();
this.maybeParsedMessage = Optional.empty();
}
public Builder withFlags(Flags flags) {
this.flags = Optional.of(flags);
return this;
}
public Builder withInternalDate(Date date) {
this.internalDate = Optional.of(date);
return this;
}
public Builder withInternalDate(Optional date) {
this.internalDate = date;
return this;
}
public Builder isRecent(boolean recent) {
this.isRecent = Optional.of(recent);
return this;
}
public Builder recent() {
return isRecent(true);
}
public Builder notRecent() {
return isRecent(false);
}
public Builder withParsedMessage(Message message) {
this.maybeParsedMessage = Optional.of(message);
return this;
}
public AppendCommand build(Content msgIn) {
return new AppendCommand(
msgIn,
internalDate.orElse(new Date()),
isRecent.orElse(true),
flags.orElse(new Flags()),
maybeParsedMessage);
}
public AppendCommand build(SharedInputStream msgIn) {
return build(new Content() {
@Override
public InputStream getInputStream() {
return msgIn.newStream(0, -1);
}
@Override
public long size() throws MailboxException {
try {
return IOUtils.consume(getInputStream());
} catch (IOException e) {
throw new MailboxException("Cannot compute content size", e);
}
}
});
}
public AppendCommand build(byte[] msgIn) {
return build(new ByteContent(msgIn));
}
public AppendCommand build(String msgIn) {
return build(msgIn.getBytes(StandardCharsets.UTF_8));
}
public AppendCommand build(Message message) throws IOException {
return withParsedMessage(message)
.build(DefaultMessageWriter.asBytes(message));
}
public AppendCommand build(Message.Builder messageBuilder) throws IOException {
return build(messageBuilder.build());
}
}
public static Builder builder() {
return new Builder();
}
private final Content msgIn;
private final Date internalDate;
private final boolean isRecent;
private final Flags flags;
private final Optional maybeParsedMessage;
private AppendCommand(Content msgIn, Date internalDate, boolean isRecent, Flags flags, Optional maybeParsedMessage) {
this.msgIn = msgIn;
this.internalDate = internalDate;
this.isRecent = isRecent;
this.flags = flags;
this.maybeParsedMessage = maybeParsedMessage;
}
public Content getMsgIn() {
return msgIn;
}
public Date getInternalDate() {
return internalDate;
}
public boolean isRecent() {
return isRecent;
}
public Flags getFlags() {
return flags;
}
public Optional getMaybeParsedMessage() {
return maybeParsedMessage;
}
}
AppendResult appendMessage(AppendCommand appendCommand, MailboxSession session) throws MailboxException;
Publisher appendMessageReactive(AppendCommand appendCommand, MailboxSession session);
/**
* Gets messages in the given range. The messages may get fetched under
* the-hood in batches so the caller should check if
* {@link MessageResultIterator#getException()} returns null
* after {@link MessageResultIterator#hasNext()} returns false.
*
* @param fetchGroup
* data to fetch
* @param mailboxSession
* not null
* @return MessageResult with the fields defined by FetchGroup
*/
MessageResultIterator getMessages(MessageRange set, FetchGroup fetchGroup, MailboxSession mailboxSession) throws MailboxException;
Publisher listMessagesMetadata(MessageRange set, MailboxSession session);
/**
* Return the underlying {@link Mailbox}
*/
Mailbox getMailboxEntity() throws MailboxException;
EnumSet getSupportedMessageCapabilities();
/**
* Gets the id of the referenced mailbox
*/
MailboxId getId();
/**
* Gets the path of the referenced mailbox
*/
MailboxPath getMailboxPath() throws MailboxException;
Flags getApplicableFlags(MailboxSession session) throws MailboxException;
/**
* Gets current meta data for the mailbox.
* Consolidates common calls together to allow improved performance.
* The meta-data returned should be immutable and represent the current
* state of the mailbox.
*
* @param resetRecent
* true when recent flags should be reset, false otherwise
* @param mailboxSession
* context, not null
* @param fetchGroup
* describes which optional data should be returned
* @return metadata view filtered for the session's user, not null
*/
MailboxMetaData getMetaData(boolean resetRecent, MailboxSession mailboxSession, MailboxMetaData.FetchGroup fetchGroup) throws MailboxException;
/**
* Meta data about the current state of the mailbox.
*/
class MailboxMetaData {
/**
* Describes the optional data types which will get set in the
* {@link MailboxMetaData}.
*
* These are always set: - HIGHESTMODSEQ - PERMANENTFLAGS - UIDNEXT -
* UIDVALIDITY - MODSEQPERMANET - WRITABLE
*/
public enum FetchGroup {
/**
* Only include the message and recent count
*/
NO_UNSEEN,
/**
* Only include the unseen message and recent count
*/
UNSEEN_COUNT,
/**
* Only include the first unseen and the recent count
*/
FIRST_UNSEEN,
/**
* Only return the "always set" metadata as documented above
*/
NO_COUNT
}
/**
* Neutral MailboxMetaData to be safely displayed for mailboxes a user can Lookup without Read write.
*
* @return MailboxMetaData with default values for all fields
*/
public static MailboxMetaData sensibleInformationFree(MailboxACL resolvedAcl, UidValidity uidValidity, boolean writeable, boolean modSeqPermanent) {
ImmutableList recents = ImmutableList.of();
MessageUid uidNext = MessageUid.MIN_VALUE;
ModSeq highestModSeq = ModSeq.first();
long messageCount = 0L;
long unseenCount = 0L;
MessageUid firstUnseen = null;
return new MailboxMetaData(
recents,
new Flags(),
uidValidity,
uidNext,
highestModSeq,
messageCount,
unseenCount,
firstUnseen,
writeable,
modSeqPermanent,
resolvedAcl);
}
private final long recentCount;
private final ImmutableList recent;
private final Flags permanentFlags;
private final UidValidity uidValidity;
private final MessageUid nextUid;
private final long messageCount;
private final long unseenCount;
private final MessageUid firstUnseen;
private final boolean writeable;
private final ModSeq highestModSeq;
private final boolean modSeqPermanent;
private final MailboxACL acl;
public MailboxMetaData(List recent, Flags permanentFlags, UidValidity uidValidity, MessageUid uidNext, ModSeq highestModSeq, long messageCount, long unseenCount, MessageUid firstUnseen, boolean writeable, boolean modSeqPermanent, MailboxACL acl) {
this.recent = Optional.ofNullable(recent).map(ImmutableList::copyOf).orElseGet(ImmutableList::of);
this.highestModSeq = highestModSeq;
this.recentCount = this.recent.size();
this.permanentFlags = permanentFlags;
this.uidValidity = uidValidity;
this.nextUid = uidNext;
this.messageCount = messageCount;
this.unseenCount = unseenCount;
this.firstUnseen = firstUnseen;
this.writeable = writeable;
this.modSeqPermanent = modSeqPermanent;
this.acl = acl;
}
/**
* Gets the number of recent messages.
*
* @return the number of messages flagged RECENT in this mailbox
*/
public long countRecent() {
return recentCount;
}
/**
* Gets the flags which can be stored by this mailbox.
*
* @return Flags that can be stored
*/
public Flags getPermanentFlags() {
return permanentFlags;
}
/**
* Gets the UIDs of recent messages if requested or an empty
* {@link List} otherwise.
*
* @return the uids flagged RECENT in this mailbox,
*/
public List getRecent() {
return recent;
}
/**
* Gets the UIDVALIDITY.
*
* @return UIDVALIDITY
*/
public UidValidity getUidValidity() {
return uidValidity;
}
/**
* Gets the next UID predicted. The returned UID is not guaranteed to be
* the one that is assigned to the next message. Its only guaranteed
* that it will be at least equals or bigger then the value
*
* @return the uid that will be assigned to the next appended message
*/
public MessageUid getUidNext() {
return nextUid;
}
/**
* Gets the number of messages that this mailbox contains. This is an
* optional property.
*
* @return number of messages contained or -1 when this optional data
* has not be requested
*
*/
public long getMessageCount() {
return messageCount;
}
/**
* Gets the number of unseen messages contained in this mailbox. This is
* an optional property.
*
* @return number of unseen messages contained or zero when this
* optional data has not been requested
* @see FetchGroup#UNSEEN_COUNT
*/
public long getUnseenCount() {
return unseenCount;
}
/**
* Gets the UID of the first unseen message. This is an optional
* property.
*
* @return uid of the first unseen message, or null when there are no
* unseen messages
* @see FetchGroup#FIRST_UNSEEN
*/
public MessageUid getFirstUnseen() {
return firstUnseen;
}
/**
* Is this mailbox writable?
*
* @return true if read-write, false if read only
*/
public boolean isWriteable() {
return writeable;
}
/**
* Return the highest mod-sequence for the mailbox. If this value has
* changed till the last check you can be sure that some changes where
* happen on the mailbox
*
* @return higestModSeq
*/
public ModSeq getHighestModSeq() {
return highestModSeq;
}
/**
* Return true if the mailbox does store the mod-sequences in a
* permanent way
*
* @return permanent
*/
public boolean isModSeqPermanent() {
return modSeqPermanent;
}
/**
* Returns the ACL concerning this mailbox.
*
* @return acl
*/
public MailboxACL getACL() {
return acl;
}
}
/**
* Get resolved ACL on this Mailbox for the given Session
*
* The result will be the same as calling {MessageManager#getMetaDtata().getAcl()} but will load fewer data
*/
MailboxACL getResolvedAcl(MailboxSession mailboxSession) throws UnsupportedRightException;
}