/*
* 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
*
* 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 org.apache.streams.facebook.serializer;
import org.apache.streams.data.util.ActivityUtil;
import org.apache.streams.exceptions.ActivitySerializerException;
import org.apache.streams.facebook.Cover;
import org.apache.streams.facebook.Datum;
import org.apache.streams.facebook.Like;
import org.apache.streams.facebook.Location;
import org.apache.streams.facebook.Page;
import org.apache.streams.facebook.Place;
import org.apache.streams.facebook.Post;
import org.apache.streams.facebook.To;
import org.apache.streams.jackson.StreamsJacksonMapper;
import org.apache.streams.pojo.extensions.ExtensionUtil;
import org.apache.streams.pojo.json.Activity;
import org.apache.streams.pojo.json.ActivityObject;
import org.apache.streams.pojo.json.Image;
import org.apache.streams.pojo.json.Provider;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* FacebookActivityUtil helps convert facebook data to activity formats.
*/
public class FacebookActivityUtil {
private static final Logger LOGGER = LoggerFactory.getLogger(FacebookActivityUtil.class);
/**
* Updates the given Activity object with the values from the Page.
* @param page the object to use as the source
* @param activity the target of the updates. Will receive all values from the Page.
* @throws ActivitySerializerException
*/
public static void updateActivity(Page page, Activity activity) throws ActivitySerializerException {
activity.setActor(buildActor(page));
activity.setId(null);
activity.setProvider(getProvider());
}
/**
* Updates the given Activity object with the values from the Post.
* @param post post
* @param activity activity
* @throws ActivitySerializerException
*/
public static void updateActivity(Post post, Activity activity) throws ActivitySerializerException {
activity.setActor(buildActor(post));
activity.setId(formatId(post.getId()));
activity.setProvider(getProvider());
activity.setUpdated(post.getUpdatedTime());
activity.setPublished(post.getCreatedTime());
if (post.getLink() != null && post.getLink().length() > 0) {
List<String> links = new ArrayList<>();
links.add(post.getLink());
activity.setLinks(links);
}
activity.setContent(post.getMessage());
activity.setVerb("post");
activity.setObject(buildObject(post));
buildExtensions(activity, post);
}
/**
* Builds out the {@link ActivityObject} from the given {@link Post}.
* @param post
* @return {@link ActivityObject}
*/
public static ActivityObject buildObject(Post post) {
ActivityObject activityObject = new ActivityObject();
try {
activityObject.setContent(post.getMessage());
activityObject.setPublished(post.getCreatedTime());
activityObject.setUpdated(post.getUpdatedTime());
activityObject.setDisplayName(post.getFrom().getName());
activityObject.setId(formatId(post.getId()));
activityObject.setObjectType(post.getType());
activityObject.setUrl(post.getLink());
if (activityObject.getObjectType().equals("photo")) {
Image image = new Image();
image.setUrl(activityObject.getUrl());
activityObject.setImage(image);
}
} catch (Exception ex) {
LOGGER.error("Exception while trying to build Activity object for post: {}, exception: {}", post, ex);
}
return activityObject;
}
/**
* Gets the common facebook {@link Provider} object.
* @return a provider object representing Facebook
*/
public static Provider getProvider() {
Provider provider = new Provider();
provider.setId("id:providers:facebook");
provider.setDisplayName("Facebook");
return provider;
}
/**
* Builds the activity {@link ActivityObject} actor from the Page.
* @param page the object to use as the source
* @return a valid Actor populated from the Page
*/
public static ActivityObject buildActor(Page page) {
ActivityObject actor = new ActivityObject();
actor.setId(formatId(
Optional.ofNullable(Optional.ofNullable(page.getId())
.orElseGet(Optional.of(page.getId())::get)).orElse(null)
));
actor.setDisplayName(page.getName());
actor.setAdditionalProperty("handle", page.getUsername());
actor.setSummary(page.getAbout());
if (page.getLink() != null) {
actor.setUrl(page.getLink());
}
Image profileImage = new Image();
Cover cover = page.getCover();
if (cover != null) {
profileImage.setUrl(cover.getSource());
}
actor.setImage(profileImage);
buildExtensions(actor, page);
return actor;
}
/**
* Builds an {@link ActivityObject} object from the {@link Post}.
* @param post post
* @return {@link ActivityObject}
*/
public static ActivityObject buildActor(Post post) {
ActivityObject actor = new ActivityObject();
try {
actor.setId(formatId(
Optional.ofNullable(Optional.ofNullable(post.getFrom().getId())
.orElseGet(Optional.of(post.getFrom().getId())::get)).orElse(null)
));
actor.setDisplayName(post.getFrom().getName());
actor.setAdditionalProperty("handle", post.getFrom().getName());
} catch (Exception ex) {
LOGGER.error("Exception trying to build actor for Post: {}, {}", post, ex);
}
return actor;
}
/**
* Builds the actor extensions given the page object.
* @param actor actor
* @param page page
*/
public static void buildExtensions(ActivityObject actor, Page page) {
Map<String, Object> extensions = new HashMap<>();
Location location = page.getLocation();
if (location != null) {
extensions.put("location", page.getLocation().toString());
}
extensions.put("favorites", page.getTalkingAboutCount());
extensions.put("followers", page.getFanCount());
extensions.put("facebook", page);
actor.setAdditionalProperty("extensions", extensions);
}
/**
* Fills out the extensions attribute of the passed in {@link Activity}
* @param activity
* @param post
*/
@SuppressWarnings("unchecked")
public static void buildExtensions(Activity activity, Post post) {
ObjectMapper mapper = StreamsJacksonMapper.getInstance();
Map<String, Object> extensions = ExtensionUtil.getInstance().ensureExtensions(activity);
if(post.getLikes() != null && post.getLikes().size() > 0) {
Map<String, Object> likes = new HashMap<>();
Like like = post.getLikes().get(0);
if(like.getAdditionalProperties().containsKey("data")) {
extensions.put("likes", likes);
}
}
if(post.getShares() != null) {
Map<String, Object> shares = new HashMap<>();
shares.put("count", ((Map<String, Object>)post.getShares()).get("count"));
extensions.put("rebroadcasts", shares);
}
if(post.getTo() != null) {
To to = post.getTo();
List<Datum> data = to.getData();
extensions.put("user_mentions", new ArrayList<>());
for(Datum d : data) {
Map<String, String> mention = new HashMap<>();
mention.put("id", d.getId());
mention.put("displayName", d.getName());
mention.put("handle", d.getName());
((List<Map<String,String>>)extensions.get("user_mentions")).add(mention);
}
}
if(post.getPlace() != null) {
Place place = post.getPlace();
if(place.getAdditionalProperties().containsKey("location")) {
extensions.put(ActivityUtil.LOCATION_EXTENSION, place.getAdditionalProperties().get("location"));
}
}
extensions.put("facebook", mapper.convertValue(post, ObjectNode.class));
}
/**
* Formats the ID to conform with the Apache Streams activity ID convention
* @param idparts the parts of the ID to join
* @return a valid Activity ID in format "id:facebook:part1:part2:...partN"
*/
public static String formatId(String... idparts) {
return String.join(":",
Stream.concat(Arrays.stream(new String[]{"id:facebook"}), Arrays.stream(idparts)).collect(Collectors.toList()));
}
}