package edu.umd.rhsmith.diads.meater.modules.tweater.storage.legacy; import java.util.LinkedList; import java.util.List; import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; import edu.umd.rhsmith.diads.meater.core.app.MEaterConfigurationException; import edu.umd.rhsmith.diads.meater.core.app.components.Component; import edu.umd.rhsmith.diads.meater.core.app.components.media.MediaProcessor; import edu.umd.rhsmith.diads.meater.core.app.components.media.sets.SimpleMediaSetUpdater; import edu.umd.rhsmith.diads.meater.core.app.components.media.sets.MediaSetUpdater; import edu.umd.rhsmith.diads.meater.modules.tweater.media.UserStatusData; import edu.umd.rhsmith.diads.meater.modules.tweater.queries.QueryItem; /** * Base implementation of a <code>StatusEater</code> that maintains a set of * <code>QueryItem</code>s * that it cares about. It implements basic methods for adding to and deleting * from this set, and * implements <code>process</code> to find all <code>QueryItem</code>s * associated with a given <code>Status<code>. Leaves the <code>persist</code> * method for implementation by subclasses * focusing on a specific long-term storage system. * * @author dmonner * */ public abstract class StatusEater extends Component implements MediaProcessor<UserStatusData> { public static final String PNAME_QRMV = "removeQueries"; public static final String PNAME_QADD = "addQueries"; /** * The set of <code>QueryItem</code>s that this <code>StatusEater</code> * cares about. */ private final Set<QueryItem> queries; private final MediaSetUpdater<QueryItem> queryUpdater; private final boolean discardsUnmatched; public StatusEater(StatusEaterInitializer init) throws MEaterConfigurationException { super(init); this.discardsUnmatched = init.isDiscardsUnmatched(); this.registerMediaProcessor(this); this.queries = new CopyOnWriteArraySet<QueryItem>(); this.queryUpdater = new SimpleMediaSetUpdater<QueryItem>(PNAME_QADD, PNAME_QRMV, QueryItem.class) { @Override public boolean add(QueryItem media) { queries.add(media); return true; } @Override public boolean remove(QueryItem media) { queries.remove(media); return true; } }; this.registerMediaProcessor(queryUpdater.getMediaAdder()); this.registerMediaProcessor(queryUpdater.getMediaRemover()); } @Override public Class<UserStatusData> getMediaClass() { return UserStatusData.class; } @Override public String getProcessorName() { return ""; } @Override public boolean processMedia(UserStatusData media) { this.eat(media); return true; } /** * Instructs this <code>StatusEater</code> to match the given * <code>Status</code> against its list * of <code>QueryItem</code>s to see which match, and then pass the results * along to <code>persist</code>. * * @param status */ public void eat(UserStatusData status) { logFinest(MSG_PROCESSING_FMT, status.getStatusId()); // generate a list of QueryItems that match the status List<QueryItem> matched = new LinkedList<QueryItem>(); for (final QueryItem item : queries) if (item.matches(status)) matched.add(item); // if there are any matches, or we don't factor matches into the choice // to persist, persist the status if (!matched.isEmpty() || !discardsUnmatched) { persist(matched, status); } else { logFine(MSG_SKIP_UNMATCHED_FMT, status.getStatusId()); } } /** * Instructs this <code>StatusEater</code> to persist the given * <code>Status</code>, possibly * including which <code>QueryItem</code>s were matched. The method of * persistent storage (for * example, a database or a text file) is chosen by the implementing class. * * @param matches * @param status */ public abstract void persist(List<QueryItem> matches, UserStatusData status); /* * -------------------------------- * Messages * -------------------------------- */ private static final String MSG_SKIP_UNMATCHED_FMT = "Skipping persist() because there are not QueryItem matches for status id %d"; private static final String MSG_PROCESSING_FMT = "Entering process() for status id %d"; }