This page introduces the UserEventList, which is the common data type that will
be used in all implementations of our example application.
The goal is not only to introduce the specific data type used in our
examples, but to show some generic requirements for objects stored
in a cache:
The UserEventList used throughout the example application provides these
properties. Each instance represents the event list for a user.
New UserEventList instances can be created via static factory methods:
UserEventList list = UserEventList.emptyList();
UserEventList otherList = UserEventList.append(list, "A new event.");
The internal List<String>
is copied for each new instance.
The total number of messages in a UserEventList is limited by SIZE_LIMIT,
i.e. when the SIZE_LIMIT + 1st String is appended, the new instance
will not contain the oldest entry.
public class UserEventList implements Serializable {
private static final int SIZE_LIMIT = 10; // Max number of messages
private final List<String> messages;
public static UserEventList emptyList() {
return new UserEventList(new ArrayList<String>());
}
public static UserEventList append(UserEventList list, String msg) {
List<String> newMessageList = new ArrayList<>();
newMessageList.addAll(list.messages);
newMessageList.add(format(msg));
while ( newMessageList.size() > SIZE_LIMIT ) {
newMessageList.remove(0);
}
return new UserEventList(newMessageList);
}
private static String format(String msg) {
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return dateFormat.format(new Date()) + " " + msg;
}
private UserEventList(List<String> origMessageList) {
if ( origMessageList == null || origMessageList.size() > SIZE_LIMIT ) {
throw new IllegalArgumentException();
}
this.messages = Collections.unmodifiableList(origMessageList);
}
public List<String> getMessages() {
return messages;
}
@Override
public boolean equals(Object other) {
if ( other instanceof UserEventList) {
return messages.equals(((UserEventList) other).getMessages());
}
return false;
}
@Override
public int hashCode() {
return messages.hashCode();
}
}
The final page in part 01 will show a ConcurrentMap-based implementation of
our example. We will refer to that implementation in the following parts
when we point out the differences between a cache and a ConcurrentMap: