/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.streams.twitter.api; import org.apache.streams.jackson.StreamsJacksonMapper; import org.apache.streams.twitter.TwitterConfiguration; import org.apache.streams.twitter.pojo.Tweet; import org.apache.streams.twitter.pojo.User; import org.apache.streams.twitter.provider.TwitterProviderUtil; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ArrayNode; import org.apache.commons.lang3.StringUtils; import org.apache.http.HttpRequestInterceptor; import org.apache.http.client.HttpRequestRetryHandler; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.params.ClientPNames; import org.apache.http.client.params.CookiePolicy; import org.apache.http.client.utils.URIBuilder; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.juneau.json.JsonParser; import org.apache.juneau.parser.ParseException; import org.apache.juneau.plaintext.PlainTextSerializer; import org.apache.juneau.rest.client.RestCall; import org.apache.juneau.rest.client.RestCallException; import org.apache.juneau.rest.client.RestClient; //import org.apache.juneau.rest.client.RestClientBuilder; import org.apache.juneau.rest.client.RetryOn; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; /** * Implementation of all twitter interfaces using juneau. */ public class Twitter implements Followers, Friends, Statuses, Users { private static final Logger LOGGER = LoggerFactory.getLogger(Twitter.class); private static Map<TwitterConfiguration, Twitter> INSTANCE_MAP = new ConcurrentHashMap<>(); private TwitterConfiguration configuration; private ObjectMapper mapper; private String rootUrl; private CloseableHttpClient httpclient; private HttpRequestInterceptor oauthInterceptor; RestClient restClient; private Twitter(TwitterConfiguration configuration) throws InstantiationException { this.configuration = configuration; this.rootUrl = TwitterProviderUtil.baseUrl(configuration); this.oauthInterceptor = new TwitterOAuthRequestInterceptor(configuration.getOauth()); this.httpclient = HttpClientBuilder.create() .addInterceptorFirst(oauthInterceptor) .setDefaultRequestConfig(RequestConfig.custom() .setConnectionRequestTimeout(5000) .setConnectTimeout(5000) .setSocketTimeout(5000) .setCookieSpec("easy") .build() ) .setMaxConnPerRoute(20) .setMaxConnTotal(100) .build(); // TODO: juneau-6.3.x-incubating // this.restClient = new RestClientBuilder() // .httpClient(httpclient, true) // .parser(JsonParser.class) // .rootUrl(rootUrl) // .retryable( // configuration.getRetryMax().intValue(), // configuration.getRetrySleepMs(), // new TwitterRetryHandler()) // .build(); this.restClient = new RestClient() .setHttpClient(httpclient) .setParser(JsonParser.class) .setRootUrl(rootUrl); this.mapper = StreamsJacksonMapper.getInstance(); } public static Twitter getInstance(TwitterConfiguration configuration) throws InstantiationException { if (INSTANCE_MAP.containsKey(configuration) && INSTANCE_MAP.get(configuration) != null) { return INSTANCE_MAP.get(configuration); } else { Twitter twitter = new Twitter(configuration); INSTANCE_MAP.put(configuration, twitter); return INSTANCE_MAP.get(configuration); } } @Override public List<Tweet> userTimeline(StatusesUserTimelineRequest parameters) { try { // TODO: juneau-6.3.x-incubating // Statuses restStatuses = restClient.getRemoteableProxy("/statuses/user_timeline.json", Statuses.class); // List<Tweet> result = restStatuses.userTimeline(parameters); // return result; URIBuilder uriBuilder = new URIBuilder() .setPath("/statuses/user_timeline.json"); if( Objects.nonNull(parameters.getUserId()) && StringUtils.isNotBlank(parameters.getUserId().toString())) { uriBuilder.addParameter("user_id", parameters.getUserId().toString()); } if( StringUtils.isNotBlank(parameters.getScreenName())) { uriBuilder.addParameter("screen_name", parameters.getScreenName()); } if( Objects.nonNull(parameters.getSinceId()) && StringUtils.isNotBlank(parameters.getSinceId().toString())) { uriBuilder.addParameter("since_id", parameters.getSinceId().toString()); } if( Objects.nonNull(parameters.getCount()) && StringUtils.isNotBlank(parameters.getCount().toString())) { uriBuilder.addParameter("count", parameters.getCount().toString()); } if( Objects.nonNull(parameters.getMaxId()) && StringUtils.isNotBlank(parameters.getMaxId().toString())) { uriBuilder.addParameter("max_id", parameters.getMaxId().toString()); } if( Objects.nonNull(parameters.getTrimUser()) && StringUtils.isNotBlank(parameters.getTrimUser().toString())) { uriBuilder.addParameter("trim_user", parameters.getTrimUser().toString()); } if( Objects.nonNull(parameters.getExcludeReplies()) && StringUtils.isNotBlank(parameters.getExcludeReplies().toString())) { uriBuilder.addParameter("exclude_replies", parameters.getExcludeReplies().toString()); } if( Objects.nonNull(parameters.getContributorDetails()) && StringUtils.isNotBlank(parameters.getContributorDetails().toString())) { uriBuilder.addParameter("contributor_details", parameters.getContributorDetails().toString()); } if( Objects.nonNull(parameters.getIncludeRts()) && StringUtils.isNotBlank(parameters.getIncludeRts().toString())) { uriBuilder.addParameter("include_rts", parameters.getIncludeRts().toString()); } RestCall restCall = restClient.doGet(uriBuilder.build().toString()); try { String restResponseEntity = restCall .setRetryable(configuration.getRetryMax().intValue(), configuration.getRetrySleepMs().intValue(), new TwitterRetryHandler()) .getResponseAsString(); ArrayNode resultArrayNode = mapper.readValue(restResponseEntity, ArrayNode.class); List<Tweet> result = new ArrayList(); resultArrayNode.iterator().forEachRemaining(item -> result.add(mapper.convertValue(item, Tweet.class))); return result; } catch (RestCallException e) { LOGGER.warn("RestCallException", e); } } catch (IOException e) { LOGGER.warn("IOException", e); } catch (URISyntaxException e) { LOGGER.warn("URISyntaxException", e); } return new ArrayList<>(); } @Override public List<Tweet> lookup(StatusesLookupRequest parameters) { // TODO: juneau-6.3.x-incubating // Statuses restStatuses = restClient.getRemoteableProxy("/statuses/lookup.json", Statuses.class); // List<Tweet> result = restStatuses.lookup(parameters); // return result; String ids = StringUtils.join(parameters.getId(), ','); try { URIBuilder uriBuilder = new URIBuilder() .setPath("/statuses/lookup.json"); if( Objects.nonNull(parameters.getId()) && StringUtils.isNotBlank(parameters.getId().toString())) { uriBuilder.addParameter("id", parameters.getId().toString()); } if( Objects.nonNull(parameters.getTrimUser()) && StringUtils.isNotBlank(parameters.getTrimUser().toString())) { uriBuilder.addParameter("trim_user", parameters.getTrimUser().toString()); } if( Objects.nonNull(parameters.getIncludeEntities()) && StringUtils.isNotBlank(parameters.getIncludeEntities().toString())) { uriBuilder.addParameter("include_entities", parameters.getIncludeEntities().toString()); } if( Objects.nonNull(parameters.getMap()) && StringUtils.isNotBlank(parameters.getMap().toString())) { uriBuilder.addParameter("map", parameters.getMap().toString()); } RestCall restCall = restClient.doGet(uriBuilder.build().toString()); try { String restResponseEntity = restCall .setRetryable(configuration.getRetryMax().intValue(), configuration.getRetrySleepMs().intValue(), new TwitterRetryHandler()) .getResponseAsString(); ArrayNode resultArrayNode = mapper.readValue(restResponseEntity, ArrayNode.class); List<Tweet> result = new ArrayList(); resultArrayNode.iterator().forEachRemaining(item -> result.add(mapper.convertValue(item, Tweet.class))); //List<Tweet> result = restCall.getResponse(LinkedList.class, Tweet.class); return result; } catch (RestCallException e) { LOGGER.warn("RestCallException", e); } } catch (IOException e) { LOGGER.warn("IOException", e); } catch (URISyntaxException e) { LOGGER.warn("URISyntaxException", e); } return new ArrayList<>(); } @Override public Tweet show(StatusesShowRequest parameters) { // TODO: juneau-6.3.x-incubating // Statuses restStatuses = restClient.getRemoteableProxy("/statuses/show.json", Statuses.class); // Tweet result = restStatuses.show(parameters); // return result; try { URIBuilder uriBuilder = new URIBuilder() .setPath("/statuses/show.json"); if (Objects.nonNull(parameters.getId()) && StringUtils.isNotBlank(parameters.getId().toString())) { uriBuilder.addParameter("id", parameters.getId().toString()); } if (Objects.nonNull(parameters.getTrimUser()) && StringUtils.isNotBlank(parameters.getTrimUser().toString())) { uriBuilder.addParameter("trim_user", parameters.getTrimUser().toString()); } if (Objects.nonNull(parameters.getIncludeEntities()) && StringUtils.isNotBlank(parameters.getIncludeEntities().toString())) { uriBuilder.addParameter("include_entities", parameters.getIncludeEntities().toString()); } if (Objects.nonNull(parameters.getIncludeMyRetweet()) && StringUtils.isNotBlank(parameters.getIncludeMyRetweet().toString())) { uriBuilder.addParameter("include_my_retweet", parameters.getIncludeMyRetweet().toString()); } RestCall restCall = restClient.doGet(uriBuilder.build().toString()); try { String restResponseEntity = restCall .setRetryable(configuration.getRetryMax().intValue(), configuration.getRetrySleepMs().intValue(), new TwitterRetryHandler()) .getResponseAsString(); //Tweet result = restCall.getResponse(Tweet.class); Tweet result = mapper.readValue(restResponseEntity, Tweet.class); return result; } catch (RestCallException e) { LOGGER.warn("RestCallException", e); } } catch (IOException e) { LOGGER.warn("IOException", e); } catch (URISyntaxException e) { LOGGER.warn("URISyntaxException", e); } return null; } @Override public FriendsIdsResponse ids(FriendsIdsRequest parameters) { // TODO: juneau-6.3.x-incubating // Friends restFriends = restClient.getRemoteableProxy("/friends/ids.json", Friends.class); // FriendsIdsResponse result = restFriends.ids(parameters); // return result; try { URIBuilder uriBuilder = new URIBuilder() .setPath("/friends/ids.json"); if( Objects.nonNull(parameters.getCount()) && StringUtils.isNotBlank(parameters.getCount().toString())) { uriBuilder.addParameter("count", parameters.getCount().toString()); } if( Objects.nonNull(parameters.getCursor()) && StringUtils.isNotBlank(parameters.getCursor().toString())) { uriBuilder.addParameter("cursor", parameters.getCursor().toString()); } if( Objects.nonNull(parameters.getId()) && StringUtils.isNotBlank(parameters.getId().toString())) { uriBuilder.addParameter("id", parameters.getId().toString()); } if( StringUtils.isNotBlank(parameters.getScreenName())) { uriBuilder.addParameter("screen_name", parameters.getScreenName()); } if( Objects.nonNull(parameters.getStringifyIds()) && StringUtils.isNotBlank(parameters.getStringifyIds().toString())) { uriBuilder.addParameter("stringify_ids", parameters.getStringifyIds().toString()); } RestCall restCall = restClient.doGet(uriBuilder.build().toString()); try { String restResponseEntity = restCall .setRetryable(configuration.getRetryMax().intValue(), configuration.getRetrySleepMs().intValue(), new TwitterRetryHandler()) .getResponseAsString(); //FriendsIdsResponse result = restCall.getResponse(FriendsIdsResponse.class); FriendsIdsResponse result = mapper.readValue(restResponseEntity, FriendsIdsResponse.class); return result; } catch (RestCallException e) { LOGGER.warn("RestCallException", e); } } catch (IOException e) { LOGGER.warn("IOException", e); } catch (URISyntaxException e) { LOGGER.warn("URISyntaxException", e); } return null; } @Override public FriendsListResponse list(FriendsListRequest parameters) { // TODO: juneau-6.3.x-incubating // Friends restFriends = restClient.getRemoteableProxy("/friends/list.json", Friends.class); // FriendsListResponse result = restFriends.list(parameters); // return result; try { URIBuilder uriBuilder = new URIBuilder() .setPath("/friends/list.json"); if (Objects.nonNull(parameters.getCount()) && StringUtils.isNotBlank(parameters.getCount().toString())) { uriBuilder.addParameter("count", parameters.getCount().toString()); } if (Objects.nonNull(parameters.getCursor()) && StringUtils.isNotBlank(parameters.getCursor().toString())) { uriBuilder.addParameter("cursor", parameters.getCursor().toString()); } if (Objects.nonNull(parameters.getId()) && StringUtils.isNotBlank(parameters.getId().toString())) { uriBuilder.addParameter("id", parameters.getId().toString()); } if (Objects.nonNull(parameters.getIncludeUserEntities()) && StringUtils.isNotBlank(parameters.getIncludeUserEntities().toString())) { uriBuilder.addParameter("include_user_entities", parameters.getIncludeUserEntities().toString()); } if (StringUtils.isNotBlank(parameters.getScreenName())) { uriBuilder.addParameter("screen_name", parameters.getScreenName()); } if (Objects.nonNull(parameters.getSkipStatus()) && StringUtils.isNotBlank(parameters.getSkipStatus().toString())) { uriBuilder.addParameter("skip_status", parameters.getSkipStatus().toString()); } RestCall restCall = restClient.doGet(uriBuilder.build().toString()); try { String restResponseEntity = restCall .setRetryable(configuration.getRetryMax().intValue(), configuration.getRetrySleepMs().intValue(), new TwitterRetryHandler()) .getResponseAsString(); //FriendsListResponse result = restCall.getResponse(FriendsListResponse.class); FriendsListResponse result = mapper.readValue(restResponseEntity, FriendsListResponse.class); return result; } catch (RestCallException e) { LOGGER.warn("RestCallException", e); } }catch (IOException e) { LOGGER.warn("IOException", e); } catch (URISyntaxException e) { LOGGER.warn("URISyntaxException", e); } return null; } @Override public FollowersIdsResponse ids(FollowersIdsRequest parameters) { // TODO: juneau-6.3.x-incubating // Followers restFollowers = restClient.getRemoteableProxy("/friends/list.json", Followers.class); // FollowersIdsResponse result = restFollowers.ids(parameters); // return result; try { URIBuilder uriBuilder = new URIBuilder() .setPath("/followers/ids.json"); if (Objects.nonNull(parameters.getCount()) && StringUtils.isNotBlank(parameters.getCount().toString())) { uriBuilder.addParameter("count", parameters.getCount().toString()); } if (Objects.nonNull(parameters.getCursor()) && StringUtils.isNotBlank(parameters.getCursor().toString())) { uriBuilder.addParameter("cursor", parameters.getCursor().toString()); } if (Objects.nonNull(parameters.getId()) && StringUtils.isNotBlank(parameters.getId().toString())) { uriBuilder.addParameter("id", parameters.getId().toString()); } if (StringUtils.isNotBlank(parameters.getScreenName())) { uriBuilder.addParameter("screen_name", parameters.getScreenName()); } if (Objects.nonNull(parameters.getStringifyIds()) && StringUtils.isNotBlank(parameters.getStringifyIds().toString())) { uriBuilder.addParameter("stringify_ids", parameters.getStringifyIds().toString()); } RestCall restCall = restClient.doGet(uriBuilder.build().toString()); try { //FollowersIdsResponse result = restCall.getResponse(FollowersIdsResponse.class); String restResponseEntity = restCall .setRetryable(configuration.getRetryMax().intValue(), configuration.getRetrySleepMs().intValue(), new TwitterRetryHandler()) .getResponseAsString(); FollowersIdsResponse result = mapper.readValue(restResponseEntity, FollowersIdsResponse.class); return result; } catch (RestCallException e) { LOGGER.warn("RestCallException", e); } } catch (IOException e) { LOGGER.warn("IOException", e); } catch (URISyntaxException e) { LOGGER.warn("URISyntaxException", e); } return null; } @Override public FollowersListResponse list(FollowersListRequest parameters) { // TODO: juneau-6.3.x-incubating // Followers restFollowers = restClient.getRemoteableProxy("/friends/list.json", Followers.class); // FollowersListResponse result = restFollowers.list(parameters); // return result; try { URIBuilder uriBuilder = new URIBuilder() .setPath("/followers/list.json"); if (Objects.nonNull(parameters.getCount()) && StringUtils.isNotBlank(parameters.getCount().toString())) { uriBuilder.addParameter("count", parameters.getCount().toString()); } if (Objects.nonNull(parameters.getCursor()) && StringUtils.isNotBlank(parameters.getCursor().toString())) { uriBuilder.addParameter("cursor", parameters.getCursor().toString()); } if (Objects.nonNull(parameters.getId()) && StringUtils.isNotBlank(parameters.getId().toString())) { uriBuilder.addParameter("id", parameters.getId().toString()); } if (Objects.nonNull(parameters.getIncludeUserEntities()) && StringUtils.isNotBlank(parameters.getIncludeUserEntities().toString())) { uriBuilder.addParameter("include_user_entities", parameters.getIncludeUserEntities().toString()); } if (StringUtils.isNotBlank(parameters.getScreenName())) { uriBuilder.addParameter("screen_name", parameters.getScreenName()); } if (Objects.nonNull(parameters.getSkipStatus()) && StringUtils.isNotBlank(parameters.getSkipStatus().toString())) { uriBuilder.addParameter("skip_status", parameters.getSkipStatus().toString()); } RestCall restCall = restClient.doGet(uriBuilder.build().toString()); try { String restResponseEntity = restCall .setRetryable(configuration.getRetryMax().intValue(), configuration.getRetrySleepMs().intValue(), new TwitterRetryHandler()) .getResponseAsString(); //FollowersListResponse result = restCall.getResponse(FollowersListResponse.class); FollowersListResponse result = mapper.readValue(restResponseEntity, FollowersListResponse.class); return result; } catch (RestCallException e) { LOGGER.warn("RestCallException", e); } }catch (IOException e) { LOGGER.warn("IOException", e); } catch (URISyntaxException e) { LOGGER.warn("URISyntaxException", e); } return null; } @Override public List<User> lookup(UsersLookupRequest parameters) { // TODO: juneau-6.3.x-incubating // Users restUsers = restClient.getRemoteableProxy("/users/lookup.json", Users.class); // List<User> result = restUsers.lookup(parameters); // return result; String user_ids = StringUtils.join(parameters.getUserId(), ','); String screen_names = StringUtils.join(parameters.getScreenName(), ','); try { URIBuilder uriBuilder = new URIBuilder() .setPath("/users/lookup.json"); if (Objects.nonNull(parameters.getIncludeEntities()) && StringUtils.isNotBlank(parameters.getIncludeEntities().toString())) { uriBuilder.addParameter("include_entities", parameters.getIncludeEntities().toString()); } if (Objects.nonNull(screen_names) && StringUtils.isNotBlank(screen_names)) { uriBuilder.addParameter("screen_name", screen_names); } if (Objects.nonNull(user_ids) && StringUtils.isNotBlank(user_ids)) { uriBuilder.addParameter("user_id", user_ids); } RestCall restCall = restClient.doGet(uriBuilder.build().toString()); // List<User> result = restCall.getResponse(LinkedList.class, User.class); try { String restResponseEntity = restCall .setRetryable(configuration.getRetryMax().intValue(), configuration.getRetrySleepMs().intValue(), new TwitterRetryHandler()) .getResponseAsString(); ArrayNode resultArrayNode = mapper.readValue(restResponseEntity, ArrayNode.class); List<User> result = new ArrayList(); resultArrayNode.iterator().forEachRemaining(item -> result.add(mapper.convertValue(item, User.class))); return result; } catch (RestCallException e) { LOGGER.warn("RestCallException", e); } } catch (IOException e) { LOGGER.warn("IOException", e); } catch (URISyntaxException e) { LOGGER.warn("URISyntaxException", e); } return new ArrayList<>(); } @Override public User show(UsersShowRequest parameters) { // TODO: juneau-6.3.x-incubating // Users restUsers = restClient.getRemoteableProxy("/users/lookup.json", Users.class); // User result = restUsers.show(parameters); // return result; try { URIBuilder uriBuilder = new URIBuilder() .setPath("/users/show.json"); if (Objects.nonNull(parameters.getIncludeEntities()) && StringUtils.isNotBlank(parameters.getIncludeEntities().toString())) { uriBuilder.addParameter("include_entities", parameters.getIncludeEntities().toString()); } if (Objects.nonNull(parameters.getScreenName()) && StringUtils.isNotBlank(parameters.getScreenName())) { uriBuilder.addParameter("screen_name", parameters.getScreenName()); } if (Objects.nonNull(parameters.getUserId()) && StringUtils.isNotBlank(parameters.getUserId().toString())) { uriBuilder.addParameter("user_id", parameters.getUserId().toString()); } RestCall restCall = restClient.doGet(uriBuilder.build().toString()); try { String restResponseEntity = restCall .setRetryable(configuration.getRetryMax().intValue(), configuration.getRetrySleepMs().intValue(), new TwitterRetryHandler()) .getResponseAsString(); User result = mapper.readValue(restResponseEntity, User.class); return result; } catch (RestCallException e) { LOGGER.warn("RestCallException", e); } } catch (IOException e) { LOGGER.warn("IOException", e); } catch (URISyntaxException e) { LOGGER.warn("URISyntaxException", e); } return null; } }