Email Price Checker – Part 3: Filtering From Addresses

In the part 2, the basic app and splitting into sub codes had been built. To keep this part short, I’ll just be adding fromAddress filtering.

When a price request is received via email, not only does the payload have to be of the correct type and contain a code, but the email needs to have originated from an email address in a “white list” (someone I know about and let use the feature). So the first step is to add a filter reference and a new filter which checks the inbound property “fromAddress” against a list of addresses in the properties file.

price-checker-16

The next step is to have a basic filter which can take a list of spring injected valid from addresses to check the inbound property against. Because the fromAddress is similar to the replyToAddresses in that looks like this: “Fred Bloggs ” I’ve split the email address cleaning out into a separate class which can be reused from the filter and in the ReplyToAddressTransformer.

These are the classes:

EmailCleaningComponentImpl.java

package uk.co.vsf.pricechecker.component.impl;

import uk.co.vsf.pricechecker.component.EmailCleaningComponent;

public class EmailCleaningComponentImpl implements EmailCleaningComponent {

	/**
	 * {@inheritDoc}
	 */
	@Override
	public String cleanEmail(String uncleanedEmail) {
		String[] parts = uncleanedEmail.split("<");
		if (parts.length > 1) {
			parts = parts[1].split(">");
			if (parts.length == 1) {
				return parts[0];
			}
		}

		throw new IllegalArgumentException("No valid email address in - " + uncleanedEmail);
	}
}

ReplyToAddressTransformer.java

package uk.co.vsf.pricechecker.transformer;

import org.mule.api.MuleMessage;
import org.mule.api.transformer.TransformerException;
import org.mule.transformer.AbstractMessageTransformer;

import uk.co.vsf.pricechecker.component.EmailCleaningComponent;

/**
 * Transforms the incoming message replyToAddresses into a clean email address.
 */
public class ReplyToAddressTransformer extends AbstractMessageTransformer {
	public static final String CLEANED_REPLY_TO_ADDRESS = "CleanedReplyToAddress";

	private EmailCleaningComponent emailCleaningComponent;

	@Override
	public Object transformMessage(MuleMessage message, String outputEncoding) throws TransformerException {
		String replyToAddresses = message.getInboundProperty("replyToAddresses");
		if (replyToAddresses == null) {
			throw new IllegalArgumentException("Need a replyToAddress in order to return email");
		}

		String cleanedEmail = emailCleaningComponent.cleanEmail(replyToAddresses);
		message.setOutboundProperty(CLEANED_REPLY_TO_ADDRESS, cleanedEmail);
		return message;
	}

	public void setEmailCleaningComponent(EmailCleaningComponent emailCleaningComponent) {
		this.emailCleaningComponent = emailCleaningComponent;
	}
}

And…

FromAddressFilter.java

package uk.co.vsf.pricechecker.filter;

import java.util.ArrayList;
import java.util.List;

import org.mule.api.MuleMessage;
import org.mule.api.routing.filter.*;

import uk.co.vsf.pricechecker.component.EmailCleaningComponent;

/**
 * Determines whether the from address is in the list of valid email addresses
 * and if so lets the message through.
 */
public class FromAddressFilter implements Filter {

	private EmailCleaningComponent emailCleaningComponent;
	private List<String> validFromAddresses = new ArrayList<String>();

	@Override
	public boolean accept(MuleMessage message) {
		String fromAddress = message.getInboundProperty("fromAddress", "");
		String cleanedFromAddress = emailCleaningComponent.cleanEmail(fromAddress);

		return validFromAddresses.contains(cleanedFromAddress.toUpperCase());
	}

	/**
	 * Complex setter which converts from the string array values spring injects
	 * to a list of upper case email addresses.
	 * 
	 * @param values
	 *            list of valid email addresses
	 */
	public void setValidFromAddresses(String[] values) {
		if (values != null) {
			for (String value : values) {
				validFromAddresses.add(value.toUpperCase());
			}
		}
	}

	public void setEmailCleaningComponent(EmailCleaningComponent emailCleaningComponent) {
		this.emailCleaningComponent = emailCleaningComponent;
	}
}

Add the EmailCleaningComponent and FromAddressFilter as a spring bean into the mule config file and tie them together as well as setting the filter reference to the spring bean. Additionally alter the ReplyToAddressTransformer to have a spring property of the EmailCleaningComponent.

<spring:beans>
        <spring:bean id="FromAddressFilter" name="FromAddressFilter" class="uk.co.vsf.pricechecker.filter.FromAddressFilter" scope="singleton">
            <spring:property name="emailCleaningComponent" ref="EmailCleaningComponent"/>
            <spring:property name="validFromAddresses" value="${valid.from.addresses}" />
        </spring:bean>
        <spring:bean id="EmailCleaningComponent" name="EmailCleaningComponent" class="uk.co.vsf.pricechecker.component.impl.EmailCleaningComponentImpl" scope="singleton"/>
    </spring:beans>
    ...
    <filter ref="FromAddressFilter" doc:name="Filter Reference"/>
    <custom-transformer class="uk.co.vsf.pricechecker.transformer.ReplyToAddressTransformer"
			doc:name="Java">
	<spring:property name="emailCleaningComponent" ref="EmailCleaningComponent"/>
    </custom-transformer>