/* * Copyright 2007 Yusuke Yamamoto * * Licensed 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 twitter4j.internal.json; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.util.Arrays; import java.util.Date; import twitter4j.CardEntity; import twitter4j.GeoLocation; import twitter4j.HashtagEntity; import twitter4j.MediaEntity; import twitter4j.Place; import twitter4j.ResponseList; import twitter4j.Status; import twitter4j.TwitterException; import twitter4j.URLEntity; import twitter4j.User; import twitter4j.UserMentionEntity; import twitter4j.conf.Configuration; import twitter4j.http.HttpResponse; import twitter4j.internal.logging.Logger; import static twitter4j.internal.util.InternalParseUtil.getBoolean; import static twitter4j.internal.util.InternalParseUtil.getDate; import static twitter4j.internal.util.InternalParseUtil.getHTMLUnescapedString; import static twitter4j.internal.util.InternalParseUtil.getLong; import static twitter4j.internal.util.InternalParseUtil.getRawString; import static twitter4j.internal.util.InternalParseUtil.getUnescapedString; /** * A data class representing one single status of a user. * * @author Yusuke Yamamoto - yusuke at mac.com */ final class StatusJSONImpl extends TwitterResponseImpl implements Status { /** * */ private static final long serialVersionUID = 8982739445731837548L; private static final Logger logger = Logger.getLogger(StatusJSONImpl.class); private Date createdAt; private long id; private String text; private String rawText; private String source; private boolean isTruncated; private long inReplyToStatusId; private long inReplyToUserId; private long currentUserRetweet; private boolean isFavorited; private String inReplyToScreenName; private GeoLocation geoLocation = null; private Place place = null; private long retweetCount; private long favoriteCount; private CardEntity cardEntity; public long getReplyCount() { return replyCount; } public long getDescendentReplyCount() { return descendentReplyCount; } private long replyCount; private long descendentReplyCount; private boolean wasRetweetedByMe; private boolean isPossiblySensitive; private String[] contributors = null; private long[] contributorsIDs; private Status retweetedStatus; private Status quotedStatus; private UserMentionEntity[] userMentionEntities; private URLEntity[] urlEntities; private HashtagEntity[] hashtagEntities; private MediaEntity[] mediaEntities; private MediaEntity[] extendedMediaEntities; private User user = null; /* package */StatusJSONImpl(final HttpResponse res, final Configuration conf) throws TwitterException { super(res); final JSONObject json = res.asJSONObject(); init(json); } /* package */StatusJSONImpl(final JSONObject json) throws TwitterException { super(); init(json); } @Override public int compareTo(final Status that) { final long delta = id - that.getId(); if (delta < Integer.MIN_VALUE) return Integer.MIN_VALUE; else if (delta > Integer.MAX_VALUE) return Integer.MAX_VALUE; return (int) delta; } @Override public boolean equals(final Object obj) { if (null == obj) return false; if (this == obj) return true; return obj instanceof Status && ((Status) obj).getId() == id; } /** * {@inheritDoc} */ @Override public long[] getContributors() { if (contributors != null) { // http://twitter4j.org/jira/browse/TFJ-592 // preserving serialized form compatibility with older versions contributorsIDs = new long[contributors.length]; for (int i = 0; i < contributors.length; i++) { try { contributorsIDs[i] = Long.parseLong(contributors[i]); } catch (final NumberFormatException nfe) { nfe.printStackTrace(); logger.warn("failed to parse contributors:" + nfe); } } contributors = null; } return contributorsIDs; } /** * {@inheritDoc} */ @Override public Date getCreatedAt() { return createdAt; } @Override public long getCurrentUserRetweet() { return currentUserRetweet; } @Override public long getFavoriteCount() { return favoriteCount; } /** * {@inheritDoc} */ @Override public GeoLocation getGeoLocation() { return geoLocation; } /** * {@inheritDoc} */ @Override public HashtagEntity[] getHashtagEntities() { return hashtagEntities; } /** * {@inheritDoc} */ @Override public long getId() { return id; } /** * {@inheritDoc} */ @Override public String getInReplyToScreenName() { return inReplyToScreenName; } /** * {@inheritDoc} */ @Override public long getInReplyToStatusId() { return inReplyToStatusId; } /** * {@inheritDoc} */ @Override public long getInReplyToUserId() { return inReplyToUserId; } /** * {@inheritDoc} */ @Override public MediaEntity[] getMediaEntities() { return mediaEntities; } /** * {@inheritDoc} */ @Override public Place getPlace() { return place; } @Override public String getRawText() { return rawText; } /** * {@inheritDoc} */ @Override public long getRetweetCount() { return retweetCount; } /** * {@inheritDoc} */ @Override public Status getRetweetedStatus() { return retweetedStatus; } @Override public Status getQuotedStatus() { return quotedStatus; } /** * {@inheritDoc} */ @Override public String getSource() { return source; } /** * {@inheritDoc} */ @Override public String getText() { return text; } /** * {@inheritDoc} */ @Override public URLEntity[] getURLEntities() { return urlEntities; } /** * {@inheritDoc} */ @Override public User getUser() { return user; } /** * {@inheritDoc} */ @Override public UserMentionEntity[] getUserMentionEntities() { return userMentionEntities; } @Override public int hashCode() { return (int) id; } /** * {@inheritDoc} */ @Override public boolean isFavorited() { return isFavorited; } @Override public boolean isPossiblySensitive() { return isPossiblySensitive; } /** * {@inheritDoc} */ @Override public boolean isRetweet() { return retweetedStatus != null; } @Override public boolean isQuote() { return quotedStatus != null; } /** * {@inheritDoc} */ @Override public boolean isRetweetedByMe() { return wasRetweetedByMe; } /** * {@inheritDoc} */ @Override public boolean isTruncated() { return isTruncated; } @Override public CardEntity getCard() { return cardEntity; } @Override public String toString() { return "StatusJSONImpl{createdAt=" + createdAt + ", id=" + id + ", text=" + text + ", rawText=" + rawText + ", source=" + source + ", isTruncated=" + isTruncated + ", inReplyToStatusId=" + inReplyToStatusId + ", inReplyToUserId=" + inReplyToUserId + ", currentUserRetweet=" + currentUserRetweet + ", isFavorited=" + isFavorited + ", inReplyToScreenName=" + inReplyToScreenName + ", geoLocation=" + geoLocation + ", place=" + place + ", retweetCount=" + retweetCount + ", wasRetweetedByMe=" + wasRetweetedByMe + ", isPossiblySensitive=" + isPossiblySensitive + ", contributors=" + Arrays.toString(contributors) + ", contributorsIDs=" + Arrays.toString(contributorsIDs) + ", retweetedStatus=" + retweetedStatus + ", userMentionEntities=" + Arrays.toString(userMentionEntities) + ", urlEntities=" + Arrays.toString(urlEntities) + ", hashtagEntities=" + Arrays.toString(hashtagEntities) + ", mediaEntities=" + Arrays.toString(mediaEntities) + ", user=" + user + "}"; } private void init(final JSONObject json) throws TwitterException { id = getLong("id", json); rawText = getRawString("text", json); text = getUnescapedString("text", json); source = getHTMLUnescapedString("source", json); createdAt = getDate("created_at", json); isTruncated = getBoolean("truncated", json); inReplyToStatusId = getLong("in_reply_to_status_id", json); inReplyToUserId = getLong("in_reply_to_user_id", json); isFavorited = getBoolean("favorited", json); inReplyToScreenName = getHTMLUnescapedString("in_reply_to_screen_name", json); isPossiblySensitive = getBoolean("possibly_sensitive", json); retweetCount = getLong("retweet_count", json); favoriteCount = getLong("favorite_count", json); replyCount = getLong("reply_count", json); descendentReplyCount = getLong("descendent_reply_count", json); try { if (!json.isNull("user")) { user = new UserJSONImpl(json.getJSONObject("user")); } } catch (final JSONException jsone) { throw new TwitterException(jsone); } geoLocation = InternalJSONFactoryImpl.createGeoLocation(json); if (!json.isNull("place")) { try { place = new PlaceJSONImpl(json.getJSONObject("place")); } catch (final JSONException ignore) { ignore.printStackTrace(); logger.warn("failed to parse place:" + json); } } if (!json.isNull("retweeted_status")) { try { retweetedStatus = new StatusJSONImpl(json.getJSONObject("retweeted_status")); } catch (final JSONException ignore) { ignore.printStackTrace(); logger.warn("failed to parse retweeted_status:" + json); } } if (!json.isNull("quoted_status")) { try { quotedStatus = new StatusJSONImpl(json.getJSONObject("quoted_status")); } catch (final JSONException ignore) { ignore.printStackTrace(); logger.warn("failed to parse retweeted_status:" + json); } } if (!json.isNull("contributors")) { try { final JSONArray contributorsArray = json.getJSONArray("contributors"); contributorsIDs = new long[contributorsArray.length()]; for (int i = 0; i < contributorsArray.length(); i++) { contributorsIDs[i] = Long.parseLong(contributorsArray.getString(i)); } } catch (final NumberFormatException ignore) { ignore.printStackTrace(); logger.warn("failed to parse contributors:" + json); } catch (final JSONException ignore) { ignore.printStackTrace(); logger.warn("failed to parse contributors:" + json); } } else { contributors = null; } if (!json.isNull("entities")) { try { final JSONObject entities = json.getJSONObject("entities"); int len; if (!entities.isNull("user_mentions")) { final JSONArray userMentionsArray = entities.getJSONArray("user_mentions"); len = userMentionsArray.length(); userMentionEntities = new UserMentionEntity[len]; for (int i = 0; i < len; i++) { userMentionEntities[i] = new UserMentionEntityJSONImpl(userMentionsArray.getJSONObject(i)); } } if (!entities.isNull("urls")) { final JSONArray urlsArray = entities.getJSONArray("urls"); len = urlsArray.length(); urlEntities = new URLEntity[len]; for (int i = 0; i < len; i++) { urlEntities[i] = new URLEntityJSONImpl(urlsArray.getJSONObject(i)); } } if (!entities.isNull("hashtags")) { final JSONArray hashtagsArray = entities.getJSONArray("hashtags"); len = hashtagsArray.length(); hashtagEntities = new HashtagEntity[len]; for (int i = 0; i < len; i++) { hashtagEntities[i] = new HashtagEntityJSONImpl(hashtagsArray.getJSONObject(i)); } } if (!entities.isNull("media")) { final JSONArray mediaArray = entities.getJSONArray("media"); len = mediaArray.length(); mediaEntities = new MediaEntity[len]; for (int i = 0; i < len; i++) { mediaEntities[i] = new MediaEntityJSONImpl(mediaArray.getJSONObject(i)); } } } catch (final JSONException jsone) { throw new TwitterException(jsone); } } if (!json.isNull("extended_entities")) { try { final JSONObject entities = json.getJSONObject("extended_entities"); if (!entities.isNull("media")) { int len; final JSONArray mediaArray = entities.getJSONArray("media"); len = mediaArray.length(); extendedMediaEntities = new MediaEntity[len]; for (int i = 0; i < len; i++) { extendedMediaEntities[i] = new MediaEntityJSONImpl(mediaArray.getJSONObject(i)); } } } catch (final JSONException jsone) { throw new TwitterException(jsone); } } if (!json.isNull("current_user_retweet")) { try { currentUserRetweet = getLong("id", json.getJSONObject("current_user_retweet")); wasRetweetedByMe = currentUserRetweet > 0; } catch (final JSONException ignore) { ignore.printStackTrace(); logger.warn("failed to parse current_user_retweet:" + json); } } if (!json.isNull("card")) { try { cardEntity = new CardEntityJSONImpl(json.getJSONObject("card")); } catch (JSONException jsone) { throw new TwitterException(jsone); } } } /* package */ static ResponseList<Status> createStatusList(final HttpResponse res, final Configuration conf) throws TwitterException { try { final JSONArray list = res.asJSONArray(); final int size = list.length(); final ResponseList<Status> statuses = new ResponseListImpl<Status>(size, res); for (int i = 0; i < size; i++) { final JSONObject json = list.getJSONObject(i); final Status status = new StatusJSONImpl(json); statuses.add(status); } return statuses; } catch (final JSONException jsone) { throw new TwitterException(jsone); } catch (final TwitterException te) { throw te; } } @Override public MediaEntity[] getExtendedMediaEntities() { return extendedMediaEntities; } }