You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@shindig.apache.org by li...@apache.org on 2010/05/06 16:25:16 UTC

svn commit: r941753 - in /shindig/trunk: java/gadgets/pom.xml java/gadgets/src/main/java/org/apache/shindig/gadgets/FeedProcessor.java java/gadgets/src/test/java/org/apache/shindig/gadgets/FeedProcessorTest.java pom.xml

Author: lindner
Date: Thu May  6 14:25:15 2010
New Revision: 941753

URL: http://svn.apache.org/viewvc?rev=941753&view=rev
Log:
Patch from Mat Mannion | Shindig Feed Processor: Parse MediaRSS items into optional Media element

Modified:
    shindig/trunk/java/gadgets/pom.xml
    shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/FeedProcessor.java
    shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/FeedProcessorTest.java
    shindig/trunk/pom.xml

Modified: shindig/trunk/java/gadgets/pom.xml
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/pom.xml?rev=941753&r1=941752&r2=941753&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/pom.xml (original)
+++ shindig/trunk/java/gadgets/pom.xml Thu May  6 14:25:15 2010
@@ -162,6 +162,10 @@
       <artifactId>rome</artifactId>
     </dependency>
     <dependency>
+      <groupId>rome</groupId>
+      <artifactId>modules</artifactId>
+    </dependency>
+    <dependency>
       <groupId>com.ibm.icu</groupId>
       <artifactId>icu4j</artifactId>
     </dependency>

Modified: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/FeedProcessor.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/FeedProcessor.java?rev=941753&r1=941752&r2=941753&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/FeedProcessor.java (original)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/FeedProcessor.java Thu May  6 14:25:15 2010
@@ -18,21 +18,26 @@
  */
 package org.apache.shindig.gadgets;
 
+import java.io.StringReader;
+import java.util.List;
+
+import com.sun.syndication.feed.module.mediarss.types.UrlReference;
+
+import com.sun.syndication.feed.module.mediarss.MediaEntryModule;
+import com.sun.syndication.feed.module.mediarss.MediaModule;
+import com.sun.syndication.feed.module.mediarss.types.MediaContent;
+import com.sun.syndication.feed.module.mediarss.types.Thumbnail;
 import com.sun.syndication.feed.synd.SyndContent;
 import com.sun.syndication.feed.synd.SyndEntry;
 import com.sun.syndication.feed.synd.SyndFeed;
 import com.sun.syndication.feed.synd.SyndPerson;
 import com.sun.syndication.io.FeedException;
 import com.sun.syndication.io.SyndFeedInput;
-
 import org.apache.shindig.gadgets.http.HttpResponse;
 import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
 
-import java.io.StringReader;
-import java.util.List;
-
 /**
  * Processes RSS & Atom Feeds and converts them into JSON output.
  */
@@ -40,16 +45,20 @@ public class FeedProcessor {
 
   /**
    * Converts feed XML to JSON.
-   *
-   * @param feedUrl The url that the feed was retrieved from.
-   * @param feedXml The raw XML of the feed to be converted.
-   * @param getSummaries True if summaries should be returned.
-   * @param numEntries Number of entries to return.
+   * 
+   * @param feedUrl
+   *            The url that the feed was retrieved from.
+   * @param feedXml
+   *            The raw XML of the feed to be converted.
+   * @param getSummaries
+   *            True if summaries should be returned.
+   * @param numEntries
+   *            Number of entries to return.
    * @return The JSON representation of the feed.
    */
   @SuppressWarnings("unchecked")
-  public JSONObject process(String feedUrl, String feedXml,
-      boolean getSummaries, int numEntries) throws GadgetException {
+  public JSONObject process(String feedUrl, String feedXml, boolean getSummaries, int numEntries)
+          throws GadgetException {
     try {
       SyndFeed feed = new SyndFeedInput().build(new StringReader(feedXml));
       JSONObject json = new JSONObject();
@@ -84,11 +93,9 @@ public class FeedProcessor {
         entry.put("Link", e.getLink());
         if (getSummaries) {
           if (e.getContents() != null && !e.getContents().isEmpty()) {
-            entry.put("Summary",
-                ((SyndContent)e.getContents().get(0)).getValue());
+            entry.put("Summary", ((SyndContent) e.getContents().get(0)).getValue());
           } else {
-            entry.put("Summary",
-                e.getDescription() != null ? e.getDescription().getValue() : "");
+            entry.put("Summary", e.getDescription() != null ? e.getDescription().getValue() : "");
           }
         }
 
@@ -105,6 +112,63 @@ public class FeedProcessor {
           jsonAuthor = e.getAuthor();
         }
 
+        JSONObject media = new JSONObject();
+        MediaEntryModule mediaModule = (MediaEntryModule) e.getModule(MediaModule.URI);
+        if (mediaModule != null) {
+          if (mediaModule.getMediaContents().length > 0) {
+            JSONArray contents = new JSONArray();
+
+            for (MediaContent c : mediaModule.getMediaContents()) {
+              JSONObject content = new JSONObject();
+
+              if (c.getReference() instanceof UrlReference) {
+                content.put("URL", ((UrlReference) c.getReference()).getUrl().toString());
+              }
+
+              if (c.getType() != null) {
+                content.put("Type", c.getType());
+              }
+
+              if (c.getWidth() != null) {
+                content.put("Width", c.getWidth());
+              }
+
+              if (c.getHeight() != null) {
+                content.put("Height", c.getHeight());
+              }
+
+              contents.put(content);
+            }
+
+            media.put("Contents", contents);
+          }
+
+          if (mediaModule.getMetadata() != null) {
+            if (mediaModule.getMetadata().getThumbnail().length > 0) {
+              // "If multiple thumbnails are included, it is assumed that they are in order of importance"
+              // Only use the first thumbnail for simplicity's
+              // sake
+
+              JSONObject thumbnail = new JSONObject();
+
+              Thumbnail t = mediaModule.getMetadata().getThumbnail()[0];
+              thumbnail.put("URL", t.getUrl().toString());
+
+              if (t.getWidth() != null) {
+                thumbnail.put("Width", t.getWidth());
+              }
+
+              if (t.getHeight() != null) {
+                thumbnail.put("Height", t.getHeight());
+              }
+
+              media.put("Thumbnail", thumbnail);
+            }
+          }
+        }
+
+        entry.put("Media", media);
+
         entries.put(entry);
       }
 
@@ -114,11 +178,9 @@ public class FeedProcessor {
       // This shouldn't ever happen.
       throw new RuntimeException(e);
     } catch (FeedException e) {
-      throw new GadgetException(GadgetException.Code.MALFORMED_XML_DOCUMENT, e,
-          HttpResponse.SC_BAD_GATEWAY);
+      throw new GadgetException(GadgetException.Code.MALFORMED_XML_DOCUMENT, e, HttpResponse.SC_BAD_GATEWAY);
     } catch (IllegalArgumentException e) {
-      throw new GadgetException(GadgetException.Code.MALFORMED_XML_DOCUMENT, e,
-          HttpResponse.SC_BAD_GATEWAY);
+      throw new GadgetException(GadgetException.Code.MALFORMED_XML_DOCUMENT, e, HttpResponse.SC_BAD_GATEWAY);
     }
   }
 }

Modified: shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/FeedProcessorTest.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/FeedProcessorTest.java?rev=941753&r1=941752&r2=941753&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/FeedProcessorTest.java (original)
+++ shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/FeedProcessorTest.java Thu May  6 14:25:15 2010
@@ -61,6 +61,43 @@ public class FeedProcessorTest {
       "<description>" + FEED_ENTRY_SUMMARY + "</description>" +
       "</item>" +
       "</channel></rss>";
+  private final static String MEDIA_CONTENT_URL1 = "http://example.com/img1.jpg";
+  private final static String MEDIA_CONTENT_URL2 = "http://example.com/img2.jpg";
+  private final static String MEDIA_CONTENT_URL3 = "http://example.com/img3.jpg";
+  private final static String MEDIA_CONTENT_TYPE = "image/jpeg";
+  private final static int MEDIA_CONTENT_WIDTH = 800;
+  private final static int MEDIA_CONTENT_HEIGHT = 600;
+  private final static String MEDIA_THUMB_URL = "http://exmaple.com/thumb.jpg";
+  private final static int MEDIA_THUMB_WIDTH = 75;
+  private final static int MEDIA_THUMB_HEIGHT = 50;
+  private final static String DATA_RSS_WITH_MEDIARSS =
+      "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
+      "<rss version=\"2.0\" xmlns:media=\"http://search.yahoo.com/mrss/\"><channel>" +
+      "<title>" + FEED_TITLE + "</title>" +
+      "<link>http://example.org/</link>" +
+      "<description>Example RSS Feed</description>" +
+      "<pubDate>Sun, 19 May 2002 15:21:36 GMT</pubDate>" +
+      "<item>" +
+      "<title>" + FEED_ENTRY_TITLE + "</title>" +
+      "<link>" + FEED_ENTRY_LINK + "</link>" +
+      "<guid>" + FEED_ENTRY_LINK + "#item1" + "</guid>" +
+      "<pubDate>" + DATE_RSS + "</pubDate>" +
+      "<description>" + FEED_ENTRY_SUMMARY + "</description>" +
+      "<author>" + FEED_AUTHOR_EMAIL + "</author>" +
+      "<media:content url=\"" + MEDIA_CONTENT_URL1 + "\" type=\"" + MEDIA_CONTENT_TYPE + "\" isDefault=\"false\" expression=\"sample\" width=\"" + MEDIA_CONTENT_WIDTH + "\" height=\"" + MEDIA_CONTENT_HEIGHT + "\" />" +
+      "<media:content url=\"" + MEDIA_CONTENT_URL2 + "\" type=\"" + MEDIA_CONTENT_TYPE + "\" isDefault=\"false\" expression=\"sample\" width=\"" + MEDIA_CONTENT_WIDTH + "\" height=\"" + MEDIA_CONTENT_HEIGHT + "\" />" +
+      "<media:content url=\"" + MEDIA_CONTENT_URL3 + "\" type=\"" + MEDIA_CONTENT_TYPE + "\" isDefault=\"false\" expression=\"sample\" width=\"" + MEDIA_CONTENT_WIDTH + "\" height=\"" + MEDIA_CONTENT_HEIGHT + "\" />" +
+      "<media:thumbnail url=\"" + MEDIA_THUMB_URL + "\" width=\"" + MEDIA_THUMB_WIDTH + "\" height=\"" + MEDIA_THUMB_HEIGHT + "\" />" +
+      "</item>" +
+      "<item>" +
+      "<title>" + FEED_ENTRY_TITLE + "</title>" +
+      "<link>" + FEED_ENTRY_LINK + "</link>" +
+      "<guid>" + FEED_ENTRY_LINK + "#item1" + "</guid>" +
+      "<description>" + FEED_ENTRY_SUMMARY + "</description>" +
+      "<media:thumbnail url=\"" + MEDIA_THUMB_URL + "\" />" +
+      "</item>" +
+      "</channel></rss>";
+      
   private final static String URL_ATOM = "http://www.example.com/feed.atom";
   private final static String DATE_ATOM = "2008-06-06T22:20:00Z";
   private final static String DATA_ATOM =
@@ -85,6 +122,33 @@ public class FeedProcessorTest {
       "<summary>" + FEED_ENTRY_SUMMARY + "</summary>" +
       "</entry>" +
       "</feed>";
+  private final static String DATA_ATOM_WITH_MEDIARSS =
+      "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
+      "<feed xmlns=\"http://www.w3.org/2005/Atom\" xmlns:media=\"http://search.yahoo.com/mrss/\">" +
+      "<title>" + FEED_TITLE + "</title>" +
+      "<link href=\"http://example.org/\"/>" +
+      "<updated>2003-12-13T18:30:02Z</updated>" +
+      "<id>urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6</id>" +
+      "<author><name>" + FEED_AUTHOR + "</name></author>" +
+      "<entry>" +
+      "<title>" + FEED_ENTRY_TITLE + "</title>" +
+      "<link href=\"" + FEED_ENTRY_LINK + "\"/>" +
+      "<id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>" +
+      "<updated>" + DATE_ATOM + "</updated>" +
+      "<summary>" + FEED_ENTRY_SUMMARY + "</summary>" +
+      "<media:content url=\"" + MEDIA_CONTENT_URL1 + "\" type=\"" + MEDIA_CONTENT_TYPE + "\" isDefault=\"false\" expression=\"sample\" width=\"" + MEDIA_CONTENT_WIDTH + "\" height=\"" + MEDIA_CONTENT_HEIGHT + "\" />" +
+      "<media:content url=\"" + MEDIA_CONTENT_URL2 + "\" type=\"" + MEDIA_CONTENT_TYPE + "\" isDefault=\"false\" expression=\"sample\" width=\"" + MEDIA_CONTENT_WIDTH + "\" height=\"" + MEDIA_CONTENT_HEIGHT + "\" />" +
+      "<media:content url=\"" + MEDIA_CONTENT_URL3 + "\" type=\"" + MEDIA_CONTENT_TYPE + "\" isDefault=\"false\" expression=\"sample\" width=\"" + MEDIA_CONTENT_WIDTH + "\" height=\"" + MEDIA_CONTENT_HEIGHT + "\" />" +
+      "<media:thumbnail url=\"" + MEDIA_THUMB_URL + "\" width=\"" + MEDIA_THUMB_WIDTH + "\" height=\"" + MEDIA_THUMB_HEIGHT + "\" />" +
+      "</entry>" +
+      "<entry>" +
+      "<title>" + FEED_ENTRY_TITLE + "</title>" +
+      "<link href=\"" + FEED_ENTRY_LINK + "\"/>" +
+      "<id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da3443fa6a</id>" +
+      "<summary>" + FEED_ENTRY_SUMMARY + "</summary>" +
+      "<media:thumbnail url=\"" + MEDIA_THUMB_URL + "\" />" +
+      "</entry>" +
+      "</feed>";
   private final static String BAD_XML = "broken xml !!!! & ><";
   private final static String INVALID_XML = "<data><foo/></data>";
 
@@ -134,6 +198,52 @@ public class FeedProcessorTest {
     assertNull("Summary should not be returned when getSummaries is false",
         entry.optString("Summary", null));
   }
+  
+  @Test
+  public void parseMediaRss() throws Exception {
+      JSONObject feed = processor.process(URL_RSS, DATA_RSS_WITH_MEDIARSS, true, 1);
+
+      assertEquals(URL_RSS, feed.getString("URL"));
+      assertEquals(FEED_TITLE, feed.getString("Title"));
+      assertEquals(FEED_AUTHOR_EMAIL, feed.getString("Author"));
+
+      JSONArray entryArray = feed.getJSONArray("Entry");
+      JSONObject entry = entryArray.getJSONObject(0);
+
+      assertEquals(1, entryArray.length());
+      assertEquals(FEED_ENTRY_TITLE, entry.getString("Title"));
+      assertEquals(FEED_ENTRY_LINK, entry.getString("Link"));
+      assertEquals(FEED_ENTRY_SUMMARY, entry.getString("Summary"));
+      
+      // Three lots of content, each with a width/height and type
+      JSONObject media = entry.getJSONObject("Media");
+      JSONArray contents = media.getJSONArray("Contents");
+      
+      assertEquals(3, contents.length());
+      
+      JSONObject contents1 = contents.getJSONObject(0);
+      assertEquals(MEDIA_CONTENT_URL1, contents1.getString("URL"));
+      assertEquals(MEDIA_CONTENT_TYPE, contents1.getString("Type"));
+      assertEquals(MEDIA_CONTENT_WIDTH, contents1.getInt("Width"));
+      assertEquals(MEDIA_CONTENT_HEIGHT, contents1.getInt("Height"));
+      
+      JSONObject contents2 = contents.getJSONObject(1);
+      assertEquals(MEDIA_CONTENT_URL2, contents2.getString("URL"));
+      assertEquals(MEDIA_CONTENT_TYPE, contents2.getString("Type"));
+      assertEquals(MEDIA_CONTENT_WIDTH, contents2.getInt("Width"));
+      assertEquals(MEDIA_CONTENT_HEIGHT, contents2.getInt("Height"));
+      
+      JSONObject contents3 = contents.getJSONObject(2);
+      assertEquals(MEDIA_CONTENT_URL3, contents3.getString("URL"));
+      assertEquals(MEDIA_CONTENT_TYPE, contents3.getString("Type"));
+      assertEquals(MEDIA_CONTENT_WIDTH, contents3.getInt("Width"));
+      assertEquals(MEDIA_CONTENT_HEIGHT, contents3.getInt("Height"));
+      
+      JSONObject thumbnail = media.getJSONObject("Thumbnail");
+      assertEquals(MEDIA_THUMB_URL, thumbnail.getString("URL"));
+      assertEquals(MEDIA_THUMB_WIDTH, thumbnail.getInt("Width"));
+      assertEquals(MEDIA_THUMB_HEIGHT, thumbnail.getInt("Height"));
+  }
 
   @Test
   public void parseAtom() throws Exception {
@@ -175,6 +285,52 @@ public class FeedProcessorTest {
     assertNull("Summary should not be returned when getSummaries is false",
         entry.optString("Summary", null));
   }
+  
+  @Test
+  public void parseMediaAtom() throws Exception {
+      JSONObject feed = processor.process(URL_ATOM, DATA_ATOM_WITH_MEDIARSS, true, 1);
+
+      assertEquals(URL_ATOM, feed.getString("URL"));
+      assertEquals(FEED_TITLE, feed.getString("Title"));
+      assertEquals(FEED_AUTHOR, feed.getString("Author"));
+
+      JSONArray entryArray = feed.getJSONArray("Entry");
+      JSONObject entry = entryArray.getJSONObject(0);
+
+      assertEquals(1, entryArray.length());
+      assertEquals(FEED_ENTRY_TITLE, entry.getString("Title"));
+      assertEquals(FEED_ENTRY_LINK, entry.getString("Link"));
+      assertEquals(FEED_ENTRY_SUMMARY, entry.getString("Summary"));
+      
+      // Three lots of content, each with a width/height and type
+      JSONObject media = entry.getJSONObject("Media");
+      JSONArray contents = media.getJSONArray("Contents");
+      
+      assertEquals(3, contents.length());
+      
+      JSONObject contents1 = contents.getJSONObject(0);
+      assertEquals(MEDIA_CONTENT_URL1, contents1.getString("URL"));
+      assertEquals(MEDIA_CONTENT_TYPE, contents1.getString("Type"));
+      assertEquals(MEDIA_CONTENT_WIDTH, contents1.getInt("Width"));
+      assertEquals(MEDIA_CONTENT_HEIGHT, contents1.getInt("Height"));
+      
+      JSONObject contents2 = contents.getJSONObject(1);
+      assertEquals(MEDIA_CONTENT_URL2, contents2.getString("URL"));
+      assertEquals(MEDIA_CONTENT_TYPE, contents2.getString("Type"));
+      assertEquals(MEDIA_CONTENT_WIDTH, contents2.getInt("Width"));
+      assertEquals(MEDIA_CONTENT_HEIGHT, contents2.getInt("Height"));
+      
+      JSONObject contents3 = contents.getJSONObject(2);
+      assertEquals(MEDIA_CONTENT_URL3, contents3.getString("URL"));
+      assertEquals(MEDIA_CONTENT_TYPE, contents3.getString("Type"));
+      assertEquals(MEDIA_CONTENT_WIDTH, contents3.getInt("Width"));
+      assertEquals(MEDIA_CONTENT_HEIGHT, contents3.getInt("Height"));
+      
+      JSONObject thumbnail = media.getJSONObject("Thumbnail");
+      assertEquals(MEDIA_THUMB_URL, thumbnail.getString("URL"));
+      assertEquals(MEDIA_THUMB_WIDTH, thumbnail.getInt("Width"));
+      assertEquals(MEDIA_THUMB_HEIGHT, thumbnail.getInt("Height"));
+  }
 
   @Test(expected=GadgetException.class)
   public void parseBadXml() throws GadgetException {

Modified: shindig/trunk/pom.xml
URL: http://svn.apache.org/viewvc/shindig/trunk/pom.xml?rev=941753&r1=941752&r2=941753&view=diff
==============================================================================
--- shindig/trunk/pom.xml (original)
+++ shindig/trunk/pom.xml Thu May  6 14:25:15 2010
@@ -1449,6 +1449,11 @@
         <version>1.0</version>
       </dependency>
       <dependency>
+        <groupId>rome</groupId>
+        <artifactId>modules</artifactId>
+        <version>0.3.2</version>
+      </dependency>
+      <dependency>
         <groupId>com.ibm.icu</groupId>
         <artifactId>icu4j</artifactId>
         <version>3.8</version>