package org.marketcetera.event.beans; import java.io.Serializable; import java.util.Date; import java.util.concurrent.atomic.AtomicLong; import javax.annotation.concurrent.NotThreadSafe; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlAttribute; import org.apache.commons.lang.builder.EqualsBuilder; import org.apache.commons.lang.builder.HashCodeBuilder; import org.marketcetera.event.Event; import org.marketcetera.event.Messages; import org.marketcetera.event.util.EventServices; import org.marketcetera.util.log.I18NBoundMessage1P; import org.marketcetera.util.misc.ClassVersion; /* $License$ */ /** * Stores the attributes necessary for {@link Event}. * * <p>This class is not thread-safe because {@link #validate()} and * {@link #setDefaults()} need a consistent state which is not guaranteed * by design. In order to make the state consistent, all methods would * need to be made synchronized, or all attributes volatile and <code>validate</code> * and <code>setDefaults</code> synchronized. Therefore, the easiest way * to achieve thread-safety is to externally synchronize instances of this * object. There is another path to thread-safety that is more complicated * to arrange and does not provide a cast-iron guarantee from the point-of-view * of this class. This class may be used in a thread-safe manner by invoking * <code>validate</code> and <code>setDefaults</code> <em>only</em> during instantiation of * an owning object and forbidding mutation of any attribute except via {@link #setSource(Object)}. * This is the intended use of this object. * * @author <a href="mailto:colin@marketcetera.com">Colin DuPlantis</a> * @version $Id: EventBean.java 16854 2014-03-12 01:54:42Z colin $ * @since 2.0.0 */ @NotThreadSafe @XmlAccessorType(XmlAccessType.NONE) @ClassVersion("$Id: EventBean.java 16854 2014-03-12 01:54:42Z colin $") public class EventBean implements Serializable { /** * Creates a shallow copy of the given <code>EventBean</code>. * * @param inBean an <code>EventBean</code> value * @return an <code>EventBean</code> value */ public static EventBean copy(EventBean inBean) { EventBean newBean = new EventBean(); copyAttributes(inBean, newBean); return newBean; } /** * Get the messageId value. * * @return a <code>long</code> value */ public final long getMessageId() { return messageId; } /** * Sets the messageId value. * * <p>If the given <code>inMessageId</code> is equal to * {@link Long#MIN_VALUE}, the object <code>MessageId</code> * will be assigned a unique value if {@link #setDefaults()} * is invoked. * * @param inMessageId a <code>long</code> value */ public final void setMessageId(long inMessageId) { messageId = inMessageId; } /** * Get the timestamp value. * * @return a <code>Date</code> value */ public final Date getTimestamp() { return timestamp; } /** * Get the timestamp value as millis. * * @return a <code>long</code> value * @throws NullPointerException if the timestamp value has not been set with * {@link #setTimestamp(Date)} */ public final long getTimeMillis() { return getTimestamp().getTime(); } /** * Sets the timestamp value. * * @param inTimestamp a <code>Date</code> value */ public final void setTimestamp(Date inTimestamp) { timestamp = inTimestamp; } /** * Get the source value. * * @return a <code>Object</code> value */ public final Object getSource() { return source; } /** * Sets the source value. * * @param inSource a <code>Object</code> value */ public final void setSource(Object inSource) { source = inSource; } /** * Get the provider value. * * @return a <code>String</code> value */ public String getProvider() { return provider; } /** * Sets the provider value. * * @param inProvider a <code>String</code> value */ public void setProvider(String inProvider) { provider = inProvider; } /** * Performs validation of the attributes. * * <p>Subclasses should override this method to validate * their attributes as necessary and invoke the parent method. * @throws IllegalArgumentException if <code>MessageId</code> < 0 * @throws IllegalArgumentException if <code>Timestamp</code> is <code>null</code> */ public void validate() { if(messageId < 0) { EventServices.error(new I18NBoundMessage1P(Messages.VALIDATION_INVALID_MESSAGEID, messageId)); } if(timestamp == null) { EventServices.error(Messages.VALIDATION_NULL_TIMESTAMP); } } /** * Sets the attributes to their appropriate default values, if any. * * <p>Subclasses should override this method to set default values to * their attributes as necessary and invoke the parent method. */ public void setDefaults() { if(messageId == Long.MIN_VALUE) { messageId = counter.incrementAndGet(); } if(timestamp == null) { timestamp = new Date(); } } /* (non-Javadoc) * @see java.lang.Object#hashCode() */ @Override public int hashCode() { return new HashCodeBuilder().append(messageId).append(source).append(provider).append(timestamp).toHashCode(); } /* (non-Javadoc) * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof EventBean)) { return false; } EventBean other = (EventBean) obj; return new EqualsBuilder().append(messageId,other.messageId).append(source,other.source).append(provider,other.provider).append(timestamp,other.timestamp).isEquals(); } /* (non-Javadoc) * @see java.lang.Object#toString() */ @Override public String toString() { return String.format("Event: [%s with source %s from %s at %s]", //$NON-NLS-1$ messageId, source, provider, timestamp); } /** * Copies all member attributes from the donor to the recipient. * * @param inDonor an <code>EventBean</code> value * @param inRecipient an <code>EventBean</code> value */ protected static void copyAttributes(EventBean inDonor, EventBean inRecipient) { inRecipient.setMessageId(inDonor.getMessageId()); inRecipient.setSource(inDonor.getSource()); inRecipient.setTimestamp(inDonor.getTimestamp()); inRecipient.setProvider(inDonor.getProvider()); } /** * the event messageId */ @XmlAttribute private long messageId = Long.MIN_VALUE; /** * the event timestamp */ @XmlAttribute private Date timestamp = null; /** * the event source */ private transient Object source; /** * event provider value */ @XmlAttribute private String provider; /** * counter used to assign default values */ private static final AtomicLong counter = new AtomicLong(0); private static final long serialVersionUID = -1463953196194132003L; }