/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.dlect.events;
import com.google.common.base.Objects;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import static org.dlect.helper.Conditions.checkNonNull;
/**
*
* @author lee
*/
public class Event {
@Nonnull
private final Object source;
@Nonnull
private final EventID eventID;
@Nullable
private final Object before;
@Nullable
private final Object after;
/**
* Creates a new event with the given source, eventID, before and after states.
*
* @param source A non-null source that is assignable from the given {@code eventID}'s
* {@link EventID#getAppliedClass()}.
* @param eventID A non-null eventID that must represent an event that is applied to a super-type of the given
* {@code source}.
* @param before The state before the change. This object is not checked for equality with {@code after}; or
* null-ness. It is recommended that this object be immutable as no copy is made.
* @param after The state after the change. This object is not checked for equality with {@code before}; or
* null-ness. It is recommended that this object be immutable as no copy is made.
*/
public Event(@Nonnull Object source, @Nonnull EventID eventID, @Nullable Object before, @Nullable Object after) {
checkNonNull(source, "Source");
checkNonNull(eventID, "Event ID");
if (!eventID.getAppliedClass().isAssignableFrom(source.getClass())) {
// If the event ID represents a supertype of or equal to source class; then good. Otherwise error.
throw new IllegalArgumentException("Source(" + source.getClass() + ") is not a sub-type of the class that the event ID(" + eventID.getAppliedClass() + ") applies to.");
}
this.source = source;
this.eventID = eventID;
this.before = before;
this.after = after;
}
public String debugVars() {
return "source=" + source + ", eventID=" + eventID + ", before=" + before + ", after=" + after;
}
@Override
public String toString() {
return "Event{" + debugVars() + '}';
}
@Override
public int hashCode() {
return Objects.hashCode(this.getSource(),
this.getEventID(),
this.getBefore(),
this.getAfter());
}
@Override
public boolean equals(Object obj) {
if (obj != null && obj.getClass().equals(this.getClass())) {
final Event other = (Event) obj;
return equalsImpl(other);
} else {
return false;
}
}
/**
* Perform an implementer independent equality check. This method will only check for equality with the elements of
* this class. This method does not perform any type checking and is safe to use in an implementation to check if
* the root event is equal.
*
* This method will check equality on {@link #getBefore()}, {@link #getAfter()}, {@link #getEventID()}, and
* {@link #getSource()}
*
* @param other The event to check equality on.
*
* @return {@code true} if this event has the same event data as {@code other}. Otherwise {@code false}
*/
protected final boolean equalsImpl(Event other) {
return Objects.equal(this.getSource(), other.getSource())
&& Objects.equal(this.getEventID(), other.getEventID())
&& Objects.equal(this.getBefore(), other.getBefore())
&& Objects.equal(this.getAfter(), other.getAfter());
}
/**
* The source class that this event represents. This is generated by calling {@link EventID#getAppliedClass() }.
*
* @return The source class that this event represents.
*/
@Nonnull
public Class<?> getSourceClass() {
return eventID.getAppliedClass();
}
/**
* The source object of this event. Note that this source is guaranteed to be castable to, but not necessarily the
* same as, the class returned by {@link #getSourceClass()}
*
* @return The source of the object.
*/
@Nonnull
public Object getSource() {
return source;
}
/**
* The ID of the event.
*
* @return The ID of event.
*/
@Nonnull
public EventID getEventID() {
return eventID;
}
/**
* The object before it was changed.This may be equal to {@link #getAfter() }; this class makes no assumptions on
* this.
*
* @return The object before it was changed.
*/
@Nullable
public Object getBefore() {
return before;
}
/**
* The object after the change. This may be equal to {@link #getBefore() }; this class makes no assumptions on this.
*
* @return The object after the change.
*/
@Nullable
public Object getAfter() {
return after;
}
}