Repository: incubator-streams Updated Branches: refs/heads/master 3341415d9 -> 9aebd0b1a
STREAMS-203 | Created mechanisms to convert a GooglePlus Activity object to a Streams Activity object. Updated serializers and TypeConverters accordingly. Added in appropriate unit tests. Updated documentation. Project: http://git-wip-us.apache.org/repos/asf/incubator-streams/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-streams/commit/c921f674 Tree: http://git-wip-us.apache.org/repos/asf/incubator-streams/tree/c921f674 Diff: http://git-wip-us.apache.org/repos/asf/incubator-streams/diff/c921f674 Branch: refs/heads/master Commit: c921f6741804f745e6d4926166bf1cf792603bbd Parents: 42d0ab3 Author: Robert Douglas <[email protected]> Authored: Tue Oct 28 17:42:39 2014 -0500 Committer: Robert Douglas <[email protected]> Committed: Tue Oct 28 17:42:39 2014 -0500 ---------------------------------------------------------------------- .../processor/GooglePlusTypeConverter.java | 5 +- .../gplus/provider/GPlusActivitySerializer.java | 77 +--------- .../gplus/provider/GPlusEventProcessor.java | 3 - .../util/GPlusActivityDeserializer.java | 129 +++++++++++++++++ .../serializer/util/GooglePlusActivityUtil.java | 143 +++++++++++++++++-- .../processor/GooglePlusActivitySerDeTest.java | 112 +++++++++++++++ .../processor/GooglePlusTypeConverterTest.java | 63 +++++--- .../resources/google_plus_activity_jsons.txt | 5 + 8 files changed, 434 insertions(+), 103 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-streams/blob/c921f674/streams-contrib/streams-provider-google/google-gplus/src/main/java/com/google/gplus/processor/GooglePlusTypeConverter.java ---------------------------------------------------------------------- diff --git a/streams-contrib/streams-provider-google/google-gplus/src/main/java/com/google/gplus/processor/GooglePlusTypeConverter.java b/streams-contrib/streams-provider-google/google-gplus/src/main/java/com/google/gplus/processor/GooglePlusTypeConverter.java index 928eec9..b4cf21d 100644 --- a/streams-contrib/streams-provider-google/google-gplus/src/main/java/com/google/gplus/processor/GooglePlusTypeConverter.java +++ b/streams-contrib/streams-provider-google/google-gplus/src/main/java/com/google/gplus/processor/GooglePlusTypeConverter.java @@ -58,10 +58,13 @@ public class GooglePlusTypeConverter implements StreamsProcessor { LOGGER.debug("{} processing {}", STREAMS_ID, item.getClass()); Activity activity = null; + if(item instanceof Person) { activity = new Activity(); - googlePlusActivityUtil.updateActivity((Person)item, activity); + } else if(item instanceof com.google.api.services.plus.model.Activity) { + activity = new Activity(); + googlePlusActivityUtil.updateActivity((com.google.api.services.plus.model.Activity)item, activity); } if(activity != null) { http://git-wip-us.apache.org/repos/asf/incubator-streams/blob/c921f674/streams-contrib/streams-provider-google/google-gplus/src/main/java/com/google/gplus/provider/GPlusActivitySerializer.java ---------------------------------------------------------------------- diff --git a/streams-contrib/streams-provider-google/google-gplus/src/main/java/com/google/gplus/provider/GPlusActivitySerializer.java b/streams-contrib/streams-provider-google/google-gplus/src/main/java/com/google/gplus/provider/GPlusActivitySerializer.java index 8eaa90a..1659ae3 100644 --- a/streams-contrib/streams-provider-google/google-gplus/src/main/java/com/google/gplus/provider/GPlusActivitySerializer.java +++ b/streams-contrib/streams-provider-google/google-gplus/src/main/java/com/google/gplus/provider/GPlusActivitySerializer.java @@ -18,42 +18,25 @@ package com.google.gplus.provider; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; -import com.fasterxml.jackson.databind.node.ObjectNode; -import com.google.common.base.Joiner; -import com.google.common.collect.Lists; +import com.google.gplus.serializer.util.GooglePlusActivityUtil; import org.apache.commons.lang.NotImplementedException; import org.apache.streams.data.ActivitySerializer; -import org.apache.streams.pojo.json.*; -import org.joda.time.DateTime; +import org.apache.streams.pojo.json.Activity; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.Date; import java.util.List; -/** -* Created with IntelliJ IDEA. -* User: mdelaet -* Date: 9/30/13 -* Time: 9:24 AM -* To change this template use File | Settings | File Templates. -*/ + public class GPlusActivitySerializer implements ActivitySerializer<com.google.api.services.plus.model.Activity> { private static final Logger LOGGER = LoggerFactory.getLogger(GPlusActivitySerializer.class); GPlusProvider provider; - ObjectMapper mapper = new ObjectMapper(); - public GPlusActivitySerializer(GPlusProvider provider) { this.provider = provider; - - mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, Boolean.FALSE); - } public GPlusActivitySerializer() { @@ -71,34 +54,9 @@ public class GPlusActivitySerializer implements ActivitySerializer<com.google.ap @Override public Activity deserialize(com.google.api.services.plus.model.Activity gplusActivity) { - - // There is totally a better way to do this - // 1) Deep copy all jackson fields that overlap - // 2) Check all objects are present - // 3) Check essential fields have values - // 4) Any that don't, set them based on other fields that are present - Activity activity = new Activity(); - activity.setId(formatId(gplusActivity.getId())); - activity.setPublished(new DateTime(gplusActivity.getPublished().getValue())); - Provider provider = new Provider(); - provider.setId("http://plus.google.com"); - provider.setDisplayName("GPlus"); - activity.setProvider(provider); - Actor actor = new Actor(); - actor.setId(gplusActivity.getActor().getId()); - actor.setDisplayName(gplusActivity.getActor().getDisplayName()); - actor.setUrl(gplusActivity.getActor().getUrl()); - activity.setActor(actor); - activity.setVerb(gplusActivity.getVerb()); - ActivityObject object = new ActivityObject(); - object.setId(gplusActivity.getObject().getId()); - object.setUrl(gplusActivity.getObject().getUrl()); - object.setContent(gplusActivity.getObject().getContent()); - activity.setTitle(gplusActivity.getTitle()); - activity.setContent(gplusActivity.getObject().getContent()); - activity.setObject(object); + GooglePlusActivityUtil.updateActivity(gplusActivity, activity); return activity; } @@ -106,31 +64,4 @@ public class GPlusActivitySerializer implements ActivitySerializer<com.google.ap public List<Activity> deserializeAll(List<com.google.api.services.plus.model.Activity> serializedList) { throw new NotImplementedException("Not currently implemented"); } - - public static Generator buildGenerator(ObjectNode event) { - return null; - } - - public static Icon getIcon(ObjectNode event) { - return null; - } - - public static Provider buildProvider(ObjectNode event) { - Provider provider = new Provider(); - provider.setId("id:providers:gmail"); - return provider; - } - - public static List<Object> getLinks(ObjectNode event) { - return null; - } - - public static String getUrls(ObjectNode event) { - return null; - } - - public static String formatId(String... idparts) { - return Joiner.on(":").join(Lists.asList("id:gmail", idparts)); - } - } http://git-wip-us.apache.org/repos/asf/incubator-streams/blob/c921f674/streams-contrib/streams-provider-google/google-gplus/src/main/java/com/google/gplus/provider/GPlusEventProcessor.java ---------------------------------------------------------------------- diff --git a/streams-contrib/streams-provider-google/google-gplus/src/main/java/com/google/gplus/provider/GPlusEventProcessor.java b/streams-contrib/streams-provider-google/google-gplus/src/main/java/com/google/gplus/provider/GPlusEventProcessor.java index 81cac86..6ed2ae1 100644 --- a/streams-contrib/streams-provider-google/google-gplus/src/main/java/com/google/gplus/provider/GPlusEventProcessor.java +++ b/streams-contrib/streams-provider-google/google-gplus/src/main/java/com/google/gplus/provider/GPlusEventProcessor.java @@ -29,9 +29,6 @@ import java.util.Queue; import java.util.Random; import java.util.concurrent.BlockingQueue; -/** - * Created by sblackmon on 12/10/13. - */ public class GPlusEventProcessor implements Runnable { private final static Logger LOGGER = LoggerFactory.getLogger(GPlusEventProcessor.class); http://git-wip-us.apache.org/repos/asf/incubator-streams/blob/c921f674/streams-contrib/streams-provider-google/google-gplus/src/main/java/com/google/gplus/serializer/util/GPlusActivityDeserializer.java ---------------------------------------------------------------------- diff --git a/streams-contrib/streams-provider-google/google-gplus/src/main/java/com/google/gplus/serializer/util/GPlusActivityDeserializer.java b/streams-contrib/streams-provider-google/google-gplus/src/main/java/com/google/gplus/serializer/util/GPlusActivityDeserializer.java new file mode 100644 index 0000000..9cb1d61 --- /dev/null +++ b/streams-contrib/streams-provider-google/google-gplus/src/main/java/com/google/gplus/serializer/util/GPlusActivityDeserializer.java @@ -0,0 +1,129 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.google.gplus.serializer.util; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.JsonNode; +import com.google.api.client.util.DateTime; +import com.google.api.client.util.Lists; +import com.google.api.services.plus.model.Activity; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.util.List; + +/** + * Custom deserializer for GooglePlus' Person model + */ +public class GPlusActivityDeserializer extends JsonDeserializer<Activity> { + private final static Logger LOGGER = LoggerFactory.getLogger(GPlusActivityDeserializer.class); + + /** + * Because the GooglePlus Activity object {@link com.google.api.services.plus.model.Activity} contains complex objects + * within its hierarchy, we have to use a custom deserializer + * + * @param jsonParser + * @param deserializationContext + * @return The deserialized {@link com.google.api.services.plus.model.Activity} object + * @throws IOException + * @throws JsonProcessingException + */ + @Override + public Activity deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException { + + JsonNode node = jsonParser.getCodec().readTree(jsonParser); + Activity activity = new Activity(); + + try { + activity.setUrl(node.get("url").asText()); + activity.setEtag(node.get("etag").asText()); + activity.setTitle(node.get("title").asText()); + activity.setPublished(DateTime.parseRfc3339(node.get("published").asText())); + activity.setUpdated(DateTime.parseRfc3339(node.get("updated").asText())); + activity.setId(node.get("id").asText()); + activity.setVerb(node.get("verb").asText()); + + Activity.Actor actor = new Activity.Actor(); + JsonNode actorNode = node.get("actor"); + + actor.setId(actorNode.get("id").asText()); + actor.setDisplayName(actorNode.get("displayName").asText()); + actor.setUrl(actorNode.get("url").asText()); + + Activity.Actor.Image image = new Activity.Actor.Image(); + JsonNode imageNode = actorNode.get("image"); + image.setUrl(imageNode.get("url").asText()); + + actor.setImage(image); + activity.setActor(actor); + + Activity.PlusObject object = new Activity.PlusObject(); + JsonNode objectNode = node.get("object"); + object.setObjectType(objectNode.get("objectType").asText()); + object.setContent(objectNode.get("content").asText()); + object.setUrl(objectNode.get("url").asText()); + + Activity.PlusObject.Replies replies = new Activity.PlusObject.Replies(); + JsonNode repliesNode = objectNode.get("replies"); + replies.setTotalItems(repliesNode.get("totalItems").asLong()); + replies.setSelfLink(repliesNode.get("selfLink").asText()); + object.setReplies(replies); + + Activity.PlusObject.Plusoners plusoners = new Activity.PlusObject.Plusoners(); + JsonNode plusonersNode = objectNode.get("plusoners"); + plusoners.setTotalItems(plusonersNode.get("totalItems").asLong()); + plusoners.setSelfLink(plusonersNode.get("selfLink").asText()); + object.setPlusoners(plusoners); + + Activity.PlusObject.Resharers resharers = new Activity.PlusObject.Resharers(); + JsonNode resharersNode = objectNode.get("resharers"); + resharers.setTotalItems(resharersNode.get("totalItems").asLong()); + resharers.setSelfLink(resharersNode.get("selfLink").asText()); + object.setResharers(resharers); + + List<Activity.PlusObject.Attachments> attachments = Lists.newArrayList(); + for (JsonNode attachmentNode : objectNode.get("attachments")) { + Activity.PlusObject.Attachments attachments1 = new Activity.PlusObject.Attachments(); + attachments1.setObjectType(attachmentNode.get("objectType").asText()); + attachments1.setDisplayName(attachmentNode.get("displayName").asText()); + attachments1.setContent(attachmentNode.get("content").asText()); + attachments1.setUrl(attachmentNode.get("url").asText()); + + Activity.PlusObject.Attachments.Image image1 = new Activity.PlusObject.Attachments.Image(); + JsonNode imageNode1 = attachmentNode.get("image"); + image1.setUrl(imageNode1.get("url").asText()); + attachments1.setImage(image1); + + attachments.add(attachments1); + } + object.setAttachments(attachments); + + activity.setObject(object); + } catch (Exception e) { + LOGGER.error("Exception while trying to deserialize activity object: {}", e); + } + + return activity; + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-streams/blob/c921f674/streams-contrib/streams-provider-google/google-gplus/src/main/java/com/google/gplus/serializer/util/GooglePlusActivityUtil.java ---------------------------------------------------------------------- diff --git a/streams-contrib/streams-provider-google/google-gplus/src/main/java/com/google/gplus/serializer/util/GooglePlusActivityUtil.java b/streams-contrib/streams-provider-google/google-gplus/src/main/java/com/google/gplus/serializer/util/GooglePlusActivityUtil.java index 3fce398..73b4b0d 100644 --- a/streams-contrib/streams-provider-google/google-gplus/src/main/java/com/google/gplus/serializer/util/GooglePlusActivityUtil.java +++ b/streams-contrib/streams-provider-google/google-gplus/src/main/java/com/google/gplus/serializer/util/GooglePlusActivityUtil.java @@ -20,25 +20,26 @@ package com.google.gplus.serializer.util; import com.google.api.services.plus.model.Person; +import org.apache.streams.pojo.json.*; +import org.apache.streams.pojo.json.Activity; +import org.joda.time.DateTime; 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.Actor; -import org.apache.streams.pojo.json.Image; -import org.apache.streams.pojo.json.Provider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.HashMap; -import java.util.Map; +import java.util.*; + +import static org.apache.streams.data.util.ActivityUtil.ensureExtensions; public class GooglePlusActivityUtil { private static final Logger LOGGER = LoggerFactory.getLogger(GooglePlusActivityUtil.class); /** - * Given a Person object and an activity, fill out the appropriate actor details + * Given a {@link com.google.api.services.plus.model.Person} object and an + * {@link org.apache.streams.pojo.json.Activity} object, fill out the appropriate details * * @param item * @param activity @@ -57,7 +58,133 @@ public class GooglePlusActivityUtil { } /** - * Extract the relevant details from the passed in Person object and build + * Given a Google Plus {@link com.google.api.services.plus.model.Activity}, + * convert that into an Activity streams formatted {@link org.apache.streams.pojo.json.Activity} + * + * @param gPlusActivity + * @param activity + */ + public static void updateActivity(com.google.api.services.plus.model.Activity gPlusActivity, Activity activity) { + activity.setActor(buildActor(gPlusActivity.getActor())); + activity.setVerb("post"); + activity.setTitle(gPlusActivity.getTitle()); + activity.setUrl(gPlusActivity.getUrl()); + activity.setProvider(getProvider()); + + if(gPlusActivity.getObject() != null) { + activity.setContent(gPlusActivity.getObject().getContent()); + } + + activity.setId(formatId(activity.getVerb(), + Optional.fromNullable( + gPlusActivity.getId()) + .orNull())); + + DateTime published = new DateTime(String.valueOf(gPlusActivity.getPublished())); + activity.setPublished(published); + + setObject(activity, gPlusActivity.getObject()); + addGPlusExtensions(activity, gPlusActivity); + } + + /** + * Add in necessary extensions from the passed in {@link com.google.api.services.plus.model.Activity} to the + * {@link org.apache.streams.pojo.json.Activity} object + * + * @param activity + * @param gPlusActivity + */ + private static void addGPlusExtensions(Activity activity, com.google.api.services.plus.model.Activity gPlusActivity) { + Map<String, Object> extensions = ensureExtensions(activity); + + com.google.api.services.plus.model.Activity.PlusObject object = gPlusActivity.getObject(); + extensions.put("googlePlus", gPlusActivity); + + if(object != null) { + com.google.api.services.plus.model.Activity.PlusObject.Plusoners plusoners = object.getPlusoners(); + if(plusoners != null) { + Map<String, Object> likes = new HashMap<>(); + likes.put("count", plusoners.getTotalItems()); + extensions.put("likes", likes); + } + + com.google.api.services.plus.model.Activity.PlusObject.Resharers resharers = object.getResharers(); + if(resharers != null) { + Map<String, Object> rebroadcasts = new HashMap<>(); + rebroadcasts.put("count", resharers.getTotalItems()); + extensions.put("rebroadcasts", rebroadcasts); + } + + extensions.put("keywords", object.getContent()); + } + } + + /** + * Set the {@link org.apache.streams.pojo.json.ActivityObject} field given the passed in + * {@link com.google.api.services.plus.model.Activity.PlusObject} + * + * @param activity + * @param object + */ + private static void setObject(Activity activity, com.google.api.services.plus.model.Activity.PlusObject object) { + if(object != null) { + ActivityObject activityObject = new ActivityObject(); + + activityObject.setContent(object.getContent()); + activityObject.setObjectType(object.getObjectType()); + + java.util.List<ActivityObject> attachmentsList = Lists.newArrayList(); + for (com.google.api.services.plus.model.Activity.PlusObject.Attachments attachments : object.getAttachments()) { + ActivityObject attach = new ActivityObject(); + + attach.setContent(attachments.getContent()); + attach.setDisplayName(attachments.getDisplayName()); + attach.setObjectType(attachments.getObjectType()); + attach.setUrl(attachments.getUrl()); + + Image image = new Image(); + com.google.api.services.plus.model.Activity.PlusObject.Attachments.Image image1 = attachments.getImage(); + + if (image1 != null) { + image.setUrl(image1.getUrl()); + attach.setImage(image); + } + + attachmentsList.add(attach); + } + + activityObject.setAttachments(attachmentsList); + + activity.setObject(activityObject); + } + } + + /** + * Given a {@link com.google.api.services.plus.model.Activity.Actor} object, return a fully fleshed + * out {@link org.apache.streams.pojo.json.Actor} object + * + * @param gPlusActor + * @return + */ + private static Actor buildActor(com.google.api.services.plus.model.Activity.Actor gPlusActor) { + Actor actor = new Actor(); + + actor.setDisplayName(gPlusActor.getDisplayName()); + actor.setId(formatId(String.valueOf(gPlusActor.getId()))); + actor.setUrl(gPlusActor.getUrl()); + + Image image = new Image(); + com.google.api.services.plus.model.Activity.Actor.Image googlePlusImage = gPlusActor.getImage(); + + if(googlePlusImage != null) { + image.setUrl(googlePlusImage.getUrl()); + } + actor.setImage(image); + + return actor; + } + /** + * Extract the relevant details from the passed in {@link com.google.api.services.plus.model.Person} object and build * an actor with them * * @param person http://git-wip-us.apache.org/repos/asf/incubator-streams/blob/c921f674/streams-contrib/streams-provider-google/google-gplus/src/test/java/com/google/gplus/processor/GooglePlusActivitySerDeTest.java ---------------------------------------------------------------------- diff --git a/streams-contrib/streams-provider-google/google-gplus/src/test/java/com/google/gplus/processor/GooglePlusActivitySerDeTest.java b/streams-contrib/streams-provider-google/google-gplus/src/test/java/com/google/gplus/processor/GooglePlusActivitySerDeTest.java new file mode 100644 index 0000000..6babea0 --- /dev/null +++ b/streams-contrib/streams-provider-google/google-gplus/src/test/java/com/google/gplus/processor/GooglePlusActivitySerDeTest.java @@ -0,0 +1,112 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.google.gplus.processor; + +import com.fasterxml.jackson.databind.*; +import com.fasterxml.jackson.databind.module.SimpleModule; +import com.google.gplus.serializer.util.GPlusActivityDeserializer; +import com.google.gplus.serializer.util.GooglePlusActivityUtil; +import org.apache.commons.lang.StringUtils; +import org.apache.streams.jackson.StreamsJacksonMapper; +import org.apache.streams.pojo.json.Activity; +import org.apache.streams.pojo.json.Actor; +import org.apache.streams.pojo.json.Provider; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +public class GooglePlusActivitySerDeTest { + private final static Logger LOGGER = LoggerFactory.getLogger(GooglePlusActivitySerDeTest.class); + private ObjectMapper objectMapper; + private GooglePlusActivityUtil googlePlusActivityUtil; + + @Before + public void setup() { + objectMapper = new StreamsJacksonMapper(); + SimpleModule simpleModule = new SimpleModule(); + simpleModule.addDeserializer(com.google.api.services.plus.model.Activity.class, new GPlusActivityDeserializer()); + objectMapper.registerModule(simpleModule); + objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + + googlePlusActivityUtil = new GooglePlusActivityUtil(); + } + + @Test + public void TestActivityObjects() { + InputStream is = GooglePlusActivitySerDeTest.class.getResourceAsStream("/google_plus_activity_jsons.txt"); + InputStreamReader isr = new InputStreamReader(is); + BufferedReader br = new BufferedReader(isr); + + try { + while (br.ready()) { + String line = br.readLine(); + if (!StringUtils.isEmpty(line)) { + LOGGER.info("raw: {}", line); + Activity activity = new Activity(); + + com.google.api.services.plus.model.Activity gPlusActivity = objectMapper.readValue(line, com.google.api.services.plus.model.Activity.class); + + googlePlusActivityUtil.updateActivity(gPlusActivity, activity); + LOGGER.info("activity: {}", activity); + + assertNotNull(activity); + assert(activity.getId().contains("id:googleplus:post")); + assertEquals(activity.getVerb(), "post"); + + Provider provider = activity.getProvider(); + assertEquals(provider.getId(), "id:providers:googleplus"); + assertEquals(provider.getDisplayName(), "GooglePlus"); + + Actor actor = activity.getActor(); + assertNotNull(actor.getImage()); + assert(actor.getId().contains("id:googleplus:")); + assertNotNull(actor.getUrl()); + + assertNotNull(activity.getPublished()); + assertNotNull(activity.getTitle()); + assertNotNull(activity.getUrl()); + + Map<String, Object> extensions = (Map<String, Object>)activity.getAdditionalProperties().get("extensions"); + assertNotNull(extensions); + assertNotNull(extensions.get("googlePlus")); + + if(activity.getContent() != null) { + assertNotNull(extensions.get("rebroadcasts")); + assertNotNull(extensions.get("keywords")); + assertNotNull(extensions.get("likes")); + assert (((Map<String, Object>) extensions.get("rebroadcasts")).containsKey("count")); + assert (((Map<String, Object>) extensions.get("likes")).containsKey("count")); + } + } + } + } catch (Exception e) { + LOGGER.error("Exception while testing serializability: {}", e); + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-streams/blob/c921f674/streams-contrib/streams-provider-google/google-gplus/src/test/java/com/google/gplus/processor/GooglePlusTypeConverterTest.java ---------------------------------------------------------------------- diff --git a/streams-contrib/streams-provider-google/google-gplus/src/test/java/com/google/gplus/processor/GooglePlusTypeConverterTest.java b/streams-contrib/streams-provider-google/google-gplus/src/test/java/com/google/gplus/processor/GooglePlusTypeConverterTest.java index 6fbdf19..a8a44c0 100644 --- a/streams-contrib/streams-provider-google/google-gplus/src/test/java/com/google/gplus/processor/GooglePlusTypeConverterTest.java +++ b/streams-contrib/streams-provider-google/google-gplus/src/test/java/com/google/gplus/processor/GooglePlusTypeConverterTest.java @@ -22,10 +22,12 @@ import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.module.SimpleModule; import com.google.api.services.plus.model.Person; +import com.google.gplus.serializer.util.GPlusActivityDeserializer; import com.google.gplus.serializer.util.GPlusPersonDeserializer; import com.google.gplus.serializer.util.GooglePlusActivityUtil; import org.apache.commons.lang.StringUtils; import org.apache.streams.core.StreamsDatum; +import org.apache.streams.exceptions.ActivitySerializerException; import org.apache.streams.jackson.StreamsJacksonMapper; import org.apache.streams.pojo.json.Activity; import org.junit.Before; @@ -34,6 +36,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.BufferedReader; +import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.List; @@ -51,6 +54,7 @@ public class GooglePlusTypeConverterTest { objectMapper = new StreamsJacksonMapper(); SimpleModule simpleModule = new SimpleModule(); simpleModule.addDeserializer(Person.class, new GPlusPersonDeserializer()); + simpleModule.addDeserializer(com.google.api.services.plus.model.Activity.class, new GPlusActivityDeserializer()); objectMapper.registerModule(simpleModule); objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); @@ -59,33 +63,56 @@ public class GooglePlusTypeConverterTest { } @Test - public void testProcess() { + public void testProcessPerson() throws IOException, ActivitySerializerException { InputStream is = GooglePlusTypeConverterTest.class.getResourceAsStream("/google_plus_person_jsons.txt"); InputStreamReader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr); - try { - while (br.ready()) { - String line = br.readLine(); - if (!StringUtils.isEmpty(line)) { - LOGGER.info("raw: {}", line); - Activity activity = new Activity(); + while (br.ready()) { + String line = br.readLine(); + if (!StringUtils.isEmpty(line)) { + LOGGER.info("raw: {}", line); + Activity activity = new Activity(); - Person person = objectMapper.readValue(line, Person.class); - StreamsDatum streamsDatum = new StreamsDatum(person); + Person person = objectMapper.readValue(line, Person.class); + StreamsDatum streamsDatum = new StreamsDatum(person); - assertNotNull(streamsDatum.getDocument()); + assertNotNull(streamsDatum.getDocument()); - List<StreamsDatum> retList = googlePlusTypeConverter.process(streamsDatum); - GooglePlusActivityUtil.updateActivity(person, activity); + List<StreamsDatum> retList = googlePlusTypeConverter.process(streamsDatum); + GooglePlusActivityUtil.updateActivity(person, activity); - assertEquals(retList.size(), 1); - assert(retList.get(0).getDocument() instanceof Activity); - assertEquals(activity, retList.get(0).getDocument()); - } + assertEquals(retList.size(), 1); + assert(retList.get(0).getDocument() instanceof Activity); + assertEquals(activity, retList.get(0).getDocument()); + } + } + } + + @Test + public void testProcessActivity() throws IOException, ActivitySerializerException{ + InputStream is = GooglePlusTypeConverterTest.class.getResourceAsStream("/google_plus_activity_jsons.txt"); + InputStreamReader isr = new InputStreamReader(is); + BufferedReader br = new BufferedReader(isr); + + while (br.ready()) { + String line = br.readLine(); + if (!StringUtils.isEmpty(line)) { + LOGGER.info("raw: {}", line); + Activity activity = new Activity(); + + com.google.api.services.plus.model.Activity gPlusActivity = objectMapper.readValue(line, com.google.api.services.plus.model.Activity.class); + StreamsDatum streamsDatum = new StreamsDatum(gPlusActivity); + + assertNotNull(streamsDatum.getDocument()); + + List<StreamsDatum> retList = googlePlusTypeConverter.process(streamsDatum); + GooglePlusActivityUtil.updateActivity(gPlusActivity, activity); + + assertEquals(retList.size(), 1); + assert(retList.get(0).getDocument() instanceof Activity); + assertEquals(activity, retList.get(0).getDocument()); } - } catch (Exception e) { - LOGGER.error("Exception testing the GooglePlusTypeConverter: {}", e); } } http://git-wip-us.apache.org/repos/asf/incubator-streams/blob/c921f674/streams-contrib/streams-provider-google/google-gplus/src/test/resources/google_plus_activity_jsons.txt ---------------------------------------------------------------------- diff --git a/streams-contrib/streams-provider-google/google-gplus/src/test/resources/google_plus_activity_jsons.txt b/streams-contrib/streams-provider-google/google-gplus/src/test/resources/google_plus_activity_jsons.txt new file mode 100644 index 0000000..079251b --- /dev/null +++ b/streams-contrib/streams-provider-google/google-gplus/src/test/resources/google_plus_activity_jsons.txt @@ -0,0 +1,5 @@ +{ "kind": "plus#activity", "etag": "\"Vea_b94Y77GDGgRK7gFNPnolKQw/NWJTEjOXM_BKuKTTfM8bvWt5c0E\"", "title": "", "published": "2014-10-08T15:53:52.703Z", "updated": "2014-10-08T15:53:52.703Z", "id": "z130ipoawvulthecp22otlwonv2gutmnm", "url": "https://plus.google.com/118376908737486995861/posts/4Zr85DnfdsV", "actor": { "id": "118376908737486995861", "displayName": "Steve Blackmon", "url": "https://plus.google.com/118376908737486995861", "image": { "url": "https://lh3.googleusercontent.com/-XdUIqdMkCWA/AAAAAAAAAAI/AAAAAAAAAAA/4252rscbv5M/photo.jpg?sz=50" } }, "verb": "post", "object": { "objectType": "note", "content": "", "url": "https://plus.google.com/118376908737486995861/posts/4Zr85DnfdsV", "replies": { "totalItems": 0, "selfLink": "https://content.googleapis.com/plus/v1/activities/z130ipoawvulthecp22otlwonv2gutmnm/comments" }, "plusoners": { "totalItems": 0, "selfLink": "https://content.googleapis.com/plus/v1/activities/z130ipoawvulthecp22otlwonv2gutmnm/people/plusoners" }, "resh arers": { "totalItems": 0, "selfLink": "https://content.googleapis.com/plus/v1/activities/z130ipoawvulthecp22otlwonv2gutmnm/people/resharers" }, "attachments": [ { "objectType": "article", "displayName": "Diction in Software Development (i.e. Don't be a d1ck!)", "content": "Over the years, I've come to realize how important diction is in software development (and life in general). It may mean the difference between a 15 minute meeting where everyone nods their heads, and a day long battle of eg...", "url": "http://brianoneill.blogspot.com/2014/10/diction-in-software-development-ie-dont.html", "image": { "url": "https://lh3.googleusercontent.com/proxy/3BTfJNati40qZ5zdoAK1Zc-udwAMRqYbPX6huwDSHU3HXW9ZlJ2OIaWtoAG3ta1rSy5X=w120-h120", "type": "image/jpeg", "height": 120, "width": 120 }, "fullImage": { "url": "http://www.mindrain.com/fishing.jpg", "type": "image/jpeg" } } ] }, "provider": { "title": "Google+" }, "access": { "kind": "plus#acl", "description": "Public", "items": [ { "type": "public" } ] } } +{ "kind": "plus#activity", "etag": "\"Vea_b94Y77GDGgRK7gFNPnolKQw/ZRTkaAm2NktNymi4G6PNueqVXV0\"", "title": "I have almost all positive thoughts on this phone. Minor concerns on looks (not that important I know...", "published": "2014-10-28T16:27:31.774Z", "updated": "2014-10-28T16:27:31.774Z", "id": "z12pwxry0qapdj5wr04cedb4bs20ilg55zk0k", "url": "https://plus.google.com/116771159471120611293/posts/SHeUgMcXLpz", "actor": { "id": "116771159471120611293", "displayName": "Matt Neithercott", "url": "https://plus.google.com/116771159471120611293", "image": { "url": "https://lh6.googleusercontent.com/-C0fiZBxdvw0/AAAAAAAAAAI/AAAAAAAAJ5k/K4pgR3_-_ms/photo.jpg?sz=50" } }, "verb": "post", "object": { "objectType": "note", "content": "I have almost all positive thoughts on this phone. Minor concerns on looks (not that important I know, but I like the Moto X/Nexus 6 look) and more importantly I'm wondering if they will be as good with the Droid line with Android updates... those seem to ha ve lagged a bit more for this line in the past. Mainly I want Android Lollipop. <br /><br />Over all this phone looks like a beast and easily one of the best phones on the market. Oh, can we talk about the battery?!? \ufeff", "url": "https://plus.google.com/116771159471120611293/posts/SHeUgMcXLpz", "replies": { "totalItems": 2, "selfLink": "https://content.googleapis.com/plus/v1/activities/z12pwxry0qapdj5wr04cedb4bs20ilg55zk0k/comments" }, "plusoners": { "totalItems": 3, "selfLink": "https://content.googleapis.com/plus/v1/activities/z12pwxry0qapdj5wr04cedb4bs20ilg55zk0k/people/plusoners" }, "resharers": { "totalItems": 0, "selfLink": "https://content.googleapis.com/plus/v1/activities/z12pwxry0qapdj5wr04cedb4bs20ilg55zk0k/people/resharers" }, "attachments": [ { "objectType": "video", "displayName": "Motorola Droid Turbo hands-on", "content": "Motorola's partnership with Verizon continues with the Droid Turbo, a unique smartphone exclusive to Verizon Wireless. Subscribe: http://www.yo utube.com/subs...", "url": "http://www.youtube.com/attribution_link?a=k_fPNZUvh50&u=/watch?v%3DVo3jj4GvEG0%26feature%3Dshare", "image": { "url": "https://lh3.googleusercontent.com/proxy/1MR0ExMhC2wxZj_g0dMnChwzNkg9-eC9N3VVfdfsBAuQZ1Li9U-kZoqPJ8N1YD452vASBH6_6Meh90GyrK1cSdXqZw=w506-h284-n", "type": "image/jpeg", "height": 284, "width": 506 }, "embed": { "url": "https://www.youtube.com/embed/Vo3jj4GvEG0", "type": "application/x-shockwave-flash" } } ] }, "provider": { "title": "Google+" }, "access": { "kind": "plus#acl", "description": "Public", "items": [ { "type": "public" } ] } } +{ "kind": "plus#activity", "etag": "\"Vea_b94Y77GDGgRK7gFNPnolKQw/U-nMv_RITNj07a6rnKIZ4z6Dk4k\"", "title": "Truth hurts...", "published": "2014-10-28T15:36:47.423Z", "updated": "2014-10-28T15:36:47.423Z", "id": "z12nwnsbkoivjjwvt22mdt1y0k3of1djw04", "url": "https://plus.google.com/116771159471120611293/posts/MPe25pfK4hU", "actor": { "id": "116771159471120611293", "displayName": "Matt Neithercott", "url": "https://plus.google.com/116771159471120611293", "image": { "url": "https://lh6.googleusercontent.com/-C0fiZBxdvw0/AAAAAAAAAAI/AAAAAAAAJ5k/K4pgR3_-_ms/photo.jpg?sz=50" } }, "verb": "share", "object": { "objectType": "activity", "id": "z13tv1wasli0ypjih04cfpk4dti3yrhjawo0k", "actor": { "id": "109198125327200245055", "displayName": "Stephani Renteria", "url": "https://plus.google.com/109198125327200245055", "image": { "url": "https://lh4.googleusercontent.com/-WJeeS-ny6Ac/AAAAAAAAAAI/AAAAAAAAB5I/zdPCWdOGQuQ/photo.jpg?sz=50" } }, "content": "Truth hurts...\ufeff", "url": "https://plus. google.com/109198125327200245055/posts/bNSgdkCPmbG", "replies": { "totalItems": 0, "selfLink": "https://content.googleapis.com/plus/v1/activities/z12nwnsbkoivjjwvt22mdt1y0k3of1djw04/comments" }, "plusoners": { "totalItems": 2, "selfLink": "https://content.googleapis.com/plus/v1/activities/z12nwnsbkoivjjwvt22mdt1y0k3of1djw04/people/plusoners" }, "resharers": { "totalItems": 1, "selfLink": "https://content.googleapis.com/plus/v1/activities/z12nwnsbkoivjjwvt22mdt1y0k3of1djw04/people/resharers" }, "attachments": [ { "objectType": "photo", "displayName": "Truth hurts...", "id": "109198125327200245055.6075076220744786466", "content": "16/9/14 - 1", "url": "https://plus.google.com/photos/109198125327200245055/albums/6075076218164640065/6075076220744786466", "image": { "url": "https://lh4.googleusercontent.com/-WjV4kLfSUjo/VE8BorjqYiI/AAAAAAAAC2g/D46Yfy7xO_U/w506-h750/14%2B-%2B1", "type": "image/jpeg" }, "fullImage": { "url": "https://lh4.googleusercontent.com/-WjV4kLfSUjo/VE8BorjqYiI/AAAAA AAAC2g/D46Yfy7xO_U/w476-h626/14%2B-%2B1", "type": "image/jpeg", "height": 626, "width": 476 } } ] }, "provider": { "title": "Reshared Post" }, "access": { "kind": "plus#acl", "description": "Public", "items": [ { "type": "public" } ] } } +{ "kind": "plus#activity", "etag": "\"Vea_b94Y77GDGgRK7gFNPnolKQw/Syi_EzWY7OiXcsP6iOpMGjnQnFk\"", "title": "The Droid Turbo might be hard to say no to... ", "published": "2014-10-28T02:44:40.380Z", "updated": "2014-10-28T02:44:40.380Z", "id": "z12bzbxrmlzoxvzl222mdt1y0k3of1djw04", "url": "https://plus.google.com/116771159471120611293/posts/6rSySsYPAVL", "actor": { "id": "116771159471120611293", "displayName": "Matt Neithercott", "url": "https://plus.google.com/116771159471120611293", "image": { "url": "https://lh6.googleusercontent.com/-C0fiZBxdvw0/AAAAAAAAAAI/AAAAAAAAJ5k/K4pgR3_-_ms/photo.jpg?sz=50" } }, "verb": "post", "object": { "objectType": "note", "content": "The Droid Turbo might be hard to say no to... \ufeff", "url": "https://plus.google.com/116771159471120611293/posts/6rSySsYPAVL", "replies": { "totalItems": 4, "selfLink": "https://content.googleapis.com/plus/v1/activities/z12bzbxrmlzoxvzl222mdt1y0k3of1djw04/comments" }, "plusoners": { "totalItems": 1, "selfLink": "https: //content.googleapis.com/plus/v1/activities/z12bzbxrmlzoxvzl222mdt1y0k3of1djw04/people/plusoners" }, "resharers": { "totalItems": 0, "selfLink": "https://content.googleapis.com/plus/v1/activities/z12bzbxrmlzoxvzl222mdt1y0k3of1djw04/people/resharers" } }, "provider": { "title": "Google+" }, "access": { "kind": "plus#acl", "description": "Public", "items": [ { "type": "public" } ] } }, { "kind": "plus#activity", "etag": "\"Vea_b94Y77GDGgRK7gFNPnolKQw/rQfbBZAN11iZKWdIm2RX3g2kIys\"", "title": "", "published": "2014-10-28T01:13:08.582Z", "updated": "2014-10-28T01:13:08.582Z", "id": "z12itxgadmqsfpjut22mdt1y0k3of1djw04", "url": "https://plus.google.com/116771159471120611293/posts/FyDp4gDoxya", "actor": { "id": "116771159471120611293", "displayName": "Matt Neithercott", "url": "https://plus.google.com/116771159471120611293", "image": { "url": "https://lh6.googleusercontent.com/-C0fiZBxdvw0/AAAAAAAAAAI/AAAAAAAAJ5k/K4pgR3_-_ms/photo.jpg?sz=50" } }, "verb": "post", "object": { "objectType": " note", "content": "", "url": "https://plus.google.com/116771159471120611293/posts/FyDp4gDoxya", "replies": { "totalItems": 0, "selfLink": "https://content.googleapis.com/plus/v1/activities/z12itxgadmqsfpjut22mdt1y0k3of1djw04/comments" }, "plusoners": { "totalItems": 2, "selfLink": "https://content.googleapis.com/plus/v1/activities/z12itxgadmqsfpjut22mdt1y0k3of1djw04/people/plusoners" }, "resharers": { "totalItems": 0, "selfLink": "https://content.googleapis.com/plus/v1/activities/z12itxgadmqsfpjut22mdt1y0k3of1djw04/people/resharers" }, "attachments": [ { "objectType": "article", "displayName": "iPhone fans and Android fans finally find something they hate more than each other", "content": "It looks like Walmart, CVS and other merchants have stepped into a major hornets' nest. In the wake of news that several major retailers are turning off NFC payment sensors in their stores because ...", "url": "http://bgr.com/2014/10/27/apple-pay-google-wallet-vs-currentc/", "image": { "url": "htt ps://lh6.googleusercontent.com/proxy/6iMaeS_62HVihJjR77NQXujzcoGwSkSZUsafEp3DJiSyyvp7VyT5KU8-_o6zL3DpXGAjbvAJv3GnEIyKG6gYGg1SU6eCfbYX=w506-h303-p", "type": "image/jpeg", "height": 303, "width": 506 }, "fullImage": { "url": "http://cdn.bgr.com/2012/09/androidios-e1346785636929.jpg", "type": "image/jpeg" } } ] }, "provider": { "title": "Google+" }, "access": { "kind": "plus#acl", "description": "Public", "items": [ { "type": "public" } ] } } +{ "kind": "plus#activity", "etag": "\"Vea_b94Y77GDGgRK7gFNPnolKQw/v1-6aVSBGT4qiStMoz7f2_AN2fM\"", "title": "", "published": "2014-10-27T06:26:33.927Z", "updated": "2014-10-27T06:26:33.927Z", "id": "z13twrlznpvtzz52w22mdt1y0k3of1djw04", "url": "https://plus.google.com/116771159471120611293/posts/GR7CGR8N5VL", "actor": { "id": "116771159471120611293", "displayName": "Matt Neithercott", "url": "https://plus.google.com/116771159471120611293", "image": { "url": "https://lh6.googleusercontent.com/-C0fiZBxdvw0/AAAAAAAAAAI/AAAAAAAAJ5k/K4pgR3_-_ms/photo.jpg?sz=50" } }, "verb": "share", "object": { "objectType": "activity", "id": "z13zgvtiurjgfti1v234iflghvq2c1dge04", "actor": { "id": "104954254300557350002", "displayName": "Adam Balm", "url": "https://plus.google.com/104954254300557350002", "image": { "url": "https://lh4.googleusercontent.com/-SO1scj4p2LA/AAAAAAAAAAI/AAAAAAAAI-s/efA9LBVe144/photo.jpg?sz=50" } }, "content": "", "url": "https://plus.google.com/104954254300557350002/posts/AwewX htn7ws", "replies": { "totalItems": 0, "selfLink": "https://content.googleapis.com/plus/v1/activities/z13twrlznpvtzz52w22mdt1y0k3of1djw04/comments" }, "plusoners": { "totalItems": 9, "selfLink": "https://content.googleapis.com/plus/v1/activities/z13twrlznpvtzz52w22mdt1y0k3of1djw04/people/plusoners" }, "resharers": { "totalItems": 0, "selfLink": "https://content.googleapis.com/plus/v1/activities/z13twrlznpvtzz52w22mdt1y0k3of1djw04/people/resharers" }, "attachments": [ { "objectType": "photo", "id": "104954254300557350002.6074732746360957410", "content": "26/10/2014 - 1", "url": "https://plus.google.com/photos/104954254300557350002/albums/6074732747132702225/6074732746360957410", "image": { "url": "https://lh4.googleusercontent.com/-oO3fnARlDm0/VE3JP1xHKeI/AAAAAAAAeCY/-X2jzc6HruA/w506-h750/2014%2B-%2B1", "type": "image/jpeg" }, "fullImage": { "url": "https://lh4.googleusercontent.com/-oO3fnARlDm0/VE3JP1xHKeI/AAAAAAAAeCY/-X2jzc6HruA/w600-h1141/2014%2B-%2B1", "type": "image/jpeg", "heig ht": 1141, "width": 600 } } ] }, "annotation": "Truth ð", "provider": { "title": "Reshared Post" }, "access": { "kind": "plus#acl", "description": "Public", "items": [ { "type": "public" } ] } } \ No newline at end of file
