package org.subethamail.entity; import java.io.Serializable; import java.util.Date; import java.util.logging.Level; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.Transient; import lombok.extern.java.Log; import org.hibernate.annotations.Cache; import org.hibernate.annotations.CacheConcurrencyStrategy; import org.subethamail.entity.i.Validator; /** * Entity of an email address. People can have many email * addresses, any of which can be used to send mail. Note that * all addresses are stored in their normalized form. * * @see Validator#normalizeEmail(String) * * Note that this entity uses a natural key - the email address * itself. This enables efficient 2nd-level cache lookups. * One consequence is that you never change email addresses; * you add new ones and delete old ones. * * Email addresses track their bounce count so we know when * to disable them. * * @author Jeff Schnitzer */ @Entity @Cache(usage=CacheConcurrencyStrategy.TRANSACTIONAL) @Log public class EmailAddress implements Serializable, Comparable<EmailAddress> { private static final long serialVersionUID = 1L; /** * We only increment or decrement once for this period, in millis. * One day. */ @Transient public static final long BOUNCE_IGNORE_PERIOD = 1000 * 60 * 60 * 24; /** */ @Id @Column(length=Validator.MAX_EMAIL_ADDRESS) String id; /** */ @ManyToOne @JoinColumn(name="personId", nullable=false) Person person; /** * Not actually the number of bounces, but this number does * go up when bounces happen. */ @Column(nullable=false) int bounces; @Column(nullable=true) Date lastBounceIncrement; @Column(nullable=true) Date lastBounceDecrement; /** */ public EmailAddress() {} /** */ public EmailAddress(Person person, String email) { log.log(Level.FINE,"Creating new EmailAddress"); this.setId(email); this.setPerson(person); } /** */ public String getId() { return this.id; } /** * Always normalizes the email address. Note that this * is not public - only settible when creating the object. */ private void setId(String value) { value = Validator.normalizeEmail(value); log.log(Level.FINE,"Setting address to {0}", value); this.id = value; } /** */ public Person getPerson() { return this.person; } public void setPerson(Person value) { this.person = value; } /** * Not actually the number of bounces, but this number does * go up when bounces happen. It decays if bounces don't. */ public int getBounces() { return this.bounces; } /** * When a bounce occurs, it increments the count by 2. Only * do this once per day. */ public void bounceIncrement() { if (this.lastBounceIncrement == null || System.currentTimeMillis() > (this.lastBounceIncrement.getTime() + BOUNCE_IGNORE_PERIOD)) { this.bounces += 2; this.lastBounceIncrement = new Date(); } } /** * When mail goes out, the bounce count should decay slightly. * Only do this once per day. */ public void bounceDecay() { if (this.bounces > 0) { if (this.lastBounceDecrement == null || System.currentTimeMillis() > (this.lastBounceDecrement.getTime() + BOUNCE_IGNORE_PERIOD)) { this.bounces--; this.lastBounceDecrement = new Date(); } } } /** */ @Override public String toString() { return this.getClass().getName() + "{id=" + this.id + "}"; } /** * Natural sort order is based on email text */ public int compareTo(EmailAddress other) { return this.id.compareTo(other.getId()); } }