/** * Computes RFC 2104-compliant HMAC signature. * * @param data the data to be signed * @param token the token * @return signature * @see <a href="http://oauth.net/core/1.0a/#rfc.section.9.2.1">OAuth Core - 9.2.1. Generating * Signature</a> */ /* package */ String generateSignature(final String data, final OAuthToken token) { byte[] byteHMAC = null; try { final Mac mac = Mac.getInstance(HMAC_SHA1); SecretKeySpec spec; if (null == token) { final String oauthSignature = HttpParameter.encode(consumerSecret) + "&"; spec = new SecretKeySpec(oauthSignature.getBytes(), HMAC_SHA1); } else { spec = token.getSecretKeySpec(); if (null == spec) { final String oauthSignature = HttpParameter.encode(consumerSecret) + "&" + HttpParameter.encode(token.getTokenSecret()); spec = new SecretKeySpec(oauthSignature.getBytes(), HMAC_SHA1); token.setSecretKeySpec(spec); } } mac.init(spec); byteHMAC = mac.doFinal(data.getBytes()); } catch (final InvalidKeyException ike) { logger.error("Failed initialize \"Message Authentication Code\" (MAC)", ike); throw new AssertionError(ike); } catch (final NoSuchAlgorithmException nsae) { logger.error("Failed to get HmacSHA1 \"Message Authentication Code\" (MAC)", nsae); throw new AssertionError(nsae); } return BASE64Encoder.encode(byteHMAC); }
private void setHeaders(HttpRequest httprequest, HttpURLConnection httpurlconnection) { if (logger.isDebugEnabled()) { logger.debug("Request: "); logger.debug((new StringBuilder()).append(httprequest.getMethod().name()).append(" ").toString(), httprequest.getURL()); } if (httprequest.getAuthorization() != null) { String s = httprequest.getAuthorization().getAuthorizationHeader(httprequest); if (s != null) { if (logger.isDebugEnabled()) { logger.debug("Authorization: ", z_T4JInternalStringUtil.maskString(s)); } httpurlconnection.addRequestProperty("Authorization", s); } } if (httprequest.getRequestHeaders() != null) { String s1; for (Iterator iterator = httprequest.getRequestHeaders().keySet().iterator(); iterator.hasNext(); logger.debug((new StringBuilder()).append(s1).append(": ").append((String)httprequest.getRequestHeaders().get(s1)).toString())) { s1 = (String)iterator.next(); httpurlconnection.addRequestProperty(s1, (String)httprequest.getRequestHeaders().get(s1)); } } }
protected HttpURLConnection getConnection(String s) { if (isProxyConfigured()) { if (CONF.getHttpProxyUser() != null && !CONF.getHttpProxyUser().equals("")) { if (logger.isDebugEnabled()) { logger.debug((new StringBuilder("Proxy AuthUser: "******"Proxy AuthPassword: "******"Opening proxied connection(")).append(CONF.getHttpProxyHost()).append(":").append(CONF.getHttpProxyPort()).append(")").toString()); } s = (HttpURLConnection)(new URL(s)).openConnection(proxy); } else { s = (HttpURLConnection)(new URL(s)).openConnection(); } if (CONF.getHttpConnectionTimeout() > 0) { s.setConnectTimeout(CONF.getHttpConnectionTimeout()); } if (CONF.getHttpReadTimeout() > 0) { s.setReadTimeout(CONF.getHttpReadTimeout()); } s.setInstanceFollowRedirects(false); return s; }
/* package */ String generateAuthorizationHeader( final String method, final String sign_url, HttpParameter[] params, final String nonce, final String timestamp, final OAuthToken otoken) { if (null == params) { params = new HttpParameter[0]; } final List<HttpParameter> oauthHeaderParams = new ArrayList<HttpParameter>(5); oauthHeaderParams.add(new HttpParameter("oauth_consumer_key", consumerKey)); oauthHeaderParams.add(OAUTH_SIGNATURE_METHOD); oauthHeaderParams.add(new HttpParameter("oauth_timestamp", timestamp)); oauthHeaderParams.add(new HttpParameter("oauth_nonce", nonce)); oauthHeaderParams.add(new HttpParameter("oauth_version", "1.0")); if (otoken != null) { oauthHeaderParams.add(new HttpParameter("oauth_token", otoken.getToken())); } final List<HttpParameter> signatureBaseParams = new ArrayList<HttpParameter>(oauthHeaderParams.size() + params.length); signatureBaseParams.addAll(oauthHeaderParams); if (!HttpParameter.containsFile(params)) { signatureBaseParams.addAll(toParamList(params)); } parseGetParameters(sign_url, signatureBaseParams); final StringBuffer base = new StringBuffer(method) .append("&") .append(HttpParameter.encode(constructRequestURL(sign_url))) .append("&"); base.append(HttpParameter.encode(normalizeRequestParameters(signatureBaseParams))); final String oauthBaseString = base.toString(); logger.debug("OAuth base string: ", oauthBaseString); final String signature = generateSignature(oauthBaseString, otoken); logger.debug("OAuth signature: ", signature); oauthHeaderParams.add(new HttpParameter("oauth_signature", signature)); // http://oauth.net/core/1.0/#rfc.section.9.1.1 if (realm != null) { oauthHeaderParams.add(new HttpParameter("realm", realm)); } return "OAuth " + encodeParameters(oauthHeaderParams, ",", true); }
((HttpURLConnection) (obj4)).setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); obj1 = HttpParameter.encodeParameters(httprequest.getParameters()); logger.debug("Post Params: ", ((String) (obj1))); abyte0 = ((String) (obj1)).getBytes("UTF-8"); ((HttpURLConnection) (obj4)).setRequestProperty("Content-Length", Integer.toString(abyte0.length)); ((HttpURLConnection) (obj4)).setDoOutput(true); obj2 = ((HttpURLConnection) (obj4)).getOutputStream(); obj1 = obj2; ((OutputStream) (obj2)).write(abyte0); goto _L26
public String upload() throws TwitterException { preUpload(); if (this.postParameter == null) { throw new AssertionError("Incomplete implementation. postParameter is not set."); } if (this.uploadUrl == null) { throw new AssertionError("Incomplete implementation. uploadUrl is not set."); } httpResponse = client.post(uploadUrl, postParameter, headers); String mediaUrl = postUpload(); logger.debug("uploaded url [" + mediaUrl + "]"); return mediaUrl; }
/** {@inheritDoc} */ 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 (NumberFormatException nfe) { nfe.printStackTrace(); logger.warn("failed to parse contributors:" + nfe); } } contributors = null; } return contributorsIDs; }
/** * @author Rémy Rakic - remy.rakic at gmail.com * @author Takao Nakaguchi - takao.nakaguchi at gmail.com * @author withgod - noname at withgod.jp * @since Twitter4J 2.1.8 */ abstract class AbstractImageUploadImpl implements ImageUpload { public static final String TWITTER_VERIFY_CREDENTIALS_JSON = "https://api.twitter.com/1/account/verify_credentials.json"; public static final String TWITTER_VERIFY_CREDENTIALS_XML = "https://api.twitter.com/1/account/verify_credentials.xml"; private HttpClientWrapper client; protected String apiKey = null; protected OAuthAuthorization oauth = null; protected String uploadUrl = null; protected HttpParameter[] postParameter = null; protected HttpParameter image = null; protected HttpParameter message = null; protected Map<String, String> headers = new HashMap<String, String>(); protected HttpResponse httpResponse = null; protected static final Logger logger = Logger.getLogger(AbstractImageUploadImpl.class); AbstractImageUploadImpl(Configuration conf, OAuthAuthorization oauth) { this.oauth = oauth; client = new HttpClientWrapper(conf); } public AbstractImageUploadImpl(Configuration conf, String apiKey, OAuthAuthorization oauth) { this(conf, oauth); this.apiKey = apiKey; } public String upload(String imageFileName, InputStream imageBody) throws TwitterException { this.image = new HttpParameter("media", imageFileName, imageBody); return upload(); } public String upload(String imageFileName, InputStream imageBody, String message) throws TwitterException { this.image = new HttpParameter("media", imageFileName, imageBody); this.message = new HttpParameter("message", message); return upload(); } public String upload(File file, String message) throws TwitterException { this.image = new HttpParameter("media", file); this.message = new HttpParameter("message", message); return upload(); } public String upload(File file) throws TwitterException { this.image = new HttpParameter("media", file); return upload(); } public String upload() throws TwitterException { preUpload(); if (this.postParameter == null) { throw new AssertionError("Incomplete implementation. postParameter is not set."); } if (this.uploadUrl == null) { throw new AssertionError("Incomplete implementation. uploadUrl is not set."); } httpResponse = client.post(uploadUrl, postParameter, headers); String mediaUrl = postUpload(); logger.debug("uploaded url [" + mediaUrl + "]"); return mediaUrl; } protected abstract void preUpload() throws TwitterException; protected abstract String postUpload() throws TwitterException; protected HttpParameter[] appendHttpParameters(HttpParameter[] src, HttpParameter[] dst) { int srcLen = src.length; int dstLen = dst.length; HttpParameter[] ret = new HttpParameter[srcLen + dstLen]; for (int i = 0; i < srcLen; i++) { ret[i] = src[i]; } for (int i = 0; i < dstLen; i++) { ret[srcLen + i] = dst[i]; } return ret; } protected String generateVerifyCredentialsAuthorizationHeader(String verifyCredentialsUrl) { List<HttpParameter> oauthSignatureParams = oauth.generateOAuthSignatureHttpParams("GET", verifyCredentialsUrl); return "OAuth realm=\"http://api.twitter.com/\"," + OAuthAuthorization.encodeParameters(oauthSignatureParams, ",", true); } protected String generateVerifyCredentialsAuthorizationURL(String verifyCredentialsUrl) { List<HttpParameter> oauthSignatureParams = oauth.generateOAuthSignatureHttpParams("GET", verifyCredentialsUrl); return verifyCredentialsUrl + "?" + OAuthAuthorization.encodeParameters(oauthSignatureParams); } }
/** * @author Yusuke Yamamoto - yusuke at mac.com * @see <a href="http://oauth.net/core/1.0a/">OAuth Core 1.0a</a> */ public class OAuthAuthorization implements Authorization, OAuthSupport { private final Configuration conf; private static transient HttpClientWrapper http; private static final String HMAC_SHA1 = "HmacSHA1"; private static final HttpParameter OAUTH_SIGNATURE_METHOD = new HttpParameter("oauth_signature_method", "HMAC-SHA1"); private static final Logger logger = Logger.getLogger(OAuthAuthorization.class); private String consumerKey = ""; private String consumerSecret; private String realm = null; private OAuthToken oauthToken = null; // constructors private static Random RAND = new Random(); /** @param conf configuration */ public OAuthAuthorization(final Configuration conf) { this.conf = conf; http = new HttpClientWrapper(conf); setOAuthConsumer(conf.getOAuthConsumerKey(), conf.getOAuthConsumerSecret()); if (conf.getOAuthAccessToken() != null && conf.getOAuthAccessTokenSecret() != null) { setOAuthAccessToken( new AccessToken(conf.getOAuthAccessToken(), conf.getOAuthAccessTokenSecret())); } } @Override public boolean equals(final Object o) { if (this == o) return true; if (!(o instanceof OAuthSupport)) return false; final OAuthAuthorization that = (OAuthAuthorization) o; if (consumerKey != null ? !consumerKey.equals(that.consumerKey) : that.consumerKey != null) return false; if (consumerSecret != null ? !consumerSecret.equals(that.consumerSecret) : that.consumerSecret != null) return false; if (oauthToken != null ? !oauthToken.equals(that.oauthToken) : that.oauthToken != null) return false; return true; } public List<HttpParameter> generateOAuthSignatureHttpParams( final String method, final String sign_url) { final long timestamp = System.currentTimeMillis() / 1000; final long nonce = timestamp + RAND.nextInt(); final List<HttpParameter> oauthHeaderParams = new ArrayList<HttpParameter>(5); oauthHeaderParams.add(new HttpParameter("oauth_consumer_key", consumerKey)); oauthHeaderParams.add(OAUTH_SIGNATURE_METHOD); oauthHeaderParams.add(new HttpParameter("oauth_timestamp", timestamp)); oauthHeaderParams.add(new HttpParameter("oauth_nonce", nonce)); oauthHeaderParams.add(new HttpParameter("oauth_version", "1.0")); if (oauthToken != null) { oauthHeaderParams.add(new HttpParameter("oauth_token", oauthToken.getToken())); } final List<HttpParameter> signatureBaseParams = new ArrayList<HttpParameter>(oauthHeaderParams.size()); signatureBaseParams.addAll(oauthHeaderParams); parseGetParameters(sign_url, signatureBaseParams); final StringBuffer base = new StringBuffer(method) .append("&") .append(HttpParameter.encode(constructRequestURL(sign_url))) .append("&"); base.append(HttpParameter.encode(normalizeRequestParameters(signatureBaseParams))); final String oauthBaseString = base.toString(); final String signature = generateSignature(oauthBaseString, oauthToken); oauthHeaderParams.add(new HttpParameter("oauth_signature", signature)); return oauthHeaderParams; } // implementation for OAuthSupport interface // implementations for Authorization @Override public String getAuthorizationHeader(final HttpRequest req) { return generateAuthorizationHeader( req.getMethod().name(), req.getSignURL(), req.getParameters(), oauthToken); } /** {@inheritDoc} */ @Override public AccessToken getOAuthAccessToken() throws TwitterException { ensureTokenIsAvailable(); if (oauthToken instanceof AccessToken) return (AccessToken) oauthToken; oauthToken = new AccessToken( http.post(conf.getOAuthAccessTokenURL(), conf.getSigningOAuthAccessTokenURL(), this)); return (AccessToken) oauthToken; } /** {@inheritDoc} */ @Override public AccessToken getOAuthAccessToken(final RequestToken requestToken) throws TwitterException { oauthToken = requestToken; return getOAuthAccessToken(); } /** {@inheritDoc} */ @Override public AccessToken getOAuthAccessToken( final RequestToken requestToken, final String oauthVerifier) throws TwitterException { oauthToken = requestToken; return getOAuthAccessToken(oauthVerifier); } /** {@inheritDoc} */ @Override public AccessToken getOAuthAccessToken(final String oauthVerifier) throws TwitterException { ensureTokenIsAvailable(); final String url = conf.getOAuthAccessTokenURL(); if (0 == url.indexOf("http://")) { // SSL is required // @see https://dev.twitter.com/docs/oauth/xauth // url = "https://" + url.substring(7); } final String sign_url = conf.getSigningOAuthAccessTokenURL(); if (0 == sign_url.indexOf("http://")) { // SSL is required // @see https://dev.twitter.com/docs/oauth/xauth // sign_url = "https://" + sign_url.substring(7); } oauthToken = new AccessToken( http.post( url, sign_url, new HttpParameter[] {new HttpParameter("oauth_verifier", oauthVerifier)}, this)); return (AccessToken) oauthToken; } /** {@inheritDoc} */ @Override public AccessToken getOAuthAccessToken(final String screenName, final String password) throws TwitterException { try { final String url = conf.getOAuthAccessTokenURL(); if (0 == url.indexOf("http://")) { // SSL is required // @see https://dev.twitter.com/docs/oauth/xauth // url = "https://" + url.substring(7); } final String sign_url = conf.getSigningOAuthAccessTokenURL(); if (0 == sign_url.indexOf("http://")) { // SSL is required // @see https://dev.twitter.com/docs/oauth/xauth // sign_url = "https://" + sign_url.substring(7); } oauthToken = new AccessToken( http.post( url, sign_url, new HttpParameter[] { new HttpParameter("x_auth_username", screenName), new HttpParameter("x_auth_password", password), new HttpParameter("x_auth_mode", "client_auth") }, this)); return (AccessToken) oauthToken; } catch (final TwitterException te) { throw new TwitterException( "The screen name / password combination seems to be invalid.", te, te.getStatusCode()); } } /** {@inheritDoc} */ @Override public RequestToken getOAuthRequestToken() throws TwitterException { return getOAuthRequestToken(null, null); } /** {@inheritDoc} */ @Override public RequestToken getOAuthRequestToken(final String callbackURL) throws TwitterException { return getOAuthRequestToken(callbackURL, null); } /** {@inheritDoc} */ @Override public RequestToken getOAuthRequestToken(final String callbackURL, final String xAuthAccessType) throws TwitterException { if (oauthToken instanceof AccessToken) throw new IllegalStateException("Access token already available."); final List<HttpParameter> params = new ArrayList<HttpParameter>(); if (callbackURL != null) { params.add(new HttpParameter("oauth_callback", callbackURL)); } if (xAuthAccessType != null) { params.add(new HttpParameter("x_auth_access_type", xAuthAccessType)); } final String url = conf.getOAuthRequestTokenURL(); if (0 == url.indexOf("http://")) { // SSL is required // @see https://dev.twitter.com/docs/oauth/xauth // url = "https://" + url.substring(7); } final String sign_url = conf.getSigningOAuthRequestTokenURL(); if (0 == sign_url.indexOf("http://")) { // SSL is required // @see https://dev.twitter.com/docs/oauth/xauth // sign_url = "https://" + sign_url.substring(7); } oauthToken = new RequestToken( conf, http.post(url, sign_url, params.toArray(new HttpParameter[params.size()]), this), this); return (RequestToken) oauthToken; } @Override public int hashCode() { int result = consumerKey != null ? consumerKey.hashCode() : 0; result = 31 * result + (consumerSecret != null ? consumerSecret.hashCode() : 0); result = 31 * result + (oauthToken != null ? oauthToken.hashCode() : 0); return result; } /** #{inheritDoc} */ @Override public boolean isEnabled() { return oauthToken != null && oauthToken instanceof AccessToken; } /** {@inheritDoc} */ @Override public void setOAuthAccessToken(final AccessToken accessToken) { oauthToken = accessToken; } @Override public void setOAuthConsumer(final String consumerKey, final String consumerSecret) { this.consumerKey = consumerKey != null ? consumerKey : ""; this.consumerSecret = consumerSecret != null ? consumerSecret : ""; } /** * Sets the OAuth realm * * @param realm OAuth realm * @since Twitter 2.1.4 */ public void setOAuthRealm(final String realm) { this.realm = realm; } @Override public String toString() { return "OAuthAuthorization{" + "consumerKey='" + consumerKey + '\'' + ", consumerSecret='******************************************\'" + ", oauthToken=" + oauthToken + '}'; } private void ensureTokenIsAvailable() { if (null == oauthToken) throw new IllegalStateException("No Token available."); } /* package */ private void parseGetParameters(final String url, final List<HttpParameter> signatureBaseParams) { final int queryStart = url.indexOf("?"); if (-1 != queryStart) { final String[] queryStrs = InternalStringUtil.split(url.substring(queryStart + 1), "&"); try { for (final String query : queryStrs) { final String[] split = InternalStringUtil.split(query, "="); if (split.length == 2) { signatureBaseParams.add( new HttpParameter( URLDecoder.decode(split[0], "UTF-8"), URLDecoder.decode(split[1], "UTF-8"))); } else { signatureBaseParams.add(new HttpParameter(URLDecoder.decode(split[0], "UTF-8"), "")); } } } catch (final UnsupportedEncodingException ignore) { } } } /** * @return generated authorization header * @see <a href="http://oauth.net/core/1.0a/#rfc.section.5.4.1">OAuth Core - 5.4.1. Authorization * Header</a> */ /* package */ String generateAuthorizationHeader( final String method, final String sign_url, final HttpParameter[] params, final OAuthToken token) { final long timestamp = System.currentTimeMillis() / 1000; final long nonce = timestamp + RAND.nextInt(); return generateAuthorizationHeader( method, sign_url, params, String.valueOf(nonce), String.valueOf(timestamp), token); } /* package */ String generateAuthorizationHeader( final String method, final String sign_url, HttpParameter[] params, final String nonce, final String timestamp, final OAuthToken otoken) { if (null == params) { params = new HttpParameter[0]; } final List<HttpParameter> oauthHeaderParams = new ArrayList<HttpParameter>(5); oauthHeaderParams.add(new HttpParameter("oauth_consumer_key", consumerKey)); oauthHeaderParams.add(OAUTH_SIGNATURE_METHOD); oauthHeaderParams.add(new HttpParameter("oauth_timestamp", timestamp)); oauthHeaderParams.add(new HttpParameter("oauth_nonce", nonce)); oauthHeaderParams.add(new HttpParameter("oauth_version", "1.0")); if (otoken != null) { oauthHeaderParams.add(new HttpParameter("oauth_token", otoken.getToken())); } final List<HttpParameter> signatureBaseParams = new ArrayList<HttpParameter>(oauthHeaderParams.size() + params.length); signatureBaseParams.addAll(oauthHeaderParams); if (!HttpParameter.containsFile(params)) { signatureBaseParams.addAll(toParamList(params)); } parseGetParameters(sign_url, signatureBaseParams); final StringBuffer base = new StringBuffer(method) .append("&") .append(HttpParameter.encode(constructRequestURL(sign_url))) .append("&"); base.append(HttpParameter.encode(normalizeRequestParameters(signatureBaseParams))); final String oauthBaseString = base.toString(); logger.debug("OAuth base string: ", oauthBaseString); final String signature = generateSignature(oauthBaseString, otoken); logger.debug("OAuth signature: ", signature); oauthHeaderParams.add(new HttpParameter("oauth_signature", signature)); // http://oauth.net/core/1.0/#rfc.section.9.1.1 if (realm != null) { oauthHeaderParams.add(new HttpParameter("realm", realm)); } return "OAuth " + encodeParameters(oauthHeaderParams, ",", true); } String generateSignature(final String data) { return generateSignature(data, null); } /** * Computes RFC 2104-compliant HMAC signature. * * @param data the data to be signed * @param token the token * @return signature * @see <a href="http://oauth.net/core/1.0a/#rfc.section.9.2.1">OAuth Core - 9.2.1. Generating * Signature</a> */ /* package */ String generateSignature(final String data, final OAuthToken token) { byte[] byteHMAC = null; try { final Mac mac = Mac.getInstance(HMAC_SHA1); SecretKeySpec spec; if (null == token) { final String oauthSignature = HttpParameter.encode(consumerSecret) + "&"; spec = new SecretKeySpec(oauthSignature.getBytes(), HMAC_SHA1); } else { spec = token.getSecretKeySpec(); if (null == spec) { final String oauthSignature = HttpParameter.encode(consumerSecret) + "&" + HttpParameter.encode(token.getTokenSecret()); spec = new SecretKeySpec(oauthSignature.getBytes(), HMAC_SHA1); token.setSecretKeySpec(spec); } } mac.init(spec); byteHMAC = mac.doFinal(data.getBytes()); } catch (final InvalidKeyException ike) { logger.error("Failed initialize \"Message Authentication Code\" (MAC)", ike); throw new AssertionError(ike); } catch (final NoSuchAlgorithmException nsae) { logger.error("Failed to get HmacSHA1 \"Message Authentication Code\" (MAC)", nsae); throw new AssertionError(nsae); } return BASE64Encoder.encode(byteHMAC); } /** * The Signature Base String includes the request absolute URL, tying the signature to a specific * endpoint. The URL used in the Signature Base String MUST include the scheme, authority, and * path, and MUST exclude the query and fragment as defined by [RFC3986] section 3.<br> * If the absolute request URL is not available to the Service Provider (it is always available to * the Consumer), it can be constructed by combining the scheme being used, the HTTP Host header, * and the relative HTTP request URL. If the Host header is not available, the Service Provider * SHOULD use the host name communicated to the Consumer in the documentation or other means.<br> * The Service Provider SHOULD document the form of URL used in the Signature Base String to avoid * ambiguity due to URL normalization. Unless specified, URL scheme and authority MUST be * lowercase and include the port number; http default port 80 and https default port 443 MUST be * excluded.<br> * <br> * For example, the request:<br> * HTTP://Example.com:80/resource?id=123<br> * Is included in the Signature Base String as:<br> * http://example.com/resource * * @param url the url to be normalized * @return the Signature Base String * @see <a href="http://oauth.net/core/1.0#rfc.section.9.1.2">OAuth Core - 9.1.2. Construct * Request URL</a> */ public static String constructRequestURL(String url) { final int index = url.indexOf("?"); if (-1 != index) { url = url.substring(0, index); } final int slashIndex = url.indexOf("/", 8); String baseURL = url.substring(0, slashIndex).toLowerCase(); final int colonIndex = baseURL.indexOf(":", 8); if (-1 != colonIndex) { // url contains port number if (baseURL.startsWith("http://") && baseURL.endsWith(":80")) { // http default port 80 MUST be excluded baseURL = baseURL.substring(0, colonIndex); } else if (baseURL.startsWith("https://") && baseURL.endsWith(":443")) { // http default port 443 MUST be excluded baseURL = baseURL.substring(0, colonIndex); } } url = baseURL + url.substring(slashIndex); return url; } /** * @param httpParams parameters to be encoded and concatenated * @return encoded string * @see <a href="http://wiki.oauth.net/TestCases">OAuth / TestCases</a> * @see <a * href="http://groups.google.com/group/oauth/browse_thread/thread/a8398d0521f4ae3d/9d79b698ab217df2?hl=en&lnk=gst&q=space+encoding#9d79b698ab217df2">Space * encoding - OAuth | Google Groups</a> */ public static String encodeParameters(final List<HttpParameter> httpParams) { return encodeParameters(httpParams, "&", false); } public static String encodeParameters( final List<HttpParameter> httpParams, final String splitter, final boolean quot) { final StringBuffer buf = new StringBuffer(); for (final HttpParameter param : httpParams) { if (!param.isFile()) { if (buf.length() != 0) { if (quot) { buf.append("\""); } buf.append(splitter); } buf.append(HttpParameter.encode(param.getName())).append("="); if (quot) { buf.append("\""); } buf.append(HttpParameter.encode(param.getValue())); } } if (buf.length() != 0) { if (quot) { buf.append("\""); } } return buf.toString(); } public static String normalizeAuthorizationHeaders(final List<HttpParameter> params) { Collections.sort(params); return encodeParameters(params); } /** * The request parameters are collected, sorted and concatenated into a normalized string:<br> * • Parameters in the OAuth HTTP Authorization header excluding the realm parameter.<br> * • Parameters in the HTTP POST request body (with a content-type of * application/x-www-form-urlencoded).<br> * • HTTP GET parameters added to the URLs in the query part (as defined by [RFC3986] section 3). * <br> * <br> * The oauth_signature parameter MUST be excluded.<br> * The parameters are normalized into a single string as follows:<br> * 1. Parameters are sorted by name, using lexicographical byte value ordering. If two or more * parameters share the same name, they are sorted by their value. For example:<br> * 2. a=1, c=hi%20there, f=25, f=50, f=a, z=p, z=t<br> * 3. <br> * 4. Parameters are concatenated in their sorted order into a single string. For each parameter, * the name is separated from the corresponding value by an ‘=’ character (ASCII code 61), even if * the value is empty. Each name-value pair is separated by an ‘&’ character (ASCII code 38). For * example:<br> * 5. a=1&c=hi%20there&f=25&f=50&f=a&z=p&z=t<br> * 6. <br> * * @param params parameters to be normalized and concatenated * @return normalized and concatenated parameters * @see <a href="http://oauth.net/core/1.0#rfc.section.9.1.1">OAuth Core - 9.1.1. Normalize * Request Parameters</a> */ public static String normalizeRequestParameters(final HttpParameter[] params) { return normalizeRequestParameters(toParamList(params)); } public static String normalizeRequestParameters(final List<HttpParameter> params) { Collections.sort(params); return encodeParameters(params); } public static List<HttpParameter> toParamList(final HttpParameter[] params) { final List<HttpParameter> paramList = new ArrayList<HttpParameter>(params.length); paramList.addAll(Arrays.asList(params)); return paramList; } }
/** * @author Yusuke Yamamoto - yusuke at mac.com * @see <a href="http://oauth.net/core/1.0a/">OAuth Core 1.0a</a> */ public final class OAuthAuthorization implements Authorization, java.io.Serializable, OAuthSupport { private final Configuration conf; private static transient HttpClientWrapper http; private static final String HMAC_SHA1 = "HmacSHA1"; private static final HttpParameter OAUTH_SIGNATURE_METHOD = new HttpParameter("oauth_signature_method", "HMAC-SHA1"); private static final Logger logger = Logger.getLogger(OAuthAuthorization.class); static final long serialVersionUID = -4368426677157998618L; private String consumerKey = ""; private String consumerSecret; private OAuthToken oauthToken = null; // constructors public OAuthAuthorization(Configuration conf) { this(conf, conf.getOAuthConsumerKey(), conf.getOAuthConsumerSecret()); } public OAuthAuthorization(Configuration conf, String consumerKey, String consumerSecret) { this.conf = conf; init(consumerKey, consumerSecret); } public OAuthAuthorization( Configuration conf, String consumerKey, String consumerSecret, AccessToken accessToken) { this.conf = conf; init(consumerKey, consumerSecret, accessToken); } private void init(String consumerKey, String consumerSecret) { http = new HttpClientWrapper(conf); setConsumerKey(consumerKey); setConsumerSecret(consumerSecret); } private void init(String consumerKey, String consumerSecret, AccessToken accessToken) { init(consumerKey, consumerSecret); setOAuthAccessToken(accessToken); } // implementations for Authorization public String getAuthorizationHeader(HttpRequest req) { return generateAuthorizationHeader( req.getMethod().name(), req.getURL(), req.getParameters(), oauthToken); } private void ensureTokenIsAvailable() { if (null == oauthToken) { throw new IllegalStateException("No Token available."); } } public boolean isEnabled() { return null != oauthToken && oauthToken instanceof AccessToken; } // implementation for OAuthSupport interface /** {@inheritDoc} */ public RequestToken getOAuthRequestToken() throws TwitterException { return getOAuthRequestToken(null); } /** {@inheritDoc} */ public RequestToken getOAuthRequestToken(String callbackURL) throws TwitterException { HttpParameter[] params = null != callbackURL ? new HttpParameter[] {new HttpParameter("oauth_callback", callbackURL)} : new HttpParameter[0]; oauthToken = new RequestToken(http.post(conf.getOAuthRequestTokenURL(), params, this), this); return (RequestToken) oauthToken; } /** {@inheritDoc} */ public AccessToken getOAuthAccessToken() throws TwitterException { ensureTokenIsAvailable(); if (oauthToken instanceof AccessToken) { return (AccessToken) oauthToken; } oauthToken = new AccessToken(http.post(conf.getOAuthAccessTokenURL(), this)); return (AccessToken) oauthToken; } /** {@inheritDoc} */ public AccessToken getOAuthAccessToken(String oauthVerifier) throws TwitterException { ensureTokenIsAvailable(); oauthToken = new AccessToken( http.post( conf.getOAuthAccessTokenURL(), new HttpParameter[] {new HttpParameter("oauth_verifier", oauthVerifier)}, this)); return (AccessToken) oauthToken; } /** {@inheritDoc} */ public AccessToken getOAuthAccessToken(RequestToken requestToken) throws TwitterException { this.oauthToken = requestToken; return getOAuthAccessToken(); } /** {@inheritDoc} */ public AccessToken getOAuthAccessToken(RequestToken requestToken, String oauthVerifier) throws TwitterException { this.oauthToken = requestToken; return getOAuthAccessToken(oauthVerifier); } /** * Retrieves an access token associated with the supplied screen name and password using xAuth. * <br> * In order to get access acquire AccessToken using xAuth, you must apply by sending an email to * [email protected] — all other applications will receive an HTTP 401 error. Web-based applications * will not be granted access, except on a temporary basis for when they are converting from * basic-authentication support to full OAuth support.<br> * Storage of Twitter usernames and passwords is forbidden. By using xAuth, you are required to * store only access tokens and access token secrets. If the access token expires or is expunged * by a user, you must ask for their login and password again before exchanging the credentials * for an access token. * * @param screenName the screen name * @param password the password * @return access token associated with the supplied request token. * @throws TwitterException when Twitter service or network is unavailable, or the user has not * authorized * @see <a href="http://dev.twitter.com/pages/oauth_faq">OAuth FAQ | dev.twitter.com - How long * does an access token last?</a> * @see <a * href="http://apiwiki.twitter.com/Twitter-REST-API-Method%3A-oauth-access_token-for-xAuth">Twitter * REST API Method: oauth access_token for xAuth</a> * @since Twitter 2.1.1 */ public AccessToken getOAuthAccessToken(String screenName, String password) throws TwitterException { try { oauthToken = new AccessToken( http.post( conf.getOAuthAccessTokenURL(), new HttpParameter[] { new HttpParameter("x_auth_username", screenName), new HttpParameter("x_auth_password", password), new HttpParameter("x_auth_mode", "client_auth") }, this)); return (AccessToken) oauthToken; } catch (TwitterException te) { throw new TwitterException( "The screen name / password combination seems to be invalid.", te, te.getStatusCode()); } } /** {@inheritDoc} */ public void setOAuthAccessToken(AccessToken accessToken) { this.oauthToken = accessToken; } /*package*/ String generateAuthorizationHeader( String method, String url, HttpParameter[] params, String nonce, String timestamp, OAuthToken otoken) { if (null == params) { params = new HttpParameter[0]; } List<HttpParameter> oauthHeaderParams = new ArrayList<HttpParameter>(5); oauthHeaderParams.add(new HttpParameter("oauth_consumer_key", consumerKey)); oauthHeaderParams.add(OAUTH_SIGNATURE_METHOD); oauthHeaderParams.add(new HttpParameter("oauth_timestamp", timestamp)); oauthHeaderParams.add(new HttpParameter("oauth_nonce", nonce)); oauthHeaderParams.add(new HttpParameter("oauth_version", "1.0")); if (null != otoken) { oauthHeaderParams.add(new HttpParameter("oauth_token", otoken.getToken())); } List<HttpParameter> signatureBaseParams = new ArrayList<HttpParameter>(oauthHeaderParams.size() + params.length); signatureBaseParams.addAll(oauthHeaderParams); if (!HttpParameter.containsFile(params)) { signatureBaseParams.addAll(toParamList(params)); } parseGetParameters(url, signatureBaseParams); StringBuffer base = new StringBuffer(method).append("&").append(encode(constructRequestURL(url))).append("&"); base.append(encode(normalizeRequestParameters(signatureBaseParams))); String oauthBaseString = base.toString(); logger.debug("OAuth base string: ", oauthBaseString); String signature = generateSignature(oauthBaseString, otoken); logger.debug("OAuth signature: ", signature); oauthHeaderParams.add(new HttpParameter("oauth_signature", signature)); return "OAuth " + encodeParameters(oauthHeaderParams, ",", true); } private void parseGetParameters(String url, List<HttpParameter> signatureBaseParams) { int queryStart = url.indexOf("?"); if (-1 != queryStart) { String[] queryStrs = url.substring(queryStart + 1).split("&"); try { for (String query : queryStrs) { String[] split = query.split("="); if (split.length == 2) { signatureBaseParams.add( new HttpParameter( URLDecoder.decode(split[0], "UTF-8"), URLDecoder.decode(split[1], "UTF-8"))); } else { signatureBaseParams.add(new HttpParameter(URLDecoder.decode(split[0], "UTF-8"), "")); } } } catch (UnsupportedEncodingException ignore) { } } } private static Random RAND = new Random(); /** * @return generated authorization header * @see <a href="http://oauth.net/core/1.0a/#rfc.section.5.4.1">OAuth Core - 5.4.1. Authorization * Header</a> */ /*package*/ String generateAuthorizationHeader( String method, String url, HttpParameter[] params, OAuthToken token) { long timestamp = System.currentTimeMillis() / 1000; long nonce = timestamp + RAND.nextInt(); return generateAuthorizationHeader( method, url, params, String.valueOf(nonce), String.valueOf(timestamp), token); } public List<HttpParameter> generateOAuthSignatureHttpParams(String method, String url) { long timestamp = System.currentTimeMillis() / 1000; long nonce = timestamp + RAND.nextInt(); List<HttpParameter> oauthHeaderParams = new ArrayList<HttpParameter>(5); oauthHeaderParams.add(new HttpParameter("oauth_consumer_key", consumerKey)); oauthHeaderParams.add(OAUTH_SIGNATURE_METHOD); oauthHeaderParams.add(new HttpParameter("oauth_timestamp", timestamp)); oauthHeaderParams.add(new HttpParameter("oauth_nonce", nonce)); oauthHeaderParams.add(new HttpParameter("oauth_version", "1.0")); if (null != oauthToken) { oauthHeaderParams.add(new HttpParameter("oauth_token", oauthToken.getToken())); } List<HttpParameter> signatureBaseParams = new ArrayList<HttpParameter>(oauthHeaderParams.size()); signatureBaseParams.addAll(oauthHeaderParams); parseGetParameters(url, signatureBaseParams); StringBuffer base = new StringBuffer(method).append("&").append(encode(constructRequestURL(url))).append("&"); base.append(encode(normalizeRequestParameters(signatureBaseParams))); String oauthBaseString = base.toString(); String signature = generateSignature(oauthBaseString, oauthToken); oauthHeaderParams.add(new HttpParameter("oauth_signature", signature)); return oauthHeaderParams; } /** * Computes RFC 2104-compliant HMAC signature. * * @param data the data to be signed * @param token the token * @return signature * @see <a href="http://oauth.net/core/1.0a/#rfc.section.9.2.1">OAuth Core - 9.2.1. Generating * Signature</a> */ /*package*/ String generateSignature(String data, OAuthToken token) { byte[] byteHMAC = null; try { Mac mac = Mac.getInstance(HMAC_SHA1); SecretKeySpec spec; if (null == token) { String oauthSignature = encode(consumerSecret) + "&"; spec = new SecretKeySpec(oauthSignature.getBytes(), HMAC_SHA1); } else { spec = token.getSecretKeySpec(); if (null == spec) { String oauthSignature = encode(consumerSecret) + "&" + encode(token.getTokenSecret()); spec = new SecretKeySpec(oauthSignature.getBytes(), HMAC_SHA1); token.setSecretKeySpec(spec); } } mac.init(spec); byteHMAC = mac.doFinal(data.getBytes()); } catch (InvalidKeyException e) { e.printStackTrace(); } catch (NoSuchAlgorithmException ignore) { // should never happen } return BASE64Encoder.encode(byteHMAC); } /*package*/ String generateSignature(String data) { return generateSignature(data, null); } /** * The request parameters are collected, sorted and concatenated into a normalized string:<br> * • Parameters in the OAuth HTTP Authorization header excluding the realm parameter.<br> * • Parameters in the HTTP POST request body (with a content-type of * application/x-www-form-urlencoded).<br> * • HTTP GET parameters added to the URLs in the query part (as defined by [RFC3986] section 3). * <br> * <br> * The oauth_signature parameter MUST be excluded.<br> * The parameters are normalized into a single string as follows:<br> * 1. Parameters are sorted by name, using lexicographical byte value ordering. If two or more * parameters share the same name, they are sorted by their value. For example:<br> * 2. a=1, c=hi%20there, f=25, f=50, f=a, z=p, z=t<br> * 3. <br> * 4. Parameters are concatenated in their sorted order into a single string. For each parameter, * the name is separated from the corresponding value by an ‘=’ character (ASCII code 61), even if * the value is empty. Each name-value pair is separated by an ‘&’ character (ASCII code 38). For * example:<br> * 5. a=1&c=hi%20there&f=25&f=50&f=a&z=p&z=t<br> * 6. <br> * * @param params parameters to be normalized and concatenated * @return normalized and concatenated parameters * @see <a href="http://oauth.net/core/1.0#rfc.section.9.1.1">OAuth Core - 9.1.1. Normalize * Request Parameters</a> */ public static String normalizeRequestParameters(HttpParameter[] params) { return normalizeRequestParameters(toParamList(params)); } public static String normalizeRequestParameters(List<HttpParameter> params) { Collections.sort(params); return encodeParameters(params); } public static String normalizeAuthorizationHeaders(List<HttpParameter> params) { Collections.sort(params); return encodeParameters(params); } public static List<HttpParameter> toParamList(HttpParameter[] params) { List<HttpParameter> paramList = new ArrayList<HttpParameter>(params.length); paramList.addAll(Arrays.asList(params)); return paramList; } /** * @param httpParams parameters to be encoded and concatenated * @return encoded string * @see <a href="http://wiki.oauth.net/TestCases">OAuth / TestCases</a> * @see <a * href="http://groups.google.com/group/oauth/browse_thread/thread/a8398d0521f4ae3d/9d79b698ab217df2?hl=en&lnk=gst&q=space+encoding#9d79b698ab217df2">Space * encoding - OAuth | Google Groups</a> */ public static String encodeParameters(List<HttpParameter> httpParams) { return encodeParameters(httpParams, "&", false); } public static String encodeParameters( List<HttpParameter> httpParams, String splitter, boolean quot) { StringBuffer buf = new StringBuffer(); for (HttpParameter param : httpParams) { if (!param.isFile()) { if (buf.length() != 0) { if (quot) { buf.append("\""); } buf.append(splitter); } buf.append(encode(param.getName())).append("="); if (quot) { buf.append("\""); } buf.append(encode(param.getValue())); } } if (buf.length() != 0) { if (quot) { buf.append("\""); } } return buf.toString(); } /** * @param value string to be encoded * @return encoded string * @see <a href="http://wiki.oauth.net/TestCases">OAuth / TestCases</a> * @see <a * href="http://groups.google.com/group/oauth/browse_thread/thread/a8398d0521f4ae3d/9d79b698ab217df2?hl=en&lnk=gst&q=space+encoding#9d79b698ab217df2">Space * encoding - OAuth | Google Groups</a> * @see <a href="http://tools.ietf.org/html/rfc3986#section-2.1">RFC 3986 - Uniform Resource * Identifier (URI): Generic Syntax - 2.1. Percent-Encoding</a> */ public static String encode(String value) { String encoded = null; try { encoded = URLEncoder.encode(value, "UTF-8"); } catch (UnsupportedEncodingException ignore) { } StringBuffer buf = new StringBuffer(encoded.length()); char focus; for (int i = 0; i < encoded.length(); i++) { focus = encoded.charAt(i); if (focus == '*') { buf.append("%2A"); } else if (focus == '+') { buf.append("%20"); } else if (focus == '%' && (i + 1) < encoded.length() && encoded.charAt(i + 1) == '7' && encoded.charAt(i + 2) == 'E') { buf.append('~'); i += 2; } else { buf.append(focus); } } return buf.toString(); } /** * The Signature Base String includes the request absolute URL, tying the signature to a specific * endpoint. The URL used in the Signature Base String MUST include the scheme, authority, and * path, and MUST exclude the query and fragment as defined by [RFC3986] section 3.<br> * If the absolute request URL is not available to the Service Provider (it is always available to * the Consumer), it can be constructed by combining the scheme being used, the HTTP Host header, * and the relative HTTP request URL. If the Host header is not available, the Service Provider * SHOULD use the host name communicated to the Consumer in the documentation or other means.<br> * The Service Provider SHOULD document the form of URL used in the Signature Base String to avoid * ambiguity due to URL normalization. Unless specified, URL scheme and authority MUST be * lowercase and include the port number; http default port 80 and https default port 443 MUST be * excluded.<br> * <br> * For example, the request:<br> * HTTP://Example.com:80/resource?id=123<br> * Is included in the Signature Base String as:<br> * http://example.com/resource * * @param url the url to be normalized * @return the Signature Base String * @see <a href="http://oauth.net/core/1.0#rfc.section.9.1.2">OAuth Core - 9.1.2. Construct * Request URL</a> */ public static String constructRequestURL(String url) { int index = url.indexOf("?"); if (-1 != index) { url = url.substring(0, index); } int slashIndex = url.indexOf("/", 8); String baseURL = url.substring(0, slashIndex).toLowerCase(); int colonIndex = baseURL.indexOf(":", 8); if (-1 != colonIndex) { // url contains port number if (baseURL.startsWith("http://") && baseURL.endsWith(":80")) { // http default port 80 MUST be excluded baseURL = baseURL.substring(0, colonIndex); } else if (baseURL.startsWith("https://") && baseURL.endsWith(":443")) { // http default port 443 MUST be excluded baseURL = baseURL.substring(0, colonIndex); } } url = baseURL + url.substring(slashIndex); return url; } private void setConsumerKey(String consumerKey) { this.consumerKey = null != consumerKey ? consumerKey : ""; } private void setConsumerSecret(String consumerSecret) { this.consumerSecret = null != consumerSecret ? consumerSecret : ""; } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof OAuthSupport)) return false; OAuthAuthorization that = (OAuthAuthorization) o; if (consumerKey != null ? !consumerKey.equals(that.consumerKey) : that.consumerKey != null) return false; if (consumerSecret != null ? !consumerSecret.equals(that.consumerSecret) : that.consumerSecret != null) return false; if (oauthToken != null ? !oauthToken.equals(that.oauthToken) : that.oauthToken != null) return false; return true; } @Override public int hashCode() { int result = consumerKey != null ? consumerKey.hashCode() : 0; result = 31 * result + (consumerSecret != null ? consumerSecret.hashCode() : 0); result = 31 * result + (oauthToken != null ? oauthToken.hashCode() : 0); return result; } @Override public String toString() { return "OAuthAuthorization{" + "consumerKey='" + consumerKey + '\'' + ", consumerSecret='******************************************\'" + ", oauthToken=" + oauthToken + '}'; } }
private void init(JSONObject json) throws TwitterException { id = getLong("id", json); text = getUnescapedString("text", json); source = getUnescapedString("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 = getUnescapedString("in_reply_to_screen_name", json); retweetCount = getLong("retweet_count", json); try { if (!json.isNull("user")) { user = new UserJSONImpl(json.getJSONObject("user")); } } catch (JSONException jsone) { throw new TwitterException(jsone); } geoLocation = z_T4JInternalJSONImplFactory.createGeoLocation(json); if (!json.isNull("place")) { try { place = new PlaceJSONImpl(json.getJSONObject("place")); } catch (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 (JSONException ignore) { ignore.printStackTrace(); logger.warn("failed to parse retweeted_status:" + json); } } if (!json.isNull("contributors")) { try { 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 (NumberFormatException ignore) { ignore.printStackTrace(); logger.warn("failed to parse contributors:" + json); } catch (JSONException ignore) { ignore.printStackTrace(); logger.warn("failed to parse contributors:" + json); } } else { contributors = null; } if (!json.isNull("entities")) { try { JSONObject entities = json.getJSONObject("entities"); int len; if (!entities.isNull("user_mentions")) { 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")) { 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")) { 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")) { 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 (JSONException jsone) { throw new TwitterException(jsone); } } if (!json.isNull("annotations")) { try { JSONArray annotationsArray = json.getJSONArray("annotations"); annotations = new Annotations(annotationsArray); } catch (JSONException ignore) { } } if (!json.isNull("current_user_retweet")) { try { myRetweetedStatus = new StatusJSONImpl(json.getJSONObject("current_user_retweet")); } catch (JSONException ignore) { ignore.printStackTrace(); logger.warn("failed to parse current_user_retweet:" + json); } } }
/** * A data class representing one single status of a user. * * @author Yusuke Yamamoto - yusuke at mac.com */ /*package*/ final class StatusJSONImpl extends TwitterResponseImpl implements Status, java.io.Serializable { private static final Logger logger = Logger.getLogger(StatusJSONImpl.class); private static final long serialVersionUID = 7548618898682727465L; private Date createdAt; private long id; private String text; private String source; private boolean isTruncated; private long inReplyToStatusId; private long inReplyToUserId; private boolean isFavorited; private String inReplyToScreenName; private GeoLocation geoLocation = null; private Place place = null; private long retweetCount; private String[] contributors = null; private long[] contributorsIDs; private Annotations annotations = null; private Status retweetedStatus; private UserMentionEntity[] userMentionEntities; private URLEntity[] urlEntities; private HashtagEntity[] hashtagEntities; private MediaEntity[] mediaEntities; private Status myRetweetedStatus; /*package*/ StatusJSONImpl(HttpResponse res, Configuration conf) throws TwitterException { super(res); JSONObject json = res.asJSONObject(); init(json); if (conf.isJSONStoreEnabled()) { DataObjectFactoryUtil.clearThreadLocalMap(); DataObjectFactoryUtil.registerJSONObject(this, json); } } /*package*/ StatusJSONImpl(JSONObject json) throws TwitterException { super(); init(json); } private void init(JSONObject json) throws TwitterException { id = getLong("id", json); text = getUnescapedString("text", json); source = getUnescapedString("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 = getUnescapedString("in_reply_to_screen_name", json); retweetCount = getLong("retweet_count", json); try { if (!json.isNull("user")) { user = new UserJSONImpl(json.getJSONObject("user")); } } catch (JSONException jsone) { throw new TwitterException(jsone); } geoLocation = z_T4JInternalJSONImplFactory.createGeoLocation(json); if (!json.isNull("place")) { try { place = new PlaceJSONImpl(json.getJSONObject("place")); } catch (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 (JSONException ignore) { ignore.printStackTrace(); logger.warn("failed to parse retweeted_status:" + json); } } if (!json.isNull("contributors")) { try { 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 (NumberFormatException ignore) { ignore.printStackTrace(); logger.warn("failed to parse contributors:" + json); } catch (JSONException ignore) { ignore.printStackTrace(); logger.warn("failed to parse contributors:" + json); } } else { contributors = null; } if (!json.isNull("entities")) { try { JSONObject entities = json.getJSONObject("entities"); int len; if (!entities.isNull("user_mentions")) { 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")) { 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")) { 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")) { 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 (JSONException jsone) { throw new TwitterException(jsone); } } if (!json.isNull("annotations")) { try { JSONArray annotationsArray = json.getJSONArray("annotations"); annotations = new Annotations(annotationsArray); } catch (JSONException ignore) { } } if (!json.isNull("current_user_retweet")) { try { myRetweetedStatus = new StatusJSONImpl(json.getJSONObject("current_user_retweet")); } catch (JSONException ignore) { ignore.printStackTrace(); logger.warn("failed to parse current_user_retweet:" + json); } } } public int compareTo(Status that) { long delta = this.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; } /** {@inheritDoc} */ public Date getCreatedAt() { return this.createdAt; } /** {@inheritDoc} */ public long getId() { return this.id; } /** {@inheritDoc} */ public String getText() { return this.text; } /** {@inheritDoc} */ public String getSource() { return this.source; } /** {@inheritDoc} */ public boolean isTruncated() { return isTruncated; } /** {@inheritDoc} */ public long getInReplyToStatusId() { return inReplyToStatusId; } /** {@inheritDoc} */ public long getInReplyToUserId() { return inReplyToUserId; } /** {@inheritDoc} */ public String getInReplyToScreenName() { return inReplyToScreenName; } /** {@inheritDoc} */ public GeoLocation getGeoLocation() { return geoLocation; } /** {@inheritDoc} */ public Place getPlace() { return place; } /** {@inheritDoc} */ 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 (NumberFormatException nfe) { nfe.printStackTrace(); logger.warn("failed to parse contributors:" + nfe); } } contributors = null; } return contributorsIDs; } /** {@inheritDoc} */ public Annotations getAnnotations() { return annotations; } /** {@inheritDoc} */ public boolean isFavorited() { return isFavorited; } private User user = null; /** {@inheritDoc} */ public User getUser() { return user; } /** {@inheritDoc} */ public boolean isRetweet() { return retweetedStatus != null; } /** {@inheritDoc} */ public Status getRetweetedStatus() { return retweetedStatus; } /** {@inheritDoc} */ public long getRetweetCount() { return retweetCount; } /** {@inheritDoc} */ public boolean isRetweetedByMe() { return myRetweetedStatus != null; } /** {@inheritDoc} */ public Status getMyRetweet() { return myRetweetedStatus; } /** {@inheritDoc} */ public UserMentionEntity[] getUserMentionEntities() { return userMentionEntities; } /** {@inheritDoc} */ public URLEntity[] getURLEntities() { return urlEntities; } /** {@inheritDoc} */ public HashtagEntity[] getHashtagEntities() { return hashtagEntities; } /** {@inheritDoc} */ public MediaEntity[] getMediaEntities() { return mediaEntities; } /*package*/ static ResponseList<Status> createStatusList(HttpResponse res, Configuration conf) throws TwitterException { try { if (conf.isJSONStoreEnabled()) { DataObjectFactoryUtil.clearThreadLocalMap(); } JSONArray list = res.asJSONArray(); int size = list.length(); ResponseList<Status> statuses = new ResponseListImpl<Status>(size, res); for (int i = 0; i < size; i++) { JSONObject json = list.getJSONObject(i); Status status = new StatusJSONImpl(json); if (conf.isJSONStoreEnabled()) { DataObjectFactoryUtil.registerJSONObject(status, json); } statuses.add(status); } if (conf.isJSONStoreEnabled()) { DataObjectFactoryUtil.registerJSONObject(statuses, list); } return statuses; } catch (JSONException jsone) { throw new TwitterException(jsone); } catch (TwitterException te) { throw te; } } @Override public int hashCode() { return (int) id; } @Override public boolean equals(Object obj) { if (null == obj) { return false; } if (this == obj) { return true; } return obj instanceof Status && ((Status) obj).getId() == this.id; } @Override public String toString() { return "StatusJSONImpl{" + "createdAt=" + createdAt + ", id=" + id + ", text='" + text + '\'' + ", source='" + source + '\'' + ", isTruncated=" + isTruncated + ", inReplyToStatusId=" + inReplyToStatusId + ", inReplyToUserId=" + inReplyToUserId + ", isFavorited=" + isFavorited + ", inReplyToScreenName='" + inReplyToScreenName + '\'' + ", geoLocation=" + geoLocation + ", place=" + place + ", retweetCount=" + retweetCount + ", myRetweetedStatus=" + myRetweetedStatus + ", contributors=" + (contributorsIDs == null ? null : Arrays.asList(contributorsIDs)) + ", annotations=" + annotations + ", retweetedStatus=" + retweetedStatus + ", userMentionEntities=" + (userMentionEntities == null ? null : Arrays.asList(userMentionEntities)) + ", urlEntities=" + (urlEntities == null ? null : Arrays.asList(urlEntities)) + ", hashtagEntities=" + (hashtagEntities == null ? null : Arrays.asList(hashtagEntities)) + ", user=" + user + '}'; } }
/** * A java representation of the <a * href="https://dev.twitter.com/docs/streaming-api/methods">Streaming API: Methods</a><br> * Note that this class is NOT compatible with Google App Engine as GAE is not capable of handling * requests longer than 30 seconds. * * @author Yusuke Yamamoto - yusuke at mac.com * @since Twitter4J 2.0.4 */ class TwitterStreamImpl extends TwitterBaseImpl implements TwitterStream { private static final long serialVersionUID = 5529611191443189901L; private final HttpClientWrapper http; private static final Logger logger = Logger.getLogger(TwitterStreamImpl.class); private List<ConnectionLifeCycleListener> lifeCycleListeners = new ArrayList<ConnectionLifeCycleListener>(0); private TwitterStreamConsumer handler = null; private String stallWarningsGetParam; private HttpParameter stallWarningsParam; /*package*/ TwitterStreamImpl(Configuration conf, Authorization auth) { super(conf, auth); http = new HttpClientWrapper(new StreamingReadTimeoutConfiguration(conf)); stallWarningsGetParam = "stall_warnings=" + (conf.isStallWarningsEnabled() ? "true" : "false"); stallWarningsParam = new HttpParameter("stall_warnings", conf.isStallWarningsEnabled()); } /* Streaming API */ /** {@inheritDoc} */ @Override public void firehose(final int count) { ensureAuthorizationEnabled(); ensureStatusStreamListenerIsSet(); startHandler( new TwitterStreamConsumer(statusListeners, rawStreamListeners) { @Override public StatusStream getStream() throws TwitterException { return getFirehoseStream(count); } }); } /** {@inheritDoc} */ @Override public StatusStream getFirehoseStream(int count) throws TwitterException { ensureAuthorizationEnabled(); return getCountStream("statuses/firehose.json", count); } /** {@inheritDoc} */ @Override public void links(final int count) { ensureAuthorizationEnabled(); ensureStatusStreamListenerIsSet(); startHandler( new TwitterStreamConsumer(statusListeners, rawStreamListeners) { @Override public StatusStream getStream() throws TwitterException { return getLinksStream(count); } }); } /** {@inheritDoc} */ @Override public StatusStream getLinksStream(int count) throws TwitterException { ensureAuthorizationEnabled(); return getCountStream("statuses/links.json", count); } private StatusStream getCountStream(String relativeUrl, int count) throws TwitterException { ensureAuthorizationEnabled(); try { return new StatusStreamImpl( getDispatcher(), http.post( conf.getStreamBaseURL() + relativeUrl, new HttpParameter[] { new HttpParameter("count", String.valueOf(count)), stallWarningsParam }, auth), conf); } catch (IOException e) { throw new TwitterException(e); } } /** {@inheritDoc} */ @Override public void retweet() { ensureAuthorizationEnabled(); ensureStatusStreamListenerIsSet(); startHandler( new TwitterStreamConsumer(statusListeners, rawStreamListeners) { @Override public StatusStream getStream() throws TwitterException { return getRetweetStream(); } }); } /** {@inheritDoc} */ @Override public StatusStream getRetweetStream() throws TwitterException { ensureAuthorizationEnabled(); try { return new StatusStreamImpl( getDispatcher(), http.post( conf.getStreamBaseURL() + "statuses/retweet.json", new HttpParameter[] {stallWarningsParam}, auth), conf); } catch (IOException e) { throw new TwitterException(e); } } /** {@inheritDoc} */ @Override public void sample() { ensureAuthorizationEnabled(); ensureStatusStreamListenerIsSet(); startHandler( new TwitterStreamConsumer(statusListeners, rawStreamListeners) { @Override public StatusStream getStream() throws TwitterException { return getSampleStream(); } }); } /** {@inheritDoc} */ @Override public StatusStream getSampleStream() throws TwitterException { ensureAuthorizationEnabled(); try { return new StatusStreamImpl( getDispatcher(), http.get(conf.getStreamBaseURL() + "statuses/sample.json?" + stallWarningsGetParam, auth), conf); } catch (IOException e) { throw new TwitterException(e); } } /** {@inheritDoc} */ public void user() { user(null); } /** {@inheritDoc} */ @Override public void user(final String[] track) { ensureAuthorizationEnabled(); ensureUserStreamListenerIsSet(); startHandler( new TwitterStreamConsumer(statusListeners, rawStreamListeners) { @Override public StatusStream getStream() throws TwitterException { return getUserStream(track); } }); } /** {@inheritDoc} */ @Override public UserStream getUserStream() throws TwitterException { return getUserStream(null); } /** {@inheritDoc} */ @Override public UserStream getUserStream(String[] track) throws TwitterException { ensureAuthorizationEnabled(); try { List<HttpParameter> params = new ArrayList<HttpParameter>(); params.add(stallWarningsParam); if (conf.isUserStreamRepliesAllEnabled()) { params.add(new HttpParameter("replies", "all")); } if (track != null) { params.add(new HttpParameter("track", z_T4JInternalStringUtil.join(track))); } return new UserStreamImpl( getDispatcher(), http.post( conf.getUserStreamBaseURL() + "user.json", params.toArray(new HttpParameter[params.size()]), auth), conf); } catch (IOException e) { throw new TwitterException(e); } } /** {@inheritDoc} */ @Override public StreamController site(final boolean withFollowings, final long[] follow) { ensureOAuthEnabled(); ensureSiteStreamsListenerIsSet(); final StreamController cs = new StreamController(http, auth); startHandler( new TwitterStreamConsumer(siteStreamsListeners, rawStreamListeners) { @Override public StatusStream getStream() throws TwitterException { try { return new SiteStreamsImpl( getDispatcher(), getSiteStream(withFollowings, follow), conf, cs); } catch (IOException e) { throw new TwitterException(e); } } }); return cs; } private Dispatcher getDispatcher() { if (null == TwitterStreamImpl.dispatcher) { synchronized (TwitterStreamImpl.class) { if (null == TwitterStreamImpl.dispatcher) { // dispatcher is held statically, but it'll be instantiated with // the configuration instance associated with this TwitterStream // instance which invokes getDispatcher() on the first time. TwitterStreamImpl.dispatcher = new DispatcherFactory(conf).getInstance(); } } } return TwitterStreamImpl.dispatcher; } private static transient Dispatcher dispatcher; InputStream getSiteStream(boolean withFollowings, long[] follow) throws TwitterException { ensureOAuthEnabled(); return http.post( conf.getSiteStreamBaseURL() + "site.json", new HttpParameter[] { new HttpParameter("with", withFollowings ? "followings" : "user"), new HttpParameter("follow", z_T4JInternalStringUtil.join(follow)), stallWarningsParam }, auth) .asStream(); } /** {@inheritDoc} */ @Override public void filter(final FilterQuery query) { ensureAuthorizationEnabled(); ensureStatusStreamListenerIsSet(); // handle.start() startHandler( new TwitterStreamConsumer(statusListeners, rawStreamListeners) { @Override public StatusStream getStream() throws TwitterException { return getFilterStream(query); // 重写了getStream的方法 } }); } /** {@inheritDoc} */ @Override public StatusStream getFilterStream(FilterQuery query) throws TwitterException { ensureAuthorizationEnabled(); try { return new StatusStreamImpl( getDispatcher(), http.post( conf.getStreamBaseURL() + "statuses/filter.json", query.asHttpParameterArray(stallWarningsParam), auth), conf); } catch (IOException e) { throw new TwitterException(e); } } /** * check if any listener is set. Throws IllegalStateException if no listener is set. * * @throws IllegalStateException when no listener is set. */ private void ensureStatusStreamListenerIsSet() { if (statusListeners.size() == 0 && rawStreamListeners.size() == 0) { throw new IllegalStateException("StatusListener is not set."); } } private void ensureUserStreamListenerIsSet() { if (userStreamListeners.size() == 0 && rawStreamListeners.size() == 0) { throw new IllegalStateException("UserStreamListener is not set."); } } private void ensureSiteStreamsListenerIsSet() { if (siteStreamsListeners.size() == 0 && rawStreamListeners.size() == 0) { throw new IllegalStateException("SiteStreamsListener is not set."); } } private static int numberOfHandlers = 0; private synchronized void startHandler(TwitterStreamConsumer handler) { cleanUp(); this.handler = handler; this.handler.start(); numberOfHandlers++; } /** {@inheritDoc} */ @Override public synchronized void cleanUp() { if (handler != null) { handler.close(); numberOfHandlers--; } } /** {@inheritDoc} */ @Override public synchronized void shutdown() { super.shutdown(); cleanUp(); synchronized (TwitterStreamImpl.class) { if (0 == numberOfHandlers) { if (dispatcher != null) { dispatcher.shutdown(); dispatcher = null; } } } } /** {@inheritDoc} */ @Override public void addConnectionLifeCycleListener(ConnectionLifeCycleListener listener) { this.lifeCycleListeners.add(listener); } private List<StreamListener> userStreamListeners = new ArrayList<StreamListener>(0); /** {@inheritDoc} */ @Override public void addListener(UserStreamListener listener) { statusListeners.add(listener); userStreamListeners.add(listener); } private List<StreamListener> statusListeners = new ArrayList<StreamListener>(0); /** {@inheritDoc} */ @Override public void addListener(StatusListener listener) { statusListeners.add(listener); } private List<StreamListener> siteStreamsListeners = new ArrayList<StreamListener>(0); /** {@inheritDoc} */ @Override public void addListener(SiteStreamsListener listener) { siteStreamsListeners.add(listener); } private List<RawStreamListener> rawStreamListeners = new ArrayList<RawStreamListener>(0); /** {@inheritDoc} */ public void addListener(RawStreamListener listener) { rawStreamListeners.add(listener); } /* https://dev.twitter.com/docs/streaming-api/concepts#connecting When a network error (TCP/IP level) is encountered, back off linearly. Perhaps start at 250 milliseconds, double, and cap at 16 seconds When a HTTP error (> 200) is returned, back off exponentially. Perhaps start with a 10 second wait, double on each subsequent failure, and finally cap the wait at 240 seconds. Consider sending an alert to a human operator after multiple HTTP errors, as there is probably a client configuration issue that is unlikely to be resolved without human intervention. There's not much point in polling any faster in the face of HTTP error codes and your client is may run afoul of a rate limit. */ private static final int TCP_ERROR_INITIAL_WAIT = 250; private static final int TCP_ERROR_WAIT_CAP = 16 * 1000; private static final int HTTP_ERROR_INITIAL_WAIT = 10 * 1000; private static final int HTTP_ERROR_WAIT_CAP = 240 * 1000; private static final int NO_WAIT = 0; static int count = 0; abstract class TwitterStreamConsumer extends Thread { private StatusStreamBase stream = null; private final String NAME = "Twitter Stream consumer-" + (++count); private volatile boolean closed = false; private final StreamListener[] streamListeners; private final RawStreamListener[] rawStreamListeners; TwitterStreamConsumer( List<StreamListener> streamListeners, List<RawStreamListener> rawStreamListeners) { super(); setName(NAME + "[initializing]"); this.streamListeners = streamListeners.toArray(new StreamListener[streamListeners.size()]); this.rawStreamListeners = rawStreamListeners.toArray(new RawStreamListener[rawStreamListeners.size()]); } @Override public void run() { int timeToSleep = NO_WAIT; boolean connected = false; while (!closed) { try { if (!closed && null == stream) { // try establishing connection logger.info("Establishing connection."); setStatus("[Establishing connection]"); stream = (StatusStreamBase) getStream(); connected = true; logger.info("Connection established."); for (ConnectionLifeCycleListener listener : lifeCycleListeners) { try { listener.onConnect(); } catch (Exception e) { logger.warn(e.getMessage()); } } // connection established successfully timeToSleep = NO_WAIT; logger.info("Receiving status stream."); setStatus("[Receiving stream]"); while (!closed) { try { /* * new built */ stream.next(this.streamListeners, this.rawStreamListeners); } catch (IllegalStateException ise) { logger.warn(ise.getMessage()); break; } catch (TwitterException e) { logger.info(e.getMessage()); stream.onException(e, this.streamListeners, this.rawStreamListeners); throw e; } catch (Exception e) { logger.info(e.getMessage()); stream.onException(e, this.streamListeners, this.rawStreamListeners); closed = true; break; } } } } catch (TwitterException te) { logger.info(te.getMessage()); if (!closed) { if (NO_WAIT == timeToSleep) { if (te.getStatusCode() == FORBIDDEN) { logger.warn("This account is not in required role. ", te.getMessage()); closed = true; for (StreamListener statusListener : streamListeners) { statusListener.onException(te); } break; } if (te.getStatusCode() == NOT_ACCEPTABLE) { logger.warn("Parameter not accepted with the role. ", te.getMessage()); closed = true; for (StreamListener statusListener : streamListeners) { statusListener.onException(te); } break; } connected = false; for (ConnectionLifeCycleListener listener : lifeCycleListeners) { try { listener.onDisconnect(); } catch (Exception e) { logger.warn(e.getMessage()); } } if (te.getStatusCode() > 200) { timeToSleep = HTTP_ERROR_INITIAL_WAIT; } else if (0 == timeToSleep) { timeToSleep = TCP_ERROR_INITIAL_WAIT; } } if (te.getStatusCode() > 200 && timeToSleep < HTTP_ERROR_INITIAL_WAIT) { timeToSleep = HTTP_ERROR_INITIAL_WAIT; } if (connected) { for (ConnectionLifeCycleListener listener : lifeCycleListeners) { try { listener.onDisconnect(); } catch (Exception e) { logger.warn(e.getMessage()); } } } for (StreamListener statusListener : streamListeners) { statusListener.onException(te); } // there was a problem establishing the connection, or the connection closed by peer if (!closed) { // wait for a moment not to overload Twitter API logger.info("Waiting for " + (timeToSleep) + " milliseconds"); setStatus("[Waiting for " + (timeToSleep) + " milliseconds]"); try { Thread.sleep(timeToSleep); } catch (InterruptedException ignore) { } timeToSleep = Math.min( timeToSleep * 2, (te.getStatusCode() > 200) ? HTTP_ERROR_WAIT_CAP : TCP_ERROR_WAIT_CAP); } stream = null; logger.debug(te.getMessage()); connected = false; } } } // end for while if (this.stream != null && connected) { try { /* * new built */ String line = "{\"created_at\":\"Fri\",\"id\":123,\"id_str\":\"123\",\"text\":\"YOU are WORNG!.\",\"source\":\"123\",\"truncated\":false,\"in_reply_to_status_id\":null,\"in_reply_to_status_id_str\":null,\"in_reply_to_user_id\":null,\"in_reply_to_user_id_str\":null,\"in_reply_to_screen_name\":null,\"user\":{\"id\":319351645,\"id_str\":\"319351645\",\"name\":\"Briana who? \",\"screen_name\":\"Yo_daddyknows\",\"location\":\"\",\"url\":null,\"description\":null,\"protected\":false,\"followers_count\":811,\"friends_count\":735,\"listed_count\":0,\"created_at\":\"Fri Jun 17 23:58:49 +0000 2011\",\"favourites_count\":10,\"utc_offset\":-18000,\"time_zone\":\"Central Time (US & Canada)\",\"geo_enabled\":false,\"verified\":false,\"statuses_count\":34697,\"lang\":\"en\",\"contributors_enabled\":false,\"is_translator\":false,\"profile_background_color\":\"642D8B\",\"profile_background_image_url\":\"g.gif\",\"profile_background_image_url_https\":\"g.gif\",\"profile_background_tile\":true,\"profile_image_url\":\"http:l.jpeg\",\"profile_image_url_https\":\"l.jpeg\",\"profile_banner_url\":\"923\",\"profile_link_color\":\"FF0000\",\"profile_sidebar_border_color\":\"65B0DA\",\"profile_sidebar_fill_color\":\"7AC3EE\",\"profile_text_color\":\"3D1957\",\"profile_use_background_image\":true,\"default_profile\":false,\"default_profile_image\":false,\"following\":null,\"follow_request_sent\":null,\"notifications\":null},\"geo\":null,\"coordinates\":null,\"place\":null,\"contributors\":null,\"retweet_count\":0,\"entities\":{\"hashtags\":[],\"urls\":[],\"user_mentions\":[]},\"favorited\":false,\"retweeted\":false,\"filter_level\":\"medium\",\"lang\":\"en\"}"; JSONObject json = new JSONObject(line); // System.out.println(line); JSONObjectType.Type event = JSONObjectType.determine(json); this.stream.onStatus(json, this.streamListeners); this.stream.close(); } catch (IOException ignore) { } catch (Exception e) { e.printStackTrace(); logger.warn(e.getMessage()); } finally { for (ConnectionLifeCycleListener listener : lifeCycleListeners) { try { listener.onDisconnect(); } catch (Exception e) { logger.warn(e.getMessage()); } } } } for (ConnectionLifeCycleListener listener : lifeCycleListeners) { try { listener.onCleanUp(); } catch (Exception e) { logger.warn(e.getMessage()); } } } public synchronized void close() { setStatus("[Disposing thread]"); try { if (stream != null) { try { stream.close(); } catch (IOException ignore) { } catch (Exception e) { e.printStackTrace(); logger.warn(e.getMessage()); } } } finally { closed = true; } } private void setStatus(String message) { String actualMessage = NAME + message; setName(actualMessage); logger.debug(actualMessage); } abstract StatusStream getStream() throws TwitterException; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; if (!super.equals(o)) return false; TwitterStreamImpl that = (TwitterStreamImpl) o; if (handler != null ? !handler.equals(that.handler) : that.handler != null) return false; if (http != null ? !http.equals(that.http) : that.http != null) return false; if (lifeCycleListeners != null ? !lifeCycleListeners.equals(that.lifeCycleListeners) : that.lifeCycleListeners != null) return false; if (rawStreamListeners != null ? !rawStreamListeners.equals(that.rawStreamListeners) : that.rawStreamListeners != null) return false; if (siteStreamsListeners != null ? !siteStreamsListeners.equals(that.siteStreamsListeners) : that.siteStreamsListeners != null) return false; if (stallWarningsGetParam != null ? !stallWarningsGetParam.equals(that.stallWarningsGetParam) : that.stallWarningsGetParam != null) return false; if (stallWarningsParam != null ? !stallWarningsParam.equals(that.stallWarningsParam) : that.stallWarningsParam != null) return false; if (statusListeners != null ? !statusListeners.equals(that.statusListeners) : that.statusListeners != null) return false; if (userStreamListeners != null ? !userStreamListeners.equals(that.userStreamListeners) : that.userStreamListeners != null) return false; return true; } @Override public int hashCode() { int result = super.hashCode(); result = 31 * result + (http != null ? http.hashCode() : 0); result = 31 * result + (lifeCycleListeners != null ? lifeCycleListeners.hashCode() : 0); result = 31 * result + (handler != null ? handler.hashCode() : 0); result = 31 * result + (stallWarningsGetParam != null ? stallWarningsGetParam.hashCode() : 0); result = 31 * result + (stallWarningsParam != null ? stallWarningsParam.hashCode() : 0); result = 31 * result + (userStreamListeners != null ? userStreamListeners.hashCode() : 0); result = 31 * result + (statusListeners != null ? statusListeners.hashCode() : 0); result = 31 * result + (siteStreamsListeners != null ? siteStreamsListeners.hashCode() : 0); result = 31 * result + (rawStreamListeners != null ? rawStreamListeners.hashCode() : 0); return result; } @Override public String toString() { return "TwitterStreamImpl{" + "http=" + http + ", lifeCycleListeners=" + lifeCycleListeners + ", handler=" + handler + ", stallWarningsGetParam='" + stallWarningsGetParam + '\'' + ", stallWarningsParam=" + stallWarningsParam + ", userStreamListeners=" + userStreamListeners + ", statusListeners=" + statusListeners + ", siteStreamsListeners=" + siteStreamsListeners + ", rawStreamListeners=" + rawStreamListeners + '}'; } }
/** * A java representation of the <a * href="http://dev.twitter.com/pages/streaming_api_methods">Streaming API: Methods</a><br> * Note that this class is NOT compatible with Google App Engine as GAE is not capable of handling * requests longer than 30 seconds. * * @author Yusuke Yamamoto - yusuke at mac.com * @since Twitter4J 2.0.4 */ class TwitterStreamImpl extends TwitterBaseImpl implements TwitterStream { private static final long serialVersionUID = 5529611191443189901L; private final HttpClientWrapper http; private static final Logger logger = Logger.getLogger(TwitterStreamImpl.class); private StreamListener[] streamListeners = new StreamListener[0]; private List<ConnectionLifeCycleListener> lifeCycleListeners = new ArrayList<ConnectionLifeCycleListener>(0); private TwitterStreamConsumer handler = null; /*package*/ TwitterStreamImpl(Configuration conf, Authorization auth) { super(conf, auth); http = new HttpClientWrapper(new StreamingReadTimeoutConfiguration(conf)); } /*package*/ TwitterStreamImpl(Configuration conf) { super(conf); http = new HttpClientWrapper(new StreamingReadTimeoutConfiguration(conf)); } /* Streaming API */ /** {@inheritDoc} */ public void firehose(final int count) { ensureAuthorizationEnabled(); ensureListenerIsSet(); ensureStatusStreamListenerIsSet(); startHandler( new TwitterStreamConsumer() { public StatusStream getStream() throws TwitterException { return getFirehoseStream(count); } }); } /** {@inheritDoc} */ public StatusStream getFirehoseStream(int count) throws TwitterException { ensureAuthorizationEnabled(); return getCountStream("statuses/firehose.json", count); } /** {@inheritDoc} */ public void links(final int count) { ensureAuthorizationEnabled(); ensureListenerIsSet(); ensureStatusStreamListenerIsSet(); startHandler( new TwitterStreamConsumer() { public StatusStream getStream() throws TwitterException { return getLinksStream(count); } }); } /** {@inheritDoc} */ public StatusStream getLinksStream(int count) throws TwitterException { ensureAuthorizationEnabled(); return getCountStream("statuses/links.json", count); } private StatusStream getCountStream(String relativeUrl, int count) throws TwitterException { ensureAuthorizationEnabled(); try { return new StatusStreamImpl( getDispatcher(), http.post( conf.getStreamBaseURL() + relativeUrl, new HttpParameter[] {new HttpParameter("count", String.valueOf(count))}, auth), conf); } catch (IOException e) { throw new TwitterException(e); } } /** {@inheritDoc} */ public void retweet() { ensureAuthorizationEnabled(); ensureListenerIsSet(); ensureStatusStreamListenerIsSet(); startHandler( new TwitterStreamConsumer() { public StatusStream getStream() throws TwitterException { return getRetweetStream(); } }); } /** {@inheritDoc} */ public StatusStream getRetweetStream() throws TwitterException { ensureAuthorizationEnabled(); try { return new StatusStreamImpl( getDispatcher(), http.post( conf.getStreamBaseURL() + "statuses/retweet.json", new HttpParameter[] {}, auth), conf); } catch (IOException e) { throw new TwitterException(e); } } /** {@inheritDoc} */ public void sample() { ensureAuthorizationEnabled(); ensureListenerIsSet(); ensureStatusStreamListenerIsSet(); startHandler( new TwitterStreamConsumer() { public StatusStream getStream() throws TwitterException { return getSampleStream(); } }); } /** {@inheritDoc} */ public StatusStream getSampleStream() throws TwitterException { ensureAuthorizationEnabled(); try { return new StatusStreamImpl( getDispatcher(), http.get(conf.getStreamBaseURL() + "statuses/sample.json", auth), conf); } catch (IOException e) { throw new TwitterException(e); } } /** {@inheritDoc} */ public void user() { user(null); } /** {@inheritDoc} */ public void user(final String[] track) { ensureAuthorizationEnabled(); ensureListenerIsSet(); for (StreamListener listener : streamListeners) { if (!(listener instanceof UserStreamListener)) { throw new IllegalStateException( "Only UserStreamListener is supported. found: " + listener.getClass()); } } startHandler( new TwitterStreamConsumer() { public UserStream getStream() throws TwitterException { return getUserStream(track); } }); } /** {@inheritDoc} */ public UserStream getUserStream() throws TwitterException { return getUserStream(null); } /** {@inheritDoc} */ public UserStream getUserStream(String[] track) throws TwitterException { ensureAuthorizationEnabled(); try { List<HttpParameter> params = new ArrayList<HttpParameter>(); if (conf.isUserStreamRepliesAllEnabled()) { params.add(new HttpParameter("replies", "all")); } if (null != track) { params.add(new HttpParameter("track", T4JInternalStringUtil.join(track))); } return new UserStreamImpl( getDispatcher(), http.post( conf.getUserStreamBaseURL() + "user.json", params.toArray(new HttpParameter[params.size()]), auth), conf); } catch (IOException e) { throw new TwitterException(e); } } /** {@inheritDoc} */ public void site(final boolean withFollowings, final long[] follow) { ensureOAuthEnabled(); ensureListenerIsSet(); for (StreamListener listener : streamListeners) { if (!(listener instanceof SiteStreamsListener)) { throw new IllegalStateException( "Only SiteStreamListener is supported. found: " + listener.getClass()); } } startHandler( new TwitterStreamConsumer() { public StreamImplementation getStream() throws TwitterException { try { return new SiteStreamsImpl( getDispatcher(), getSiteStream(withFollowings, follow), conf); } catch (IOException e) { throw new TwitterException(e); } } }); } private Dispatcher getDispatcher() { if (null == TwitterStreamImpl.dispatcher) { synchronized (TwitterStreamImpl.class) { if (null == TwitterStreamImpl.dispatcher) { // dispatcher is held statically, but it'll be instantiated with // the configuration instance associated with this TwitterStream // instance which invokes getDispatcher() on the first time. TwitterStreamImpl.dispatcher = new DispatcherFactory(conf).getInstance(); } } } return TwitterStreamImpl.dispatcher; } private static transient Dispatcher dispatcher; InputStream getSiteStream(boolean withFollowings, long[] follow) throws TwitterException { ensureOAuthEnabled(); return http.post( conf.getSiteStreamBaseURL() + "site.json", new HttpParameter[] { new HttpParameter("with", withFollowings ? "followings" : "user"), new HttpParameter("follow", T4JInternalStringUtil.join(follow)) }, auth) .asStream(); } /** {@inheritDoc} */ public void filter(final FilterQuery query) { ensureAuthorizationEnabled(); ensureListenerIsSet(); ensureStatusStreamListenerIsSet(); startHandler( new TwitterStreamConsumer() { public StatusStream getStream() throws TwitterException { return getFilterStream(query); } }); } /** {@inheritDoc} */ public StatusStream getFilterStream(FilterQuery query) throws TwitterException { ensureAuthorizationEnabled(); try { return new StatusStreamImpl( getDispatcher(), http.post( conf.getStreamBaseURL() + "statuses/filter.json", query.asHttpParameterArray(), auth), conf); } catch (IOException e) { throw new TwitterException(e); } } /** * check if any listener is set. Throws IllegalStateException if no listener is set. * * @throws IllegalStateException when no listener is set. */ private void ensureListenerIsSet() { if (streamListeners.length == 0) { throw new IllegalStateException("No listener is set."); } } private void ensureStatusStreamListenerIsSet() { for (StreamListener listener : streamListeners) { if (!(listener instanceof StatusListener)) { throw new IllegalStateException( "Only StatusListener is supported. found: " + listener.getClass()); } } } private static int numberOfHandlers = 0; private synchronized void startHandler(TwitterStreamConsumer handler) { cleanUp(); if (streamListeners.length == 0) { throw new IllegalStateException("StatusListener is not set."); } this.handler = handler; this.handler.start(); numberOfHandlers++; } /** {@inheritDoc} */ public synchronized void cleanUp() { if (null != handler) { handler.close(); numberOfHandlers--; } } /** {@inheritDoc} */ public synchronized void shutdown() { super.shutdown(); cleanUp(); synchronized (TwitterStreamImpl.class) { if (0 == numberOfHandlers) { if (dispatcher != null) { dispatcher.shutdown(); dispatcher = null; } } } } /** {@inheritDoc} */ public void addConnectionLifeCycleListener(ConnectionLifeCycleListener listener) { this.lifeCycleListeners.add(listener); } /** {@inheritDoc} */ public void addListener(UserStreamListener listener) { addListener((StreamListener) listener); } /** {@inheritDoc} */ public void addListener(StatusListener listener) { addListener((StreamListener) listener); } /** {@inheritDoc} */ public void addListener(SiteStreamsListener listener) { addListener((StreamListener) listener); } private synchronized void addListener(StreamListener listener) { StreamListener[] newListeners = new StreamListener[this.streamListeners.length + 1]; System.arraycopy(this.streamListeners, 0, newListeners, 0, this.streamListeners.length); newListeners[newListeners.length - 1] = listener; this.streamListeners = newListeners; } /* http://apiwiki.twitter.com/Streaming-API-Documentation#Connecting When a network error (TCP/IP level) is encountered, back off linearly. Perhaps start at 250 milliseconds, double, and cap at 16 seconds When a HTTP error (> 200) is returned, back off exponentially. Perhaps start with a 10 second wait, double on each subsequent failure, and finally cap the wait at 240 seconds. Consider sending an alert to a human operator after multiple HTTP errors, as there is probably a client configuration issue that is unlikely to be resolved without human intervention. There's not much point in polling any faster in the face of HTTP error codes and your client is may run afoul of a rate limit. */ private static final int TCP_ERROR_INITIAL_WAIT = 250; private static final int TCP_ERROR_WAIT_CAP = 16 * 1000; private static final int HTTP_ERROR_INITIAL_WAIT = 10 * 1000; private static final int HTTP_ERROR_WAIT_CAP = 240 * 1000; private static final int NO_WAIT = 0; static int count = 0; abstract class TwitterStreamConsumer extends Thread { private StreamImplementation stream = null; private final String NAME = "Twitter Stream consumer-" + (++count); private volatile boolean closed = false; TwitterStreamConsumer() { super(); setName(NAME + "[initializing]"); } public void run() { int timeToSleep = NO_WAIT; boolean connected = false; while (!closed) { try { if (!closed && null == stream) { // try establishing connection logger.info("Establishing connection."); setStatus("[Establishing connection]"); stream = getStream(); connected = true; logger.info("Connection established."); for (ConnectionLifeCycleListener listener : lifeCycleListeners) { try { listener.onConnect(); } catch (Exception e) { logger.warn(e.getMessage()); } } // connection established successfully timeToSleep = NO_WAIT; logger.info("Receiving status stream."); setStatus("[Receiving stream]"); while (!closed) { try { stream.next(streamListeners); } catch (IllegalStateException ise) { logger.warn(ise.getMessage()); break; } catch (TwitterException e) { logger.info(e.getMessage()); stream.onException(e); throw e; } catch (Exception e) { logger.info(e.getMessage()); stream.onException(e); closed = true; break; } } } } catch (TwitterException te) { logger.info(te.getMessage()); if (!closed) { if (NO_WAIT == timeToSleep) { if (te.getStatusCode() == FORBIDDEN) { logger.warn("This account is not in required role. ", te.getMessage()); closed = true; break; } if (te.getStatusCode() == NOT_ACCEPTABLE) { logger.warn("Parameter not accepted with the role. ", te.getMessage()); closed = true; break; } connected = false; for (ConnectionLifeCycleListener listener : lifeCycleListeners) { try { listener.onDisconnect(); } catch (Exception e) { logger.warn(e.getMessage()); } } if (te.getStatusCode() > 200) { timeToSleep = HTTP_ERROR_INITIAL_WAIT; } else if (0 == timeToSleep) { timeToSleep = TCP_ERROR_INITIAL_WAIT; } } if (te.getStatusCode() > 200 && timeToSleep < HTTP_ERROR_INITIAL_WAIT) { timeToSleep = HTTP_ERROR_INITIAL_WAIT; } if (connected) { for (ConnectionLifeCycleListener listener : lifeCycleListeners) { try { listener.onDisconnect(); } catch (Exception e) { logger.warn(e.getMessage()); } } } // there was a problem establishing the connection, or the connection closed by peer if (!closed) { // wait for a moment not to overload Twitter API logger.info("Waiting for " + (timeToSleep) + " milliseconds"); setStatus("[Waiting for " + (timeToSleep) + " milliseconds]"); try { Thread.sleep(timeToSleep); } catch (InterruptedException ignore) { } timeToSleep = Math.min( timeToSleep * 2, (te.getStatusCode() > 200) ? HTTP_ERROR_WAIT_CAP : TCP_ERROR_WAIT_CAP); } stream = null; logger.debug(te.getMessage()); for (StreamListener statusListener : streamListeners) { statusListener.onException(te); } connected = false; } } } if (null != this.stream && connected) { try { this.stream.close(); } catch (IOException ignore) { } catch (Exception e) { e.printStackTrace(); logger.warn(e.getMessage()); } finally { for (ConnectionLifeCycleListener listener : lifeCycleListeners) { try { listener.onDisconnect(); } catch (Exception e) { logger.warn(e.getMessage()); } } } } for (ConnectionLifeCycleListener listener : lifeCycleListeners) { try { listener.onCleanUp(); } catch (Exception e) { logger.warn(e.getMessage()); } } } public synchronized void close() { setStatus("[Disposing thread]"); try { if (null != stream) { try { stream.close(); } catch (IOException ignore) { } catch (Exception e) { e.printStackTrace(); logger.warn(e.getMessage()); } } } finally { closed = true; } } private void setStatus(String message) { String actualMessage = NAME + message; setName(actualMessage); logger.debug(actualMessage); } abstract StreamImplementation getStream() throws TwitterException; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; if (!super.equals(o)) return false; TwitterStreamImpl that = (TwitterStreamImpl) o; if (handler != null ? !handler.equals(that.handler) : that.handler != null) return false; if (http != null ? !http.equals(that.http) : that.http != null) return false; if (lifeCycleListeners != null ? !lifeCycleListeners.equals(that.lifeCycleListeners) : that.lifeCycleListeners != null) return false; if (!Arrays.equals(streamListeners, that.streamListeners)) return false; return true; } @Override public int hashCode() { int result = super.hashCode(); result = 31 * result + (http != null ? http.hashCode() : 0); result = 31 * result + (streamListeners != null ? Arrays.hashCode(streamListeners) : 0); result = 31 * result + (lifeCycleListeners != null ? lifeCycleListeners.hashCode() : 0); result = 31 * result + (handler != null ? handler.hashCode() : 0); return result; } @Override public String toString() { return "TwitterStreamImpl{" + "http=" + http + ", streamListeners=" + (streamListeners == null ? null : Arrays.asList(streamListeners)) + ", lifeCycleListeners=" + lifeCycleListeners + ", handler=" + handler + '}'; } }
public class HttpClientImpl extends HttpClientBase implements Serializable, HttpResponseCode { private static final Map instanceMap = new HashMap(1); private static final Logger logger = Logger.getLogger(twitter4j/internal/http/HttpClientImpl); private static final long serialVersionUID = 0x859c02532b19cd01L; public HttpClientImpl() { super(ConfigurationContext.getInstance()); } public HttpClientImpl(HttpClientConfiguration httpclientconfiguration) { super(httpclientconfiguration); } public static HttpClient getInstance(HttpClientConfiguration httpclientconfiguration) { HttpClient httpclient = (HttpClient)instanceMap.get(httpclientconfiguration); Object obj = httpclient; if (httpclient == null) { obj = new HttpClientImpl(httpclientconfiguration); instanceMap.put(httpclientconfiguration, obj); } return ((HttpClient) (obj)); } private void setHeaders(HttpRequest httprequest, HttpURLConnection httpurlconnection) { if (logger.isDebugEnabled()) { logger.debug("Request: "); logger.debug((new StringBuilder()).append(httprequest.getMethod().name()).append(" ").toString(), httprequest.getURL()); } if (httprequest.getAuthorization() != null) { String s = httprequest.getAuthorization().getAuthorizationHeader(httprequest); if (s != null) { if (logger.isDebugEnabled()) { logger.debug("Authorization: ", z_T4JInternalStringUtil.maskString(s)); } httpurlconnection.addRequestProperty("Authorization", s); } } if (httprequest.getRequestHeaders() != null) { String s1; for (Iterator iterator = httprequest.getRequestHeaders().keySet().iterator(); iterator.hasNext(); logger.debug((new StringBuilder()).append(s1).append(": ").append((String)httprequest.getRequestHeaders().get(s1)).toString())) { s1 = (String)iterator.next(); httpurlconnection.addRequestProperty(s1, (String)httprequest.getRequestHeaders().get(s1)); } } } public HttpResponse get(String s) { return request(new HttpRequest(RequestMethod.GET, s, null, null, null)); } protected HttpURLConnection getConnection(String s) { if (isProxyConfigured()) { if (CONF.getHttpProxyUser() != null && !CONF.getHttpProxyUser().equals("")) { if (logger.isDebugEnabled()) { logger.debug((new StringBuilder("Proxy AuthUser: "******"Proxy AuthPassword: "******"Opening proxied connection(")).append(CONF.getHttpProxyHost()).append(":").append(CONF.getHttpProxyPort()).append(")").toString()); } s = (HttpURLConnection)(new URL(s)).openConnection(proxy); } else { s = (HttpURLConnection)(new URL(s)).openConnection(); } if (CONF.getHttpConnectionTimeout() > 0) { s.setConnectTimeout(CONF.getHttpConnectionTimeout()); } if (CONF.getHttpReadTimeout() > 0) { s.setReadTimeout(CONF.getHttpReadTimeout()); } s.setInstanceFollowRedirects(false); return s; } public HttpResponse post(String s, HttpParameter ahttpparameter[]) { return request(new HttpRequest(RequestMethod.POST, s, ahttpparameter, null, null)); } public HttpResponse request(HttpRequest httprequest) { Object obj; int j; int l; l = CONF.getHttpRetryCount(); obj = null; j = 0; _L30: Object obj1 = obj; if (j >= l + 1) goto _L2; else goto _L1 _L1: int k = -1; Object obj4; obj4 = getConnection(httprequest.getURL()); ((HttpURLConnection) (obj4)).setDoInput(true); setHeaders(httprequest, ((HttpURLConnection) (obj4))); ((HttpURLConnection) (obj4)).setRequestMethod(httprequest.getMethod().name()); if (httprequest.getMethod() != RequestMethod.POST) goto _L4; else goto _L3 _L3: if (!HttpParameter.containsFile(httprequest.getParameters())) goto _L6; else goto _L5 _L5: Object obj2; Object obj5; obj1 = (new StringBuilder("----Twitter4J-upload")).append(System.currentTimeMillis()).toString(); ((HttpURLConnection) (obj4)).setRequestProperty("Content-Type", (new StringBuilder("multipart/form-data; boundary=")).append(((String) (obj1))).toString()); obj5 = (new StringBuilder("--")).append(((String) (obj1))).toString(); ((HttpURLConnection) (obj4)).setDoOutput(true); obj2 = ((HttpURLConnection) (obj4)).getOutputStream(); obj1 = obj2; Object obj6 = new DataOutputStream(((OutputStream) (obj2))); obj1 = obj2; HttpParameter ahttpparameter[] = httprequest.getParameters(); obj1 = obj2; int i1 = ahttpparameter.length; int i = 0; _L35: if (i >= i1) goto _L8; else goto _L7 _L7: Object obj3; obj3 = ahttpparameter[i]; obj1 = obj2; if (!((HttpParameter) (obj3)).isFile()) goto _L10; else goto _L9 _L9: obj1 = obj2; write(((DataOutputStream) (obj6)), (new StringBuilder()).append(((String) (obj5))).append("\r\n").toString()); obj1 = obj2; write(((DataOutputStream) (obj6)), (new StringBuilder("Content-Disposition: form-data; name=\"")).append(((HttpParameter) (obj3)).getName()).append("\"; filename=\"").append(((HttpParameter) (obj3)).getFile().getName()).append("\"\r\n").toString()); obj1 = obj2; write(((DataOutputStream) (obj6)), (new StringBuilder("Content-Type: ")).append(((HttpParameter) (obj3)).getContentType()).append("\r\n\r\n").toString()); obj1 = obj2; if (!((HttpParameter) (obj3)).hasFileBody()) goto _L12; else goto _L11 _L11: obj1 = obj2; obj3 = ((HttpParameter) (obj3)).getFileBody(); _L15: obj1 = obj2; obj3 = new BufferedInputStream(((java.io.InputStream) (obj3))); obj1 = obj2; byte abyte1[] = new byte[1024]; _L14: obj1 = obj2; int j1 = ((BufferedInputStream) (obj3)).read(abyte1); if (j1 == -1) { break; /* Loop/switch isn't completed */ } obj1 = obj2; ((DataOutputStream) (obj6)).write(abyte1, 0, j1); if (true) goto _L14; else goto _L13 obj3; i = -1; obj2 = obj1; obj1 = obj3; _L25: try { ((OutputStream) (obj2)).close(); } // Misplaced declaration of an exception variable catch (Object obj2) { } throw obj1; obj2; obj1 = obj; obj = obj2; break MISSING_BLOCK_LABEL_444; _L12: obj1 = obj2; obj3 = new FileInputStream(((HttpParameter) (obj3)).getFile()); goto _L15 _L13: obj1 = obj2; write(((DataOutputStream) (obj6)), "\r\n"); obj1 = obj2; ((BufferedInputStream) (obj3)).close(); goto _L16 _L10: obj1 = obj2; write(((DataOutputStream) (obj6)), (new StringBuilder()).append(((String) (obj5))).append("\r\n").toString()); obj1 = obj2; write(((DataOutputStream) (obj6)), (new StringBuilder("Content-Disposition: form-data; name=\"")).append(((HttpParameter) (obj3)).getName()).append("\"\r\n").toString()); obj1 = obj2; write(((DataOutputStream) (obj6)), "Content-Type: text/plain; charset=UTF-8\r\n\r\n"); obj1 = obj2; logger.debug(((HttpParameter) (obj3)).getValue()); obj1 = obj2; ((DataOutputStream) (obj6)).write(((HttpParameter) (obj3)).getValue().getBytes("UTF-8")); obj1 = obj2; write(((DataOutputStream) (obj6)), "\r\n"); goto _L16 _L8: obj1 = obj2; write(((DataOutputStream) (obj6)), (new StringBuilder()).append(((String) (obj5))).append("--\r\n").toString()); obj1 = obj2; write(((DataOutputStream) (obj6)), "\r\n"); _L26: obj1 = obj2; ((OutputStream) (obj2)).flush(); obj1 = obj2; ((OutputStream) (obj2)).close(); _L34: obj1 = new HttpResponseImpl(((HttpURLConnection) (obj4)), CONF); i = k; k = ((HttpURLConnection) (obj4)).getResponseCode(); i = k; if (!logger.isDebugEnabled()) goto _L18; else goto _L17 _L17: i = k; logger.debug("Response: "); i = k; obj = ((HttpURLConnection) (obj4)).getHeaderFields(); i = k; obj3 = ((Map) (obj)).keySet().iterator(); _L21: i = k; if (!((Iterator) (obj3)).hasNext()) goto _L18; else goto _L19 _L19: i = k; obj4 = (String)((Iterator) (obj3)).next(); i = k; obj5 = ((List)((Map) (obj)).get(obj4)).iterator(); _L24: i = k; if (!((Iterator) (obj5)).hasNext()) goto _L21; else goto _L20 _L20: i = k; obj6 = (String)((Iterator) (obj5)).next(); if (obj4 == null) goto _L23; else goto _L22 _L22: i = k; logger.debug((new StringBuilder()).append(((String) (obj4))).append(": ").append(((String) (obj6))).toString()); goto _L24 exception; obj = obj1; obj1 = exception; goto _L25 _L6: ((HttpURLConnection) (obj4)).setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); obj1 = HttpParameter.encodeParameters(httprequest.getParameters()); logger.debug("Post Params: ", ((String) (obj1))); abyte0 = ((String) (obj1)).getBytes("UTF-8"); ((HttpURLConnection) (obj4)).setRequestProperty("Content-Length", Integer.toString(abyte0.length)); ((HttpURLConnection) (obj4)).setDoOutput(true); obj2 = ((HttpURLConnection) (obj4)).getOutputStream(); obj1 = obj2; ((OutputStream) (obj2)).write(abyte0); goto _L26 _L23: i = k; logger.debug(((String) (obj6))); goto _L24 _L36: if (k == 420 || k == 400 || k < 500) goto _L28; else goto _L27 _L27: i = k; if (j != CONF.getHttpRetryCount()) goto _L29; else goto _L28 _L28: i = k; throw new TwitterException(((HttpResponse) (obj1)).asString(), ((HttpResponse) (obj1))); _L37: ((OutputStream) (obj2)).close(); _L2: return ((HttpResponse) (obj1)); httprequest; return ((HttpResponse) (obj1)); _L29: ((OutputStream) (obj2)).close(); obj = obj1; _L31: if (!logger.isDebugEnabled() || obj == null) { break MISSING_BLOCK_LABEL_1100; } ((HttpResponse) (obj)).asString(); logger.debug((new StringBuilder("Sleeping ")).append(CONF.getHttpRetryIntervalSeconds()).append(" seconds until the next retry.").toString()); Thread.sleep(CONF.getHttpRetryIntervalSeconds() * 1000); _L32: j++; goto _L30 obj; obj = obj1; goto _L31 obj1; goto _L32 obj; i = k; goto _L33 obj1; obj2 = null; i = -1; goto _L25 obj1; i = -1; goto _L25 _L4: obj2 = null; goto _L34 _L33: Exception exception; byte abyte0[]; if (j == CONF.getHttpRetryCount()) { throw new TwitterException(((IOException) (obj)).getMessage(), ((Exception) (obj)), i); } obj = obj1; goto _L31 _L16: i++; goto _L35 _L18: if (k >= 200 && (k == 302 || 300 > k)) goto _L37; else goto _L36 }