package com.collabinate.server.activitystreams; import java.util.UUID; import org.joda.time.DateTime; import org.joda.time.format.ISODateTimeFormat; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParseException; import com.google.gson.JsonParser; /** * Represents an Activity Streams object serialization. * http://activitystrea.ms/specs/json/1.0/#object * * @author mafuba * */ public class ActivityStreamsObject { /** * The internal representation of the object as JSON. */ protected JsonObject jsonObject; /** * Default constructor for an empty object. */ public ActivityStreamsObject() { jsonObject = new JsonObject(); ensureDefaultFields(); } /** * Constructs a new ActivityStreamsObject from the given string. If the * string contains a JSON object, it will be used as the base of the object. * If the string is not a valid JSON object, it will instead be added to the * content property of a new ActivityStreams JSON object representation. * * @param content */ public ActivityStreamsObject(String content) { if (null != content) { JsonParser parser = new JsonParser(); try { JsonElement element = parser.parse(content); if (element.isJsonObject()) jsonObject = element.getAsJsonObject(); } catch (JsonParseException e) { } } if (null == jsonObject) { jsonObject = new JsonObject(); setContent(content); } ensureDefaultFields(); } /** * Provides a means of ensuring that all required fields for the object * are in place. Called in the constructor. By default nothing is required * in the base ActivityStreamsObject. */ protected void ensureDefaultFields() { } /** * Gets a natural-language description of the object encoded as a single * JSON String containing HTML markup. Visual elements such as thumbnail * images MAY be included. An object MAY contain a content property. * * @return content a JSON [RFC4627] String containing the content. */ public String getContent() { return getStringValue(CONTENT); } /** * Sets a natural-language description of the object encoded as a single * JSON String containing HTML markup. Visual elements such as thumbnail * images MAY be included. An object MAY contain a content property. * * @param content a JSON [RFC4627] String containing the content. */ public void setContent(String content) { jsonObject.addProperty(CONTENT, content); } /** * Gets a natural-language, human-readable and plain-text name for the * object. HTML markup MUST NOT be included. An object MAY contain a * displayName property. If the object does not specify an objectType * property, the object SHOULD specify a displayName. * * @return displayName a JSON [RFC4627] String containing the display name. */ public String getDisplayName(String displayName) { return getStringValue(DISPLAY_NAME); } /** * Sets a natural-language, human-readable and plain-text name for the * object. HTML markup MUST NOT be included. An object MAY contain a * displayName property. If the object does not specify an objectType * property, the object SHOULD specify a displayName. * * @param displayName a JSON [RFC4627] String containing the display name. */ public void setDisplayName(String displayName) { jsonObject.addProperty(DISPLAY_NAME, displayName); } /** * Gets the permanent, universally unique identifier for the object in the * form of an absolute IRI [RFC3987]. An object SHOULD contain a single id * property. If an object does not contain an id property, consumers MAY use * the value of the url property as a less-reliable, non-unique identifier. * * @return A permanent, universally unique identifier for the object in the * form of an absolute IRI [RFC3987]. */ public String getId() { return getStringValue(ID); } /** * Sets the permanent, universally unique identifier for the object in the * form of an absolute IRI [RFC3987]. An object SHOULD contain a single id * property. If an object does not contain an id property, consumers MAY use * the value of the url property as a less-reliable, non-unique identifier. * * @param id A permanent, universally unique identifier for the object in * the form of an absolute IRI [RFC3987]. */ public void setId(String id) { if (null == id) { throw new IllegalArgumentException("id must not be null"); } jsonObject.addProperty(ID, id); } /** * Gets the type of object. An object MAY contain an objectType property * whose value is a JSON String that is non-empty and matches either the * "isegment-nz-nc" or the "IRI" production in [RFC3987]. Note that the use * of a relative reference other than a simple name is not allowed. If no * objectType property is contained, the object has no specific type. * * @return JSON [RFC4627] String. */ public String getObjectType() { return getStringValue(OBJECT_TYPE); } /** * Gets the type of object. An object MAY contain an objectType property * whose value is a JSON String that is non-empty and matches either the * "isegment-nz-nc" or the "IRI" production in [RFC3987]. Note that the use * of a relative reference other than a simple name is not allowed. If no * objectType property is contained, the object has no specific type. * @param objectType JSON [RFC4627] String. */ public void setObjectType(String objectType) { if (null == objectType) { throw new IllegalArgumentException("objectType must not be null"); } jsonObject.addProperty(OBJECT_TYPE, objectType); } /** * Gets the date by which the activity should be sorted. The updated date is * preferred, but if it is not available the published date is used. * * @return The date by which the activity should be sorted. */ public DateTime getSortTime() { DateTime updated = getUpdated(); if (null != updated) { return updated; } return getPublished(); } /** * Gets the date and time at which the object was published. An object MAY * contain a published property. * * @return The [RFC3339] date-time at which the object was published. */ public DateTime getPublished() { JsonElement element = jsonObject.get(PUBLISHED); DateTime published = null; try { if (null != element) { String publishedString = element.getAsString(); published = DateTime.parse(publishedString, ISODateTimeFormat.dateTimeParser().withZoneUTC()); } } catch (ClassCastException | IllegalStateException e) { } return published; } /** * Sets the date and time at which the object was published. An object MAY * contain a published property. * * @param dateTime The [RFC3339] date-time at which the object was * published. */ public void setPublished(DateTime dateTime) { if (null == dateTime) { throw new IllegalArgumentException("dateTime must not be null"); } jsonObject.addProperty(PUBLISHED, dateTime.toString( ISODateTimeFormat.dateTime().withZoneUTC())); } /** * Gets the date and time at which a previously published object has been * modified. An Object MAY contain an updated property. * * @return The [RFC3339] date-time at which the object was published. */ public DateTime getUpdated() { JsonElement element = jsonObject.get(UPDATED); DateTime updated = null; try { if (null != element) { String updatedString = element.getAsString(); updated = DateTime.parse(updatedString, ISODateTimeFormat.dateTimeParser().withZoneUTC()); } } catch (ClassCastException | IllegalStateException e) { } return updated; } /** * Sets the date and time at which a previously published object has been * modified. An Object MAY contain an updated property. * * @param dateTime The [RFC3339] date-time at which the object was * updated. */ public void setUpdated(DateTime dateTime) { jsonObject.addProperty(UPDATED, dateTime.toString( ISODateTimeFormat.dateTime().withZoneUTC())); } /** * Gets information about the set of objects that can be considered to be * replies to the containing object. * * @return An ActivityStreamsCollection representation of the replies * property. */ public ActivityStreamsCollection getReplies() { JsonElement replies = jsonObject.get(REPLIES); if (null != replies) { return new ActivityStreamsCollection(replies.toString()); } return null; } /** * Sets information about the set of objects that can be considered to be * replies to the containing object. * * @param replies An ActivityStreamsCollection containing the replies. */ public void setReplies(ActivityStreamsCollection replies) { jsonObject.add(REPLIES, replies.jsonObject); } /** * Gets information about the set of objects that can be considered to be * likes of the containing object. * * @return An ActivityStreamsCollection representation of the likes * property. */ public ActivityStreamsCollection getLikes() { JsonElement likes = jsonObject.get(LIKES); if (null != likes) { return new ActivityStreamsCollection(likes.toString()); } return null; } /** * Sets information about the set of objects that can be considered to be * likes of the containing object. * * @param replies An ActivityStreamsCollection containing the likes. */ public void setLikes(ActivityStreamsCollection likes) { jsonObject.add(LIKES, likes.jsonObject); } @Override public String toString() { return jsonObject.toString(); } /** * Gets a string value from the activity streams object. * * @param key The key of the value to retrieve. * @return The value of the given string key, or null if it does not exist. */ protected String getStringValue(String key) { return getStringValue(key, jsonObject); } /** * Gets a string value from the given json object. * * @param key The key of the value to retrieve. * @param container The json object from which to retrieve a string. * @return The value of the given string key, or null if it does not exist. */ private String getStringValue(String key, JsonObject container) { if (null == key || null == container) return null; String value = null; JsonElement element = container.get(key); if (null != element) { try { value = element.getAsString(); } catch (ClassCastException | IllegalStateException e) { } } return value; } /** * Gets a Collabinate metadata string value from the activity streams * object. * * @param key The key for the Collabinate metadata value. * @return The value for the given key, or null if it does not exist. */ public String getCollabinateValue(String key) { return getStringValue(key, jsonObject.getAsJsonObject(COLLABINATE)); } /** * Sets a Collabinate metadata string value in the activity streams object. * * @param key The key for the Collabinate metadata value. * @param value The value for the given key. */ public void setCollabinateValue(String key, String value) { if (!jsonObject.has(COLLABINATE)) { jsonObject.add(COLLABINATE, new JsonObject()); } jsonObject.getAsJsonObject(COLLABINATE).addProperty(key, value); } /** * Returns a new, randomly generated UUID URN. * * @return a new randomly generated UUID URN.ß */ public static String generateUuidUrn() { return UUID_URN_PREFIX + UUID.randomUUID().toString(); } protected static final String ID = "id"; protected static final String CONTENT = "content"; protected static final String DISPLAY_NAME = "displayName"; protected static final String OBJECT_TYPE = "objectType"; protected static final String PUBLISHED = "published"; protected static final String UPDATED = "updated"; protected static final String REPLIES = "replies"; protected static final String LIKES = "likes"; protected static final String COLLABINATE = "collabinate"; protected static final String UUID_URN_PREFIX = "urn:uuid:"; }