package org.atlasapi.persistence.content.people;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import javax.annotation.PreDestroy;
import org.atlasapi.media.entity.ChildRef;
import org.atlasapi.media.entity.Item;
import org.atlasapi.media.entity.Person;
import org.atlasapi.persistence.logging.AdapterLog;
import org.atlasapi.persistence.logging.AdapterLogEntry;
import org.atlasapi.persistence.logging.AdapterLogEntry.Severity;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
public class QueuingPersonWriter {
private final PersonStore store;
private final BlockingQueue<Person> queue = new LinkedBlockingQueue<Person>();
private final ScheduledExecutorService schedule;
private final Set<String> processedUris = Sets.newHashSet();
private final AdapterLog log;
public QueuingPersonWriter(PersonStore store, AdapterLog log) {
this(store, log, Executors.newSingleThreadScheduledExecutor());
}
public QueuingPersonWriter(PersonStore store, AdapterLog log, ScheduledExecutorService schedule) {
this.store = store;
this.log = log;
this.schedule = schedule;
this.schedule.scheduleWithFixedDelay(new WritePeople(), 2, 2, TimeUnit.MINUTES);
}
@PreDestroy
public void shutDown() {
schedule.shutdown();
try {
new WritePeople().run();
} catch (Exception e) {
e.printStackTrace();
}
}
public void addItemToPerson(Person person, Item item) {
person.setContents(ImmutableList.<ChildRef>builder().addAll(person.getContents()).add(item.childRef()).build());
queue.add(person);
}
class WritePeople implements Runnable {
@Override
public void run() {
try {
List<Person> people = Lists.newArrayListWithExpectedSize(queue.size());
queue.drainTo(people);
for (Person person: dedupePeople(people)) {
if (! processedUris.contains(person.getCanonicalUri())) {
if (! store.person(person.getCanonicalUri()).isPresent()) {
store.createOrUpdatePerson(person);
}
processedUris.add(person.getCanonicalUri());
}
store.updatePersonItems(person);
}
} catch (Exception e) {
log.record(new AdapterLogEntry(Severity.ERROR).withCause(e).withSource(this.getClass()));
}
}
private Set<Person> dedupePeople(List<Person> people) {
Map<String, Person> peopleLookup = Maps.newHashMap();
for (Person person: people) {
if (peopleLookup.containsKey(person.getCanonicalUri())) {
Person existingPerson = peopleLookup.get(person.getCanonicalUri());
existingPerson.setContents(ImmutableList.<ChildRef>builder().addAll(existingPerson.getContents()).addAll(person.getContents()).build());
} else {
peopleLookup.put(person.getCanonicalUri(), person);
}
}
return ImmutableSet.copyOf(peopleLookup.values());
}
}
}