Package mireka.destination

Source Code of mireka.destination.DestinationProcessorFilter

package mireka.destination;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import mireka.MailData;
import mireka.address.ReversePath;
import mireka.filter.AbstractDataRecipientFilter;
import mireka.filter.DataRecipientFilterAdapter;
import mireka.filter.Filter;
import mireka.filter.FilterType;
import mireka.filter.MailTransaction;
import mireka.filter.RecipientContext;
import mireka.smtp.RejectExceptionExt;
import mireka.transmission.Mail;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.subethamail.smtp.TooMuchDataException;

/**
* DestinationProcessorFilter groups recipients by their destinations and calls
* the {@link MailDestination} or {@link SessionDestination} objects with the
* recipients to which they are assigned.
*/
public class DestinationProcessorFilter implements FilterType {

    @Override
    public Filter createInstance(MailTransaction mailTransaction) {
        FilterImpl filterInstance = new FilterImpl(mailTransaction);
        return new DataRecipientFilterAdapter(filterInstance, mailTransaction);
    }

    private class FilterImpl extends AbstractDataRecipientFilter {
        private final Logger logger = LoggerFactory.getLogger(FilterImpl.class);
        private final Map<ResponsibleDestination, DestinationState> destinations =
                new LinkedHashMap<ResponsibleDestination, DestinationState>();

        private Mail mail = new Mail();

        protected FilterImpl(MailTransaction mailTransaction) {
            super(mailTransaction);
        }

        @Override
        public void from(ReversePath from) {
            mail.from = from;
            mail.receivedFromMtaAddress =
                    mailTransaction.getRemoteInetAddress();
            mail.receivedFromMtaName =
                    mailTransaction.getMessageContext().getHelo();
        }

        @Override
        public void recipient(RecipientContext recipientContext)
                throws RejectExceptionExt {
            if (recipientContext.isResponsibilityTransferred)
                return;
            if (!(recipientContext.getDestination() instanceof ResponsibleDestination))
                return;
            ResponsibleDestination destination =
                    (ResponsibleDestination) recipientContext.getDestination();
            recipientContext.isResponsibilityTransferred = true;
            DestinationState destinationState =
                    getOrCreateDestinationState(destination);

            destinationState.recipient(recipientContext);
        }

        private DestinationState getOrCreateDestinationState(
                ResponsibleDestination destination) {
            DestinationState destinationState = destinations.get(destination);
            if (destinationState == null) {
                if (destination instanceof MailDestination) {
                    destinationState =
                            new MailDestinationState(
                                    (MailDestination) destination);
                } else if (destination instanceof SessionDestination) {
                    destinationState =
                            new SessionDestinationState(
                                    (SessionDestination) destination);
                } else {
                    throw new RuntimeException("Assertion failed");
                }
                destinations.put(destination, destinationState);
            }
            return destinationState;
        }

        @Override
        public void data(MailData data) throws TooMuchDataException,
                RejectExceptionExt, IOException {
            mail.mailData = data;
            mail.arrivalDate = new Date();
            mail.scheduleDate = mail.arrivalDate;
            for (Map.Entry<ResponsibleDestination, DestinationState> entry : destinations
                    .entrySet()) {
                ResponsibleDestination destination = entry.getKey();
                DestinationState destinationState = entry.getValue();
                Mail destinationMail = mail.copy();
                List<RecipientContext> recipientContexts =
                        destinationState.recipientContexts;
                for (RecipientContext recipientContext : recipientContexts) {
                    destinationMail.recipients.add(recipientContext.recipient);
                }
                if (recipientContexts.isEmpty()) {
                    logger.debug("Destination {} has not accepted any of the "
                            + "recipients to which it was assigned.",
                            destination);
                } else {
                    destinationState.data(destinationMail);
                }
            }
        }

        @Override
        public void done() {
            for (DestinationState destinationState : destinations.values()) {
                destinationState.done();
            }
        }

        private abstract class DestinationState {
            final List<RecipientContext> recipientContexts =
                    new ArrayList<RecipientContext>();

            abstract void recipient(RecipientContext recipientContext)
                    throws RejectExceptionExt;

            abstract void data(Mail mail) throws RejectExceptionExt,
                    IOException;

            /**
             * Safely closes the session.
             */
            abstract void done();
        }

        private class MailDestinationState extends DestinationState {
            MailDestination destination;

            public MailDestinationState(MailDestination destination) {
                this.destination = destination;
            }

            @Override
            void recipient(RecipientContext recipientContext) {
                recipientContexts.add(recipientContext);
            }

            @Override
            void data(Mail mail) throws RejectExceptionExt {
                logger.debug("Sending {} recipients to {}",
                        recipientContexts.size(), destination);
                destination.data(mail);
            }

            @Override
            void done() {
                // do nothing
            }
        }

        private class SessionDestinationState extends DestinationState {
            final SessionDestination destination;
            final Session session;
            boolean fromCalled = false;

            public SessionDestinationState(SessionDestination destination) {
                this.destination = destination;
                this.session = destination.createSession();
            }

            @Override
            void recipient(RecipientContext recipientContext)
                    throws RejectExceptionExt {
                if (!fromCalled) {
                    fromCalled = true;
                    session.from(mail.from);
                }
                session.recipient(recipientContext);
                recipientContexts.add(recipientContext);
            }

            @Override
            void data(Mail mail) throws RejectExceptionExt, IOException {
                logger.debug("Sending data for {} recipients to {}",
                        recipientContexts.size(), destination);
                session.data(mail);
            }

            @Override
            void done() {
                try {
                    session.done();
                } catch (RuntimeException e) {
                    logger.error(
                            "Cleanup of session failed for " + destination, e);
                }
            }
        }
    }
}
TOP

Related Classes of mireka.destination.DestinationProcessorFilter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.