package org.atlasapi.persistence.media.entity; import java.util.List; import java.util.Locale; import org.atlasapi.media.entity.Described; import org.atlasapi.media.entity.EntityType; import org.atlasapi.media.entity.Identified; import org.atlasapi.media.entity.Image; import org.atlasapi.media.entity.LocalizedDescription; import org.atlasapi.media.entity.LocalizedTitle; import org.atlasapi.media.entity.MediaType; import org.atlasapi.media.entity.Publisher; import org.atlasapi.media.entity.Rating; import org.atlasapi.media.entity.Review; import org.atlasapi.media.entity.Specialization; import org.atlasapi.persistence.ModelTranslator; import com.google.common.collect.ComparisonChain; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.common.collect.Ordering; import com.metabroadcast.common.persistence.translator.TranslatorUtils; import com.mongodb.BasicDBList; import com.mongodb.BasicDBObject; import com.mongodb.DBObject; public class DescribedTranslator implements ModelTranslator<Described> { private static final String TAGS_KEY = "tags"; private static final String THUMBNAIL_KEY = "thumbnail"; private static final String TITLE_KEY = "title"; public static final String MEDIA_TYPE_KEY = "mediaType"; private static final String SPECIALIZATION_KEY = "specialization"; private static final String PRESENTATION_CHANNEL_KEY = "presentationChannel"; public static final String IMAGES_KEY = "images"; private static final String IMAGE_KEY = "image"; private static final String GENRES_KEY = "genres"; private static final String FIRST_SEEN_KEY = "firstSeen"; private static final String DESCRIPTION_KEY = "description"; public static final String PUBLISHER_KEY = "publisher"; private static final String SCHEDULE_ONLY_KEY = "scheduleOnly"; public static final String THIS_OR_CHILD_LAST_UPDATED_KEY = "thisOrChildLastUpdated"; public static final String TYPE_KEY = "type"; public static final String LAST_FETCHED_KEY = "lastFetched"; public static final String SHORT_DESC_KEY = "shortDescription"; public static final String MEDIUM_DESC_KEY = "mediumDescription"; public static final String LONG_DESC_KEY = "longDescription"; public static final String ACTIVELY_PUBLISHED_KEY = "activelyPublished"; public static final String LINKS_KEY = "links"; protected static final String LOCALIZED_DESCRIPTIONS_KEY = "descriptions"; protected static final String LOCALIZED_TITLES_KEY = "titles"; protected static final String REVIEWS_KEY = "reviews"; protected static final String RATINGS_KEY = "ratings"; protected static final String AUDIENCE_STATISTICS_KEY = "audienceStatistics"; protected static final String ITEM_PRIORITY_KEY = "priority"; public static final Ordering<LocalizedDescription> LOCALIZED_DESCRIPTION_ORDERING = Ordering.from((o1, o2) -> ComparisonChain.start() .compare(o1.getLanguageTag(), o2.getLanguageTag(), Ordering.natural().nullsFirst() ) .compare(o1.getDescription(), o2.getDescription(), Ordering.natural().nullsFirst() ) .compare(o1.getLongDescription(), o2.getLongDescription(), Ordering.natural().nullsFirst() ) .compare(o1.getMediumDescription(), o2.getMediumDescription(), Ordering.natural().nullsFirst() ) .compare(o1.getShortDescription(), o2.getShortDescription(), Ordering.natural().nullsFirst() ) .result() ); private static final Ordering<Review> REVIEW_ORDERING = Ordering.from((o1, o2) -> ComparisonChain.start() .compare( localeToLanguageTag(o1.getLocale()), localeToLanguageTag(o2.getLocale()), Ordering.natural().nullsFirst() ) .compare(o1.getReview(), o2.getReview(), Ordering.natural().nullsFirst()) .result() ); private static final String localeToLanguageTag(Locale locale) { if (locale == null) { return null; } return locale.toLanguageTag(); } public static final Ordering<LocalizedTitle> LOCALIZED_TITLE_ORDERING = Ordering.from((o1, o2) -> ComparisonChain.start() .compare( o1.getLanguageTag(), o2.getLanguageTag(), Ordering.natural().nullsFirst() ) .compare(o1.getTitle(), o2.getTitle(), Ordering.natural().nullsFirst()) .result() ); private final IdentifiedTranslator identifiedTranslator; private final ImageTranslator imageTranslator; private final RelatedLinkTranslator relatedLinkTranslator; private final LocalizedDescriptionTranslator localizedDescriptionTranslator; private final LocalizedTitleTranslator localizedTitleTranslator; private final ReviewTranslator reviewTranslator; private final AudienceStatisticsTranslator audienceStatisticsTranslator; private final RatingsTranslator ratingsTranslator; private final PriorityTranslator priorityTranslator; public DescribedTranslator(IdentifiedTranslator identifiedTranslator, ImageTranslator imageTranslator) { this.identifiedTranslator = identifiedTranslator; this.imageTranslator = imageTranslator; this.relatedLinkTranslator = new RelatedLinkTranslator(); this.localizedDescriptionTranslator = new LocalizedDescriptionTranslator(); this.localizedTitleTranslator = new LocalizedTitleTranslator(); this.reviewTranslator = new ReviewTranslator(); this.ratingsTranslator = new RatingsTranslator(); this.audienceStatisticsTranslator = new AudienceStatisticsTranslator(); this.priorityTranslator = new PriorityTranslator(); } @Override public Described fromDBObject(DBObject dbObject, Described entity) { identifiedTranslator.fromDBObject(dbObject, entity); decodeRelatedLinks(dbObject, entity); // this is needed in order to translate some Segments which have Object in the description field. Object description = dbObject.get(DESCRIPTION_KEY); if(description instanceof DBObject) { entity.setDescription(TranslatorUtils.toString((DBObject)description, TITLE_KEY)); } else { entity.setDescription((String) description); } entity.setShortDescription(TranslatorUtils.toString(dbObject, SHORT_DESC_KEY)); entity.setMediumDescription(TranslatorUtils.toString(dbObject, MEDIUM_DESC_KEY)); entity.setLongDescription(TranslatorUtils.toString(dbObject, LONG_DESC_KEY)); if (dbObject.containsField(ITEM_PRIORITY_KEY)) { entity.setPriority(priorityTranslator.getPriority(dbObject)); } entity.setFirstSeen(TranslatorUtils.toDateTime(dbObject, FIRST_SEEN_KEY)); entity.setThisOrChildLastUpdated(TranslatorUtils.toDateTime(dbObject, THIS_OR_CHILD_LAST_UPDATED_KEY)); entity.setGenres(TranslatorUtils.toSet(dbObject, GENRES_KEY)); entity.setImage((String) dbObject.get(IMAGE_KEY)); entity.setLastFetched(TranslatorUtils.toDateTime(dbObject, LAST_FETCHED_KEY)); Boolean scheduleOnly = TranslatorUtils.toBoolean(dbObject, SCHEDULE_ONLY_KEY); entity.setScheduleOnly(scheduleOnly != null ? scheduleOnly : false); String publisherKey = (String) dbObject.get(PUBLISHER_KEY); if (publisherKey != null) { entity.setPublisher(Publisher.fromKey(publisherKey).valueOrDefault(null)); } List<DBObject> imagesDboList = TranslatorUtils.toDBObjectList(dbObject, IMAGES_KEY); if (imagesDboList != null) { ImmutableSet.Builder<Image> images = ImmutableSet.builder(); for (DBObject imagesDbo : imagesDboList) { images.add(imageTranslator.fromDBObject(imagesDbo, null)); } entity.setImages(images.build()); } entity.setTags(TranslatorUtils.toSet(dbObject, TAGS_KEY)); entity.setThumbnail((String) dbObject.get(THUMBNAIL_KEY)); entity.setTitle((String) dbObject.get(TITLE_KEY)); String cType = (String) dbObject.get(MEDIA_TYPE_KEY); if (cType != null) { entity.setMediaType(MediaType.valueOf(cType.toUpperCase())); } String specialization = (String) dbObject.get(SPECIALIZATION_KEY); if (specialization != null) { entity.setSpecialization(Specialization.valueOf(specialization.toUpperCase())); } entity.setPresentationChannel(TranslatorUtils.toString(dbObject, PRESENTATION_CHANNEL_KEY)); if (dbObject.containsField(ACTIVELY_PUBLISHED_KEY)) { entity.setActivelyPublished(TranslatorUtils.toBoolean(dbObject, ACTIVELY_PUBLISHED_KEY)); } if (dbObject.containsField(AUDIENCE_STATISTICS_KEY)) { entity.setAudienceStatistics(audienceStatisticsTranslator.fromDBObject((DBObject) dbObject.get(AUDIENCE_STATISTICS_KEY))); } decodeLocalizedDescriptions(dbObject, entity); decodeLocalizedTitles(dbObject, entity); decodeReviews(dbObject, entity); decodeRatings(dbObject, entity, entity.getPublisher()); return entity; } private void decodeLocalizedTitles(DBObject dbObject, Described entity) { List<DBObject> localisedTitlesDBO = TranslatorUtils.toDBObjectList(dbObject, LOCALIZED_TITLES_KEY); entity.setLocalizedTitles(Iterables.transform( localisedTitlesDBO, input -> localizedTitleTranslator.fromDBObject(input, new LocalizedTitle()) )); } private void decodeLocalizedDescriptions(DBObject dbObject, Described entity) { List<DBObject> localisedDescriptionsDBO = TranslatorUtils.toDBObjectList(dbObject, LOCALIZED_DESCRIPTIONS_KEY); entity.setLocalizedDescriptions(Iterables.transform(localisedDescriptionsDBO, input -> localizedDescriptionTranslator.fromDBObject(input, new LocalizedDescription()))); } @SuppressWarnings("unchecked") private void decodeRelatedLinks(DBObject dbObject, Described entity) { if (dbObject.containsField(LINKS_KEY)) { entity.setRelatedLinks(Iterables.transform( (Iterable<DBObject>) dbObject.get(LINKS_KEY), relatedLinkTranslator::fromDBObject) ); } } private void decodeReviews(DBObject dbObject, Described entity) { entity.setReviews(TranslatorUtils.toIterable( dbObject, REVIEWS_KEY, reviewTranslator::fromDBObject ) .or(ImmutableSet.of()) ); } private void decodeRatings(DBObject dbObject, Described entity, final Publisher publisher) { entity.setRatings( TranslatorUtils.toIterable(dbObject, RATINGS_KEY, ratingsTranslator.fromDbo(publisher)) .or(ImmutableSet.of()) ); } @Override public DBObject toDBObject(DBObject dbObject, Described entity) { if (dbObject == null) { dbObject = new BasicDBObject(); } identifiedTranslator.toDBObject(dbObject, entity); encodeRelatedLinks(dbObject, entity); TranslatorUtils.from(dbObject, SHORT_DESC_KEY, entity.getShortDescription()); TranslatorUtils.from(dbObject, MEDIUM_DESC_KEY, entity.getMediumDescription()); TranslatorUtils.from(dbObject, LONG_DESC_KEY, entity.getLongDescription()); TranslatorUtils.from(dbObject, DESCRIPTION_KEY, entity.getDescription()); TranslatorUtils.fromDateTime(dbObject, FIRST_SEEN_KEY, entity.getFirstSeen()); TranslatorUtils.fromDateTime(dbObject, THIS_OR_CHILD_LAST_UPDATED_KEY, entity.getThisOrChildLastUpdated()); TranslatorUtils.fromSet(dbObject, entity.getGenres(), GENRES_KEY); TranslatorUtils.from(dbObject, IMAGE_KEY, entity.getImage()); TranslatorUtils.fromDateTime(dbObject, LAST_FETCHED_KEY, entity.getLastFetched()); if (entity.getPublisher() != null) { TranslatorUtils.from(dbObject, PUBLISHER_KEY, entity.getPublisher().key()); } TranslatorUtils.fromSet(dbObject, entity.getTags(), TAGS_KEY); TranslatorUtils.from(dbObject, THUMBNAIL_KEY, entity.getThumbnail()); TranslatorUtils.from(dbObject, TITLE_KEY, entity.getTitle()); if (entity.isScheduleOnly()) { dbObject.put(SCHEDULE_ONLY_KEY, Boolean.TRUE); } if (entity.getMediaType() != null) { TranslatorUtils.from(dbObject, MEDIA_TYPE_KEY, entity.getMediaType().toString().toLowerCase()); } if (entity.getSpecialization() != null) { TranslatorUtils.from(dbObject, SPECIALIZATION_KEY, entity.getSpecialization().toString().toLowerCase()); } BasicDBList images = new BasicDBList(); if (entity.getImages() != null) { for (Image image : entity.getImages()) { images.add(imageTranslator.toDBObject(null, image)); } } dbObject.put(IMAGES_KEY, images); TranslatorUtils.from(dbObject, PRESENTATION_CHANNEL_KEY, entity.getPresentationChannel()); TranslatorUtils.from(dbObject, ACTIVELY_PUBLISHED_KEY, entity.isActivelyPublished()); if (entity.getAudienceStatistics() != null) { DBObject audienceDbo = new BasicDBObject(); audienceStatisticsTranslator.toDBObject(audienceDbo, entity.getAudienceStatistics()); dbObject.put(AUDIENCE_STATISTICS_KEY, audienceDbo); } if (entity.getPriority() != null) { priorityTranslator.setPriority(dbObject, entity); } encodeLocalizedDescriptions(entity, dbObject); encodeLocalizedTitles(entity, dbObject); encodeReviews(dbObject, entity); encodeRatings(dbObject, entity); return dbObject; } private void encodeLocalizedTitles(Described entity, DBObject dbObject) { List<LocalizedTitle> sortedTitles = LOCALIZED_TITLE_ORDERING.sortedCopy( entity.getLocalizedTitles() ); BasicDBList dbTitles = new BasicDBList(); sortedTitles.forEach(title -> dbTitles.add(localizedTitleTranslator.toDBObject(new BasicDBObject(), title)) ); dbObject.put(LOCALIZED_TITLES_KEY, dbTitles); } private void encodeLocalizedDescriptions(Described entity, DBObject dbObject) { List<LocalizedDescription> sortedDescriptions = LOCALIZED_DESCRIPTION_ORDERING.sortedCopy( entity.getLocalizedDescriptions() ); BasicDBList dbDescriptions = new BasicDBList(); sortedDescriptions.forEach(description -> dbDescriptions.add(localizedDescriptionTranslator.toDBObject( new BasicDBObject(), description )) ); dbObject.put(LOCALIZED_DESCRIPTIONS_KEY, dbDescriptions); } private void encodeRelatedLinks(DBObject dbObject, Described entity) { if (!entity.getRelatedLinks().isEmpty()) { BasicDBList values = new BasicDBList(); entity.getRelatedLinks().forEach(link -> values.add(relatedLinkTranslator.toDBObject(link)) ); dbObject.put(LINKS_KEY, values); } } private void encodeRatings(DBObject dbObject, Described entity) { if (!entity.getRatings().isEmpty()) { BasicDBList values = new BasicDBList(); for(Rating rating : entity.getRatings()) { DBObject dbo = new BasicDBObject(); values.add(ratingsTranslator.toDBObject(dbo, rating)); } dbObject.put(RATINGS_KEY, values); } } private void encodeReviews(DBObject dbObject, Described entity) { TranslatorUtils.fromIterable(dbObject, REVIEWS_KEY, REVIEW_ORDERING.sortedCopy(entity.getReviews()), review -> reviewTranslator.toDBObject(new BasicDBObject(), review)); } static Identified newModel(DBObject dbObject) { EntityType type = EntityType.from((String) dbObject.get(TYPE_KEY)); try { return type.getModelClass().newInstance(); } catch (Exception e) { throw new RuntimeException(e); } } public void removeFieldsForHash(DBObject dbObject) { identifiedTranslator.removeFieldsForHash(dbObject); dbObject.removeField(LAST_FETCHED_KEY); dbObject.removeField(THIS_OR_CHILD_LAST_UPDATED_KEY); } }