From db2644adf6f9f5d7b0a813f359d28e4991911af5 Mon Sep 17 00:00:00 2001 From: Patrick Gotthard Date: Sat, 20 Feb 2016 17:10:50 +0100 Subject: [PATCH] #248 Adds support for MediaRSS 1.5.1 --- pom.xml | 7 + rome-modules/pom.xml | 5 + .../mediarss/io/MediaModuleGenerator.java | 336 +++- .../mediarss/io/MediaModuleParser.java | 783 +++++++-- .../modules/mediarss/types/Community.java | 109 ++ .../modules/mediarss/types/Embed.java | 219 +++ .../modules/mediarss/types/License.java | 114 ++ .../modules/mediarss/types/Location.java | 132 ++ .../modules/mediarss/types/Metadata.java | 1520 ++++++++++++----- .../modules/mediarss/types/PeerLink.java | 96 ++ .../modules/mediarss/types/Price.java | 183 ++ .../modules/mediarss/types/Restriction.java | 57 +- .../modules/mediarss/types/Scene.java | 130 ++ .../modules/mediarss/types/StarRating.java | 128 ++ .../modules/mediarss/types/Statistics.java | 95 ++ .../modules/mediarss/types/Status.java | 127 ++ .../modules/mediarss/types/SubTitle.java | 113 ++ .../rometools/modules/mediarss/types/Tag.java | 122 ++ rome-modules/src/site/apt/MediaRSS.apt | 8 +- .../rometools/modules/atom/AtomLinkTest.java | 23 +- .../modules/mediarss/MediaModuleTest.java | 211 ++- .../feed/module/mediarss/issue-15.xml | 66 + 22 files changed, 3856 insertions(+), 728 deletions(-) create mode 100644 rome-modules/src/main/java/com/rometools/modules/mediarss/types/Community.java create mode 100644 rome-modules/src/main/java/com/rometools/modules/mediarss/types/Embed.java create mode 100644 rome-modules/src/main/java/com/rometools/modules/mediarss/types/License.java create mode 100644 rome-modules/src/main/java/com/rometools/modules/mediarss/types/Location.java create mode 100644 rome-modules/src/main/java/com/rometools/modules/mediarss/types/PeerLink.java create mode 100644 rome-modules/src/main/java/com/rometools/modules/mediarss/types/Price.java create mode 100644 rome-modules/src/main/java/com/rometools/modules/mediarss/types/Scene.java create mode 100644 rome-modules/src/main/java/com/rometools/modules/mediarss/types/StarRating.java create mode 100644 rome-modules/src/main/java/com/rometools/modules/mediarss/types/Statistics.java create mode 100644 rome-modules/src/main/java/com/rometools/modules/mediarss/types/Status.java create mode 100644 rome-modules/src/main/java/com/rometools/modules/mediarss/types/SubTitle.java create mode 100644 rome-modules/src/main/java/com/rometools/modules/mediarss/types/Tag.java create mode 100644 rome-modules/src/test/resources/org/rometools/feed/module/mediarss/issue-15.xml diff --git a/pom.xml b/pom.xml index 9bf38db..bb45d0f 100644 --- a/pom.xml +++ b/pom.xml @@ -241,6 +241,13 @@ junit 4.12 + + + xmlunit + xmlunit + 1.5 + test + org.hamcrest diff --git a/rome-modules/pom.xml b/rome-modules/pom.xml index 7ec06c7..b123caf 100644 --- a/rome-modules/pom.xml +++ b/rome-modules/pom.xml @@ -112,6 +112,11 @@ hamcrest-library test + + xmlunit + xmlunit + test + diff --git a/rome-modules/src/main/java/com/rometools/modules/mediarss/io/MediaModuleGenerator.java b/rome-modules/src/main/java/com/rometools/modules/mediarss/io/MediaModuleGenerator.java index 6d2ca05..5438354 100644 --- a/rome-modules/src/main/java/com/rometools/modules/mediarss/io/MediaModuleGenerator.java +++ b/rome-modules/src/main/java/com/rometools/modules/mediarss/io/MediaModuleGenerator.java @@ -21,29 +21,42 @@ */ package com.rometools.modules.mediarss.io; +import java.net.URL; import java.util.HashSet; import java.util.Set; import org.jdom2.Element; import org.jdom2.Namespace; +import com.rometools.modules.georss.GMLGenerator; import com.rometools.modules.mediarss.MediaEntryModule; import com.rometools.modules.mediarss.MediaModule; import com.rometools.modules.mediarss.types.Category; import com.rometools.modules.mediarss.types.Credit; +import com.rometools.modules.mediarss.types.Embed.Param; +import com.rometools.modules.mediarss.types.License; +import com.rometools.modules.mediarss.types.Location; import com.rometools.modules.mediarss.types.MediaContent; import com.rometools.modules.mediarss.types.MediaGroup; import com.rometools.modules.mediarss.types.Metadata; +import com.rometools.modules.mediarss.types.PeerLink; import com.rometools.modules.mediarss.types.PlayerReference; +import com.rometools.modules.mediarss.types.Price; import com.rometools.modules.mediarss.types.Rating; import com.rometools.modules.mediarss.types.Restriction; +import com.rometools.modules.mediarss.types.Scene; +import com.rometools.modules.mediarss.types.SubTitle; +import com.rometools.modules.mediarss.types.Tag; import com.rometools.modules.mediarss.types.Text; import com.rometools.modules.mediarss.types.Thumbnail; import com.rometools.modules.mediarss.types.UrlReference; import com.rometools.rome.feed.module.Module; import com.rometools.rome.io.ModuleGenerator; -//this class TBI +/** + * Generator for MediaRSS module. + * + */ public class MediaModuleGenerator implements ModuleGenerator { private static final Namespace NS = Namespace.getNamespace("media", MediaModule.URI); @@ -73,15 +86,10 @@ public class MediaModuleGenerator implements ModuleGenerator { if (module instanceof MediaEntryModule) { final MediaEntryModule m = (MediaEntryModule) module; - final MediaGroup[] g = m.getMediaGroups(); - - for (final MediaGroup element2 : g) { + for (final MediaGroup element2 : m.getMediaGroups()) { generateGroup(element2, element); } - - final MediaContent[] c = m.getMediaContents(); - - for (final MediaContent element2 : c) { + for (final MediaContent element2 : m.getMediaContents()) { generateContent(element2, element); } } @@ -197,9 +205,43 @@ public class MediaModuleGenerator implements ModuleGenerator { addNotNullAttribute(t, "end", element.getEnd()); } - final Thumbnail[] thumbs = m.getThumbnail(); + final Element title = addNotNullElement(e, "title", m.getTitle()); + addNotNullAttribute(title, "type", m.getTitleType()); - for (final Thumbnail thumb : thumbs) { + generateBackLinks(m, e); + generateComments(m, e); + generateCommunity(m, e); + generateEmbed(m, e); + generateLicenses(m, e); + generateLocations(m, e); + generatePeerLinks(m, e); + generatePrices(m, e); + generateResponses(m, e); + final Restriction[] r = m.getRestrictions(); + for (final Restriction element : r) { + final Element res = addNotNullElement(e, "restriction", element.getValue()); + addNotNullAttribute(res, "type", element.getType()); + addNotNullAttribute(res, "relationship", element.getRelationship()); + } + if (m.getRights() != null) { + final Element rights = new Element("rights", NS); + rights.setAttribute("status", m.getRights().name()); + e.addContent(rights); + } + generateScenes(m, e); + generateStatus(m, e); + generateSubTitles(m, e); + generateThumbails(m, e); + } + + /** + * Generation of thumbnail tags. + * + * @param m source + * @param e element to attach new element to + */ + private void generateThumbails(final Metadata m, final Element e) { + for (final Thumbnail thumb : m.getThumbnail()) { final Element t = new Element("thumbnail", NS); addNotNullAttribute(t, "url", thumb.getUrl()); addNotNullAttribute(t, "width", thumb.getWidth()); @@ -207,16 +249,275 @@ public class MediaModuleGenerator implements ModuleGenerator { addNotNullAttribute(t, "time", thumb.getTime()); e.addContent(t); } + } - final Element title = addNotNullElement(e, "title", m.getTitle()); - addNotNullAttribute(title, "type", m.getTitleType()); + /** + * Generation of backLinks tag. + * + * @param m source + * @param e element to attach new element to + */ + private void generateBackLinks(final Metadata m, final Element e) { + final Element backLinksElements = new Element("backLinks", NS); + for (final URL backLink : m.getBackLinks()) { + addNotNullElement(backLinksElements, "backLink", backLink); + } + if (!backLinksElements.getChildren().isEmpty()) { + e.addContent(backLinksElements); + } + } - final Restriction[] r = m.getRestrictions(); + /** + * Generation of comments tag. + * + * @param m source + * @param e element to attach new element to + */ + private void generateComments(final Metadata m, final Element e) { + final Element commentsElements = new Element("comments", NS); + for (final String comment : m.getComments()) { + addNotNullElement(commentsElements, "comment", comment); + } + if (!commentsElements.getChildren().isEmpty()) { + e.addContent(commentsElements); + } + } - for (final Restriction element : r) { - final Element res = addNotNullElement(e, "restriction", element.getValue()); - addNotNullAttribute(res, "type", element.getType()); - addNotNullAttribute(res, "relationship", element.getRelationship()); + /** + * Generation of community tag. + * + * @param m source + * @param e element to attach new element to + */ + private void generateCommunity(final Metadata m, final Element e) { + if (m.getCommunity() == null) { + return; + } + final Element communityElement = new Element("community", NS); + if (m.getCommunity().getStarRating() != null) { + final Element starRatingElement = new Element("starRating", NS); + addNotNullAttribute(starRatingElement, "average", m.getCommunity().getStarRating().getAverage()); + addNotNullAttribute(starRatingElement, "count", m.getCommunity().getStarRating().getCount()); + addNotNullAttribute(starRatingElement, "min", m.getCommunity().getStarRating().getMin()); + addNotNullAttribute(starRatingElement, "max", m.getCommunity().getStarRating().getMax()); + if (starRatingElement.hasAttributes()) { + communityElement.addContent(starRatingElement); + } + } + if (m.getCommunity().getStatistics() != null) { + final Element statisticsElement = new Element("statistics", NS); + addNotNullAttribute(statisticsElement, "views", m.getCommunity().getStatistics().getViews()); + addNotNullAttribute(statisticsElement, "favorites", m.getCommunity().getStatistics().getFavorites()); + if (statisticsElement.hasAttributes()) { + communityElement.addContent(statisticsElement); + } + } + if (m.getCommunity().getTags() != null && !m.getCommunity().getTags().isEmpty()) { + final Element tagsElement = new Element("tags", NS); + for (final Tag tag : m.getCommunity().getTags()) { + if (!tagsElement.getTextTrim().isEmpty()) { + tagsElement.addContent(", "); + } + if (tag.getWeight() == null) { + tagsElement.addContent(tag.getName()); + } else { + tagsElement.addContent(tag.getName()); + tagsElement.addContent(":"); + tagsElement.addContent(String.valueOf(tag.getWeight())); + } + } + if (!tagsElement.getTextTrim().isEmpty()) { + communityElement.addContent(tagsElement); + } + } + if (!communityElement.getChildren().isEmpty()) { + e.addContent(communityElement); + } + } + + /** + * Generation of embed tag. + * + * @param m source + * @param e element to attach new element to + */ + private void generateEmbed(final Metadata m, final Element e) { + if (m.getEmbed() == null) { + return; + } + final Element embedElement = new Element("embed", NS); + addNotNullAttribute(embedElement, "url", m.getEmbed().getUrl()); + addNotNullAttribute(embedElement, "width", m.getEmbed().getWidth()); + addNotNullAttribute(embedElement, "height", m.getEmbed().getHeight()); + for (final Param param : m.getEmbed().getParams()) { + final Element paramElement = addNotNullElement(embedElement, "param", param.getValue()); + if (paramElement != null) { + addNotNullAttribute(paramElement, "name", param.getName()); + } + } + if (embedElement.hasAttributes() || !embedElement.getChildren().isEmpty()) { + e.addContent(embedElement); + } + } + + /** + * Generation of scenes tag. + * + * @param m source + * @param e element to attach new element to + */ + private void generateScenes(final Metadata m, final Element e) { + final Element scenesElement = new Element("scenes", NS); + for (final Scene scene : m.getScenes()) { + final Element sceneElement = new Element("scene", NS); + addNotNullElement(sceneElement, "sceneTitle", scene.getTitle()); + addNotNullElement(sceneElement, "sceneDescription", scene.getDescription()); + addNotNullElement(sceneElement, "sceneStartTime", scene.getStartTime()); + addNotNullElement(sceneElement, "sceneEndTime", scene.getEndTime()); + if (!sceneElement.getChildren().isEmpty()) { + scenesElement.addContent(sceneElement); + } + } + if (!scenesElement.getChildren().isEmpty()) { + e.addContent(scenesElement); + } + } + + /** + * Generation of location tags. + * + * @param m source + * @param e element to attach new element to + */ + private void generateLocations(final Metadata m, final Element e) { + final GMLGenerator geoRssGenerator = new GMLGenerator(); + for (final Location location : m.getLocations()) { + final Element locationElement = new Element("location", NS); + addNotNullAttribute(locationElement, "description", location.getDescription()); + addNotNullAttribute(locationElement, "start", location.getStart()); + addNotNullAttribute(locationElement, "end", location.getEnd()); + if (location.getGeoRss() != null) { + geoRssGenerator.generate(location.getGeoRss(), locationElement); + } + if (locationElement.hasAttributes() || !locationElement.getChildren().isEmpty()) { + e.addContent(locationElement); + } + } + } + + /** + * Generation of peerLink tags. + * + * @param m source + * @param e element to attach new element to + */ + private void generatePeerLinks(final Metadata m, final Element e) { + for (final PeerLink peerLink : m.getPeerLinks()) { + final Element peerLinkElement = new Element("peerLink", NS); + addNotNullAttribute(peerLinkElement, "type", peerLink.getType()); + addNotNullAttribute(peerLinkElement, "href", peerLink.getHref()); + if (peerLinkElement.hasAttributes()) { + e.addContent(peerLinkElement); + } + } + } + + /** + * Generation of subTitle tags. + * + * @param m source + * @param e element to attach new element to + */ + private void generateSubTitles(final Metadata m, final Element e) { + for (final SubTitle subTitle : m.getSubTitles()) { + final Element subTitleElement = new Element("subTitle", NS); + addNotNullAttribute(subTitleElement, "type", subTitle.getType()); + addNotNullAttribute(subTitleElement, "lang", subTitle.getLang()); + addNotNullAttribute(subTitleElement, "href", subTitle.getHref()); + if (subTitleElement.hasAttributes()) { + e.addContent(subTitleElement); + } + } + } + + /** + * Generation of license tags. + * + * @param m source + * @param e element to attach new element to + */ + private void generateLicenses(final Metadata m, final Element e) { + for (final License license : m.getLicenses()) { + final Element licenseElement = new Element("license", NS); + addNotNullAttribute(licenseElement, "type", license.getType()); + addNotNullAttribute(licenseElement, "href", license.getHref()); + if (license.getValue() != null) { + licenseElement.addContent(license.getValue()); + } + if (licenseElement.hasAttributes() || !licenseElement.getTextTrim().isEmpty()) { + e.addContent(licenseElement); + } + } + } + + /** + * Generation of backLinks tag. + * + * @param m source + * @param e element to attach new element to + */ + private void generatePrices(final Metadata m, final Element e) { + for (final Price price : m.getPrices()) { + if (price == null) { + continue; + } + final Element priceElement = new Element("price", NS); + if (price.getType() != null) { + priceElement.setAttribute("type", price.getType().name().toLowerCase()); + } + addNotNullAttribute(priceElement, "info", price.getInfo()); + addNotNullAttribute(priceElement, "price", price.getPrice()); + addNotNullAttribute(priceElement, "currency", price.getCurrency()); + if (priceElement.hasAttributes()) { + e.addContent(priceElement); + } + } + } + + /** + * Generation of responses tag. + * + * @param m source + * @param e element to attach new element to + */ + private void generateResponses(final Metadata m, final Element e) { + if (m.getResponses() == null || m.getResponses().length == 0) { + return; + } + final Element responsesElements = new Element("responses", NS); + for (final String response : m.getResponses()) { + addNotNullElement(responsesElements, "response", response); + } + e.addContent(responsesElements); + } + + /** + * Generation of status tag. + * + * @param m source + * @param e element to attach new element to + */ + private void generateStatus(final Metadata m, final Element e) { + if (m.getStatus() == null) { + return; + } + final Element statusElement = new Element("status", NS); + if (m.getStatus().getState() != null) { + statusElement.setAttribute("state", m.getStatus().getState().name()); + } + addNotNullAttribute(statusElement, "reason", m.getStatus().getReason()); + if (statusElement.hasAttributes()) { + e.addContent(statusElement); } } @@ -258,3 +559,4 @@ public class MediaModuleGenerator implements ModuleGenerator { return element; } } + diff --git a/rome-modules/src/main/java/com/rometools/modules/mediarss/io/MediaModuleParser.java b/rome-modules/src/main/java/com/rometools/modules/mediarss/io/MediaModuleParser.java index 2cfa573..512ff9d 100644 --- a/rome-modules/src/main/java/com/rometools/modules/mediarss/io/MediaModuleParser.java +++ b/rome-modules/src/main/java/com/rometools/modules/mediarss/io/MediaModuleParser.java @@ -21,7 +21,9 @@ */ package com.rometools.modules.mediarss.io; +import java.net.MalformedURLException; import java.net.URI; +import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.Locale; @@ -32,32 +34,49 @@ import org.jdom2.Namespace; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.rometools.modules.georss.GeoRSSModule; +import com.rometools.modules.georss.SimpleParser; import com.rometools.modules.mediarss.MediaEntryModuleImpl; import com.rometools.modules.mediarss.MediaModule; import com.rometools.modules.mediarss.MediaModuleImpl; import com.rometools.modules.mediarss.types.Category; +import com.rometools.modules.mediarss.types.Community; import com.rometools.modules.mediarss.types.Credit; +import com.rometools.modules.mediarss.types.Embed; +import com.rometools.modules.mediarss.types.Embed.Param; import com.rometools.modules.mediarss.types.Expression; import com.rometools.modules.mediarss.types.Hash; +import com.rometools.modules.mediarss.types.License; +import com.rometools.modules.mediarss.types.Location; import com.rometools.modules.mediarss.types.MediaContent; import com.rometools.modules.mediarss.types.MediaGroup; import com.rometools.modules.mediarss.types.Metadata; +import com.rometools.modules.mediarss.types.Metadata.RightsStatus; +import com.rometools.modules.mediarss.types.PeerLink; import com.rometools.modules.mediarss.types.PlayerReference; +import com.rometools.modules.mediarss.types.Price; import com.rometools.modules.mediarss.types.Rating; import com.rometools.modules.mediarss.types.Restriction; +import com.rometools.modules.mediarss.types.Scene; +import com.rometools.modules.mediarss.types.StarRating; +import com.rometools.modules.mediarss.types.Statistics; +import com.rometools.modules.mediarss.types.Status; +import com.rometools.modules.mediarss.types.SubTitle; +import com.rometools.modules.mediarss.types.Tag; import com.rometools.modules.mediarss.types.Text; import com.rometools.modules.mediarss.types.Thumbnail; import com.rometools.modules.mediarss.types.Time; import com.rometools.modules.mediarss.types.UrlReference; import com.rometools.rome.feed.module.Module; import com.rometools.rome.io.ModuleParser; +import com.rometools.utils.Doubles; import com.rometools.utils.Integers; import com.rometools.utils.Longs; import com.rometools.utils.Strings; /** * @author Nathanial X. Freitas - * + * */ public class MediaModuleParser implements ModuleParser { @@ -80,19 +99,24 @@ public class MediaModuleParser implements ModuleParser { mod = new MediaEntryModuleImpl(); } - mod.setMetadata(parseMetadata(mmRoot)); + mod.setMetadata(parseMetadata(mmRoot, locale)); mod.setPlayer(parsePlayer(mmRoot)); if (mod instanceof MediaEntryModuleImpl) { final MediaEntryModuleImpl m = (MediaEntryModuleImpl) mod; - m.setMediaContents(parseContent(mmRoot)); - m.setMediaGroups(parseGroup(mmRoot)); + m.setMediaContents(parseContent(mmRoot, locale)); + m.setMediaGroups(parseGroup(mmRoot, locale)); } return mod; } - private MediaContent[] parseContent(final Element e) { + /** + * @param e element to parse + * @param locale locale for parsing + * @return array of media:content elements + */ + private MediaContent[] parseContent(final Element e, final Locale locale) { final List contents = e.getChildren("content", getNS()); final ArrayList values = new ArrayList(); @@ -173,7 +197,7 @@ public class MediaModuleParser implements ModuleParser { } mc.setLanguage(content.getAttributeValue("lang")); - mc.setMetadata(parseMetadata(content)); + mc.setMetadata(parseMetadata(content, locale)); try { if (content.getAttributeValue("samplingrate") != null) { mc.setSamplingrate(Float.valueOf(content.getAttributeValue("samplingrate"))); @@ -206,13 +230,18 @@ public class MediaModuleParser implements ModuleParser { return values.toArray(new MediaContent[values.size()]); } - private MediaGroup[] parseGroup(final Element e) { + /** + * @param e element to parse + * @param locale locale for parsing + * @return array of media:group elements + */ + private MediaGroup[] parseGroup(final Element e, final Locale locale) { final List groups = e.getChildren("group", getNS()); final ArrayList values = new ArrayList(); for (int i = 0; groups != null && i < groups.size(); i++) { final Element group = groups.get(i); - final MediaGroup g = new MediaGroup(parseContent(group)); + final MediaGroup g = new MediaGroup(parseContent(group, locale)); for (int j = 0; j < g.getContents().length; j++) { if (g.getContents()[j].isDefaultContent()) { @@ -222,60 +251,372 @@ public class MediaModuleParser implements ModuleParser { } } - g.setMetadata(parseMetadata(group)); + g.setMetadata(parseMetadata(group, locale)); values.add(g); } return values.toArray(new MediaGroup[values.size()]); } - private Metadata parseMetadata(final Element e) { + /** + * @param e element to parse + * @param locale locale for parsing + * @return Metadata of media:group or media:content + */ + private Metadata parseMetadata(final Element e, final Locale locale) { final Metadata md = new Metadata(); - // categories - { - final List categories = e.getChildren("category", getNS()); - final ArrayList values = new ArrayList(); + parseCategories(e, md); + parseCopyright(e, md); + parseCredits(e, md); + parseDescription(e, md); + parseHash(e, md); + parseKeywords(e, md); + parseRatings(e, md); + parseText(e, md); + parseThumbnail(e, md); + parseTitle(e, md); + parseRestrictions(e, md); + parseAdultMetadata(e, md); + parseBackLinks(e, md); + parseComments(e, md); + parseCommunity(e, md); + parsePrices(e, md); + parseResponses(e, md); + parseStatus(e, md); + parseEmbed(e, md); + parseLicenses(e, md); + parseSubTitles(e, md); + parsePeerLinks(e, md); + parseRights(e, md); + parseLocations(e, md, locale); + parseScenes(e, md); + return md; + } - for (int i = 0; categories != null && i < categories.size(); i++) { - try { - final Element cat = categories.get(i); - values.add(new Category(cat.getAttributeValue("scheme"), cat.getAttributeValue("label"), cat.getText())); - } catch (final Exception ex) { - LOG.warn("Exception parsing category tag.", ex); + /** + * @param e element to parse + * @param md metadata to fill in + */ + private void parseScenes(final Element e, final Metadata md) { + final Element scenesElement = e.getChild("scenes", getNS()); + if (scenesElement != null) { + final List sceneElements = scenesElement.getChildren("scene", getNS()); + final Scene[] scenes = new Scene[sceneElements.size()]; + for (int i = 0; i < sceneElements.size(); i++) { + scenes[i] = new Scene(); + scenes[i].setTitle(sceneElements.get(i).getChildText("sceneTitle", getNS())); + scenes[i].setDescription(sceneElements.get(i).getChildText("sceneDescription", getNS())); + final String sceneStartTime = sceneElements.get(i).getChildText("sceneStartTime", getNS()); + if (sceneStartTime != null) { + scenes[i].setStartTime(new Time(sceneStartTime)); + } + final String sceneEndTime = sceneElements.get(i).getChildText("sceneEndTime", getNS()); + if (sceneEndTime != null) { + scenes[i].setEndTime(new Time(sceneEndTime)); } } + md.setScenes(scenes); + } + } - md.setCategories(values.toArray(new Category[values.size()])); + /** + * @param e element to parse + * @param md metadata to fill in + * @param locale locale for parser + */ + private void parseLocations(final Element e, final Metadata md, final Locale locale) { + final List locationElements = e.getChildren("location", getNS()); + final Location[] locations = new Location[locationElements.size()]; + final SimpleParser geoRssParser = new SimpleParser(); + for (int i = 0; i < locationElements.size(); i++) { + locations[i] = new Location(); + locations[i].setDescription(locationElements.get(i).getAttributeValue("description")); + if (locationElements.get(i).getAttributeValue("start") != null) { + locations[i].setStart(new Time(locationElements.get(i).getAttributeValue("start"))); + } + if (locationElements.get(i).getAttributeValue("end") != null) { + locations[i].setEnd(new Time(locationElements.get(i).getAttributeValue("end"))); + } + final Module geoRssModule = geoRssParser.parse(locationElements.get(i), locale); + if (geoRssModule != null && geoRssModule instanceof GeoRSSModule) { + locations[i].setGeoRss((GeoRSSModule) geoRssModule); + } + } + md.setLocations(locations); + } + + /** + * @param e element to parse + * @param md metadata to fill in + */ + private void parseRights(final Element e, final Metadata md) { + final Element rightsElement = e.getChild("rights", getNS()); + if (rightsElement != null && rightsElement.getAttributeValue("status") != null) { + md.setRights(RightsStatus.valueOf(rightsElement.getAttributeValue("status"))); + } + } + + /** + * @param e element to parse + * @param md metadata to fill in + */ + private void parsePeerLinks(final Element e, final Metadata md) { + final List peerLinkElements = e.getChildren("peerLink", getNS()); + final PeerLink[] peerLinks = new PeerLink[peerLinkElements.size()]; + for (int i = 0; i < peerLinkElements.size(); i++) { + peerLinks[i] = new PeerLink(); + peerLinks[i].setType(peerLinkElements.get(i).getAttributeValue("type")); + if (peerLinkElements.get(i).getAttributeValue("href") != null) { + try { + peerLinks[i].setHref(new URL(peerLinkElements.get(i).getAttributeValue("href"))); + } catch (MalformedURLException ex) { + LOG.warn("Exception parsing peerLink href attribute.", ex); + } + } + } + md.setPeerLinks(peerLinks); + } + + /** + * @param e element to parse + * @param md metadata to fill in + */ + private void parseSubTitles(final Element e, final Metadata md) { + final List subTitleElements = e.getChildren("subTitle", getNS()); + final SubTitle[] subtitles = new SubTitle[subTitleElements.size()]; + for (int i = 0; i < subTitleElements.size(); i++) { + subtitles[i] = new SubTitle(); + subtitles[i].setType(subTitleElements.get(i).getAttributeValue("type")); + subtitles[i].setLang(subTitleElements.get(i).getAttributeValue("lang")); + if (subTitleElements.get(i).getAttributeValue("href") != null) { + try { + subtitles[i].setHref(new URL(subTitleElements.get(i).getAttributeValue("href"))); + } catch (MalformedURLException ex) { + LOG.warn("Exception parsing subTitle href attribute.", ex); + } + } + } + md.setSubTitles(subtitles); + } + + /** + * @param e element to parse + * @param md metadata to fill in + */ + private void parseLicenses(final Element e, final Metadata md) { + final List licenseElements = e.getChildren("license", getNS()); + final License[] licenses = new License[licenseElements.size()]; + for (int i = 0; i < licenseElements.size(); i++) { + licenses[i] = new License(); + licenses[i].setType(licenseElements.get(i).getAttributeValue("type")); + licenses[i].setValue(licenseElements.get(i).getTextTrim()); + if (licenseElements.get(i).getAttributeValue("href") != null) { + try { + licenses[i].setHref(new URL(licenseElements.get(i).getAttributeValue("href"))); + } catch (MalformedURLException ex) { + LOG.warn("Exception parsing license href attribute.", ex); + } + } + } + md.setLicenses(licenses); + } + + /** + * @param e element to parse + * @param md metadata to fill in + */ + private void parsePrices(final Element e, final Metadata md) { + final List priceElements = e.getChildren("price", getNS()); + final Price[] prices = new Price[priceElements.size()]; + for (int i = 0; i < priceElements.size(); i++) { + final Element priceElement = priceElements.get(i); + prices[i] = new Price(); + prices[i].setCurrency(priceElement.getAttributeValue("currency")); + prices[i].setPrice(Doubles.parse(priceElement.getAttributeValue("price"))); + if (priceElement.getAttributeValue("type") != null) { + prices[i].setType(Price.Type.valueOf(priceElement.getAttributeValue("type").toUpperCase())); + } + if (priceElement.getAttributeValue("info") != null) { + try { + prices[i].setInfo(new URL(priceElement.getAttributeValue("info"))); + } catch (MalformedURLException ex) { + LOG.warn("Exception parsing price info attribute.", ex); + } + } + } + md.setPrices(prices); + } + + /** + * @param e element to parse + * @param md metadata to fill in + */ + private void parseStatus(final Element e, final Metadata md) { + final Element statusElement = e.getChild("status", getNS()); + if (statusElement != null) { + final Status status = new Status(); + status.setState(Status.State.valueOf(statusElement.getAttributeValue("state"))); + status.setReason(statusElement.getAttributeValue("reason")); + md.setStatus(status); + } + } + + /** + * @param e element to parse + * @param md metadata to fill in + */ + private void parseBackLinks(final Element e, final Metadata md) { + final Element backLinksElement = e.getChild("backLinks", getNS()); + if (backLinksElement != null) { + final List backLinkElements = backLinksElement.getChildren("backLink", getNS()); + final URL[] backLinks = new URL[backLinkElements.size()]; + for (int i = 0; i < backLinkElements.size(); i++) { + try { + backLinks[i] = new URL(backLinkElements.get(i).getTextTrim()); + } catch (MalformedURLException ex) { + LOG.warn("Exception parsing backLink tag.", ex); + } + } + md.setBackLinks(backLinks); + } + } + + /** + * @param e element to parse + * @param md metadata to fill in + */ + private void parseComments(final Element e, final Metadata md) { + final Element commentsElement = e.getChild("comments", getNS()); + if (commentsElement != null) { + final List commentElements = commentsElement.getChildren("comment", getNS()); + final String[] comments = new String[commentElements.size()]; + for (int i = 0; i < commentElements.size(); i++) { + comments[i] = commentElements.get(i).getTextTrim(); + } + md.setComments(comments); + } + } + + /** + * @param e element to parse + * @param md metadata to fill in + */ + private void parseResponses(final Element e, final Metadata md) { + final Element responsesElement = e.getChild("responses", getNS()); + if (responsesElement != null) { + final List responseElements = responsesElement.getChildren("response", getNS()); + final String[] responses = new String[responseElements.size()]; + for (int i = 0; i < responseElements.size(); i++) { + responses[i] = responseElements.get(i).getTextTrim(); + } + md.setResponses(responses); + } + } + + /** + * @param e element to parse + * @param md metadata to fill in + */ + private void parseCommunity(final Element e, final Metadata md) { + final Element communityElement = e.getChild("community", getNS()); + if (communityElement != null) { + final Community community = new Community(); + final Element starRatingElement = communityElement.getChild("starRating", getNS()); + if (starRatingElement != null) { + final StarRating starRating = new StarRating(); + starRating.setAverage(Doubles.parse(starRatingElement.getAttributeValue("average"))); + starRating.setCount(Integers.parse(starRatingElement.getAttributeValue("count"))); + starRating.setMax(Integers.parse(starRatingElement.getAttributeValue("max"))); + starRating.setMin(Integers.parse(starRatingElement.getAttributeValue("min"))); + community.setStarRating(starRating); + } + final Element statisticsElement = communityElement.getChild("statistics", getNS()); + if (statisticsElement != null) { + final Statistics statistics = new Statistics(); + statistics.setFavorites(Integers.parse(statisticsElement.getAttributeValue("favorites"))); + statistics.setViews(Integers.parse(statisticsElement.getAttributeValue("views"))); + community.setStatistics(statistics); + } + final Element tagsElement = communityElement.getChild("tags", getNS()); + if (tagsElement != null) { + final String tagsText = tagsElement.getTextTrim(); + final String[] tags = tagsText.split("\\s*,\\s*"); + for (String tagText : tags) { + final String[] tagParts = tagText.split("\\s*:\\s*"); + final Tag tag = new Tag(tagParts[0]); + if (tagParts.length > 1) { + tag.setWeight(Integers.parse(tagParts[1])); + } + community.getTags().add(tag); + } + } + md.setCommunity(community); + } + } + + /** + * @param e element to parse + * @param md metadata to fill in + */ + private void parseCategories(final Element e, final Metadata md) { + final List categories = e.getChildren("category", getNS()); + final ArrayList values = new ArrayList(); + + for (int i = 0; categories != null && i < categories.size(); i++) { + try { + final Element cat = categories.get(i); + values.add(new Category(cat.getAttributeValue("scheme"), cat.getAttributeValue("label"), cat.getText())); + } catch (final Exception ex) { + LOG.warn("Exception parsing category tag.", ex); + } } - // copyright + md.setCategories(values.toArray(new Category[values.size()])); + } + + /** + * @param e element to parse + * @param md metadata to fill in + */ + private void parseCopyright(final Element e, final Metadata md) { try { final Element copy = e.getChild("copyright", getNS()); if (copy != null) { md.setCopyright(copy.getText()); - md.setCopyrightUrl(copy.getAttributeValue("url") != null ? new URI(copy.getAttributeValue("url")) : null); + if (copy.getAttributeValue("url") != null) { + md.setCopyrightUrl(new URI(copy.getAttributeValue("url"))); + } } } catch (final Exception ex) { LOG.warn("Exception parsing copyright tag.", ex); } - // credits - { - final List credits = e.getChildren("credit", getNS()); - final ArrayList values = new ArrayList(); + } - for (int i = 0; credits != null && i < credits.size(); i++) { - try { - final Element cred = credits.get(i); - values.add(new Credit(cred.getAttributeValue("scheme"), cred.getAttributeValue("role"), cred.getText())); - md.setCredits(values.toArray(new Credit[values.size()])); - } catch (final Exception ex) { - LOG.warn("Exception parsing credit tag.", ex); - } + /** + * @param e element to parse + * @param md metadata to fill in + */ + private void parseCredits(final Element e, final Metadata md) { + final List credits = e.getChildren("credit", getNS()); + final ArrayList values = new ArrayList(); + + for (int i = 0; credits != null && i < credits.size(); i++) { + try { + final Element cred = credits.get(i); + values.add(new Credit(cred.getAttributeValue("scheme"), cred.getAttributeValue("role"), cred.getText())); + md.setCredits(values.toArray(new Credit[values.size()])); + } catch (final Exception ex) { + LOG.warn("Exception parsing credit tag.", ex); } } + } - // description + /** + * @param e element to parse + * @param md metadata to fill in + */ + private void parseDescription(final Element e, final Metadata md) { try { final Element description = e.getChild("description", getNS()); @@ -286,8 +627,39 @@ public class MediaModuleParser implements ModuleParser { } catch (final Exception ex) { LOG.warn("Exception parsing description tag.", ex); } + } - // hash + /** + * @param e element to parse + * @param md metadata to fill in + */ + private void parseEmbed(final Element e, final Metadata md) { + final Element embedElement = e.getChild("embed", getNS()); + if (embedElement != null) { + final Embed embed = new Embed(); + embed.setWidth(Integers.parse(embedElement.getAttributeValue("width"))); + embed.setHeight(Integers.parse(embedElement.getAttributeValue("height"))); + if (embedElement.getAttributeValue("url") != null) { + try { + embed.setUrl(new URL(embedElement.getAttributeValue("url"))); + } catch (MalformedURLException ex) { + LOG.warn("Exception parsing embed tag.", ex); + } + } + final List paramElements = embedElement.getChildren("param", getNS()); + embed.setParams(new Param[paramElements.size()]); + for (int i = 0; i < paramElements.size(); i++) { + embed.getParams()[i] = new Param(paramElements.get(i).getAttributeValue("name"), paramElements.get(i).getTextTrim()); + } + md.setEmbed(embed); + } + } + + /** + * @param e element to parse + * @param md metadata to fill in + */ + private void parseHash(final Element e, final Metadata md) { try { final Element hash = e.getChild("hash", getNS()); @@ -297,161 +669,204 @@ public class MediaModuleParser implements ModuleParser { } catch (final Exception ex) { LOG.warn("Exception parsing hash tag.", ex); } - // keywords - { - final Element keywords = e.getChild("keywords", getNS()); - - if (keywords != null) { - final StringTokenizer tok = new StringTokenizer(keywords.getText(), ","); - final String[] value = new String[tok.countTokens()]; - - for (int i = 0; tok.hasMoreTokens(); i++) { - value[i] = tok.nextToken().trim(); - } - - md.setKeywords(value); - } - } - // ratings - { - final ArrayList values = new ArrayList(); - - final List ratings = e.getChildren("rating", getNS()); - for (final Element ratingElement : ratings) { - try { - final String ratingText = ratingElement.getText(); - String ratingScheme = Strings.trimToNull(ratingElement.getAttributeValue("scheme")); - if (ratingScheme == null) { - ratingScheme = "urn:simple"; - } - final Rating rating = new Rating(ratingScheme, ratingText); - values.add(rating); - } catch (final Exception ex) { - LOG.warn("Exception parsing rating tag.", ex); - } - } - - md.setRatings(values.toArray(new Rating[values.size()])); - - } - // text - { - final List texts = e.getChildren("text", getNS()); - final ArrayList values = new ArrayList(); - - for (int i = 0; texts != null && i < texts.size(); i++) { - try { - final Element text = texts.get(i); - final Time start = text.getAttributeValue("start") == null ? null : new Time(text.getAttributeValue("start")); - final Time end = text.getAttributeValue("end") == null ? null : new Time(text.getAttributeValue("end")); - values.add(new Text(text.getAttributeValue("type"), text.getTextTrim(), start, end)); - } catch (final Exception ex) { - LOG.warn("Exception parsing text tag.", ex); - } - } - - md.setText(values.toArray(new Text[values.size()])); - } - // thumbnails - { - final ArrayList values = new ArrayList(); - - final List thumbnails = e.getChildren("thumbnail", getNS()); - for (final Element thumb : thumbnails) { - try { - - final String timeAttr = Strings.trimToNull(thumb.getAttributeValue("time")); - Time time = null; - if (timeAttr != null) { - time = new Time(timeAttr); - } - - final String widthAttr = thumb.getAttributeValue("width"); - final Integer width = Integers.parse(widthAttr); - - final String heightAttr = thumb.getAttributeValue("height"); - final Integer height = Integers.parse(heightAttr); - - final String url = thumb.getAttributeValue("url"); - final URI uri = new URI(url); - final Thumbnail thumbnail = new Thumbnail(uri, width, height, time); - - values.add(thumbnail); - - } catch (final Exception ex) { - LOG.warn("Exception parsing thumbnail tag.", ex); - } - } - - md.setThumbnail(values.toArray(new Thumbnail[values.size()])); - } - // title - { - final Element title = e.getChild("title", getNS()); - - if (title != null) { - md.setTitle(title.getText()); - md.setTitleType(title.getAttributeValue("type")); - } - } - // restrictions - { - final List restrictions = e.getChildren("restriction", getNS()); - final ArrayList values = new ArrayList(); - - for (int i = 0; i < restrictions.size(); i++) { - final Element r = restrictions.get(i); - Restriction.Type type = null; - - if (r.getAttributeValue("type").equalsIgnoreCase("uri")) { - type = Restriction.Type.URI; - } else if (r.getAttributeValue("type").equalsIgnoreCase("country")) { - type = Restriction.Type.COUNTRY; - } - - Restriction.Relationship relationship = null; - - if (r.getAttributeValue("relationship").equalsIgnoreCase("allow")) { - relationship = Restriction.Relationship.ALLOW; - } else if (r.getAttributeValue("relationship").equalsIgnoreCase("deny")) { - relationship = Restriction.Relationship.DENY; - } - - final Restriction value = new Restriction(relationship, type, r.getTextTrim()); - values.add(value); - } - - md.setRestrictions(values.toArray(new Restriction[values.size()])); - } - // handle adult - { - final Element adult = e.getChild("adult", getNS()); - - if (adult != null && md.getRatings().length == 0) { - final Rating[] r = new Rating[1]; - - if (adult.getTextTrim().equals("true")) { - r[0] = new Rating("urn:simple", "adult"); - } else { - r[0] = new Rating("urn:simple", "nonadult"); - } - - md.setRatings(r); - } - } - - return md; } + /** + * @param e element to parse + * @param md metadata to fill in + */ + private void parseKeywords(final Element e, final Metadata md) { + final Element keywords = e.getChild("keywords", getNS()); + + if (keywords != null) { + final StringTokenizer tok = new StringTokenizer(keywords.getText(), ","); + final String[] value = new String[tok.countTokens()]; + + for (int i = 0; tok.hasMoreTokens(); i++) { + value[i] = tok.nextToken().trim(); + } + + md.setKeywords(value); + } + } + + /** + * @param e element to parse + * @param md metadata to fill in + */ + private void parseRatings(final Element e, final Metadata md) { + final ArrayList values = new ArrayList(); + + final List ratings = e.getChildren("rating", getNS()); + for (final Element ratingElement : ratings) { + try { + final String ratingText = ratingElement.getText(); + String ratingScheme = Strings.trimToNull(ratingElement.getAttributeValue("scheme")); + if (ratingScheme == null) { + ratingScheme = "urn:simple"; + } + final Rating rating = new Rating(ratingScheme, ratingText); + values.add(rating); + } catch (final Exception ex) { + LOG.warn("Exception parsing rating tag.", ex); + } + } + + md.setRatings(values.toArray(new Rating[values.size()])); + + } + + /** + * @param e element to parse + * @param md metadata to fill in + */ + private void parseText(final Element e, final Metadata md) { + final List texts = e.getChildren("text", getNS()); + final ArrayList values = new ArrayList(); + + for (int i = 0; texts != null && i < texts.size(); i++) { + try { + final Element text = texts.get(i); + Time start = null; + if (text.getAttributeValue("start") != null) { + start = new Time(text.getAttributeValue("start")); + } + Time end = null; + if (text.getAttributeValue("end") != null) { + end = new Time(text.getAttributeValue("end")); + } + values.add(new Text(text.getAttributeValue("type"), text.getTextTrim(), start, end)); + } catch (final Exception ex) { + LOG.warn("Exception parsing text tag.", ex); + } + } + + md.setText(values.toArray(new Text[values.size()])); + } + + /** + * @param e element to parse + * @param md metadata to fill in + */ + private void parseThumbnail(final Element e, final Metadata md) { + final ArrayList values = new ArrayList(); + + final List thumbnails = e.getChildren("thumbnail", getNS()); + for (final Element thumb : thumbnails) { + try { + + final String timeAttr = Strings.trimToNull(thumb.getAttributeValue("time")); + Time time = null; + if (timeAttr != null) { + time = new Time(timeAttr); + } + + final String widthAttr = thumb.getAttributeValue("width"); + final Integer width = Integers.parse(widthAttr); + + final String heightAttr = thumb.getAttributeValue("height"); + final Integer height = Integers.parse(heightAttr); + + final String url = thumb.getAttributeValue("url"); + final URI uri = new URI(url); + final Thumbnail thumbnail = new Thumbnail(uri, width, height, time); + + values.add(thumbnail); + + } catch (final Exception ex) { + LOG.warn("Exception parsing thumbnail tag.", ex); + } + } + + md.setThumbnail(values.toArray(new Thumbnail[values.size()])); + } + + /** + * @param e element to parse + * @param md metadata to fill in + */ + private void parseTitle(final Element e, final Metadata md) { + final Element title = e.getChild("title", getNS()); + + if (title != null) { + md.setTitle(title.getText()); + md.setTitleType(title.getAttributeValue("type")); + } + } + + /** + * @param e element to parse + * @param md metadata to fill in + */ + private void parseRestrictions(final Element e, final Metadata md) { + final List restrictions = e.getChildren("restriction", getNS()); + final ArrayList values = new ArrayList(); + + for (int i = 0; i < restrictions.size(); i++) { + final Element r = restrictions.get(i); + Restriction.Type type = null; + + if (r.getAttributeValue("type").equalsIgnoreCase(Restriction.Type.URI.toString())) { + type = Restriction.Type.URI; + } else if (r.getAttributeValue("type").equalsIgnoreCase(Restriction.Type.COUNTRY.toString())) { + type = Restriction.Type.COUNTRY; + } else if (r.getAttributeValue("type").equalsIgnoreCase(Restriction.Type.SHARING.toString())) { + type = Restriction.Type.SHARING; + } + + Restriction.Relationship relationship = null; + + if (r.getAttributeValue("relationship").equalsIgnoreCase("allow")) { + relationship = Restriction.Relationship.ALLOW; + } else if (r.getAttributeValue("relationship").equalsIgnoreCase("deny")) { + relationship = Restriction.Relationship.DENY; + } + + final Restriction value = new Restriction(relationship, type, r.getTextTrim()); + values.add(value); + } + + md.setRestrictions(values.toArray(new Restriction[values.size()])); + } + + /** + * @param e element to parse + * @param md metadata to fill in + */ + private void parseAdultMetadata(final Element e, final Metadata md) { + final Element adult = e.getChild("adult", getNS()); + + if (adult != null && md.getRatings().length == 0) { + final Rating[] r = new Rating[1]; + + if (adult.getTextTrim().equals("true")) { + r[0] = new Rating("urn:simple", "adult"); + } else { + r[0] = new Rating("urn:simple", "nonadult"); + } + + md.setRatings(r); + } + } + + /** + * @param e element to parse + * @return PlayerReference element + */ private PlayerReference parsePlayer(final Element e) { final Element player = e.getChild("player", getNS()); PlayerReference p = null; if (player != null) { - final Integer width = player.getAttributeValue("width") == null ? null : new Integer(player.getAttributeValue("width")); - final Integer height = player.getAttributeValue("height") == null ? null : new Integer(player.getAttributeValue("height")); - try { + Integer width = null; + if (player.getAttributeValue("width") != null) { + width = Integer.valueOf(player.getAttributeValue("width")); + } + Integer height = null; + if (player.getAttributeValue("height") != null) { + height = Integer.valueOf(player.getAttributeValue("height")); + } p = new PlayerReference(new URI(player.getAttributeValue("url")), width, height); } catch (final Exception ex) { LOG.warn("Exception parsing player tag.", ex); diff --git a/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Community.java b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Community.java new file mode 100644 index 0000000..f6bad65 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Community.java @@ -0,0 +1,109 @@ +/* + * This code is currently released under the Mozilla Public License. + * http://www.mozilla.org/MPL/ + * + * Alternately you may apply the terms of the Apache Software License + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.rometools.modules.mediarss.types; + +import java.io.Serializable; +import java.util.Set; +import java.util.TreeSet; + +/** + * media:community element. + * + * @since MediaRSS 1.5.0 + */ +public class Community implements Serializable { + private static final long serialVersionUID = 1176552685678871066L; + private StarRating starRating; + private Statistics statistics; + private final Set tags = new TreeSet(); + + public Set getTags() { + return tags; + } + + public StarRating getStarRating() { + return starRating; + } + + public void setStarRating(final StarRating starRating) { + this.starRating = starRating; + } + + public Statistics getStatistics() { + return statistics; + } + + public void setStatistics(final Statistics statistics) { + this.statistics = statistics; + } + + //CHECKSTYLE:OFF + @Override + public String toString() { + return "Community [starRating=" + starRating + ", statistics=" + statistics + ", tags=" + tags + "]"; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (starRating == null ? 0 : starRating.hashCode()); + result = prime * result + (statistics == null ? 0 : statistics.hashCode()); + result = prime * result + (tags == null ? 0 : tags.hashCode()); + return result; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final Community other = (Community) obj; + if (starRating == null) { + if (other.starRating != null) { + return false; + } + } else if (!starRating.equals(other.starRating)) { + return false; + } + if (statistics == null) { + if (other.statistics != null) { + return false; + } + } else if (!statistics.equals(other.statistics)) { + return false; + } + if (tags == null) { + if (other.tags != null) { + return false; + } + } else if (!tags.equals(other.tags)) { + return false; + } + return true; + } + //CHECKSTYLE:ON +} diff --git a/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Embed.java b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Embed.java new file mode 100644 index 0000000..794d510 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Embed.java @@ -0,0 +1,219 @@ +/* + * This code is currently released under the Mozilla Public License. + * http://www.mozilla.org/MPL/ + * + * Alternately you may apply the terms of the Apache Software License + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.rometools.modules.mediarss.types; + +import java.io.Serializable; +import java.net.URL; +import java.util.Arrays; + +/** + * Optional tag to include embed information about a media object. + * + * @since MediaRSS 1.5.0 + */ +public class Embed implements Serializable { + private static final long serialVersionUID = -6950838495477768173L; + private Param[] params = new Param[0]; + private URL url; + private Integer width; + private Integer height; + + public URL getUrl() { + return url; + } + + public void setUrl(final URL url) { + this.url = url; + } + + public Integer getWidth() { + return width; + } + + public void setWidth(final Integer width) { + this.width = width; + } + + public Integer getHeight() { + return height; + } + + public void setHeight(final Integer height) { + this.height = height; + } + + public Param[] getParams() { + return params; + } + + /** + * @param params the embed params + */ + public void setParams(final Param[] params) { + if (params == null) { + this.params = new Param[0]; + } else { + this.params = params; + } + } + + // CHECKSTYLE:OFF + @Override + public String toString() { + return "Embed [params=" + Arrays.toString(params) + ", url=" + url + ", width=" + width + ", height=" + height + "]"; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (height == null ? 0 : height.hashCode()); + result = prime * result + Arrays.hashCode(params); + result = prime * result + (url == null ? 0 : url.hashCode()); + result = prime * result + (width == null ? 0 : width.hashCode()); + return result; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final Embed other = (Embed) obj; + if (height == null) { + if (other.height != null) { + return false; + } + } else if (!height.equals(other.height)) { + return false; + } + if (!Arrays.equals(params, other.params)) { + return false; + } + if (url == null) { + if (other.url != null) { + return false; + } + } else if (!url.equals(other.url)) { + return false; + } + if (width == null) { + if (other.width != null) { + return false; + } + } else if (!width.equals(other.width)) { + return false; + } + return true; + } + + // CHECKSTYLE:ON + + /** + * param for embed. + */ + public static class Param implements Serializable { + private static final long serialVersionUID = -1191307096400967579L; + private String name; + private String value; + + /** + */ + public Param() { + } + + /** + * @param name name of the param + * @param value value of the param + */ + public Param(final String name, final String value) { + this.name = name; + this.value = value; + } + + public String getName() { + return name; + } + + public void setName(final String name) { + this.name = name; + } + + public String getValue() { + return value; + } + + public void setValue(final String value) { + this.value = value; + } + + // CHECKSTYLE:OFF + @Override + public String toString() { + return "Param [name=" + name + ", value=" + value + "]"; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (name == null ? 0 : name.hashCode()); + result = prime * result + (value == null ? 0 : value.hashCode()); + return result; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final Param other = (Param) obj; + if (name == null) { + if (other.name != null) { + return false; + } + } else if (!name.equals(other.name)) { + return false; + } + if (value == null) { + if (other.value != null) { + return false; + } + } else if (!value.equals(other.value)) { + return false; + } + return true; + } + // CHECKSTYLE:ON + + } +} diff --git a/rome-modules/src/main/java/com/rometools/modules/mediarss/types/License.java b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/License.java new file mode 100644 index 0000000..ee3c6fe --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/License.java @@ -0,0 +1,114 @@ +/* + * This code is currently released under the Mozilla Public License. + * http://www.mozilla.org/MPL/ + * + * Alternately you may apply the terms of the Apache Software License + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.rometools.modules.mediarss.types; + +import java.io.Serializable; +import java.net.URL; + +/** + * Optional tag to include machine-readable license information about a media object. + * + * @since MediaRSS 1.5.0 + * + */ +public class License implements Serializable { + private static final long serialVersionUID = 8468812050262548541L; + private String type; + private URL href; + private String value; + + public String getType() { + return type; + } + + public void setType(final String type) { + this.type = type; + } + + public URL getHref() { + return href; + } + + public void setHref(final URL href) { + this.href = href; + } + + public String getValue() { + return value; + } + + public void setValue(final String value) { + this.value = value; + } + + // CHECKSTYLE:OFF + @Override + public String toString() { + return "License [type=" + type + ", href=" + href + ", value=" + value + "]"; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (href == null ? 0 : href.hashCode()); + result = prime * result + (type == null ? 0 : type.hashCode()); + result = prime * result + (value == null ? 0 : value.hashCode()); + return result; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final License other = (License) obj; + if (href == null) { + if (other.href != null) { + return false; + } + } else if (!href.equals(other.href)) { + return false; + } + if (type == null) { + if (other.type != null) { + return false; + } + } else if (!type.equals(other.type)) { + return false; + } + if (value == null) { + if (other.value != null) { + return false; + } + } else if (!value.equals(other.value)) { + return false; + } + return true; + } + // CHECKSTYLE:ON + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Location.java b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Location.java new file mode 100644 index 0000000..ee2fffa --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Location.java @@ -0,0 +1,132 @@ +/* + * This code is currently released under the Mozilla Public License. + * http://www.mozilla.org/MPL/ + * + * Alternately you may apply the terms of the Apache Software License + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.rometools.modules.mediarss.types; + +import java.io.Serializable; + +import com.rometools.modules.georss.GeoRSSModule; + +/** + * Optional tag to include location information about a media object. + * + * @since MediaRSS 1.5.0 + */ +public class Location implements Serializable { + + private static final long serialVersionUID = 2899286634307076735L; + private String description; + private Time start; + private Time end; + private GeoRSSModule geoRss; + + public String getDescription() { + return description; + } + + public void setDescription(final String description) { + this.description = description; + } + + public Time getStart() { + return start; + } + + public void setStart(final Time start) { + this.start = start; + } + + public Time getEnd() { + return end; + } + + public void setEnd(final Time end) { + this.end = end; + } + + public GeoRSSModule getGeoRss() { + return geoRss; + } + + public void setGeoRss(final GeoRSSModule geoRss) { + this.geoRss = geoRss; + } + + // CHECKSTYLE:OFF + @Override + public String toString() { + return "Location [description=" + description + ", start=" + start + ", end=" + end + ", geoRss=" + geoRss + "]"; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (description == null ? 0 : description.hashCode()); + result = prime * result + (end == null ? 0 : end.hashCode()); + result = prime * result + (geoRss == null ? 0 : geoRss.hashCode()); + result = prime * result + (start == null ? 0 : start.hashCode()); + return result; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final Location other = (Location) obj; + if (description == null) { + if (other.description != null) { + return false; + } + } else if (!description.equals(other.description)) { + return false; + } + if (end == null) { + if (other.end != null) { + return false; + } + } else if (!end.equals(other.end)) { + return false; + } + if (geoRss == null) { + if (other.geoRss != null) { + return false; + } + } else if (!geoRss.equals(other.geoRss)) { + return false; + } + if (start == null) { + if (other.start != null) { + return false; + } + } else if (!start.equals(other.start)) { + return false; + } + return true; + } + // CHECKSTYLE:ON + +} diff --git a/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Metadata.java b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Metadata.java index 8f4b5c0..853aec9 100644 --- a/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Metadata.java +++ b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Metadata.java @@ -25,41 +25,41 @@ package com.rometools.modules.mediarss.types; import java.io.Serializable; import java.net.URI; +import java.net.URL; import com.rometools.rome.feed.impl.EqualsBean; import com.rometools.rome.feed.impl.ToStringBean; /** - * - * - * + * + * + * * Optional Elements *

- * The following elements are optional and may appear as sub-elements of <channel>, - * <item>, <media:content> and/or <media:group>. - * - * + * The following elements are optional and may appear as sub-elements of <channel>, <item>, <media:content> and/or <media:group>. *

*

- * - * When an element appears at a shallow level, such as <channel> or <item>, it means - * that the element should be applied to every media object within its scope. + * When an element appears at a shallow level, such as <channel> or <item>, it means that the element should be applied to every media object within + * its scope. *

- * - * + * *

- * Duplicated elements appearing at deeper levels of the document tree have higher priority over - * other levels. - * - * For example, <media:content> level elements are favored over <item> level elements. - * The priority level is listed from strongest to weakest: <media:content>, - * <media:group>, <item>, <channel>. + * Duplicated elements appearing at deeper levels of the document tree have higher priority over other levels. + * + * For example, <media:content> level elements are favored over <item> level elements. The priority level is listed from strongest to weakest: + * <media:content>, <media:group>, <item>, <channel>. *

- * + * * @author cooper */ public class Metadata implements Cloneable, Serializable { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 649350950456005250L; + /** + * status is the status of the media object saying whether a media object has been created by the publisher or they have rights to circulate it. + */ + public enum RightsStatus { + userCreated, official + }; private Hash hash; private String copyright; @@ -75,55 +75,83 @@ public class Metadata implements Cloneable, Serializable { private Restriction[] restrictions = new Restriction[0]; private Text[] text = new Text[0]; private Thumbnail[] thumbnail = new Thumbnail[0]; + private Community community; + private String[] comments = new String[0]; + private String[] responses = new String[0]; + private URL[] backLinks = new URL[0]; + private Status status; + private Price[] prices = new Price[0]; + private Embed embed; + private License[] licenses = new License[0]; + private SubTitle[] subTitles = new SubTitle[0]; + private PeerLink[] peerLinks = new PeerLink[0]; + private Location[] locations = new Location[0]; + private RightsStatus rights; + private Scene[] scenes = new Scene[0]; - /** Creates a new instance of Metadata */ + /** Creates a new instance of Metadata. */ public Metadata() { super(); } /** - * <media:category>

*

- * Allows a taxonomy to be set that gives an indication of the type of media content, and its - * particular contents. It has 2 optional attributes. + * <media:backLinks> *

- * + * + *

+ * Allows inclusion of all the URLs pointing to a media object. + *

+ * *
-     * <media:category scheme="http://search.yahoo.com/mrss/category_
-     *        schema">music/artist/album/song</media:category>
-     * 
-     *        <media:category scheme="http://dmoz.org" label="Ace Ventura - Pet
-     *        Detective">Arts/Movies/Titles/A/Ace_Ventura_Series/Ace_Ventura_
-     *        -_Pet_Detective</media:category>
-     * 
-     *        <media:category scheme="urn:flickr:tags">ycantpark
-     *        mobile</media:category>
+     * <media:backLinks>
+     *   <media:backLink>http://www.backlink1.com</media:backLink>
+     *   <media:backLink>http://www.backlink2.com</media:backLink>
+     *   <media:backLink>http://www.backlink3.com</media:backLink>
+     * </media:backLinks>
      * 
- * - *

- * scheme is the URI that identifies the categorization scheme. It is an optional - * attribute. If this attribute is not included, the default scheme is - * 'http://search.yahoo.com/mrss/category_schema'. - *

- * - *

- * label is the human readable label that can be displayed in end user applications. It - * is an optional attribute. - *

- * - * @param categories categories for the item + * + * @return array of backlink urls */ - public void setCategories(final Category[] categories) { - this.categories = categories == null ? new Category[0] : categories; + public URL[] getBackLinks() { + return backLinks; } /** - * <media:category>

*

- * Allows a taxonomy to be set that gives an indication of the type of media content, and its - * particular contents. It has 2 optional attributes. + * <media:backLinks> *

- * + * + *

+ * Allows inclusion of all the URLs pointing to a media object. + *

+ * + *
+     * <media:backLinks>
+     *   <media:backLink>http://www.backlink1.com</media:backLink>
+     *   <media:backLink>http://www.backlink2.com</media:backLink>
+     *   <media:backLink>http://www.backlink3.com</media:backLink>
+     * </media:backLinks>
+     * 
+ * + * @param backLinks array of backlink urls + */ + public void setBackLinks(final URL[] backLinks) { + if (backLinks == null) { + this.backLinks = new URL[0]; + } else { + this.backLinks = backLinks; + } + } + + /** + *

+ * <media:category> + *

+ *

+ * Allows a taxonomy to be set that gives an indication of the type of media content, and its particular contents. It has 2 optional attributes. + *

+ * *
      * <media:category scheme="http://search.yahoo.com/mrss/category_
      *        schema">music/artist/album/song</media:category>
@@ -135,18 +163,55 @@ public class Metadata implements Cloneable, Serializable {
      *        <media:category scheme="urn:flickr:tags">ycantpark
      *        mobile</media:category>
      * 
- * + * *

- * scheme is the URI that identifies the categorization scheme. It is an optional - * attribute. If this attribute is not included, the default scheme is - * 'http://search.yahoo.com/mrss/category_schema'. + * scheme is the URI that identifies the categorization scheme. It is an optional attribute. If this attribute is not included, the default scheme + * is 'http://search.yahoo.com/mrss/category_schema'. *

- * + * *

- * label is the human readable label that can be displayed in end user applications. It - * is an optional attribute. + * label is the human readable label that can be displayed in end user applications. It is an optional attribute. *

- * + * + * @param categories categories for the item + */ + public void setCategories(final Category[] categories) { + if (categories == null) { + this.categories = new Category[0]; + } else { + this.categories = categories; + } + } + + /** + *

+ * <media:category> + *

+ *

+ * Allows a taxonomy to be set that gives an indication of the type of media content, and its particular contents. It has 2 optional attributes. + *

+ * + *
+     * <media:category scheme="http://search.yahoo.com/mrss/category_
+     *        schema">music/artist/album/song</media:category>
+     * 
+     *        <media:category scheme="http://dmoz.org" label="Ace Ventura - Pet
+     *        Detective">Arts/Movies/Titles/A/Ace_Ventura_Series/Ace_Ventura_
+     *        -_Pet_Detective</media:category>
+     * 
+     *        <media:category scheme="urn:flickr:tags">ycantpark
+     *        mobile</media:category>
+     * 
+ * + *

+ * scheme is the URI that identifies the categorization scheme. It is an optional attribute. If this attribute is not included, the default scheme + * is 'http://search.yahoo.com/mrss/category_schema'. + *

+ * + *

+ * label is the human readable label that can be displayed in end user applications. It is an optional attribute. + *

+ * * @return categories for the item. */ public Category[] getCategories() { @@ -154,20 +219,149 @@ public class Metadata implements Cloneable, Serializable { } /** - * <media:copyright>

+ *

+ * <media:comments> + *

+ * + *

+ * Allows inclusion of all the comments a media object has received. + *

+ * + *
+     * <media:comments>
+     *   <media:comment>comment1</media:comment>
+     *   <media:comment>comment2</media:comment>
+     *   <media:comment>comment3</media:comment>
+     * </media:comments>
+     * 
+ * + * @return array of comments + */ + public String[] getComments() { + return comments; + } + + /** + *

+ * <media:comments> + *

+ * + *

+ * Allows inclusion of all the comments a media object has received. + *

+ * + *
+     * <media:comments>
+     *   <media:comment>comment1</media:comment>
+     *   <media:comment>comment2</media:comment>
+     *   <media:comment>comment3</media:comment>
+     * </media:comments>
+     * 
+ * + * @param comments array of comments + */ + public void setComments(final String[] comments) { + if (comments == null) { + this.comments = new String[0]; + } else { + this.comments = comments; + } + } + + /** + *

+ * <media:community> + *

+ * + *

+ * This element stands for the community related content. This allows inclusion of the user perception about a media object in the form of view count, + * ratings and tags. + *

+ * + *
+     * <media:community>
+     *   <media:starRating average="3.5" count="20" min="1" max="10" />
+     *   <media:statistics views="5" favorites="5" />
+     *   <media:tags>news: 5, abc:3, reuters</media:tags>
+     * </media:community>
+     * 
+ * + *

+ * starRating This element specifies the rating-related information about a media object. Valid attributes are average, count, min and max. + *

+ * + *

+ * statistics This element specifies various statistics about a media object like the view count and the favorite count. Valid attributes are views and + * favorites. + *

+ * + *

+ * tags This element contains user-generated tags separated by commas in the decreasing order of each tag's weight. Each tag can be assigned an integer + * weight in tag_name:weight format. It's up to the provider to choose the way weight is determined for a tag; for example, number of occurences can be one + * way to decide weight of a particular tag. Default weight is 1. + *

+ * + * @return Community element + */ + public Community getCommunity() { + return community; + } + + /** + *

+ * <media:community> + *

+ * + *

+ * This element stands for the community related content. This allows inclusion of the user perception about a media object in the form of view count, + * ratings and tags. + *

+ * + *
+     * <media:community>
+     *   <media:starRating average="3.5" count="20" min="1" max="10" />
+     *   <media:statistics views="5" favorites="5" />
+     *   <media:tags>news: 5, abc:3, reuters</media:tags>
+     * </media:community>
+     * 
+ * + *

+ * starRating This element specifies the rating-related information about a media object. Valid attributes are average, count, min and max. + *

+ * + *

+ * statistics This element specifies various statistics about a media object like the view count and the favorite count. Valid attributes are views and + * favorites. + *

+ * + *

+ * tags This element contains user-generated tags separated by commas in the decreasing order of each tag's weight. Each tag can be assigned an integer + * weight in tag_name:weight format. It's up to the provider to choose the way weight is determined for a tag; for example, number of occurences can be one + * way to decide weight of a particular tag. Default weight is 1. + *

+ * + * @param community Community element + */ + public void setCommunity(final Community community) { + this.community = community; + } + + /** + *

+ * <media:copyright> + *

*

* Copyright information for media object. It has 1 optional attribute. *

- * + * *
      * <media:copyright url="http://blah.com/additional-info.html">2005 FooBar Media</media:copyright>
      * 
*

- * url is the url for a terms of use page or additional copyright information. If the - * media is operating under a Creative Commons license, the Creative Commons module should be - * used instead. It is an optional attribute. + * url is the url for a terms of use page or additional copyright information. If the media is operating under a Creative Commons license, the + * Creative Commons module should be used instead. It is an optional attribute. *

- * + * * @param copyright copyright text */ public void setCopyright(final String copyright) { @@ -175,20 +369,21 @@ public class Metadata implements Cloneable, Serializable { } /** - * <media:copyright>

+ *

+ * <media:copyright> + *

*

* Copyright information for media object. It has 1 optional attribute. *

- * + * *
      * <media:copyright url="http://blah.com/additional-info.html">2005 FooBar Media</media:copyright>
      * 
*

- * url is the url for a terms of use page or additional copyright information. If the - * media is operating under a Creative Commons license, the Creative Commons module should be - * used instead. It is an optional attribute. + * url is the url for a terms of use page or additional copyright information. If the media is operating under a Creative Commons license, the + * Creative Commons module should be used instead. It is an optional attribute. *

- * + * * @return Copyright text */ public String getCopyright() { @@ -196,20 +391,21 @@ public class Metadata implements Cloneable, Serializable { } /** - * <media:copyright>

+ *

+ * <media:copyright> + *

*

* Copyright information for media object. It has 1 optional attribute. *

- * + * *
      * <media:copyright url="http://blah.com/additional-info.html">2005 FooBar Media</media:copyright>
      * 
*

- * url is the url for a terms of use page or additional copyright information. If the - * media is operating under a Creative Commons license, the Creative Commons module should be - * used instead. It is an optional attribute. + * url is the url for a terms of use page or additional copyright information. If the media is operating under a Creative Commons license, the + * Creative Commons module should be used instead. It is an optional attribute. *

- * + * * @param copyrightUrl link to more copyright information. */ public void setCopyrightUrl(final URI copyrightUrl) { @@ -217,20 +413,21 @@ public class Metadata implements Cloneable, Serializable { } /** - * <media:copyright>

+ *

+ * <media:copyright> + *

*

* Copyright information for media object. It has 1 optional attribute. *

- * + * *
      * <media:copyright url="http://blah.com/additional-info.html">2005 FooBar Media</media:copyright>
      * 
*

- * url is the url for a terms of use page or additional copyright information. If the - * media is operating under a Creative Commons license, the Creative Commons module should be - * used instead. It is an optional attribute. + * url is the url for a terms of use page or additional copyright information. If the media is operating under a Creative Commons license, the + * Creative Commons module should be used instead. It is an optional attribute. *

- * + * * @return Link to more copyright information. */ public URI getCopyrightUrl() { @@ -238,33 +435,33 @@ public class Metadata implements Cloneable, Serializable { } /** - * <media:credit>

- * *

- * Notable entity and the contribution to the creation of the media object. Current entities can - * include people, companies, locations, etc. Specific entities can have multiple roles, and - * several entities can have the same role. These should appear as distinct <media:credit> - * elements. It has 2 optional attributes. + * <media:credit> *

- * + * + *

+ * Notable entity and the contribution to the creation of the media object. Current entities can include people, companies, locations, etc. Specific + * entities can have multiple roles, and several entities can have the same role. These should appear as distinct <media:credit> elements. It has 2 + * optional attributes. + *

+ * *
      * <media:credit role="producer" scheme="urn:ebu">entity name</media:credit>
      * 
*

* role specifies the role the entity played. Must be lowercase. It is an optional attribute. *

- * + * *

- * scheme is the URI that identifies the role scheme. It is an optional attribute. If - * this attribute is not included, the default scheme is 'urn:ebu'. See: European Broadcasting - * Union Role Codes. + * scheme is the URI that identifies the role scheme. It is an optional attribute. If this attribute is not included, the default scheme is + * 'urn:ebu'. See: European Broadcasting Union Role Codes. *

- * - * + * + * *

* Example roles: *

- * + * *
      * actor
      *        anchor person
@@ -289,44 +486,46 @@ public class Metadata implements Cloneable, Serializable {
      *        vocalist
      * 
*

- * Additional roles: European - * Broadcasting Union Role Codes - * + * Additional roles: European Broadcasting Union Role Codes + * * @param credits credits for the item. */ public void setCredits(final Credit[] credits) { - this.credits = credits == null ? new Credit[0] : credits; + if (credits == null) { + this.credits = new Credit[0]; + } else { + this.credits = credits; + } } /** - * <media:credit>

- * *

- * Notable entity and the contribution to the creation of the media object. Current entities can - * include people, companies, locations, etc. Specific entities can have multiple roles, and - * several entities can have the same role. These should appear as distinct <media:credit> - * elements. It has 2 optional attributes. + * <media:credit> *

- * + * + *

+ * Notable entity and the contribution to the creation of the media object. Current entities can include people, companies, locations, etc. Specific + * entities can have multiple roles, and several entities can have the same role. These should appear as distinct <media:credit> elements. It has 2 + * optional attributes. + *

+ * *
      * <media:credit role="producer" scheme="urn:ebu">entity name</media:credit>
      * 
*

* role specifies the role the entity played. Must be lowercase. It is an optional attribute. *

- * + * *

- * scheme is the URI that identifies the role scheme. It is an optional attribute. If - * this attribute is not included, the default scheme is 'urn:ebu'. See: European Broadcasting - * Union Role Codes. + * scheme is the URI that identifies the role scheme. It is an optional attribute. If this attribute is not included, the default scheme is + * 'urn:ebu'. See: European Broadcasting Union Role Codes. *

- * - * + * + * *

* Example roles: *

- * + * *
      * actor
      *        anchor person
@@ -351,10 +550,8 @@ public class Metadata implements Cloneable, Serializable {
      *        vocalist
      * 
*

- * Additional roles: European - * Broadcasting Union Role Codes - * + * Additional roles: European Broadcasting Union Role Codes + * * @return credits for the time. */ public Credit[] getCredits() { @@ -362,21 +559,21 @@ public class Metadata implements Cloneable, Serializable { } /** - * <media:description>

*

- * Short description describing the media object typically a sentence in length. It has 1 - * optional attribute. + * <media:description> *

- * + *

+ * Short description describing the media object typically a sentence in length. It has 1 optional attribute. + *

+ * *
      * <media:description type="plain">This was some really bizarre band I listened to as a young lad.</media:description>
      * 
*

- * type specifies the type of text embedded. Possible values are either 'plain' or - * 'html'. Default value is 'plain'. All html must be entity-encoded. It is an optional - * attribute. + * type specifies the type of text embedded. Possible values are either 'plain' or 'html'. Default value is 'plain'. All html must be + * entity-encoded. It is an optional attribute. *

- * + * * @param description value of the description */ public void setDescription(final String description) { @@ -384,21 +581,21 @@ public class Metadata implements Cloneable, Serializable { } /** - * <media:description>

*

- * Short description describing the media object typically a sentence in length. It has 1 - * optional attribute. + * <media:description> *

- * + *

+ * Short description describing the media object typically a sentence in length. It has 1 optional attribute. + *

+ * *
      * <media:description type="plain">This was some really bizarre band I listened to as a young lad.</media:description>
      * 
*

- * type specifies the type of text embedded. Possible values are either 'plain' or - * 'html'. Default value is 'plain'. All html must be entity-encoded. It is an optional - * attribute. + * type specifies the type of text embedded. Possible values are either 'plain' or 'html'. Default value is 'plain'. All html must be + * entity-encoded. It is an optional attribute. *

- * + * * @return value of the description */ public String getDescription() { @@ -406,21 +603,21 @@ public class Metadata implements Cloneable, Serializable { } /** - * <media:description>

*

- * Short description describing the media object typically a sentence in length. It has 1 - * optional attribute. + * <media:description> *

- * + *

+ * Short description describing the media object typically a sentence in length. It has 1 optional attribute. + *

+ * *
      * <media:description type="plain">This was some really bizarre band I listened to as a young lad.</media:description>
      * 
*

- * type specifies the type of text embedded. Possible values are either 'plain' or - * 'html'. Default value is 'plain'. All html must be entity-encoded. It is an optional - * attribute. + * type specifies the type of text embedded. Possible values are either 'plain' or 'html'. Default value is 'plain'. All html must be + * entity-encoded. It is an optional attribute. *

- * + * * @param descriptionType type of the description. */ public void setDescriptionType(final String descriptionType) { @@ -428,21 +625,21 @@ public class Metadata implements Cloneable, Serializable { } /** - * <media:description>

*

- * Short description describing the media object typically a sentence in length. It has 1 - * optional attribute. + * <media:description> *

- * + *

+ * Short description describing the media object typically a sentence in length. It has 1 optional attribute. + *

+ * *
      * <media:description type="plain">This was some really bizarre band I listened to as a young lad.</media:description>
      * 
*

- * type specifies the type of text embedded. Possible values are either 'plain' or - * 'html'. Default value is 'plain'. All html must be entity-encoded. It is an optional - * attribute. + * type specifies the type of text embedded. Possible values are either 'plain' or 'html'. Default value is 'plain'. All html must be + * entity-encoded. It is an optional attribute. *

- * + * * @return type of the description */ public String getDescriptionType() { @@ -450,23 +647,69 @@ public class Metadata implements Cloneable, Serializable { } /** - * <media:hash>

- * + *

<media:embed> + * + *

Sometimes player-specific embed code is needed for a player to play any video. <media:embed> allows + * inclusion of such information in the form of key-value pairs.

+ * + *
<media:embed url="http://d.yimg.com/static.video.yahoo.com/yep/YV_YEP.swf?ver=2.2.2" width="512" height="323">
+     *   <media:param name="type">application/x-shockwave-flash</media:param>
+     *   <media:param name="width">512</media:param>
+     *   <media:param name="height">323</media:param>
+     *   <media:param name="allowFullScreen">true</media:param>
+     *   <media:param name="flashVars">
+     *     id=7809705&vid=2666306&lang=en-us&intl=us&thumbUrl=http%3A//us.i1.yimg.com/us.yimg.com/i/us/sch/cn/video06/2666306_rndf1e4205b_19.jpg
+     *   </media:param>
+     * </media:embed>
+ * + * @return embed information + */ + public Embed getEmbed() { + return embed; + } + + /** + *

<media:embed> + * + *

Sometimes player-specific embed code is needed for a player to play any video. <media:embed> allows + * inclusion of such information in the form of key-value pairs.

+ * + *
<media:embed url="http://d.yimg.com/static.video.yahoo.com/yep/YV_YEP.swf?ver=2.2.2" width="512" height="323">
+     *   <media:param name="type">application/x-shockwave-flash</media:param>
+     *   <media:param name="width">512</media:param>
+     *   <media:param name="height">323</media:param>
+     *   <media:param name="allowFullScreen">true</media:param>
+     *   <media:param name="flashVars">
+     *     id=7809705&vid=2666306&lang=en-us&intl=us&thumbUrl=http%3A//us.i1.yimg.com/us.yimg.com/i/us/sch/cn/video06/2666306_rndf1e4205b_19.jpg
+     *   </media:param>
+     * </media:embed>
+ * + * @param embed embed information + */ + public void setEmbed(final Embed embed) { + this.embed = embed; + } + + /** *

- * This is the hash of the binary media file. It can appear multiple times as long as each - * instance is a different algo. It has 1 optional attribute. + * <media:hash> + *

+ * + *

+ * This is the hash of the binary media file. It can appear multiple times as long as each instance is a different algo. It has 1 optional + * attribute. *

*

*

- * + * *
      * <media:hash algo="md5">dfdec888b72151965a34b4b59031290a</media:hash>
      * 
- * + * *

- * algo indicates the algorithm used to create the hash. Possible values are 'md5' and - * 'sha-1'. Default value is 'md5'. It is an optional attribute. - * + * algo indicates the algorithm used to create the hash. Possible values are 'md5' and 'sha-1'. Default value is 'md5'. It is an optional + * attribute. + * * @param hash sets the hash for the item. */ public void setHash(final Hash hash) { @@ -474,23 +717,25 @@ public class Metadata implements Cloneable, Serializable { } /** - * <media:hash>

- * *

- * This is the hash of the binary media file. It can appear multiple times as long as each - * instance is a different algo. It has 1 optional attribute. + * <media:hash> + *

+ * + *

+ * This is the hash of the binary media file. It can appear multiple times as long as each instance is a different algo. It has 1 optional + * attribute. *

*

*

- * + * *
      * <media:hash algo="md5">dfdec888b72151965a34b4b59031290a</media:hash>
      * 
- * + * *

- * algo indicates the algorithm used to create the hash. Possible values are 'md5' and - * 'sha-1'. Default value is 'md5'. It is an optional attribute. - * + * algo indicates the algorithm used to create the hash. Possible values are 'md5' and 'sha-1'. Default value is 'md5'. It is an optional + * attribute. + * * @return returns a Hash object for the item. */ public Hash getHash() { @@ -498,33 +743,39 @@ public class Metadata implements Cloneable, Serializable { } /** - * <media:keywords>

*

- * Highly relevant keywords describing the media object with typically a maximum of ten words. - * The keywords and phrases should be comma delimited. + * <media:keywords> *

- * + *

+ * Highly relevant keywords describing the media object with typically a maximum of ten words. The keywords and phrases should be comma delimited. + *

+ * *
      * <media:keywords>kitty, cat, big dog, yarn, fluffy</media:keywords>
      * 
- * + * * @param keywords Array of keywords */ public void setKeywords(final String[] keywords) { - this.keywords = keywords == null ? new String[0] : keywords; + if (keywords == null) { + this.keywords = new String[0]; + } else { + this.keywords = keywords; + } } /** - * <media:keywords>

*

- * Highly relevant keywords describing the media object with typically a maximum of ten words. - * The keywords and phrases should be comma delimited. + * <media:keywords> *

- * + *

+ * Highly relevant keywords describing the media object with typically a maximum of ten words. The keywords and phrases should be comma delimited. + *

+ * *
      * <media:keywords>kitty, cat, big dog, yarn, fluffy</media:keywords>
      * 
- * + * * @return Array of keywords */ public String[] getKeywords() { @@ -532,45 +783,214 @@ public class Metadata implements Cloneable, Serializable { } /** - * <media:rating>

- * - * - *

- * This allows the permissible audience to be declared. If this element is not included, it - * assumes that no restrictions are necessary. It has one optional attribute. - *

- * - *
-     * <media:rating scheme="urn:simple">adult</media:rating>
-     *               <media:rating scheme="urn:icra">r (cz 1 lz 1 nz 1 oz 1 vz 1)</media:rating>
-     *               <media:rating scheme="urn:mpaa">pg</media:rating>
+     * 

<media:license>

* - * <media:rating scheme="urn:v-chip">tv-y7-fv</media:rating> - *
- * - * - *

- * scheme is the URI that identifies the rating scheme. It is an optional attribute. If - * this attribute is not included, the default scheme is urn:simple (adult | nonadult). - *

- * - *

- * - * @param ratings Ratings objects + *

Optional link to specify the machine-readable license associated with the content.

+ * + *
<media:license type="text/html" href="http://creativecommons.org/licenses/by/3.0/us/">Creative Commons
+     * Attribution 3.0 United States License</media:license>
+ * + * @return the licenses */ - public void setRatings(final Rating[] ratings) { - this.ratings = ratings == null ? new Rating[0] : ratings; + public License[] getLicenses() { + return licenses; + } + + /** + *

<media:license>

+ * + *

Optional link to specify the machine-readable license associated with the content.

+ * + *
<media:license type="text/html" href="http://creativecommons.org/licenses/by/3.0/us/">Creative Commons
+     * Attribution 3.0 United States License</media:license>
+ * + * @param licenses the licenses + */ + public void setLicenses(final License[] licenses) { + if (licenses == null) { + this.licenses = new License[0]; + } else { + this.licenses = licenses; + } + } + + /** + *

<media:location>

+ * + *

Optional element to specify geographical information about various locations captured in the content of a media object. + * The format conforms to geoRSS.

+ * + *
<media:location description="My house" start="00:01" end="01:00">
+     *   <georss:where>
+     *     <gml:Point>
+     *       <gml:pos>35.669998 139.770004</gml:pos>
+     *     </gml:Point>
+     *   </georss:where>
+     * </media:location>
+ * + *

description description of the place whose location is being specified.

+ * + *

start time at which the reference to a particular location starts in the media object.

+ * + *

end time at which the reference to a particular location ends in the media object.

+ * + * @return the locations + */ + public Location[] getLocations() { + return locations; + } + + /** + *

<media:location>

+ * + *

Optional element to specify geographical information about various locations captured in the content of a media object. + * The format conforms to geoRSS.

+ * + *
<media:location description="My house" start="00:01" end="01:00">
+     *   <georss:where>
+     *     <gml:Point>
+     *       <gml:pos>35.669998 139.770004</gml:pos>
+     *     </gml:Point>
+     *   </georss:where>
+     * </media:location>
+ * + *

description description of the place whose location is being specified.

+ * + *

start time at which the reference to a particular location starts in the media object.

+ * + *

end time at which the reference to a particular location ends in the media object.

+ * + * @param locations the locations + */ + public void setLocations(final Location[] locations) { + if (locations == null) { + this.locations = new Location[0]; + } else { + this.locations = locations; + } + } + + /** + *

<media:peerLink>

+ * + *

Optional element for P2P link.

+ * + *
<media:peerLink type="application/x-bittorrent" href="http://www.example.org/sampleFile.torrent" />
+ * + * @return the peer links + */ + public PeerLink[] getPeerLinks() { + return peerLinks; + } + + /** + *

<media:peerLink>

+ * + *

Optional element for P2P link.

+ * + *
<media:peerLink type="application/x-bittorrent" href="http://www.example.org/sampleFile.torrent" />
+ * + * @param peerLinks the peer links + */ + public void setPeerLinks(final PeerLink[] peerLinks) { + if (peerLinks == null) { + this.peerLinks = new PeerLink[0]; + } else { + this.peerLinks = peerLinks; + } } /** - * <media:rating>

- * - * *

- * This allows the permissible audience to be declared. If this element is not included, it - * assumes that no restrictions are necessary. It has one optional attribute. + * <media:price> *

- * + * + *

+ * Optional tag to include pricing information about a media object. If this tag is not present, the media object is supposed to be free. One media object + * can have multiple instances of this tag for including different pricing structures. The presence of this tag would mean that media object is not free. + *

+ * + *
+     * <media:price type="rent" price="19.99" currency="EUR" />
+     * <media:price type="package" info="http://www.dummy.jp/package_info.html" price="19.99" currency="EUR" />
+     * <media:price type="subscription" info="http://www.dummy.jp/subscription_info" price="19.99" currency="EUR" />
+     * 
+ * + *

+ * type Valid values are "rent", "purchase", "package" or "subscription". If nothing is specified, then the media is free. + *

+ * + *

+ * info if the type is "package" or "subscription", then info is a URL pointing to package or subscription information. This is an optional attribute. + *

+ * + *

+ * price is the price of the media object. This is an optional attribute. + *

+ * + *

+ * currency -- use ISO 4217 for currency codes. This is an optional attribute. + *

+ * + * @return the prices + */ + public Price[] getPrices() { + return prices; + } + + /** + *

+ * <media:price> + *

+ * + *

+ * Optional tag to include pricing information about a media object. If this tag is not present, the media object is supposed to be free. One media object + * can have multiple instances of this tag for including different pricing structures. The presence of this tag would mean that media object is not free. + *

+ * + *
+     * <media:price type="rent" price="19.99" currency="EUR" />
+     * <media:price type="package" info="http://www.dummy.jp/package_info.html" price="19.99" currency="EUR" />
+     * <media:price type="subscription" info="http://www.dummy.jp/subscription_info" price="19.99" currency="EUR" />
+     * 
+ * + *

+ * type Valid values are "rent", "purchase", "package" or "subscription". If nothing is specified, then the media is free. + *

+ * + *

+ * info if the type is "package" or "subscription", then info is a URL pointing to package or subscription information. This is an optional attribute. + *

+ * + *

+ * price is the price of the media object. This is an optional attribute. + *

+ * + *

+ * currency -- use ISO 4217 for currency codes. This is an optional attribute. + *

+ * + * @param prices the prices + */ + public void setPrices(final Price[] prices) { + if (prices == null) { + this.prices = new Price[0]; + } else { + this.prices = prices; + } + } + + /** + *

+ * <media:rating> + *

+ * + * + *

+ * This allows the permissible audience to be declared. If this element is not included, it assumes that no restrictions are necessary. It has one optional + * attribute. + *

+ * *
      * <media:rating scheme="urn:simple">adult</media:rating>
      *               <media:rating scheme="urn:icra">r (cz 1 lz 1 nz 1 oz 1 vz 1)</media:rating>
@@ -578,15 +998,52 @@ public class Metadata implements Cloneable, Serializable {
      * 
      *               <media:rating scheme="urn:v-chip">tv-y7-fv</media:rating>
      * 
- * - * + * + * *

- * scheme is the URI that identifies the rating scheme. It is an optional attribute. If - * this attribute is not included, the default scheme is urn:simple (adult | nonadult). + * scheme is the URI that identifies the rating scheme. It is an optional attribute. If this attribute is not included, the default scheme is + * urn:simple (adult | nonadult). *

- * + * *

- * + * + * @param ratings Ratings objects + */ + public void setRatings(final Rating[] ratings) { + if (ratings == null) { + this.ratings = new Rating[0]; + } else { + this.ratings = ratings; + } + } + + /** + *

+ * <media:rating> + *

+ * + * + *

+ * This allows the permissible audience to be declared. If this element is not included, it assumes that no restrictions are necessary. It has one optional + * attribute. + *

+ * + *
+     * <media:rating scheme="urn:simple">adult</media:rating>
+     *               <media:rating scheme="urn:icra">r (cz 1 lz 1 nz 1 oz 1 vz 1)</media:rating>
+     *               <media:rating scheme="urn:mpaa">pg</media:rating>
+     * 
+     *               <media:rating scheme="urn:v-chip">tv-y7-fv</media:rating>
+     * 
+ * + * + *

+ * scheme is the URI that identifies the rating scheme. It is an optional attribute. If this attribute is not included, the default scheme is + * urn:simple (adult | nonadult). + *

+ * + *

+ * * @return Ratings objects */ public Rating[] getRatings() { @@ -594,59 +1051,109 @@ public class Metadata implements Cloneable, Serializable { } /** - * <media:restriction>

- * *

- * Allows restrictions to be placed on the aggregator rendering the media in the feed. - * Currently, restrictions are based on distributor (uri) and country codes. This element is - * purely informational and no obligation can be assumed or implied. Only one - * <media:restriction> element of the same type can be applied to a media object - * - all others will be ignored. Entities in this element should be space separated. To - * allow the producer to explicitly declare his/her intentions, two literals are reserved: - * 'all', 'none'. These literals can only be used once. This element has 1 required attribute, - * and 1 optional attribute (with strict requirements for its exclusion). + * <media:responses> *

- * + * + *

+ * Allows inclusion of a list of all media responses a media object has received. + *

+ * *
-     * <media:restriction relationship="allow" type="country">au us</media:restriction>
+     * <media:responses>
+     *   <media:response>response1</media:response>
+     *   <media:response>response2</media:response>
+     *   <media:response>response3</media:response>
+     * </media:responses>
      * 
- * - *

- * relationship indicates the type of relationship that the restriction represents - * (allow | deny). In the example above, the media object should only be syndicated in Australia - * and the United States. It is a required attribute. - *

- * - * @param restrictions restrictions for the item. + * + * @return array of responses */ - public void setRestrictions(final Restriction[] restrictions) { - this.restrictions = restrictions == null ? new Restriction[0] : restrictions; + public String[] getResponses() { + return responses; } /** - * <media:restriction>

- * *

- * Allows restrictions to be placed on the aggregator rendering the media in the feed. - * Currently, restrictions are based on distributor (uri) and country codes. This element is - * purely informational and no obligation can be assumed or implied. Only one - * <media:restriction> element of the same type can be applied to a media object - * - all others will be ignored. Entities in this element should be space separated. To - * allow the producer to explicitly declare his/her intentions, two literals are reserved: - * 'all', 'none'. These literals can only be used once. This element has 1 required attribute, - * and 1 optional attribute (with strict requirements for its exclusion). + * <media:responses> *

- * + * + *

+ * Allows inclusion of a list of all media responses a media object has received. + *

+ * + *
+     * <media:responses>
+     *   <media:response>response1</media:response>
+     *   <media:response>response2</media:response>
+     *   <media:response>response3</media:response>
+     * </media:responses>
+     * 
+ * + * @param responses array of responses + */ + public void setResponses(final String[] responses) { + if (responses == null) { + this.responses = new String[0]; + } else { + this.responses = responses; + } + } + + /** + *

+ * <media:restriction> + *

+ * + *

+ * Allows restrictions to be placed on the aggregator rendering the media in the feed. Currently, restrictions are based on distributor (uri) and country + * codes. This element is purely informational and no obligation can be assumed or implied. Only one <media:restriction> element of the same + * type can be applied to a media object - all others will be ignored. Entities in this element should be space separated. To allow the + * producer to explicitly declare his/her intentions, two literals are reserved: 'all', 'none'. These literals can only be used once. This element has 1 + * required attribute, and 1 optional attribute (with strict requirements for its exclusion). + *

+ * *
      * <media:restriction relationship="allow" type="country">au us</media:restriction>
      * 
- * + * *

- * relationship indicates the type of relationship that the restriction represents - * (allow | deny). In the example above, the media object should only be syndicated in Australia - * and the United States. It is a required attribute. + * relationship indicates the type of relationship that the restriction represents (allow | deny). In the example above, the media object should + * only be syndicated in Australia and the United States. It is a required attribute. *

- * + * + * @param restrictions restrictions for the item. + */ + public void setRestrictions(final Restriction[] restrictions) { + if (restrictions == null) { + this.restrictions = new Restriction[0]; + } else { + this.restrictions = restrictions; + } + } + + /** + *

+ * <media:restriction> + *

+ * + *

+ * Allows restrictions to be placed on the aggregator rendering the media in the feed. Currently, restrictions are based on distributor (uri) and country + * codes. This element is purely informational and no obligation can be assumed or implied. Only one <media:restriction> element of the same + * type can be applied to a media object - all others will be ignored. Entities in this element should be space separated. To allow the + * producer to explicitly declare his/her intentions, two literals are reserved: 'all', 'none'. These literals can only be used once. This element has 1 + * required attribute, and 1 optional attribute (with strict requirements for its exclusion). + *

+ * + *
+     * <media:restriction relationship="allow" type="country">au us</media:restriction>
+     * 
+ * + *

+ * relationship indicates the type of relationship that the restriction represents (allow | deny). In the example above, the media object should + * only be syndicated in Australia and the United States. It is a required attribute. + *

+ * * @return restrictions for the item. */ public Restriction[] getRestrictions() { @@ -654,67 +1161,193 @@ public class Metadata implements Cloneable, Serializable { } /** - * <media:text>

- *

- * Allows the inclusion of a text transcript, closed captioning, or lyrics of the media content. - * Many of these elements are permitted to provide a time series of text. In such cases, it is - * encouraged, but not required, that the elements be grouped by language and appear in time - * sequence order based on the start time. Elements can have overlapping start - * and end times. It has 4 optional attributes. - *

- * - *
-     * <media:text type="plain" lang="en" start="00:00:03.000"
-     *        end="00:00:10.000"> Oh, say, can you see</media:text>
+     * 

<media:rights>

* - * <media:text type="plain" lang="en" start="00:00:10.000" - * end="00:00:17.000">By the dawn's early light</media:text> - *
- *

- * type specifies the type of text embedded. Possible values are either 'plain' or - * 'html'. Default value is 'plain'. All html must be entity-encoded. It is an optional - * attribute. - *

- * - * - * - * - * - * - *

- * lang is the primary language encapsulated in the media object. Language codes - * possible are detailed in RFC 3066. This attribute is used similar to the xml:lang attribute - * detailed in the XML 1.0 Specification (Third Edition). It is an optional attribute. - *

- * - *

- * start specifies the start time offset that the text starts being relevant to the - * media object. An example of this would be for closed captioning. It uses the NTP time code - * format (see: the time attribute used in <media:thumbnail>). It is an optional - * attribute. - *

- * - *

- * end specifies the end time that the text is relevant. If this attribute is not - * provided, and a start time is used, it is expected that the end time is either the - * end of the clip or the start of the next <media:text> element. - * - * @param text text objects for the item. + *

Optional element to specify the rights information of a media object.

+ * + *
<media:rights status="userCreated" />
+     * <media:rights status="official" />
+ * + * @return the rights */ - public void setText(final Text[] text) { - this.text = text == null ? new Text[0] : text; + public RightsStatus getRights() { + return rights; + } + + /** + *

<media:rights>

+ * + *

Optional element to specify the rights information of a media object.

+ * + *
<media:rights status="userCreated" />
+     * <media:rights status="official" />
+ * + * @param rights the rights + */ + public void setRights(final RightsStatus rights) { + this.rights = rights; + } + + /** + *

<media:scene>

+ * + *

Optional element to specify various scenes within a media object. It can have multiple child <media:scene> + * elements, where each <media:scene> element contains information about a particular scene. <media:scene> + * has the optional sub-elements <sceneTitle>, <sceneDescription>, <sceneStartTime> and <sceneEndTime>, + * which contains title, description, start and end time of a particular scene in the media, respectively.

+ * + *
<media:scenes>
+     *   <media:scene>
+     *     <sceneTitle>sceneTitle1</sceneTitle>
+     *     <sceneDescription>sceneDesc1</sceneDescription>
+     *     <sceneStartTime>00:15</sceneStartTime>
+     *     <sceneEndTime>00:45</sceneEndTime>
+     *   </media:scene>
+     *   <media:scene>
+     *     <sceneTitle>sceneTitle2</sceneTitle>
+     *     <sceneDescription>sceneDesc2</sceneDescription>
+     *     <sceneStartTime>00:57</sceneStartTime>
+     *     <sceneEndTime>01:45</sceneEndTime>
+     *     </media:scene>
+     * </media:scenes>
+ * + * @return the scenes + */ + public Scene[] getScenes() { + return scenes; + } + + /** + *

<media:scene>

+ * + *

Optional element to specify various scenes within a media object. It can have multiple child <media:scene> + * elements, where each <media:scene> element contains information about a particular scene. <media:scene> + * has the optional sub-elements <sceneTitle>, <sceneDescription>, <sceneStartTime> and <sceneEndTime>, + * which contains title, description, start and end time of a particular scene in the media, respectively.

+ * + *
<media:scenes>
+     *   <media:scene>
+     *     <sceneTitle>sceneTitle1</sceneTitle>
+     *     <sceneDescription>sceneDesc1</sceneDescription>
+     *     <sceneStartTime>00:15</sceneStartTime>
+     *     <sceneEndTime>00:45</sceneEndTime>
+     *   </media:scene>
+     *   <media:scene>
+     *     <sceneTitle>sceneTitle2</sceneTitle>
+     *     <sceneDescription>sceneDesc2</sceneDescription>
+     *     <sceneStartTime>00:57</sceneStartTime>
+     *     <sceneEndTime>01:45</sceneEndTime>
+     *     </media:scene>
+     * </media:scenes>
+ * + * @param scenes the scenes + */ + public void setScenes(final Scene[] scenes) { + if (scenes == null) { + this.scenes = new Scene[0]; + } else { + this.scenes = scenes; + } } /** - * <media:text>

*

- * Allows the inclusion of a text transcript, closed captioning, or lyrics of the media content. - * Many of these elements are permitted to provide a time series of text. In such cases, it is - * encouraged, but not required, that the elements be grouped by language and appear in time - * sequence order based on the start time. Elements can have overlapping start - * and end times. It has 4 optional attributes. + * <media:status> *

- * + * + *

+ * Optional tag to specify the status of a media object -- whether it's still active or it has been blocked/deleted. + *

+ * + *
+     * <media:status state="blocked" reason="http://www.reasonforblocking.com" />
+     * 
+ * + *

+ * state can have values "active", "blocked" or "deleted". "active" means a media object is active in the system, "blocked" means a media object is blocked + * by the publisher, "deleted" means a media object has been deleted by the publisher. + * + *

+ * reason is a reason explaining why a media object has been blocked/deleted. It can be plain text or a URL. + *

+ * + * @return status of media + */ + public Status getStatus() { + return status; + } + + /** + *

+ * <media:status> + *

+ * + *

+ * Optional tag to specify the status of a media object -- whether it's still active or it has been blocked/deleted. + *

+ * + *
+     * <media:status state="blocked" reason="http://www.reasonforblocking.com" />
+     * 
+ * + *

+ * state can have values "active", "blocked" or "deleted". "active" means a media object is active in the system, "blocked" means a media object is blocked + * by the publisher, "deleted" means a media object has been deleted by the publisher. + * + *

+ * reason is a reason explaining why a media object has been blocked/deleted. It can be plain text or a URL. + *

+ * + * @param status status of media + */ + public void setStatus(final Status status) { + this.status = status; + } + + /** + *

<media:subTitle>

+ * + *

Optional element for subtitle/CC link. It contains type and language attributes. Language is based on RFC 3066. + * There can be more than one such tag per media element, for example one per language. Please refer to + * Timed Text spec - W3C for more information on Timed Text and Real Time Subtitling.

+ * + *
<media:subTitle type="application/smil" lang="en-us" href="http://www.example.org/subtitle.smil" />
+ * + * @return the subtitles + */ + public SubTitle[] getSubTitles() { + return subTitles; + } + + /** + *

<media:subTitle>

+ * + *

Optional element for subtitle/CC link. It contains type and language attributes. Language is based on RFC 3066. + * There can be more than one such tag per media element, for example one per language. Please refer to + * Timed Text spec - W3C for more information on Timed Text and Real Time Subtitling.

+ * + *
<media:subTitle type="application/smil" lang="en-us" href="http://www.example.org/subtitle.smil" />
+ * + * @param subTitles the subtitles + */ + public void setSubTitles(final SubTitle[] subTitles) { + if (subTitles == null) { + this.subTitles = new SubTitle[0]; + } else { + this.subTitles = subTitles; + } + } + + /** + *

+ * <media:text> + *

+ *

+ * Allows the inclusion of a text transcript, closed captioning, or lyrics of the media content. Many of these elements are permitted to provide a time + * series of text. In such cases, it is encouraged, but not required, that the elements be grouped by language and appear in time sequence order based on + * the start time. Elements can have overlapping start and end times. It has 4 optional attributes. + *

+ * *
      * <media:text type="plain" lang="en" start="00:00:03.000"
      *        end="00:00:10.000"> Oh, say, can you see</media:text>
@@ -723,34 +1356,80 @@ public class Metadata implements Cloneable, Serializable {
      *        end="00:00:17.000">By the dawn's early light</media:text>
      * 
*

- * type specifies the type of text embedded. Possible values are either 'plain' or - * 'html'. Default value is 'plain'. All html must be entity-encoded. It is an optional - * attribute. + * type specifies the type of text embedded. Possible values are either 'plain' or 'html'. Default value is 'plain'. All html must be + * entity-encoded. It is an optional attribute. *

- * - * - * - * - * - * + * + * + * + * + * + * *

- * lang is the primary language encapsulated in the media object. Language codes - * possible are detailed in RFC 3066. This attribute is used similar to the xml:lang attribute - * detailed in the XML 1.0 Specification (Third Edition). It is an optional attribute. + * lang is the primary language encapsulated in the media object. Language codes possible are detailed in RFC 3066. This attribute is used similar + * to the xml:lang attribute detailed in the XML 1.0 Specification (Third Edition). It is an optional attribute. *

- * + * *

- * start specifies the start time offset that the text starts being relevant to the - * media object. An example of this would be for closed captioning. It uses the NTP time code - * format (see: the time attribute used in <media:thumbnail>). It is an optional - * attribute. + * start specifies the start time offset that the text starts being relevant to the media object. An example of this would be for closed + * captioning. It uses the NTP time code format (see: the time attribute used in <media:thumbnail>). It is an optional attribute. *

- * + * *

- * end specifies the end time that the text is relevant. If this attribute is not - * provided, and a start time is used, it is expected that the end time is either the - * end of the clip or the start of the next <media:text> element. - * + * end specifies the end time that the text is relevant. If this attribute is not provided, and a start time is used, it is expected that + * the end time is either the end of the clip or the start of the next <media:text> element. + * + * @param text text objects for the item. + */ + public void setText(final Text[] text) { + if (text == null) { + this.text = new Text[0]; + } else { + this.text = text; + } + } + + /** + *

+ * <media:text> + *

+ *

+ * Allows the inclusion of a text transcript, closed captioning, or lyrics of the media content. Many of these elements are permitted to provide a time + * series of text. In such cases, it is encouraged, but not required, that the elements be grouped by language and appear in time sequence order based on + * the start time. Elements can have overlapping start and end times. It has 4 optional attributes. + *

+ * + *
+     * <media:text type="plain" lang="en" start="00:00:03.000"
+     *        end="00:00:10.000"> Oh, say, can you see</media:text>
+     * 
+     *        <media:text type="plain" lang="en" start="00:00:10.000"
+     *        end="00:00:17.000">By the dawn's early light</media:text>
+     * 
+ *

+ * type specifies the type of text embedded. Possible values are either 'plain' or 'html'. Default value is 'plain'. All html must be + * entity-encoded. It is an optional attribute. + *

+ * + * + * + * + * + * + *

+ * lang is the primary language encapsulated in the media object. Language codes possible are detailed in RFC 3066. This attribute is used similar + * to the xml:lang attribute detailed in the XML 1.0 Specification (Third Edition). It is an optional attribute. + *

+ * + *

+ * start specifies the start time offset that the text starts being relevant to the media object. An example of this would be for closed + * captioning. It uses the NTP time code format (see: the time attribute used in <media:thumbnail>). It is an optional attribute. + *

+ * + *

+ * end specifies the end time that the text is relevant. If this attribute is not provided, and a start time is used, it is expected that + * the end time is either the end of the clip or the start of the next <media:text> element. + * * @return Text objects for the item. */ public Text[] getText() { @@ -758,19 +1437,20 @@ public class Metadata implements Cloneable, Serializable { } /** - * <media:thumbnail>

- * - * *

- * Allows particular images to be used as representative images for the media object. If - * multiple thumbnails are included, and time coding is not at play, it is assumed that the - * images are in order of importance. It has 1 required attribute and 3 optional attributes. + * <media:thumbnail> *

- * - * - * - * - * + * + * + *

+ * Allows particular images to be used as representative images for the media object. If multiple thumbnails are included, and time coding is not at play, + * it is assumed that the images are in order of importance. It has 1 required attribute and 3 optional attributes. + *

+ * + * + * + * + * *
      * <media:thumbnail url="http://www.foo.com/keyframe.jpg" width="75" height="50" time="12:05:01.123" />
      * 
@@ -783,36 +1463,39 @@ public class Metadata implements Cloneable, Serializable { *

* width specifies the width of the thumbnail. It is an optional attribute. *

- * - * + * + * *

- * time specifies the time offset in relation to the media object. Typically this is - * used when creating multiple keyframes within a single video. The format for this attribute - * should be in the DSM-CC's Normal Play Time (NTP) as used in RTSP [RFC 2326 3.6 Normal Play Time]. It is an - * optional attribute. + * time specifies the time offset in relation to the media object. Typically this is used when creating multiple keyframes within a single video. + * The format for this attribute should be in the DSM-CC's Normal Play Time (NTP) as used in RTSP [RFC 2326 + * 3.6 Normal Play Time]. It is an optional attribute. *

- * + * * @param thumbnail thumbnails for the image */ public void setThumbnail(final Thumbnail[] thumbnail) { - this.thumbnail = thumbnail == null ? new Thumbnail[0] : thumbnail; + if (thumbnail == null) { + this.thumbnail = new Thumbnail[0]; + } else { + this.thumbnail = thumbnail; + } } /** - * <media:thumbnail>

- * - * *

- * Allows particular images to be used as representative images for the media object. If - * multiple thumbnails are included, and time coding is not at play, it is assumed that the - * images are in order of importance. It has 1 required attribute and 3 optional attributes. + * <media:thumbnail> *

- * - * - * - * - * + * + * + *

+ * Allows particular images to be used as representative images for the media object. If multiple thumbnails are included, and time coding is not at play, + * it is assumed that the images are in order of importance. It has 1 required attribute and 3 optional attributes. + *

+ * + * + * + * + * *
      * <media:thumbnail url="http://www.foo.com/keyframe.jpg" width="75" height="50" time="12:05:01.123" />
      * 
@@ -825,16 +1508,14 @@ public class Metadata implements Cloneable, Serializable { *

* width specifies the width of the thumbnail. It is an optional attribute. *

- * - * + * + * *

- * time specifies the time offset in relation to the media object. Typically this is - * used when creating multiple keyframes within a single video. The format for this attribute - * should be in the DSM-CC's Normal Play Time (NTP) as used in RTSP [RFC 2326 3.6 Normal Play Time]. It is an - * optional attribute. + * time specifies the time offset in relation to the media object. Typically this is used when creating multiple keyframes within a single video. + * The format for this attribute should be in the DSM-CC's Normal Play Time (NTP) as used in RTSP [RFC 2326 + * 3.6 Normal Play Time]. It is an optional attribute. *

- * + * * @return Thumbnails for the image */ public Thumbnail[] getThumbnail() { @@ -842,21 +1523,22 @@ public class Metadata implements Cloneable, Serializable { } /** - * <media:title>

+ *

+ * <media:title> + *

*

* The title of the particular media object. It has 1 optional attribute. *

- * + * *
      * <media:title type="plain">The Judy's - The Moo Song</media:title>
      * 
- * + * *

- * type specifies the type of text embedded. Possible values are either 'plain' or - * 'html'. Default value is 'plain'. All html must be entity-encoded. It is an optional - * attribute. + * type specifies the type of text embedded. Possible values are either 'plain' or 'html'. Default value is 'plain'. All html must be + * entity-encoded. It is an optional attribute. *

- * + * * @param title Value of the title */ public void setTitle(final String title) { @@ -864,21 +1546,22 @@ public class Metadata implements Cloneable, Serializable { } /** - * <media:title>

+ *

+ * <media:title> + *

*

* The title of the particular media object. It has 1 optional attribute. *

- * + * *
      * <media:title type="plain">The Judy's - The Moo Song</media:title>
      * 
- * + * *

- * type specifies the type of text embedded. Possible values are either 'plain' or - * 'html'. Default value is 'plain'. All html must be entity-encoded. It is an optional - * attribute. + * type specifies the type of text embedded. Possible values are either 'plain' or 'html'. Default value is 'plain'. All html must be + * entity-encoded. It is an optional attribute. *

- * + * * @return value of the title. */ public String getTitle() { @@ -886,21 +1569,22 @@ public class Metadata implements Cloneable, Serializable { } /** - * <media:title>

+ *

+ * <media:title> + *

*

* The title of the particular media object. It has 1 optional attribute. *

- * + * *
      * <media:title type="plain">The Judy's - The Moo Song</media:title>
      * 
- * + * *

- * type specifies the type of text embedded. Possible values are either 'plain' or - * 'html'. Default value is 'plain'. All html must be entity-encoded. It is an optional - * attribute. + * type specifies the type of text embedded. Possible values are either 'plain' or 'html'. Default value is 'plain'. All html must be + * entity-encoded. It is an optional attribute. *

- * + * * @param titleType type of the title. */ public void setTitleType(final String titleType) { @@ -908,44 +1592,28 @@ public class Metadata implements Cloneable, Serializable { } /** - * <media:title>

+ *

+ * <media:title> + *

*

* The title of the particular media object. It has 1 optional attribute. *

- * + * *
      * <media:title type="plain">The Judy's - The Moo Song</media:title>
      * 
- * + * *

- * type specifies the type of text embedded. Possible values are either 'plain' or - * 'html'. Default value is 'plain'. All html must be entity-encoded. It is an optional - * attribute. + * type specifies the type of text embedded. Possible values are either 'plain' or 'html'. Default value is 'plain'. All html must be + * entity-encoded. It is an optional attribute. *

- * + * * @return type of the title */ public String getTitleType() { return titleType; } - /** - * <media:copyright>

- *

- * Copyright information for media object. It has 1 optional attribute. - *

- * - *
-     * <media:copyright url="http://blah.com/additional-info.html">2005 FooBar Media</media:copyright>
-     * 
- *

- * url is the url for a terms of use page or additional copyright information. If the - * media is operating under a Creative Commons license, the Creative Commons module should be - * used instead. It is an optional attribute. - *

- * - * @return Link to more copyright information. - */ @Override public Object clone() { final Metadata md = new Metadata(); @@ -963,7 +1631,19 @@ public class Metadata implements Cloneable, Serializable { md.setTitle(getTitle()); md.setTitleType(getTitleType()); md.setRestrictions(getRestrictions()); - + md.setBackLinks(getBackLinks()); + md.setCommunity(getCommunity()); + md.setComments(getComments()); + md.setResponses(getResponses()); + md.setStatus(getStatus()); + md.setPrices(getPrices()); + md.setEmbed(getEmbed()); + md.setLicenses(getLicenses()); + md.setSubTitles(getSubTitles()); + md.setPeerLinks(getPeerLinks()); + md.setLocations(getLocations()); + md.setRights(getRights()); + md.setScenes(getScenes()); return md; } diff --git a/rome-modules/src/main/java/com/rometools/modules/mediarss/types/PeerLink.java b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/PeerLink.java new file mode 100644 index 0000000..2f0d321 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/PeerLink.java @@ -0,0 +1,96 @@ +/* + * This code is currently released under the Mozilla Public License. + * http://www.mozilla.org/MPL/ + * + * Alternately you may apply the terms of the Apache Software License + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.rometools.modules.mediarss.types; + +import java.io.Serializable; +import java.net.URL; + +/** + * Optional tag to include peerLink information about a media object. + * + * @since MediaRSS 1.5.0 + */ +public class PeerLink implements Serializable { + + private static final long serialVersionUID = -7117791317811346321L; + private String type; + private URL href; + + public String getType() { + return type; + } + + public void setType(final String type) { + this.type = type; + } + + public URL getHref() { + return href; + } + + public void setHref(final URL href) { + this.href = href; + } + + // CHECKSTYLE:OFF + @Override + public String toString() { + return "PeerLink [type=" + type + ", href=" + href + "]"; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (href == null ? 0 : href.hashCode()); + result = prime * result + (type == null ? 0 : type.hashCode()); + return result; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final PeerLink other = (PeerLink) obj; + if (href == null) { + if (other.href != null) { + return false; + } + } else if (!href.equals(other.href)) { + return false; + } + if (type == null) { + if (other.type != null) { + return false; + } + } else if (!type.equals(other.type)) { + return false; + } + return true; + } + // CHECKSTYLE:ON +} diff --git a/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Price.java b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Price.java new file mode 100644 index 0000000..b8e046e --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Price.java @@ -0,0 +1,183 @@ +/* + * This code is currently released under the Mozilla Public License. + * http://www.mozilla.org/MPL/ + * + * Alternately you may apply the terms of the Apache Software License + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.rometools.modules.mediarss.types; + +import java.io.Serializable; +import java.net.URL; + +/** + * Optional tag to include pricing information about a media object. + * + * @since MediaRSS 1.5.0 + */ +public class Price implements Serializable { + private static final long serialVersionUID = 446362162632617445L; + + /** + * Valid values are {@code rent}, {@code purchase}, {@code package} or {@code subscription}. + * + * If nothing is specified, then the media is free. + */ + public enum Type { + RENT, PURCHASE, PACKAGE, SUBSCRIPTION; + } + + private Type type; + private Double price; + private String currency; + private URL info; + + /** + * Valid values are "rent", "purchase", "package" or "subscription". If nothing is specified, then the media is free. + * + * @return the type + */ + public Type getType() { + return type; + } + + /** + * Valid values are "rent", "purchase", "package" or "subscription". If nothing is specified, then the media is free. + * + * @param type the type + */ + public void setType(final Type type) { + this.type = type; + } + + /** + * price is the price of the media object. + * + * This is an optional attribute. + * + * @return the price + */ + public Double getPrice() { + return price; + } + + /** + * price is the price of the media object. + * + * This is an optional attribute. + * + * @param price the price + */ + public void setPrice(final Double price) { + this.price = price; + } + + /** + * use ISO 4217 {@link http://en.wikipedia.org/wiki/ISO_4217} for currency codes. This is an optional attribute. + * + * @return ISO 4217 currency code + */ + public String getCurrency() { + return currency; + } + + /** + * use ISO 4217 {@link http://en.wikipedia.org/wiki/ISO_4217} for currency codes. This is an optional attribute. + * + * @param currency ISO 4217 currency code + */ + public void setCurrency(final String currency) { + this.currency = currency; + } + + /** + * if the type is "package" or "subscription", then info is a URL pointing to package or subscription information. + * + * This is an optional attribute. + * + * @return info url + */ + public URL getInfo() { + return info; + } + + /** + * if the type is "package" or "subscription", then info is a URL pointing to package or subscription information. + * + * This is an optional attribute. + * + * @param info url + */ + public void setInfo(final URL info) { + this.info = info; + } + + // CHECKSTYLE:OFF + @Override + public String toString() { + return "Price [type=" + type + ", price=" + price + ", currency=" + currency + ", info=" + info + "]"; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (currency == null ? 0 : currency.hashCode()); + result = prime * result + (info == null ? 0 : info.hashCode()); + result = prime * result + (price == null ? 0 : price.hashCode()); + result = prime * result + (type == null ? 0 : type.hashCode()); + return result; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final Price other = (Price) obj; + if (currency == null) { + if (other.currency != null) { + return false; + } + } else if (!currency.equals(other.currency)) { + return false; + } + if (info == null) { + if (other.info != null) { + return false; + } + } else if (!info.equals(other.info)) { + return false; + } + if (price == null) { + if (other.price != null) { + return false; + } + } else if (!price.equals(other.price)) { + return false; + } + if (type != other.type) { + return false; + } + return true; + } + // CHECKSTYLE:ON +} diff --git a/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Restriction.java b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Restriction.java index 1c518e1..a93d253 100644 --- a/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Restriction.java +++ b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Restriction.java @@ -31,14 +31,11 @@ import com.rometools.rome.feed.impl.ToStringBean; * <media:restriction>

* *

- * Allows restrictions to be placed on the aggregator rendering the media in the feed. Currently, - * restrictions are based on distributor (uri) and country codes. This element is purely - * informational and no obligation can be assumed or implied. Only one <media:restriction> - * element of the same type can be applied to a media object - all others will be - * ignored. Entities in this element should be space separated. To allow the producer to - * explicitly declare his/her intentions, two literals are reserved: 'all', 'none'. These literals - * can only be used once. This element has 1 required attribute, and 1 optional attribute (with - * strict requirements for its exclusion). + * Allows restrictions to be placed on the aggregator rendering the media in the feed. Currently, restrictions are based on distributor (uri) and country codes. + * This element is purely informational and no obligation can be assumed or implied. Only one <media:restriction> element of the same type can be + * applied to a media object - all others will be ignored. Entities in this element should be space separated. To allow the producer to explicitly declare + * his/her intentions, two literals are reserved: 'all', 'none'. These literals can only be used once. This element has 1 required attribute, and 1 optional + * attribute (with strict requirements for its exclusion). *

* *
@@ -46,14 +43,13 @@ import com.rometools.rome.feed.impl.ToStringBean;
  * 
* *

- * relationship indicates the type of relationship that the restriction represents (allow | - * deny). In the example above, the media object should only be syndicated in Australia and the - * United States. It is a required attribute. + * relationship indicates the type of relationship that the restriction represents (allow | deny). In the example above, the media object should only + * be syndicated in Australia and the United States. It is a required attribute. *

* *

- * Note: If the "allow" element is empty and the type is relationship is "allow", - * it is assumed that the empty list means "allow nobody" and the media should not be syndicated. + * Note: If the "allow" element is empty and the type is relationship is "allow", it is assumed that the empty list means "allow nobody" and + * the media should not be syndicated. *

*

* A more explicit method would be: @@ -64,23 +60,20 @@ import com.rometools.rome.feed.impl.ToStringBean; * * *

- * type specifies the type of restriction (country | uri) that the media can be syndicated. - * It is an optional attribute; however can only be excluded when using one of the literal values - * "all" or "none". + * type specifies the type of restriction (country | uri) that the media can be syndicated. It is an optional attribute; however can only be excluded + * when using one of the literal values "all" or "none". *

* *

- * "country" allows restrictions to be placed based on country code. [ISO 3166] + * "country" allows restrictions to be placed based on country code. [ISO 3166] *

*

- * "uri" allows restrictions based on URI. Examples: urn:apple, http://images.google.com, urn:yahoo, - * etc. + * "uri" allows restrictions based on URI. Examples: urn:apple, http://images.google.com, urn:yahoo, etc. * * @author cooper */ public class Restriction implements Serializable { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 7944281267467298628L; private final Relationship relationship; private final String value; @@ -141,11 +134,11 @@ public class Restriction implements Serializable { } /** - * Indicates the action of the relationship + * Indicates the action of the relationship. */ - public static class Relationship { + public static final class Relationship { /** - * An Allow relationship + * An Allow relationship. */ public static final Relationship ALLOW = new Relationship("allow"); @@ -155,6 +148,9 @@ public class Restriction implements Serializable { public static final Relationship DENY = new Relationship("deny"); private final String value; + /** + * @param value realtion name + */ private Relationship(final String value) { this.value = value; } @@ -166,20 +162,26 @@ public class Restriction implements Serializable { } /** - * Indicated the type of the relationship + * Indicated the type of the relationship. */ - public static class Type { + public static final class Type { /** * Indicates a Country type. */ public static final Type COUNTRY = new Type("country"); - + /** + * Indicates a sharing type. + */ + public static final Type SHARING = new Type("sharing"); /** * Indicates a URI for a special restriction type. */ public static final Type URI = new Type("uri"); private final String value; + /** + * @param value type name + */ private Type(final String value) { this.value = value; } @@ -190,3 +192,4 @@ public class Restriction implements Serializable { } } } + diff --git a/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Scene.java b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Scene.java new file mode 100644 index 0000000..3e56e11 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Scene.java @@ -0,0 +1,130 @@ +/* + * This code is currently released under the Mozilla Public License. + * http://www.mozilla.org/MPL/ + * + * Alternately you may apply the terms of the Apache Software License + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.rometools.modules.mediarss.types; + +import java.io.Serializable; + +/** + * Optional tag to include scene information about a media object. + * + * @since MediaRSS 1.5.0 + */ +public class Scene implements Serializable { + + private static final long serialVersionUID = 7901019257277734134L; + + private String title; + private String description; + private Time startTime; + private Time endTime; + + public String getTitle() { + return title; + } + + public void setTitle(final String title) { + this.title = title; + } + + public String getDescription() { + return description; + } + + public void setDescription(final String description) { + this.description = description; + } + + public Time getStartTime() { + return startTime; + } + + public void setStartTime(final Time startTime) { + this.startTime = startTime; + } + + public Time getEndTime() { + return endTime; + } + + public void setEndTime(final Time endTime) { + this.endTime = endTime; + } + + // CHECKSTYLE:OFF + @Override + public String toString() { + return "Scene [title=" + title + ", description=" + description + ", startTime=" + startTime + ", endTime=" + endTime + "]"; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (description == null ? 0 : description.hashCode()); + result = prime * result + (endTime == null ? 0 : endTime.hashCode()); + result = prime * result + (startTime == null ? 0 : startTime.hashCode()); + result = prime * result + (title == null ? 0 : title.hashCode()); + return result; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final Scene other = (Scene) obj; + if (description == null) { + if (other.description != null) { + return false; + } + } else if (!description.equals(other.description)) { + return false; + } + if (endTime == null) { + if (other.endTime != null) { + return false; + } + } else if (!endTime.equals(other.endTime)) { + return false; + } + if (startTime == null) { + if (other.startTime != null) { + return false; + } + } else if (!startTime.equals(other.startTime)) { + return false; + } + if (title == null) { + if (other.title != null) { + return false; + } + } else if (!title.equals(other.title)) { + return false; + } + return true; + } + // CHECKSTYLE:ON +} diff --git a/rome-modules/src/main/java/com/rometools/modules/mediarss/types/StarRating.java b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/StarRating.java new file mode 100644 index 0000000..4572453 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/StarRating.java @@ -0,0 +1,128 @@ +/* + * This code is currently released under the Mozilla Public License. + * http://www.mozilla.org/MPL/ + * + * Alternately you may apply the terms of the Apache Software License + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.rometools.modules.mediarss.types; + +import java.io.Serializable; + +/** + * This element specifies the rating-related information about a media object. + * + * @since MediaRSS 1.5.0 + */ +public class StarRating implements Serializable { + private static final long serialVersionUID = -6807718323210492980L; + private Double average; + private Integer count; + private Integer min; + private Integer max; + + public Double getAverage() { + return average; + } + + public void setAverage(final Double average) { + this.average = average; + } + + public Integer getCount() { + return count; + } + + public void setCount(final Integer count) { + this.count = count; + } + + public Integer getMin() { + return min; + } + + public void setMin(final Integer min) { + this.min = min; + } + + public Integer getMax() { + return max; + } + + public void setMax(final Integer max) { + this.max = max; + } + + //CHECKSTYLE:OFF + @Override + public String toString() { + return "StarRating [average=" + average + ", count=" + count + ", min=" + min + ", max=" + max + "]"; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (average == null ? 0 : average.hashCode()); + result = prime * result + (count == null ? 0 : count.hashCode()); + result = prime * result + (max == null ? 0 : max.hashCode()); + result = prime * result + (min == null ? 0 : min.hashCode()); + return result; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final StarRating other = (StarRating) obj; + if (average == null) { + if (other.average != null) { + return false; + } + } else if (!average.equals(other.average)) { + return false; + } + if (count == null) { + if (other.count != null) { + return false; + } + } else if (!count.equals(other.count)) { + return false; + } + if (max == null) { + if (other.max != null) { + return false; + } + } else if (!max.equals(other.max)) { + return false; + } + if (min == null) { + if (other.min != null) { + return false; + } + } else if (!min.equals(other.min)) { + return false; + } + return true; + } + //CHECKSTYLE:ON +} \ No newline at end of file diff --git a/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Statistics.java b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Statistics.java new file mode 100644 index 0000000..f7fb96d --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Statistics.java @@ -0,0 +1,95 @@ +/* + * This code is currently released under the Mozilla Public License. + * http://www.mozilla.org/MPL/ + * + * Alternately you may apply the terms of the Apache Software License + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.rometools.modules.mediarss.types; + +import java.io.Serializable; + +/** + * + * media:statistics element. + * + * @since MediaRSS 1.5.0 + */ +public class Statistics implements Serializable { + private static final long serialVersionUID = -2184017520632902691L; + private Integer views; + private Integer favorites; + + public Integer getViews() { + return views; + } + + public void setViews(final Integer views) { + this.views = views; + } + + public Integer getFavorites() { + return favorites; + } + + public void setFavorites(final Integer favorites) { + this.favorites = favorites; + } + + // CHECKSTYLE:OFF + @Override + public String toString() { + return "Statistics [views=" + views + ", favorites=" + favorites + "]"; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (favorites == null ? 0 : favorites.hashCode()); + result = prime * result + (views == null ? 0 : views.hashCode()); + return result; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final Statistics other = (Statistics) obj; + if (favorites == null) { + if (other.favorites != null) { + return false; + } + } else if (!favorites.equals(other.favorites)) { + return false; + } + if (views == null) { + if (other.views != null) { + return false; + } + } else if (!views.equals(other.views)) { + return false; + } + return true; + } + // CHECKSTYLE:ON +} diff --git a/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Status.java b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Status.java new file mode 100644 index 0000000..12a269d --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Status.java @@ -0,0 +1,127 @@ +/* + * This code is currently released under the Mozilla Public License. + * http://www.mozilla.org/MPL/ + * + * Alternately you may apply the terms of the Apache Software License + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.rometools.modules.mediarss.types; + +import java.io.Serializable; + +/** + * Optional tag to specify the status of a media object -- whether it's still active or it has been blocked/deleted. + * + * @since MediaRSS 1.5.0 + */ +public class Status implements Serializable { + private static final long serialVersionUID = 7136177408594285103L; + + /** + * state can have values {@code active}, {@code blocked} or {@code deleted}. + * + * {@code active} means a media object is active in the system, {@code blocked} means a media object is blocked by + * the publisher, {@code deleted} means a media object has been deleted by the publisher. + */ + public enum State { + active, blocked, deleted; + } + + private State state; + private String reason; + + /** + * state can have values {@code active}, {@code blocked} or {@code deleted}. + * + * {@code active} means a media object is active in the system, {@code blocked} means a media object is blocked by + * the publisher, {@code deleted} means a media object has been deleted by the publisher. + * + * @return the state + */ + public State getState() { + return state; + } + + /** + * state can have values {@code active}, {@code blocked} or {@code deleted}. + * + * {@code active} means a media object is active in the system, {@code blocked} means a media object is blocked by + * the publisher, {@code deleted} means a media object has been deleted by the publisher. + * + * @param state the state + */ + public void setState(final State state) { + this.state = state; + } + + /** + * reason is a reason explaining why a media object has been blocked/deleted. It can be plain text or a URL. + * + * @return plain text or URL + */ + public String getReason() { + return reason; + } + + /** + * reason is a reason explaining why a media object has been blocked/deleted. It can be plain text or a URL. + * + * @param reason plain text or URL + */ + public void setReason(final String reason) { + this.reason = reason; + } + + // CHECKSTYLE:OFF + @Override + public String toString() { + return "Status [state=" + state + ", reason=" + reason + "]"; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (reason == null ? 0 : reason.hashCode()); + result = prime * result + (state == null ? 0 : state.hashCode()); + return result; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final Status other = (Status) obj; + if (reason == null) { + if (other.reason != null) { + return false; + } + } else if (!reason.equals(other.reason)) { + return false; + } + if (state != other.state) { + return false; + } + return true; + } + // CHECKSTYLE:ON +} diff --git a/rome-modules/src/main/java/com/rometools/modules/mediarss/types/SubTitle.java b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/SubTitle.java new file mode 100644 index 0000000..56bb50e --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/SubTitle.java @@ -0,0 +1,113 @@ +/* + * This code is currently released under the Mozilla Public License. + * http://www.mozilla.org/MPL/ + * + * Alternately you may apply the terms of the Apache Software License + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.rometools.modules.mediarss.types; + +import java.io.Serializable; +import java.net.URL; + +/** + * Optional tag to include subTitle information about a media object. + * + * @since MediaRSS 1.5.0 + */ +public class SubTitle implements Serializable { + + private static final long serialVersionUID = -4453481267661711890L; + private String type; + private String lang; + private URL href; + + public String getType() { + return type; + } + + public void setType(final String type) { + this.type = type; + } + + public String getLang() { + return lang; + } + + public void setLang(final String lang) { + this.lang = lang; + } + + public URL getHref() { + return href; + } + + public void setHref(final URL href) { + this.href = href; + } + + // CHECKSTYLE:OFF + @Override + public String toString() { + return "SubTitle [type=" + type + ", lang=" + lang + ", href=" + href + "]"; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (href == null ? 0 : href.hashCode()); + result = prime * result + (lang == null ? 0 : lang.hashCode()); + result = prime * result + (type == null ? 0 : type.hashCode()); + return result; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final SubTitle other = (SubTitle) obj; + if (href == null) { + if (other.href != null) { + return false; + } + } else if (!href.equals(other.href)) { + return false; + } + if (lang == null) { + if (other.lang != null) { + return false; + } + } else if (!lang.equals(other.lang)) { + return false; + } + if (type == null) { + if (other.type != null) { + return false; + } + } else if (!type.equals(other.type)) { + return false; + } + return true; + } + // CHECKSTYLE:ON +} diff --git a/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Tag.java b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Tag.java new file mode 100644 index 0000000..2f4fdf2 --- /dev/null +++ b/rome-modules/src/main/java/com/rometools/modules/mediarss/types/Tag.java @@ -0,0 +1,122 @@ +/* + * This code is currently released under the Mozilla Public License. + * http://www.mozilla.org/MPL/ + * + * Alternately you may apply the terms of the Apache Software License + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.rometools.modules.mediarss.types; + +import java.io.Serializable; + +/** + * optionally weighted tag in media:tags. + * + * @since MediaRSS 1.5.0 + */ +public class Tag implements Serializable, Comparable { + private static final long serialVersionUID = 6410023938827034872L; + private final String name; + private Integer weight; + + /** + * @param name the tag name + */ + public Tag(final String name) { + this(name, null); + } + + /** + * @param name the tag name + * @param weight the weight of the tag + */ + public Tag(final String name, final Integer weight) { + super(); + this.name = name; + this.weight = weight; + } + + public String getName() { + return name; + } + + public Integer getWeight() { + return weight; + } + + public void setWeight(final Integer weight) { + this.weight = weight; + } + + @Override + public int compareTo(final Tag o) { + // weight is 1 when not set + Integer thisWeight = 1; + if (weight != null) { + thisWeight = weight; + } + Integer otherWeight = 1; + if (o != null && o.weight != null) { + otherWeight = o.weight; + } + // revert comparision, highest values first + return otherWeight.compareTo(thisWeight); + } + + //CHECKSTYLE:OFF + @Override + public String toString() { + return "Tag [name=" + name + ", weight=" + weight + "]"; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (name == null ? 0 : name.hashCode()); + result = prime * result + (weight == null ? 0 : weight.hashCode()); + return result; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final Tag other = (Tag) obj; + if (name == null) { + if (other.name != null) { + return false; + } + } else if (!name.equals(other.name)) { + return false; + } + if (weight == null) { + if (other.weight != null) { + return false; + } + } else if (!weight.equals(other.weight)) { + return false; + } + return true; + } + //CHECKSTYLE:ON +} diff --git a/rome-modules/src/site/apt/MediaRSS.apt b/rome-modules/src/site/apt/MediaRSS.apt index 638fd3a..02bb729 100644 --- a/rome-modules/src/site/apt/MediaRSS.apt +++ b/rome-modules/src/site/apt/MediaRSS.apt @@ -8,9 +8,7 @@ MediaRSS - This plugin is for use with Yahoo! MediaRSS/Flickr Photostreams - - The latest version is 0.1 available. + This plugin is for use with Yahoo! MediaRSS/Flickr Photostreams, see {{{http://www.rssboard.org/media-rss}Media RSS Specification}}. *Sample Usage @@ -39,6 +37,10 @@ mySyndEntry.getModules().add( module ); *Changes +**1.7.0-SNAPSHOT + + new elements from in MediaRSS 1.5.1 supported + **0.2.1 Bugfix for metadata on MediaGroups. diff --git a/rome-modules/src/test/java/com/rometools/modules/atom/AtomLinkTest.java b/rome-modules/src/test/java/com/rometools/modules/atom/AtomLinkTest.java index 508646e..a50e2f0 100644 --- a/rome-modules/src/test/java/com/rometools/modules/atom/AtomLinkTest.java +++ b/rome-modules/src/test/java/com/rometools/modules/atom/AtomLinkTest.java @@ -6,34 +6,17 @@ */ package com.rometools.modules.atom; +import java.io.File; + import com.rometools.modules.AbstractTestCase; import com.rometools.modules.atom.io.AtomModuleGenerator; import com.rometools.modules.atom.modules.AtomLinkModule; -import com.rometools.modules.sle.SimpleListExtension; -import com.rometools.modules.sse.SSE091Generator; -import com.rometools.modules.sse.modules.Conflict; -import com.rometools.modules.sse.modules.History; -import com.rometools.modules.sse.modules.SSEModule; -import com.rometools.modules.sse.modules.Sync; import com.rometools.rome.feed.atom.Link; -import com.rometools.rome.feed.rss.Item; -import com.rometools.rome.feed.synd.SyndEntry; import com.rometools.rome.feed.synd.SyndFeed; import com.rometools.rome.io.SyndFeedInput; -import com.rometools.rome.io.SyndFeedOutput; -import com.rometools.rome.io.XmlReader; -import com.rometools.rome.io.impl.DateParser; + import junit.framework.Test; import junit.framework.TestSuite; -import org.jdom2.Attribute; -import org.jdom2.Content; -import org.jdom2.Document; -import org.jdom2.Element; -import org.jdom2.input.SAXBuilder; - -import java.io.File; -import java.net.URL; -import java.util.*; /** * Test to verify correctness of SSE subproject. diff --git a/rome-modules/src/test/java/com/rometools/modules/mediarss/MediaModuleTest.java b/rome-modules/src/test/java/com/rometools/modules/mediarss/MediaModuleTest.java index f53a68f..dc1788b 100644 --- a/rome-modules/src/test/java/com/rometools/modules/mediarss/MediaModuleTest.java +++ b/rome-modules/src/test/java/com/rometools/modules/mediarss/MediaModuleTest.java @@ -13,16 +13,26 @@ import static org.hamcrest.Matchers.notNullValue; import java.io.BufferedWriter; import java.io.File; +import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; +import java.util.Arrays; import java.util.List; import junit.framework.Test; import junit.framework.TestSuite; +import org.custommonkey.xmlunit.Diff; +import org.custommonkey.xmlunit.Difference; +import org.custommonkey.xmlunit.DifferenceConstants; +import org.custommonkey.xmlunit.DifferenceListener; +import org.custommonkey.xmlunit.ElementNameQualifier; +import org.custommonkey.xmlunit.XMLAssert; +import org.custommonkey.xmlunit.XMLUnit; +import org.w3c.dom.Node; +import org.xml.sax.SAXException; + import com.rometools.modules.AbstractTestCase; -import com.rometools.modules.mediarss.MediaEntryModule; -import com.rometools.modules.mediarss.MediaModule; import com.rometools.modules.mediarss.types.MediaContent; import com.rometools.modules.mediarss.types.Rating; import com.rometools.modules.mediarss.types.Thumbnail; @@ -33,7 +43,7 @@ import com.rometools.rome.io.SyndFeedInput; import com.rometools.rome.io.SyndFeedOutput; /** - * + * * @author cooper */ public class MediaModuleTest extends AbstractTestCase { @@ -56,7 +66,7 @@ public class MediaModuleTest extends AbstractTestCase { * @throws Exception if file not found or not accessible */ public void testGoogleVideo() throws Exception { - final SyndFeed feed = getSyndFeed(new File(getTestFile("data/YouTube-MostPopular.rss"))); + final SyndFeed feed = getSyndFeed("data/YouTube-MostPopular.rss"); for (final Object element : feed.getEntries()) { final SyndEntry entry = (SyndEntry) element; final MediaEntryModule m = (MediaEntryModule) entry.getModule(MediaModule.URI); @@ -68,110 +78,197 @@ public class MediaModuleTest extends AbstractTestCase { * @throws Exception if file not found or not accessible */ public void testParse() throws Exception { - final File test = new File(super.getTestFile("xml")); + final File test = new File(getTestFile("xml")); final File[] files = test.listFiles(); for (int j = 0; j < files.length; j++) { if (!files[j].getName().endsWith(".xml")) { continue; } - final SyndFeed feed = getSyndFeed(files[j]); - final List entries = feed.getEntries(); - final SyndFeedOutput output = new SyndFeedOutput(); - output.output(feed, new File("target/" + j + ".xml")); - final SyndFeed feed2 = getSyndFeed(new File("target/" + j + ".xml")); - for (int i = 0; i < entries.size(); i++) { - BufferedWriter b = new BufferedWriter(new FileWriter("target/" + j + "a.txt")); - b.write("" + entries.get(i).getModule(MediaModule.URI)); - b.close(); - b = new BufferedWriter(new FileWriter("target/" + j + "b.txt")); - b.write("" + feed2.getEntries().get(i).getModule(MediaModule.URI)); - b.close(); - assertEquals(entries.get(i).getModule(MediaModule.URI), feed2.getEntries().get(i).getModule(MediaModule.URI)); - } + compareFeedFiles(files[j], new File("target/" + j + ".xml")); } } /** - * tests parsing thubnails with empty dimensions - * (https://github.com/rometools/rome-modules/issues/7). - * + * @param expected original file + * @param generated file for output + * @throws IOException if file not found or not accessible + * @throws FeedException when the feed can't be parsed + */ + private void compareFeedFiles(final File expected, final File generated) throws IOException, FeedException { + final SyndFeed feed = getSyndFeed(expected); + final List entries = feed.getEntries(); + final SyndFeedOutput output = new SyndFeedOutput(); + output.output(feed, generated); + final SyndFeed feed2 = getSyndFeed(generated); + for (int i = 0; i < entries.size(); i++) { + BufferedWriter b = new BufferedWriter(new FileWriter(generated.getAbsolutePath() + ".a.txt")); + b.write("" + entries.get(i).getModule(MediaModule.URI)); + b.close(); + b = new BufferedWriter(new FileWriter(generated.getAbsolutePath() + ".b.txt")); + b.write("" + feed2.getEntries().get(i).getModule(MediaModule.URI)); + b.close(); + assertEquals(entries.get(i).getModule(MediaModule.URI), feed2.getEntries().get(i).getModule(MediaModule.URI)); + } + } + + /** + * tests parsing thubnails with empty dimensions (https://github.com/rometools/rome-modules/issues/7). + * * @throws IOException if file not found or not accessible * @throws FeedException when the feed can't be parsed - * */ public void testParseThumbnailWithEmptyDimensions() throws FeedException, IOException { - - final SyndFeed feed = getSyndFeed("org/rometools/feed/module/mediarss/issue-07.xml"); - final SyndEntry entry = feed.getEntries().get(0); - final MediaEntryModule module = (MediaEntryModule) entry.getModule(MediaModule.URI); + final MediaEntryModule module = getFirstModuleFromFile("org/rometools/feed/module/mediarss/issue-07.xml"); final Thumbnail[] thumbnails = module.getMetadata().getThumbnail(); assertThat(thumbnails, is(notNullValue())); - } /** * tests parsing a decimal duration (https://github.com/rometools/rome-modules/issues/8). - * + * * @throws IOException if file not found or not accessible * @throws FeedException when the feed can't be parsed - * */ public void testParseDecimalDuration() throws FeedException, IOException { - - final SyndFeed feed = getSyndFeed("org/rometools/feed/module/mediarss/issue-08.xml"); - final SyndEntry entry = feed.getEntries().get(0); - final MediaEntryModule module = (MediaEntryModule) entry.getModule(MediaModule.URI); + final MediaEntryModule module = getFirstModuleFromFile("org/rometools/feed/module/mediarss/issue-08.xml"); final Thumbnail[] thumbnails = module.getMetadata().getThumbnail(); assertThat(thumbnails, is(notNullValue())); - } /** * tests parsing rating without scheme (https://github.com/rometools/rome-modules/issues/12). - * + * * @throws IOException if file not found or not accessible * @throws FeedException when the feed can't be parsed - * */ public void testParseRatingWithoutScheme() throws FeedException, IOException { - - final SyndFeed feed = getSyndFeed("org/rometools/feed/module/mediarss/issue-12.xml"); - final SyndEntry entry = feed.getEntries().get(0); - final MediaEntryModule module = (MediaEntryModule) entry.getModule(MediaModule.URI); + final MediaEntryModule module = getFirstModuleFromFile("org/rometools/feed/module/mediarss/issue-12.xml"); final Rating[] ratings = module.getMetadata().getRatings(); assertThat(ratings, is(notNullValue())); - } /** - * test url with whitespace in media element - * (https://github.com/rometools/rome-modules/issues/20). - * - * @throws Exception if file not found or not accessible + * test url with whitespace in media element (https://github.com/rometools/rome-modules/issues/20). + * + * @throws IOException if file not found or not accessible + * @throws FeedException when the feed can't be parsed */ - public void testParseMediaContentContainingURLWithSpaces() throws Exception { - final SyndFeed feed = getSyndFeed("org/rometools/feed/module/mediarss/issue-20.xml"); - final SyndEntry entry = feed.getEntries().get(0); - final MediaEntryModule m = (MediaEntryModule) entry.getModule(MediaModule.URI); - assertNotNull("missing media entry module", m); - final MediaContent[] mcs = m.getMediaContents(); - assertNotNull("missing media:content", mcs); - assertEquals("wrong count of media:content", 1, mcs.length); - final MediaContent mc = mcs[0]; - assertEquals("http://www.foo.com/path/containing+spaces/trailer.mov", mc.getReference().toString()); + public void testParseMediaContentContainingURLWithSpaces() throws FeedException, IOException { + final MediaEntryModule module = getFirstModuleFromFile("org/rometools/feed/module/mediarss/issue-20.xml"); + assertNotNull("missing media entry module", module); + final MediaContent[] mediaContents = module.getMediaContents(); + assertNotNull("missing media:content", mediaContents); + assertEquals("wrong count of media:content", 1, mediaContents.length); + final MediaContent mediaContent = mediaContents[0]; + assertEquals("http://www.foo.com/path/containing+spaces/trailer.mov", mediaContent.getReference().toString()); } + /** + * tests parsing of MediaRSS 1.5 elements (https://github.com/rometools/rome-modules/issues/15). + * + * @throws IOException if file not found or not accessible + * @throws FeedException when the feed can't be parsed + */ + public void testParseMediaRss15() throws FeedException, IOException { + final MediaEntryModule module = getFirstModuleFromFile("org/rometools/feed/module/mediarss/issue-15.xml"); + assertNotNull("missing media entry module", module); + assertNotNull("missing metadata element", module.getMetadata()); + assertNotNull("missing community", module.getMetadata().getCommunity()); + assertNotNull("missing community starRating", module.getMetadata().getCommunity().getStarRating()); + assertNotNull("missing community statistics", module.getMetadata().getCommunity().getStatistics()); + assertNotNull("missing community tags", module.getMetadata().getCommunity().getTags()); + assertEquals("missing comments", 2, module.getMetadata().getComments().length); + assertEquals("missing responses", 2, module.getMetadata().getResponses().length); + assertEquals("missing backLinks", 2, module.getMetadata().getBackLinks().length); + assertNotNull("missing state", module.getMetadata().getStatus()); + assertEquals("missing price", 1, module.getMetadata().getPrices().length); + assertNotNull("missing embed", module.getMetadata().getEmbed()); + assertEquals("missing embed params", 5, module.getMetadata().getEmbed().getParams().length); + assertEquals("missing license", 1, module.getMetadata().getLicenses().length); + assertEquals("missing subTitle", 1, module.getMetadata().getSubTitles().length); + assertEquals("missing peerLinks", 1, module.getMetadata().getPeerLinks().length); + assertEquals("missing subTitle", 1, module.getMetadata().getSubTitles().length); + assertEquals("missing location", 1, module.getMetadata().getLocations().length); + assertNotNull("missing rights", module.getMetadata().getRights()); + assertEquals("missing scenes", 1, module.getMetadata().getScenes().length); + } + + /** + * @throws IOException if file not found or not accessible + * @throws FeedException when the feed can't be parsed + * @throws SAXException if xml parsing fails + */ + public void testMediaRss15Generator() throws IOException, FeedException, SAXException { + final SyndFeed feed = getSyndFeed("org/rometools/feed/module/mediarss/issue-15.xml"); + final SyndFeedOutput output = new SyndFeedOutput(); + output.output(feed, new File("target/issue-15.xml")); + XMLUnit.setIgnoreWhitespace(true); + // text content and attribute values on some elements are reformatted, so they should be ignored + final List tagsToIgnoreTextContent = Arrays.asList("tags", "sceneStartTime", "sceneEndTime"); + final List attributaVluesToIgnore = Arrays.asList("bitrate", "end", "start"); + final Diff myDiff = new Diff(new FileReader(new File(getTestFile("org/rometools/feed/module/mediarss/issue-15.xml"))), + new FileReader(new File("target/issue-15.xml"))); + myDiff.overrideElementQualifier(new ElementNameQualifier()); + myDiff.overrideDifferenceListener(new DifferenceListener() { + + @Override + public void skippedComparison(final Node control, final Node test) { + } + + @Override + public int differenceFound(final Difference difference) { + if (difference.getId() == DifferenceConstants.TEXT_VALUE_ID) { + final Node diffNode = difference.getControlNodeDetail().getNode().getParentNode(); + if (MediaModule.URI.equals(diffNode.getNamespaceURI()) && tagsToIgnoreTextContent.contains(diffNode.getLocalName())) { + return DifferenceListener.RETURN_IGNORE_DIFFERENCE_NODES_IDENTICAL; + } + } else if (difference.getId() == DifferenceConstants.ATTR_VALUE_ID) { + final Node diffNode = difference.getControlNodeDetail().getNode(); + if (attributaVluesToIgnore.contains(diffNode.getLocalName())) { + return DifferenceListener.RETURN_IGNORE_DIFFERENCE_NODES_IDENTICAL; + } + } + return DifferenceListener.RETURN_ACCEPT_DIFFERENCE; + } + }); + XMLAssert.assertXMLEqual(myDiff, true); + } + + /** + * @param filePath relative path to file + * @return MediaEntryModule of first feed item + * @throws IOException if file access failed + * @throws FeedException if parsing feed failed + */ + private MediaEntryModule getFirstModuleFromFile(final String filePath) throws IOException, FeedException { + final SyndFeed feed = getSyndFeed(filePath); + final SyndEntry entry = feed.getEntries().get(0); + return (MediaEntryModule) entry.getModule(MediaEntryModule.URI); + } + + /** + * @param file to read + * @return SyndFeed from file + * @throws IOException if file not found or not accessible + * @throws FeedException when the feed can't be parsed + */ private SyndFeed getSyndFeed(final File file) throws IOException, FeedException { return new SyndFeedInput().build(file); } + /** + * @param filePath relative path to file + * @return SyndFeed from file + * @throws IOException if file not found or not accessible + * @throws FeedException when the feed can't be parsed + */ private SyndFeed getSyndFeed(final String filePath) throws IOException, FeedException { final String fullPath = getTestFile(filePath); final File file = new File(fullPath); - return new SyndFeedInput().build(file); + return getSyndFeed(file); } } diff --git a/rome-modules/src/test/resources/org/rometools/feed/module/mediarss/issue-15.xml b/rome-modules/src/test/resources/org/rometools/feed/module/mediarss/issue-15.xml new file mode 100644 index 0000000..d637608 --- /dev/null +++ b/rome-modules/src/test/resources/org/rometools/feed/module/mediarss/issue-15.xml @@ -0,0 +1,66 @@ + + + + Song Site + http://www.rssboard.org/media-rss + Media RSS example with new fields added in v1.5.0 + + http://www.foo.com + Tue, 28 Aug 2001 00:08:56 GMT + http://www.foo.com + 2001-08-28T00:08:56Z + + + + news: 5, abc:3 + + + comment1 + comment2 + + + application/x-shockwave-flash + 512 + 323 + true + + id=12345&vid=678912i&lang=en-us&intl=us&thumbUrl=http://www.foo.com/thumbnail.jpg + + + + http://www.response1.com + http://www.response2.com + + + http://www.backlink1.com + http://www.backlink2.com + + + + + Sample license for a video + + + + + + 35.669998 139.770004 + + + + + + + sceneTitle1 + sceneDesc1 + 00:15 + 00:45 + + + + + + \ No newline at end of file