All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.james.jmap.model.MessageProperties Maven / Gradle / Ivy

/****************************************************************
 * 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.util.Arrays;
import java.util.Locale;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Stream;

import com.github.steveash.guavate.Guavate;
import com.google.common.base.MoreObjects;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;

public class MessageProperties {

    public static final ImmutableSet MANDATORY_PROPERTIES = ImmutableSet.of(MessageProperty.id);

    private final Optional> messageProperties;
    private final Optional> headersProperties;

    public MessageProperties(Optional> properties) {
        this.messageProperties = properties.map(this::toMessageProperties);
        this.headersProperties = properties.map(this::toHeadersProperties);
    }

    private MessageProperties(Optional> messageProperties,
                              Optional> headersProperties) {
        this.messageProperties = messageProperties;
        this.headersProperties = headersProperties;
    }

    private ImmutableSet toMessageProperties(ImmutableSet properties) {
        return properties.stream().flatMap(MessageProperty::find).collect(Guavate.toImmutableSet());
    }
    
    private ImmutableSet toHeadersProperties(ImmutableSet properties) {
        return properties.stream().flatMap(HeaderProperty::find).collect(Guavate.toImmutableSet());
    }

    public Optional> getOptionalHeadersProperties() {
        return headersProperties;
    }
    
    public Optional> getOptionalMessageProperties() {
        return messageProperties;
    }

    public MessageProperties toOutputProperties() {
        return this.ensureContains(MANDATORY_PROPERTIES)
                .selectBody()
                .overrideHeadersFilteringOnHeadersMessageProperty()
                .ensureHeadersMessageProperty();
    }

    private ImmutableSet buildOutputMessageProperties() {
        return this.messageProperties.orElseGet(MessageProperty::allOutputProperties);
    }

    private MessageProperties usingProperties(Sets.SetView properties) {
        return new MessageProperties(
            Optional.of(properties.immutableCopy()),
            headersProperties);
    }

    private MessageProperties ensureContains(ImmutableSet mandatoryFields) {
        return usingProperties(Sets.union(buildOutputMessageProperties(), mandatoryFields));
    }

    private MessageProperties selectBody() {
        ImmutableSet messageProperties = buildOutputMessageProperties();
        if (messageProperties.contains(MessageProperty.body)) {
            return usingProperties(
                Sets.difference(
                    Sets.union(messageProperties, ImmutableSet.of(MessageProperty.textBody)),
                    ImmutableSet.of(MessageProperty.body)));
        }
        return this;
    }

    private MessageProperties ensureHeadersMessageProperty() {
        if (headersProperties.isPresent() && !headersProperties.get().isEmpty()) {
            return usingProperties(Sets.union(
                buildOutputMessageProperties(),
                ImmutableSet.of(MessageProperty.headers)));
        }
        return this;
    }

    private MessageProperties overrideHeadersFilteringOnHeadersMessageProperty() {
        if (buildOutputMessageProperties().contains(MessageProperty.headers)) {
            return new MessageProperties(messageProperties, Optional.empty());
        }
        return this;
    }


    private enum PropertyType {
        INPUTONLY,
        INPUTOUTPUT
    }

    public enum MessageProperty implements Property {
        id("id"),
        blobId("blobId"),
        threadId("threadId"),
        mailboxIds("mailboxIds"),
        inReplyToMessageId("inReplyToMessageId"),
        isUnread("isUnread"),
        isFlagged("isFlagged"),
        isAnswered("isAnswered"),
        isDraft("isDraft"),
        isForwarded("isForwarded"),
        hasAttachment("hasAttachment"),
        headers("headers"),
        from("from"),
        to("to"),
        cc("cc"),
        bcc("bcc"),
        replyTo("replyTo"),
        subject("subject"),
        date("date"),
        size("size"),
        preview("preview"),
        textBody("textBody"),
        htmlBody("htmlBody"),
        attachments("attachments"),
        attachedMessages("attachedMessages"),
        keywords("keywords"),
        body("body", PropertyType.INPUTONLY);
    
        private final String property;
        private final PropertyType type;

        MessageProperty(String property) {
            this(property, PropertyType.INPUTOUTPUT);
        }

        MessageProperty(String property, PropertyType type) {
            this.property = property;
            this.type = type;
        }
    
        @Override
        public String asFieldName() {
            return property;
        }
    
        public static Stream find(String property) {
            Preconditions.checkNotNull(property);
            return Arrays.stream(values()).filter(entry -> entry.property.equals(property));
        }

        public static ImmutableSet allOutputProperties() {
            return Arrays.stream(values()).filter(MessageProperty::outputProperty).collect(Guavate.toImmutableSet());
        }

        private static boolean outputProperty(MessageProperty p) {
            switch (p.type) {
                case INPUTONLY:
                    return false;
                case INPUTOUTPUT:
                    return true;
                default:
                    throw new IllegalStateException();
            }
        }
    }
    

    public static class HeaderProperty implements Property {
    
        public static final String HEADER_PROPERTY_PREFIX = "headers.";

        public static HeaderProperty fromFieldName(String field) {
            Preconditions.checkArgument(!isMessageHeaderProperty(field));
            return new HeaderProperty(field.toLowerCase(Locale.US));
        }
    
        public static HeaderProperty valueOf(String property) {
            Preconditions.checkArgument(isMessageHeaderProperty(property));
            return new HeaderProperty(stripPrefix(property).toLowerCase(Locale.US));
        }

        private static String stripPrefix(String property) {
            return property.substring(HEADER_PROPERTY_PREFIX.length());
        }

        public static boolean isMessageHeaderProperty(String property) {
            Preconditions.checkNotNull(property);
            return property.startsWith(HEADER_PROPERTY_PREFIX);
        }
        
        public static Stream find(String property) {
            if (isMessageHeaderProperty(property)) {
                return Stream.of(valueOf(property));
            } else {
                return Stream.of();
            }
        }
        
        private String fieldName;
    
        private HeaderProperty(String fieldName) {
            this.fieldName = fieldName;
        }
    
        @Override
        public String asFieldName() {
            return fieldName;
        }
    
        @Override
        public boolean equals(Object obj) {
            if (obj instanceof HeaderProperty) {
                HeaderProperty other = (HeaderProperty) obj;
                return Objects.equals(this.fieldName, other.fieldName);
            }
            return false;
        }
    
        @Override
        public int hashCode() {
            return Objects.hash(fieldName);
        }
    
        @Override
        public String toString() {
            return Objects.toString(fieldName);
        }
    }

    @Override
    public String toString() {
        return MoreObjects.toStringHelper(this)
            .add("headersProperties", headersProperties)
            .add("messageProperties", messageProperties)
            .toString();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy