package org.atlasapi.persistence.content.mongo; import static com.google.common.base.Preconditions.checkNotNull; import static com.metabroadcast.common.persistence.mongo.MongoBuilders.where; import java.util.Collection; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.atlasapi.media.entity.EntityType; import org.atlasapi.media.entity.Identified; import org.atlasapi.media.entity.LookupRef; import org.atlasapi.persistence.content.KnownTypeContentResolver; import org.atlasapi.persistence.content.ResolvedContent; import org.atlasapi.persistence.lookup.entry.LookupEntryStore; import org.atlasapi.persistence.media.entity.ContainerTranslator; import org.atlasapi.persistence.media.entity.DescribedTranslator; import org.atlasapi.persistence.media.entity.ItemTranslator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.collect.HashMultimap; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Sets; import com.google.common.collect.ImmutableMap.Builder; import com.google.common.collect.Multimap; import com.metabroadcast.common.ids.SubstitutionTableNumberCodec; import com.metabroadcast.common.persistence.mongo.DatabasedMongo; import com.mongodb.DBCollection; import com.mongodb.DBCursor; import com.mongodb.DBObject; public class MongoContentResolver implements KnownTypeContentResolver { private final Logger log = LoggerFactory.getLogger(getClass()); private final ItemTranslator itemTranslator; private final ContainerTranslator containerTranslator; private final MongoContentTables contentTables; private final LookupEntryStore lookupEntryStore; public MongoContentResolver(DatabasedMongo mongo, LookupEntryStore lookupEntryStore) { this.contentTables = new MongoContentTables(mongo); SubstitutionTableNumberCodec idCodec = new SubstitutionTableNumberCodec(); this.containerTranslator = new ContainerTranslator(idCodec); this.itemTranslator = new ItemTranslator(idCodec); this.lookupEntryStore = checkNotNull(lookupEntryStore); } public ResolvedContent findByLookupRefs(Iterable<LookupRef> lookupRefs) { Builder<String, Identified> results = ImmutableMap.builder(); Set<String> foundUris = Sets.newHashSet(); Multimap<DBCollection, String> idsGroupedByTable = HashMultimap.create(); for (LookupRef lookupRef : lookupRefs) { idsGroupedByTable.put(contentTables.collectionFor(lookupRef.category()), lookupRef.uri()); } for (Entry<DBCollection, Collection<String>> lookupInOneTable : idsGroupedByTable.asMap().entrySet()) { DBCursor found = lookupInOneTable.getKey().find(where().idIn(lookupInOneTable.getValue()).build()); if (found != null) { for (DBObject dbo : found) { Identified model = toModel(dbo); if (!foundUris.contains(model.getCanonicalUri())) { results.put(model.getCanonicalUri(), model); foundUris.add(model.getCanonicalUri()); } } } } ImmutableMap<String, Identified> res = results.build(); addIdsToResults(res); return ResolvedContent.builder().putAll(res).build(); } private void addIdsToResults(ImmutableMap<String, Identified> uriToIdentified) { Map<String, Long> idsForCanonicalUris = lookupEntryStore.idsForCanonicalUris(uriToIdentified.keySet()); for(Entry<String, Identified> result : uriToIdentified.entrySet()) { Long id = idsForCanonicalUris.get(result.getKey()); if (id == null) { log.info("null id for {}, {}, {}", new Object[]{result.getKey(), uriToIdentified.keySet(), idsForCanonicalUris}); } result.getValue().setId(id); } } private Identified toModel(DBObject dbo) { if(dbo == null) { return null; } if (!dbo.containsField(DescribedTranslator.TYPE_KEY)) { throw new IllegalStateException("Missing type field"); } EntityType type = EntityType.from((String) dbo.get(DescribedTranslator.TYPE_KEY)); switch(type) { case BRAND: case SERIES: case CONTAINER: return containerTranslator.fromDBObject(dbo, null); case ITEM: case EPISODE: case CLIP: case FILM: case SONG: return itemTranslator.fromDBObject(dbo, null); } throw new IllegalArgumentException("Unknown type: " + type); } }