Java tutorial
/* * 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 com.facebook.api; import com.fasterxml.jackson.core.JsonGenerationException; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.deser.std.StdDeserializer; import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.databind.ser.std.StdSerializer; import com.fasterxml.jackson.datatype.joda.JodaModule; import org.apache.commons.lang.NotImplementedException; import org.apache.streams.data.ActivitySerializer; import org.apache.streams.exceptions.ActivitySerializerException; import org.apache.streams.pojo.json.*; import org.joda.time.DateTime; import org.joda.time.format.DateTimeFormat; import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.ISODateTimeFormat; import java.io.IOException; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.*; import java.util.List; import static org.apache.streams.data.util.ActivityUtil.*; import static org.apache.streams.data.util.JsonUtil.jsonToJsonNode; /** * Serializes activity posts * sblackmon: This class needs a rewrite */ public class FacebookPostActivitySerializer implements ActivitySerializer<String> { public static final DateTimeFormatter FACEBOOK_FORMAT = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ssZ"); public static final DateTimeFormatter ACTIVITY_FORMAT = ISODateTimeFormat.basicDateTime(); public static final String PROVIDER_NAME = "facebook"; public static ObjectMapper mapper; static { mapper = new ObjectMapper(); mapper.registerModule(new JodaModule()); mapper.disable(com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); mapper.registerModule(new SimpleModule() { { addSerializer(DateTime.class, new StdSerializer<DateTime>(DateTime.class) { @Override public void serialize(DateTime value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonGenerationException { jgen.writeString(ACTIVITY_FORMAT.print(value)); } }); addDeserializer(DateTime.class, new StdDeserializer<DateTime>(DateTime.class) { @Override public DateTime deserialize(JsonParser jpar, DeserializationContext context) throws IOException, JsonProcessingException { return FACEBOOK_FORMAT.parseDateTime(jpar.getValueAsString()); } }); } }); } @Override public String serializationFormat() { return "facebook_post_json_v1"; } @Override public String serialize(Activity deserialized) { throw new UnsupportedOperationException(); } @Override public Activity deserialize(String serialized) throws ActivitySerializerException { //Deserialize the JSON string into a Jackson JsonNode JsonNode node = jsonToJsonNode(serialized); Map.Entry<String, JsonNode> field = getObjectType(node); Activity activity = new Activity(); setProvider(activity); setObjectType(field, activity); parseObject(activity, field.getValue()); fixObjectId(activity); fixContentFromSummary(activity); return activity; } @Override public java.util.List<Activity> deserializeAll(List<String> serializedList) { throw new NotImplementedException("Not currently supported by this deserializer"); } private void fixContentFromSummary(Activity activity) { //we MUST have a content field set, so choose the best option if (activity.getContent() == null) { activity.setContent(activity.getAdditionalProperties().containsKey("summary") ? (String) activity.getAdditionalProperties().get("summary") : activity.getObject().getSummary()); } } private void fixObjectId(Activity activity) { //An artifact of schema generation, the default value is {link} if (activity.getObject().getId().equals("{link}")) { activity.getObject().setId(null); } } private void setObjectType(Map.Entry<String, JsonNode> field, Activity activity) { ActivityObject object = new ActivityObject(); activity.setObject(object); object.setObjectType(field.getKey()); } private void setProvider(Activity activity) { Provider provider = new Provider(); provider.setId(getProviderId(PROVIDER_NAME)); provider.setDisplayName(PROVIDER_NAME); activity.setProvider(provider); } private Map.Entry<String, JsonNode> getObjectType(JsonNode node) { Iterator<Map.Entry<String, JsonNode>> fields = node.fields(); ensureMoreFields(fields); Map.Entry<String, JsonNode> field = fields.next(); ensureNoMoreFields(fields); return field; } private void parseObject(Activity activity, JsonNode jsonNode) throws ActivitySerializerException { for (Iterator<Map.Entry<String, JsonNode>> fields = jsonNode.fields(); fields.hasNext();) { Map.Entry<String, JsonNode> field = fields.next(); String key = field.getKey(); JsonNode value = field.getValue(); mapField(activity, key, value); } } private void mapField(Activity activity, String name, JsonNode value) throws ActivitySerializerException { if ("created_time".equals(name)) { activity.setPublished(parseDate(value)); } else if ("application".equals(name)) { addGenerator(activity, value); } else if ("caption".equals(name)) { addSummary(activity, value); } else if ("comments".equals(name)) { addAttachments(activity, value); } else if ("description".equals(name)) { addObjectSummary(activity, value); } else if ("from".equals(name)) { addActor(activity, value); } else if ("icon".equals(name)) { addIcon(activity, value); } else if ("id".equals(name)) { addId(activity, value); } else if ("is_hidden".equals(name)) { addObjectHiddenExtension(activity, value); } else if ("like_count".equals(name)) { addLikeExtension(activity, value); } else if ("link".equals(name)) { addObjectLink(activity, value); } else if ("message".equals(name)) { activity.setContent(value.asText()); } else if ("name".equals(name)) { addObjectName(activity, value); } else if ("object_id".equals(name)) { addObjectId(activity, value); } else if ("picture".equals(name)) { addObjectImage(activity, value); } else if ("place".equals(name)) { addLocationExtension(activity, value); } else if ("shares".equals(name)) { addRebroadcastExtension(activity, value); } else if ("source".equals(name)) { addObjectLink(activity, value); } else if ("story".equals(name)) { addTitle(activity, value); } else if ("updated_time".equals(name)) { addObjectUpdated(activity, value); } } private void addObjectUpdated(Activity activity, JsonNode value) { try { activity.getObject().setUpdated(parseDate(value)); } catch (ActivitySerializerException e) { // losing this field is ok } } private void addSummary(Activity activity, JsonNode value) { activity.setAdditionalProperty("summary", value.asText()); } private void addTitle(Activity activity, JsonNode value) { activity.setTitle(value.asText()); } private void addLikeExtension(Activity activity, JsonNode value) { Map<String, Object> extensions = ensureExtensions(activity); extensions.put(LIKES_EXTENSION, value.asInt()); } private void addLocationExtension(Activity activity, JsonNode value) { Map<String, Object> extensions = ensureExtensions(activity); if (value.has("location")) { Map<String, Object> location = new HashMap<String, Object>(); JsonNode fbLocation = value.get("location"); if (fbLocation.has("country")) { location.put(LOCATION_EXTENSION_COUNTRY, fbLocation.get("country")); } if (fbLocation.has("latitude") && fbLocation.has("longitude")) { location.put(LOCATION_EXTENSION_COORDINATES, String.format("%s,%s", fbLocation.get("longitude"), fbLocation.get("latitude"))); } extensions.put(LOCATION_EXTENSION, location); } } private void addObjectImage(Activity activity, JsonNode value) { Image image = new Image(); image.setUrl(value.asText()); activity.getObject().setImage(image); } private void addObjectId(Activity activity, JsonNode value) { activity.getObject().setId(getObjectId("facebook", activity.getObject().getObjectType(), value.asText())); } private void addObjectName(Activity activity, JsonNode value) { activity.getObject().setDisplayName(value.asText()); } private void addId(Activity activity, JsonNode value) { activity.setId(getActivityId(PROVIDER_NAME, value.asText())); } private void addObjectLink(Activity activity, JsonNode value) { activity.getObject().setUrl(value.asText()); } private void addRebroadcastExtension(Activity activity, JsonNode value) { Map<String, Object> extensions = ensureExtensions(activity); if (value.has("count")) { extensions.put(REBROADCAST_EXTENSION, value.get("count").asInt()); } } private void addObjectHiddenExtension(Activity activity, JsonNode value) { Map<String, Object> extensions = ensureExtensions(activity); extensions.put("hidden", value.asBoolean()); } private void addIcon(Activity activity, JsonNode value) { Icon icon = new Icon(); //Apparently the Icon didn't map from the schema very well icon.setAdditionalProperty("url", value.asText()); activity.setIcon(icon); } private void addActor(Activity activity, JsonNode value) { Actor actor = new Actor(); if (value.has("name")) { actor.setDisplayName(value.get("name").asText()); } if (value.has("id")) { actor.setId(getPersonId(PROVIDER_NAME, value.get("id").asText())); } activity.setActor(actor); } private void addObjectSummary(Activity activity, JsonNode value) { activity.getObject().setSummary(value.asText()); } private void addGenerator(Activity activity, JsonNode value) { Generator generator = new Generator(); if (value.has("id")) { generator.setId(getObjectId(PROVIDER_NAME, "generator", value.get("id").asText())); } if (value.has("name")) { generator.setDisplayName(value.get("name").asText()); } if (value.has("namespace")) { generator.setSummary(value.get("namespace").asText()); } activity.setGenerator(generator); } private void addAttachments(Activity activity, JsonNode value) { //No direct mapping at this time } private static void ensureMoreFields(Iterator<Map.Entry<String, JsonNode>> fields) { if (!fields.hasNext()) { throw new IllegalStateException("Facebook activity must have one and only one root element"); } } private static void ensureNoMoreFields(Iterator<Map.Entry<String, JsonNode>> fields) { if (fields.hasNext()) { throw new IllegalStateException("Facebook activity must have one and only one root element"); } } private static DateTime parseDate(JsonNode value) throws ActivitySerializerException { try { return FACEBOOK_FORMAT.parseDateTime(value.asText()); } catch (Exception e) { throw new ActivitySerializerException("Unable to parse date " + value.asText()); } } }