STREAMS-122 | Updated the InstagramActivityUtil class to fully map Instagram 
MediaFeedData objects to Activities. Updated tests so that this deserialization 
and mapping can be tested


Project: http://git-wip-us.apache.org/repos/asf/incubator-streams/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-streams/commit/11636535
Tree: http://git-wip-us.apache.org/repos/asf/incubator-streams/tree/11636535
Diff: http://git-wip-us.apache.org/repos/asf/incubator-streams/diff/11636535

Branch: refs/heads/STREAMS-46
Commit: 116365355dad985da52092c85378b5bd7497e907
Parents: 7b301ce
Author: Robert Douglas <[email protected]>
Authored: Tue Jul 1 17:12:57 2014 -0500
Committer: Robert Douglas <[email protected]>
Committed: Tue Jul 1 17:12:57 2014 -0500

----------------------------------------------------------------------
 streams-contrib/pom.xml                         |   1 +
 .../InstagramJsonActivitySerializer.java        |  22 ++-
 .../serializer/util/InstagramActivityUtil.java  | 170 ++++++++++++++++---
 .../test/InstagramActivitySerDeTest.java        |  24 ++-
 .../src/test/resources/testMediaFeedObjects.txt |   2 +
 5 files changed, 181 insertions(+), 38 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-streams/blob/11636535/streams-contrib/pom.xml
----------------------------------------------------------------------
diff --git a/streams-contrib/pom.xml b/streams-contrib/pom.xml
index 620f68e..699274e 100644
--- a/streams-contrib/pom.xml
+++ b/streams-contrib/pom.xml
@@ -47,6 +47,7 @@
                <module>streams-amazon-aws</module>
         <!--<module>streams-processor-lucene</module>-->
         <!--<module>streams-processor-tika</module>-->
+        <module>streams-provider-instagram</module>
         <module>streams-processor-json</module>
         <module>streams-processor-urls</module>
         <module>streams-provider-datasift</module>

http://git-wip-us.apache.org/repos/asf/incubator-streams/blob/11636535/streams-contrib/streams-provider-instagram/src/main/java/org/apache/streams/instagram/serializer/InstagramJsonActivitySerializer.java
----------------------------------------------------------------------
diff --git 
a/streams-contrib/streams-provider-instagram/src/main/java/org/apache/streams/instagram/serializer/InstagramJsonActivitySerializer.java
 
b/streams-contrib/streams-provider-instagram/src/main/java/org/apache/streams/instagram/serializer/InstagramJsonActivitySerializer.java
index 8d92641..c5bbdf1 100644
--- 
a/streams-contrib/streams-provider-instagram/src/main/java/org/apache/streams/instagram/serializer/InstagramJsonActivitySerializer.java
+++ 
b/streams-contrib/streams-provider-instagram/src/main/java/org/apache/streams/instagram/serializer/InstagramJsonActivitySerializer.java
@@ -18,14 +18,21 @@
 
 package org.apache.streams.instagram.serializer;
 
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
 import org.apache.commons.lang.NotImplementedException;
 import org.apache.streams.data.ActivitySerializer;
 import org.apache.streams.exceptions.ActivitySerializerException;
+import org.apache.streams.jackson.StreamsJacksonMapper;
 import org.apache.streams.pojo.json.Activity;
+import org.jinstagram.entity.users.feed.MediaFeedData;
 
+import java.io.IOException;
 import java.io.Serializable;
 import java.util.List;
 
+import static 
org.apache.streams.instagram.serializer.util.InstagramActivityUtil.updateActivity;
+
 public class InstagramJsonActivitySerializer implements 
ActivitySerializer<String>, Serializable
 {
 
@@ -46,9 +53,20 @@ public class InstagramJsonActivitySerializer implements 
ActivitySerializer<Strin
     @Override
     public Activity deserialize(String serialized) throws 
ActivitySerializerException {
 
-        Activity activity = null;
+        ObjectMapper mapper = StreamsJacksonMapper.getInstance();
+        MediaFeedData mediaFeedData = null;
+
+        try {
+            mediaFeedData = mapper.readValue(serialized, MediaFeedData.class);
+        } catch (JsonProcessingException e) {
+            e.printStackTrace();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+
+        Activity activity = new Activity();
 
-        // implement
+        updateActivity(mediaFeedData, activity);
 
         return activity;
     }

http://git-wip-us.apache.org/repos/asf/incubator-streams/blob/11636535/streams-contrib/streams-provider-instagram/src/main/java/org/apache/streams/instagram/serializer/util/InstagramActivityUtil.java
----------------------------------------------------------------------
diff --git 
a/streams-contrib/streams-provider-instagram/src/main/java/org/apache/streams/instagram/serializer/util/InstagramActivityUtil.java
 
b/streams-contrib/streams-provider-instagram/src/main/java/org/apache/streams/instagram/serializer/util/InstagramActivityUtil.java
index e71c43e..0561ba7 100644
--- 
a/streams-contrib/streams-provider-instagram/src/main/java/org/apache/streams/instagram/serializer/util/InstagramActivityUtil.java
+++ 
b/streams-contrib/streams-provider-instagram/src/main/java/org/apache/streams/instagram/serializer/util/InstagramActivityUtil.java
@@ -19,16 +19,21 @@
 
 package org.apache.streams.instagram.serializer.util;
 
-import com.fasterxml.jackson.databind.node.ObjectNode;
 import com.google.common.base.Joiner;
+import com.google.common.base.Optional;
 import com.google.common.collect.Lists;
 import org.apache.streams.exceptions.ActivitySerializerException;
-import org.apache.streams.pojo.json.Activity;
-import org.apache.streams.pojo.json.ActivityObject;
-import org.apache.streams.pojo.json.Actor;
-import org.apache.streams.pojo.json.Provider;
+import org.apache.streams.pojo.json.*;
+import org.jinstagram.entity.common.ImageData;
+import org.jinstagram.entity.common.Images;
+import org.jinstagram.entity.common.VideoData;
+import org.jinstagram.entity.common.Videos;
 import org.jinstagram.entity.users.feed.MediaFeedData;
+import org.joda.time.DateTime;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -39,7 +44,7 @@ import static 
org.apache.streams.data.util.ActivityUtil.ensureExtensions;
  * Provides utilities for working with Activity objects within the context of 
Instagram
  */
 public class InstagramActivityUtil {
-
+    private static final Logger LOGGER = 
LoggerFactory.getLogger(InstagramActivityUtil.class);
     /**
      * Updates the given Activity object with the values from the item
      * @param item the object to use as the source
@@ -47,7 +52,22 @@ public class InstagramActivityUtil {
      * @throws ActivitySerializerException
      */
     public static void updateActivity(MediaFeedData item, Activity activity) 
throws ActivitySerializerException {
+        activity.setActor(buildActor(item));
+        activity.setPublished(new 
DateTime(Long.parseLong(item.getCreatedTime()) * 1000));
+
+        activity.setId(formatId(activity.getVerb(),
+            Optional.fromNullable(
+                    item.getId())
+                        .orNull()));
+
+        activity.setProvider(getProvider());
+        activity.setUrl(item.getLink());
+        activity.setObject(buildActivityObject(item));
 
+        if(item.getCaption() != null)
+            activity.setContent(item.getCaption().getText());
+
+        addInstagramExtensions(activity, item);
     }
 
     /**
@@ -57,6 +77,18 @@ public class InstagramActivityUtil {
      */
     public static  Actor buildActor(MediaFeedData item) {
         Actor actor = new Actor();
+
+        Image image = new Image();
+        image.setUrl(item.getUser().getProfilePictureUrl());
+
+        Map<String, Object> extensions = new HashMap<String, Object>();
+        extensions.put("screenName", item.getUser().getUserName());
+
+        actor.setId(formatId(String.valueOf(item.getUser().getId())));
+        actor.setImage(image);
+        actor.setAdditionalProperty("extensions", extensions);
+        actor.setAdditionalProperty("handle", item.getUser().getUserName());
+
         return actor;
     }
 
@@ -67,18 +99,90 @@ public class InstagramActivityUtil {
      */
     public static ActivityObject buildActivityObject(MediaFeedData item) {
         ActivityObject actObj = new ActivityObject();
+
+        actObj.setObjectType(item.getType());
+        actObj.setAttachments(buildActivityObjectAttachments(item));
+
         return actObj;
     }
 
+    /**
+     * Builds all of the attachments associated with a MediaFeedData object
+     *
+     * @param item
+     * @return
+     */
+    public static List<ActivityObject> 
buildActivityObjectAttachments(MediaFeedData item) {
+        List<ActivityObject> attachments = new ArrayList<ActivityObject>();
+
+        addImageObjects(attachments, item);
+        addVideoObjects(attachments, item);
+
+        return attachments;
+    }
 
     /**
-     * Updates the content, and associated fields, with those from the given 
tweet
-     * @param activity the target of the updates.  Will receive all values 
from the tweet.
-     * @param item the object to use as the source
-     * @param verb the verb for the given activity's type
+     * Adds any image objects to the attachment field
+     * @param attachments
+     * @param item
+     */
+    public static void addImageObjects(List<ActivityObject> attachments, 
MediaFeedData item) {
+        Images images = item.getImages();
+
+        if(images != null) {
+            try {
+                ImageData thumbnail = images.getThumbnail();
+                ImageData lowResolution = images.getLowResolution();
+
+                ActivityObject thumbnailObject = new ActivityObject();
+                Image thumbnailImage = new Image();
+                thumbnailImage.setUrl(thumbnail.getImageUrl());
+                thumbnailImage.setHeight((double) thumbnail.getImageHeight());
+                thumbnailImage.setWidth((double) thumbnail.getImageWidth());
+                thumbnailObject.setImage(thumbnailImage);
+                thumbnailObject.setObjectType("image");
+
+                ActivityObject lowResolutionObject = new ActivityObject();
+                Image lowResolutionImage = new Image();
+                lowResolutionImage.setUrl(lowResolution.getImageUrl());
+                lowResolutionImage.setHeight((double) 
lowResolution.getImageHeight());
+                lowResolutionImage.setWidth((double) 
lowResolution.getImageWidth());
+                lowResolutionObject.setImage(lowResolutionImage);
+                lowResolutionObject.setObjectType("image");
+
+                attachments.add(thumbnailObject);
+                attachments.add(lowResolutionObject);
+            } catch (Exception e) {
+                LOGGER.error("Failed to add image objects: {}", 
e.getMessage());
+            }
+        }
+    }
+
+    /**
+     * Adds any video objects to the attachment field
+     * @param attachments
+     * @param item
      */
-    public static void updateActivityContent(Activity activity, MediaFeedData 
item, String verb) {
+    public static void addVideoObjects(List<ActivityObject> attachments, 
MediaFeedData item) {
+        Videos videos = item.getVideos();
+
+        if(videos != null) {
+            try {
+                VideoData lowResolutionVideo = videos.getLowResolution();
+
+                ActivityObject lowResolutionVideoObject = new ActivityObject();
+                Image lowResolutionVideoImage = new Image();
+                lowResolutionVideoImage.setUrl(lowResolutionVideo.getUrl());
+                lowResolutionVideoImage.setHeight((double) 
lowResolutionVideo.getHeight());
+                lowResolutionVideoImage.setWidth((double) 
lowResolutionVideo.getWidth());
+                lowResolutionVideoObject.setImage(lowResolutionVideoImage);
+                lowResolutionVideoObject.setObjectType("video");
 
+                attachments.add(lowResolutionVideoObject);
+            } catch (Exception e) {
+                LOGGER.error("Failed to add video objects: {}", 
e.getMessage());
+            }
+        }
     }
 
     /**
@@ -98,7 +202,14 @@ public class InstagramActivityUtil {
      */
     public static void addLocationExtension(Activity activity, MediaFeedData 
item) {
         Map<String, Object> extensions = ensureExtensions(activity);
-        Map<String, Object> location = new HashMap<String, Object>();
+
+        if(item.getLocation() != null) {
+            Map<String, Object> coordinates = new HashMap<String, Object>();
+            coordinates.put("type", "Point");
+            coordinates.put("coordinates", "[" + 
item.getLocation().getLatitude() + "," + item.getLocation().getLongitude() + 
"]");
+
+            extensions.put("coordinates", coordinates);
+        }
 
     }
 
@@ -112,15 +223,7 @@ public class InstagramActivityUtil {
         provider.setDisplayName("Instagram");
         return provider;
     }
-    /**
-     * Adds the given Instagram event to the activity as an extension
-     * @param activity the Activity object to update
-     * @param event the Instagram event to add as the extension
-     */
-    public static void addInstagramExtension(Activity activity, ObjectNode 
event) {
-        Map<String, Object> extensions = 
org.apache.streams.data.util.ActivityUtil.ensureExtensions(activity);
-        extensions.put("instagram", event);
-    }
+
     /**
      * Formats the ID to conform with the Apache Streams activity ID convention
      * @param idparts the parts of the ID to join
@@ -138,5 +241,28 @@ public class InstagramActivityUtil {
      */
     public static void addInstagramExtensions(Activity activity, MediaFeedData 
item) {
         Map<String, Object> extensions = ensureExtensions(activity);
+
+        addLocationExtension(activity, item);
+
+        Map<String, Object> likes = new HashMap<String, Object>();
+        likes.put("count", item.getLikes().getCount());
+        extensions.put("likes", likes);
+
+        extensions.put("hashtags", item.getTags());
+
+        Image standardResolution = new Image();
+        if(item.getType() == "image" && item.getImages() != null) {
+            ImageData standardResolutionData = 
item.getImages().getStandardResolution();
+            
standardResolution.setHeight((double)standardResolutionData.getImageHeight());
+            
standardResolution.setWidth((double)standardResolutionData.getImageWidth());
+            standardResolution.setUrl(standardResolutionData.getImageUrl());
+        } else if(item.getType() == "video" && item.getVideos() != null) {
+            VideoData standardResolutionData = 
item.getVideos().getStandardResolution();
+            
standardResolution.setHeight((double)standardResolutionData.getHeight());
+            
standardResolution.setWidth((double)standardResolutionData.getWidth());
+            standardResolution.setUrl(standardResolutionData.getUrl());
+        }
+
+        extensions.put("image", standardResolution);
     }
-}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-streams/blob/11636535/streams-contrib/streams-provider-instagram/src/test/java/org/apache/streams/twitter/test/InstagramActivitySerDeTest.java
----------------------------------------------------------------------
diff --git 
a/streams-contrib/streams-provider-instagram/src/test/java/org/apache/streams/twitter/test/InstagramActivitySerDeTest.java
 
b/streams-contrib/streams-provider-instagram/src/test/java/org/apache/streams/twitter/test/InstagramActivitySerDeTest.java
index fcf5e81..075da80 100644
--- 
a/streams-contrib/streams-provider-instagram/src/test/java/org/apache/streams/twitter/test/InstagramActivitySerDeTest.java
+++ 
b/streams-contrib/streams-provider-instagram/src/test/java/org/apache/streams/twitter/test/InstagramActivitySerDeTest.java
@@ -20,11 +20,12 @@ package org.apache.streams.twitter.test;
 
 import com.fasterxml.jackson.databind.ObjectMapper;
 import org.apache.commons.lang.StringUtils;
+import org.apache.streams.instagram.serializer.util.InstagramDeserializer;
 import org.apache.streams.instagram.serializer.InstagramJsonActivitySerializer;
 import org.apache.streams.jackson.StreamsJacksonMapper;
 import org.apache.streams.pojo.json.Activity;
+import org.jinstagram.entity.users.feed.MediaFeedData;
 import org.junit.Assert;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -33,6 +34,7 @@ import java.io.BufferedReader;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 
+import static 
org.apache.streams.instagram.serializer.util.InstagramActivityUtil.updateActivity;
 import static org.hamcrest.CoreMatchers.*;
 import static org.junit.Assert.assertThat;
 
@@ -46,16 +48,11 @@ import static org.junit.Assert.assertThat;
 public class InstagramActivitySerDeTest {
 
     private final static Logger LOGGER = 
LoggerFactory.getLogger(InstagramActivitySerDeTest.class);
-    private ObjectMapper mapper = StreamsJacksonMapper.getInstance();
 
-    private InstagramJsonActivitySerializer instagramJsonActivitySerializer = 
new InstagramJsonActivitySerializer();
-
-    // remove @Ignore after implementation
-    @Ignore
     @Test
-    public void Tests()
-    {
-        InputStream is = 
InstagramActivitySerDeTest.class.getResourceAsStream("/test.txt");
+    public void Tests() {
+        InstagramDeserializer instagramDeserializer = new 
InstagramDeserializer("");
+        InputStream is = 
InstagramActivitySerDeTest.class.getResourceAsStream("/testMediaFeedObjects.txt");
         InputStreamReader isr = new InputStreamReader(is);
         BufferedReader br = new BufferedReader(isr);
 
@@ -66,13 +63,13 @@ public class InstagramActivitySerDeTest {
                 {
                     LOGGER.info("raw: {}", line);
 
-                    // convert to MediaFeedData?
-                    Activity activity = 
instagramJsonActivitySerializer.deserialize(line);
+                    MediaFeedData mediaFeedData = 
instagramDeserializer.createObjectFromResponse(MediaFeedData.class, line);
 
-                    String activitystring = 
mapper.writeValueAsString(activity);
+                    Activity activity = new Activity();
 
-                    LOGGER.info("activity: {}", activitystring);
+                    LOGGER.info("activity: {}", activity.toString());
 
+                    updateActivity(mediaFeedData, activity);
                     assertThat(activity, is(not(nullValue())));
 
                     assertThat(activity.getId(), is(not(nullValue())));
@@ -80,7 +77,6 @@ public class InstagramActivitySerDeTest {
                     assertThat(activity.getActor().getId(), 
is(not(nullValue())));
                     assertThat(activity.getVerb(), is(not(nullValue())));
                     assertThat(activity.getProvider(), is(not(nullValue())));
-
                 }
             }
         } catch( Exception e ) {

http://git-wip-us.apache.org/repos/asf/incubator-streams/blob/11636535/streams-contrib/streams-provider-instagram/src/test/resources/testMediaFeedObjects.txt
----------------------------------------------------------------------
diff --git 
a/streams-contrib/streams-provider-instagram/src/test/resources/testMediaFeedObjects.txt
 
b/streams-contrib/streams-provider-instagram/src/test/resources/testMediaFeedObjects.txt
index e69de29..b62e599 100644
--- 
a/streams-contrib/streams-provider-instagram/src/test/resources/testMediaFeedObjects.txt
+++ 
b/streams-contrib/streams-provider-instagram/src/test/resources/testMediaFeedObjects.txt
@@ -0,0 +1,2 @@
+{ "attribution":null, "tags":[ ], "type":"image", "location":null, 
"comments":{ "count":0, "data":[ ] }, "filter":"X-Pro II", 
"created_time":"1404162054", "link":"http://instagram.com/p/p4ez__syJi/";, 
"likes":{ "count":0, "data":[ ] }, "images":{ "low_resolution":{ 
"url":"http://scontent-a.cdninstagram.com/hphotos-xpa1/t51.2885-15/10518155_283164271863608_1534480525_a.jpg";,
 "width":306, "height":306 }, "thumbnail":{ 
"url":"http://scontent-a.cdninstagram.com/hphotos-xpa1/t51.2885-15/10518155_283164271863608_1534480525_s.jpg";,
 "width":150, "height":150 }, "standard_resolution":{ 
"url":"http://scontent-a.cdninstagram.com/hphotos-xpa1/t51.2885-15/10518155_283164271863608_1534480525_n.jpg";,
 "width":640, "height":640 } }, "users_in_photo":[ ], "caption":{ 
"created_time":"1404162054", "text":"Testing streams", "from":{ 
"username":"ktsafford", 
"profile_picture":"http://images.ak.instagram.com/profiles/anonymousUser.jpg";, 
"id":"1412068271", "full_name":"ktsafford" }, "id":"754488452958068751"
  }, "user_has_liked":false, "id":"754488452387644002_1412068271", "user":{ 
"username":"ktsafford", "website":"", 
"profile_picture":"http://images.ak.instagram.com/profiles/anonymousUser.jpg";, 
"full_name":"ktsafford", "bio":"", "id":"1412068271" } }
+{ "type":"image", "users_in_photo":[ { "user":{ "username":"kevin", 
"full_name":"Kevin S", "id":"3", "profile_picture":"..." }, "position":{ 
"x":0.315, "y":0.9111 } } ], "filter":"Walden", "tags":[ ], "comments":{ 
"data":[ { "created_time":"1279332030", "text":"Love the sign here", "from":{ 
"username":"mikeyk", "full_name":"Mikey Krieger", "id":"4", 
"profile_picture":"http://distillery.s3.amazonaws.com/profiles/profile_1242695_75sq_1293915800.jpg";
 }, "id":"8" }, { "created_time":"1279341004", "text":"Chilako taco", "from":{ 
"username":"kevin", "full_name":"Kevin S", "id":"3", "profile_picture":"..." }, 
"id":"3" } ], "count":2 }, "caption":null, "likes":{ "count":1, "data":[ { 
"username":"mikeyk", "full_name":"Mikeyk", "id":"4", "profile_picture":"..." } 
] }, "link":"http://instagr.am/p/D/";, "user":{ "username":"kevin", 
"full_name":"Kevin S", "profile_picture":"...", "bio":"...", "website":"...", 
"id":"3" }, "created_time":"1279340983", "images":{ "low_resolution":{ 
"url":"http://dis
 
tillery.s3.amazonaws.com/media/2010/07/16/4de37e03aa4b4372843a7eb33fa41cad_6.jpg",
 "width":306, "height":306 }, "thumbnail":{ 
"url":"http://distillery.s3.amazonaws.com/media/2010/07/16/4de37e03aa4b4372843a7eb33fa41cad_5.jpg";,
 "width":150, "height":150 }, "standard_resolution":{ 
"url":"http://distillery.s3.amazonaws.com/media/2010/07/16/4de37e03aa4b4372843a7eb33fa41cad_7.jpg";,
 "width":612, "height":612 } }, "id":"3", "location":null }

Reply via email to