package org.atlasapi.persistence.content; import java.math.BigInteger; import java.util.UUID; import org.atlasapi.media.entity.Container; import org.atlasapi.media.entity.Content; import org.atlasapi.media.entity.Item; import org.atlasapi.messaging.v3.ContentEquivalenceAssertionMessenger; import org.atlasapi.messaging.v3.EntityUpdatedMessage; import org.atlasapi.persistence.media.entity.ContainerTranslator; import org.atlasapi.persistence.media.entity.ItemTranslator; import com.metabroadcast.common.base.Maybe; import com.metabroadcast.common.ids.SubstitutionTableNumberCodec; import com.metabroadcast.common.queue.MessageSender; import com.metabroadcast.common.stream.MoreCollectors; import com.metabroadcast.common.time.SystemClock; import com.metabroadcast.common.time.Timestamper; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.primitives.Longs; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import static com.google.common.base.Preconditions.checkNotNull; public class MessageQueueingContentWriter implements ContentWriter { private static final Logger log = LoggerFactory.getLogger(MessageQueueingContentWriter.class); private final MessageSender<EntityUpdatedMessage> sender; private final ContentWriter contentWriter; private final ContentResolver contentResolver; private final Timestamper clock; private final ContentEquivalenceAssertionMessenger messenger; private final SubstitutionTableNumberCodec idCodec = new SubstitutionTableNumberCodec(); private final ItemTranslator itemTranslator = new ItemTranslator(idCodec); private final ContainerTranslator containerTranslator = new ContainerTranslator(idCodec); private final SubstitutionTableNumberCodec entityIdCodec = SubstitutionTableNumberCodec.lowerCaseOnly(); public MessageQueueingContentWriter( ContentEquivalenceAssertionMessenger messenger, MessageSender<EntityUpdatedMessage> sender, ContentWriter contentWriter, ContentResolver contentResolver ) { this(messenger, sender, contentWriter, contentResolver, new SystemClock()); } public MessageQueueingContentWriter( ContentEquivalenceAssertionMessenger messenger, MessageSender<EntityUpdatedMessage> sender, ContentWriter contentWriter, ContentResolver contentResolver, Timestamper clock ) { this.messenger = checkNotNull(messenger); this.sender = checkNotNull(sender); this.contentWriter = checkNotNull(contentWriter); this.contentResolver = checkNotNull(contentResolver); this.clock = checkNotNull(clock); } @Override public Item createOrUpdate(Item item) { Item writtenItem = contentWriter.createOrUpdate(item); if (!item.hashChanged(itemTranslator.hashCodeOf(item))) { log.debug("{} not changed", item.getCanonicalUri()); return writtenItem; } enqueueMessageUpdatedMessage(item); return writtenItem; } @Override public void createOrUpdate(Container container) { contentWriter.createOrUpdate(container); if (!container.hashChanged(containerTranslator.hashCodeOf(container))) { log.debug("{} un-changed", container.getCanonicalUri()); return; } enqueueMessageUpdatedMessage(container); } private void enqueueMessageUpdatedMessage(final Content content) { try { if(!content.getEquivalentTo().isEmpty()){ ImmutableList<Content> adjacents = content.getEquivalentTo() .stream() .map(lookupRef -> contentResolver .findByUris(ImmutableList.of(lookupRef.uri())) .getFirstValue() ) .filter(Maybe::hasValue) .map(identifiedMaybe -> (Content) identifiedMaybe.requireValue()) .collect(MoreCollectors.toImmutableList()); ImmutableSet<String> sources = content.getEquivalentTo() .stream() .map(lookupRef -> lookupRef.publisher().key()) .collect(MoreCollectors.toImmutableSet()); messenger.sendMessage( content, adjacents, sources ); } sender.sendMessage( createEntityUpdatedMessage(content), Longs.toByteArray(content.getId()) ); } catch (Exception e) { log.error("update message failed: " + content, e); } } private EntityUpdatedMessage createEntityUpdatedMessage(Content content) { return new EntityUpdatedMessage( UUID.randomUUID().toString(), clock.timestamp(), entityIdCodec.encode(BigInteger.valueOf(content.getId())), content.getClass().getSimpleName().toLowerCase(), content.getPublisher().key()); } }