org.apache.james.queue.rabbitmq.view.cassandra.EnqueuedMailsDaoUtil.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.james.queue.rabbitmq.view.cassandra.EnqueuedMailsDaoUtil.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.queue.rabbitmq.view.cassandra;

import static org.apache.james.queue.rabbitmq.view.cassandra.CassandraMailQueueViewModule.EnqueuedMailsTable.ATTRIBUTES;
import static org.apache.james.queue.rabbitmq.view.cassandra.CassandraMailQueueViewModule.EnqueuedMailsTable.BODY_BLOB_ID;
import static org.apache.james.queue.rabbitmq.view.cassandra.CassandraMailQueueViewModule.EnqueuedMailsTable.BUCKET_ID;
import static org.apache.james.queue.rabbitmq.view.cassandra.CassandraMailQueueViewModule.EnqueuedMailsTable.ENQUEUED_TIME;
import static org.apache.james.queue.rabbitmq.view.cassandra.CassandraMailQueueViewModule.EnqueuedMailsTable.ERROR_MESSAGE;
import static org.apache.james.queue.rabbitmq.view.cassandra.CassandraMailQueueViewModule.EnqueuedMailsTable.HEADER_BLOB_ID;
import static org.apache.james.queue.rabbitmq.view.cassandra.CassandraMailQueueViewModule.EnqueuedMailsTable.HEADER_NAME;
import static org.apache.james.queue.rabbitmq.view.cassandra.CassandraMailQueueViewModule.EnqueuedMailsTable.HEADER_TYPE;
import static org.apache.james.queue.rabbitmq.view.cassandra.CassandraMailQueueViewModule.EnqueuedMailsTable.HEADER_VALUE;
import static org.apache.james.queue.rabbitmq.view.cassandra.CassandraMailQueueViewModule.EnqueuedMailsTable.LAST_UPDATED;
import static org.apache.james.queue.rabbitmq.view.cassandra.CassandraMailQueueViewModule.EnqueuedMailsTable.MAIL_KEY;
import static org.apache.james.queue.rabbitmq.view.cassandra.CassandraMailQueueViewModule.EnqueuedMailsTable.PER_RECIPIENT_SPECIFIC_HEADERS;
import static org.apache.james.queue.rabbitmq.view.cassandra.CassandraMailQueueViewModule.EnqueuedMailsTable.QUEUE_NAME;
import static org.apache.james.queue.rabbitmq.view.cassandra.CassandraMailQueueViewModule.EnqueuedMailsTable.RECIPIENTS;
import static org.apache.james.queue.rabbitmq.view.cassandra.CassandraMailQueueViewModule.EnqueuedMailsTable.REMOTE_ADDR;
import static org.apache.james.queue.rabbitmq.view.cassandra.CassandraMailQueueViewModule.EnqueuedMailsTable.REMOTE_HOST;
import static org.apache.james.queue.rabbitmq.view.cassandra.CassandraMailQueueViewModule.EnqueuedMailsTable.SENDER;
import static org.apache.james.queue.rabbitmq.view.cassandra.CassandraMailQueueViewModule.EnqueuedMailsTable.STATE;
import static org.apache.james.queue.rabbitmq.view.cassandra.CassandraMailQueueViewModule.EnqueuedMailsTable.TIME_RANGE_START;

import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import javax.mail.internet.AddressException;

import org.apache.commons.lang3.tuple.Pair;
import org.apache.james.backends.cassandra.init.CassandraTypesProvider;
import org.apache.james.blob.api.BlobId;
import org.apache.james.blob.mail.MimeMessagePartsId;
import org.apache.james.core.MailAddress;
import org.apache.james.queue.rabbitmq.EnqueuedItem;
import org.apache.james.queue.rabbitmq.MailQueueName;
import org.apache.james.queue.rabbitmq.view.cassandra.model.BucketedSlices;
import org.apache.james.queue.rabbitmq.view.cassandra.model.EnqueuedItemWithSlicingContext;
import org.apache.james.server.core.MailImpl;
import org.apache.mailet.Attribute;
import org.apache.mailet.AttributeName;
import org.apache.mailet.AttributeValue;
import org.apache.mailet.Mail;
import org.apache.mailet.PerRecipientHeaders;

import com.datastax.driver.core.Row;
import com.datastax.driver.core.UDTValue;
import com.github.fge.lambdas.Throwing;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;

public class EnqueuedMailsDaoUtil {

    static EnqueuedItemWithSlicingContext toEnqueuedMail(Row row, BlobId.Factory blobFactory) {
        MailQueueName queueName = MailQueueName.fromString(row.getString(QUEUE_NAME));
        Instant timeRangeStart = row.getTimestamp(TIME_RANGE_START).toInstant();
        BucketedSlices.BucketId bucketId = BucketedSlices.BucketId.of(row.getInt(BUCKET_ID));
        Instant enqueuedTime = row.getTimestamp(ENQUEUED_TIME).toInstant();
        BlobId headerBlobId = blobFactory.from(row.getString(HEADER_BLOB_ID));
        BlobId bodyBlobId = blobFactory.from(row.getString(BODY_BLOB_ID));
        MimeMessagePartsId mimeMessagePartsId = MimeMessagePartsId.builder().headerBlobId(headerBlobId)
                .bodyBlobId(bodyBlobId).build();

        MailAddress sender = Optional.ofNullable(row.getString(SENDER)).map(Throwing.function(MailAddress::new))
                .orElse(null);
        List<MailAddress> recipients = row.getList(RECIPIENTS, String.class).stream()
                .map(Throwing.function(MailAddress::new)).collect(ImmutableList.toImmutableList());
        String state = row.getString(STATE);
        String remoteAddr = row.getString(REMOTE_ADDR);
        String remoteHost = row.getString(REMOTE_HOST);
        String errorMessage = row.getString(ERROR_MESSAGE);
        String name = row.getString(MAIL_KEY);
        Date lastUpdated = row.getTimestamp(LAST_UPDATED);
        Map<String, ByteBuffer> rawAttributes = row.getMap(ATTRIBUTES, String.class, ByteBuffer.class);
        PerRecipientHeaders perRecipientHeaders = fromHeaderMap(
                row.getMap(PER_RECIPIENT_SPECIFIC_HEADERS, String.class, UDTValue.class));

        MailImpl mail = MailImpl.builder().name(name).sender(sender).recipients(recipients).lastUpdated(lastUpdated)
                .errorMessage(errorMessage).remoteHost(remoteHost).remoteAddr(remoteAddr).state(state)
                .addAllHeadersForRecipients(perRecipientHeaders).attributes(toAttributes(rawAttributes)).build();
        EnqueuedItem enqueuedItem = EnqueuedItem.builder().mailQueueName(queueName).mail(mail)
                .enqueuedTime(enqueuedTime).mimeMessagePartsId(mimeMessagePartsId).build();

        return EnqueuedItemWithSlicingContext.builder().enqueuedItem(enqueuedItem)
                .slicingContext(EnqueuedItemWithSlicingContext.SlicingContext.of(bucketId, timeRangeStart)).build();
    }

    @VisibleForTesting
    static List<Attribute> toAttributes(Map<String, ByteBuffer> rowAttributes) {
        return rowAttributes.entrySet().stream()
                .map(entry -> new Attribute(AttributeName.of(entry.getKey()), fromByteBuffer(entry.getValue())))
                .collect(ImmutableList.toImmutableList());
    }

    private static AttributeValue<?> fromByteBuffer(ByteBuffer byteBuffer) {
        try {
            return AttributeValue.fromJsonString(StandardCharsets.UTF_8.decode(byteBuffer).toString());
        } catch (IOException e) {
            throw new UncheckedIOException(e);
        }
    }

    private static PerRecipientHeaders fromHeaderMap(Map<String, UDTValue> rawMap) {
        PerRecipientHeaders result = new PerRecipientHeaders();

        rawMap.forEach((key,
                value) -> result.addHeaderForRecipient(PerRecipientHeaders.Header.builder()
                        .name(value.getString(HEADER_NAME)).value(value.getString(HEADER_VALUE)).build(),
                        toMailAddress(key)));
        return result;
    }

    private static MailAddress toMailAddress(String rawValue) {
        try {
            return new MailAddress(rawValue);
        } catch (AddressException e) {
            throw new RuntimeException(e);
        }
    }

    static ImmutableList<String> asStringList(Collection<MailAddress> mailAddresses) {
        return mailAddresses.stream().map(MailAddress::asString).collect(ImmutableList.toImmutableList());
    }

    static ImmutableMap<String, ByteBuffer> toRawAttributeMap(Mail mail) {
        return mail.attributes()
                .map(attribute -> Pair.of(attribute.getName().asString(), toByteBuffer(attribute.getValue())))
                .collect(ImmutableMap.toImmutableMap(Pair::getLeft, Pair::getRight));
    }

    private static ByteBuffer toByteBuffer(AttributeValue<?> attributeValue) {
        return ByteBuffer.wrap(attributeValue.toJson().toString().getBytes(StandardCharsets.UTF_8));
    }

    static ImmutableMap<String, UDTValue> toHeaderMap(CassandraTypesProvider cassandraTypesProvider,
            PerRecipientHeaders perRecipientHeaders) {
        return perRecipientHeaders.getHeadersByRecipient().asMap().entrySet().stream()
                .flatMap(entry -> entry.getValue().stream().map(value -> Pair.of(entry.getKey(), value)))
                .map(entry -> Pair.of(entry.getKey().asString(),
                        cassandraTypesProvider.getDefinedUserType(HEADER_TYPE).newValue()
                                .setString(HEADER_NAME, entry.getRight().getName())
                                .setString(HEADER_VALUE, entry.getRight().getValue())))
                .collect(ImmutableMap.toImmutableMap(Pair::getLeft, Pair::getRight));
    }
}