diff --git a/README.md b/README.md
index 4237d37..dbf7dc8 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@ You can find examples of using the SDK under the [examples/](examples/) director
**Note: Only Twitter API V2 is supported**
-- API version: 2.45
+- API version: 2.46
Twitter API v2 available endpoints
@@ -228,8 +228,8 @@ In order to use the retry mechanism call the APIs with an additional parameter `
```java
int retries = 4;
- streamResult = apiInstance.tweets()apiInstance.tweets().sampleStream()
- .tweetFields(tweetFields)
+ streamResult = apiInstance.tweets().sampleStream()
+ .parameters(new StreamQueryParameters.Builder.withTweetFields(tweetFields).build())
.execute(retries);
```
@@ -530,6 +530,13 @@ Class | Method | HTTP request | Description
- [VideoAllOfPromotedMetrics](docs/VideoAllOfPromotedMetrics.md)
- [VideoAllOfPublicMetrics](docs/VideoAllOfPublicMetrics.md)
+## Documentation for Stream Functionality
+
+
+Class | Method | HTTP request | Description
+------------ |--------------------------------------------------------| ------------- | -------------
+*TwitterStream* | [**sampleStream**](docs/TwitterStream.md#sampleStream) | **GET** /2/tweets/sample/stream | Processing stream with multiple threads accepts listeners with the produced tweets
+
diff --git a/docs/StreamQueryParameters.md b/docs/StreamQueryParameters.md
new file mode 100644
index 0000000..a9921df
--- /dev/null
+++ b/docs/StreamQueryParameters.md
@@ -0,0 +1,114 @@
+
+
+# StreamQueryParameters
+
+
+## Properties
+
+
+| Name | Type | Description | Notes |
+|------------- |----------------------------------------------| ------------- | -------------|
+| **backfillMinutes** | **Integer** | The number of minutes of backfill requested. | [optional] |
+| **tweetFields** | [**Collection<TweetField>**](#TweetField) | A comma separated list of Tweet fields to display. | [optional] [enum: attachments, author_id, context_annotations, conversation_id, created_at, entities, geo, id, in_reply_to_user_id, lang, non_public_metrics, organic_metrics, possibly_sensitive, promoted_metrics, public_metrics, referenced_tweets, reply_settings, source, text, withheld] |
+| **expansions** | [**Collection<Expansion>**](#Expansion) | A comma separated list of fields to expand. | [optional] [enum: attachments.media_keys, attachments.poll_ids, author_id, entities.mentions.username, geo.place_id, in_reply_to_user_id, referenced_tweets.id, referenced_tweets.id.author_id] |
+| **mediaFields** | [**Collection<MediaField>**](#MediaField) | A comma separated list of Media fields to display. | [optional] [enum: alt_text, duration_ms, height, media_key, non_public_metrics, organic_metrics, preview_image_url, promoted_metrics, public_metrics, type, url, variants, width] |
+| **pollFields** | [**Collection<PollField>**](#PollField) | A comma separated list of Poll fields to display. | [optional] [enum: duration_minutes, end_datetime, id, options, voting_status] |
+| **userFields** | [**Collection<UserField>**](#UserField) | A comma separated list of User fields to display. | [optional] [enum: created_at, description, entities, id, location, name, pinned_tweet_id, profile_image_url, protected, public_metrics, url, username, verified, withheld] |
+| **placeFields** | [**Collection<PlaceField>**](#PlaceField) | A comma separated list of Place fields to display. | [optional] [enum: contained_within, country, country_code, full_name, geo, id, name, place_type] |
+
+
+
+
+## Enum: TweetField
+
+| Name | Value |
+|---- | -----|
+|ATTACHMENTS|"attachments"|
+|AUTHOR_ID|"author_id"|
+|CONTEXT_ANNOTATIONS|"context_annotations"|
+|CONVERSATION_ID|"conversation_id"|
+|CREATED_AT|"created_at"|
+|ENTITIES|"entities"|
+|GEO|"geo"|
+|ID|"id"|
+|IN_REPLY_TO_USER_ID|"in_reply_to_user_id"|
+|LANG|"lang"|
+|POSSIBLE_SENSITIVE|"possibly_sensitive"|
+|PUBLIC_METRICS|"public_metrics"|
+|REFERENCED_TWEETS|"referenced_tweets"|
+|REPLY_SETTINGS|"reply_settings"|
+|SOURCE|"source"|
+|TEXT|"text"|
+|WITHHELD|"withheld"|
+
+
+## Enum: Expansion
+
+| Name | Value |
+|---- | -----|
+|ATTACHMENTS_MEDIA_KEYS|"attachments.media_keys"|
+|ATTACHMENTS_POLL_IDS|"attachments.poll_ids"|
+|AUTHOR_ID|"author_id"|
+|ENTITIES_MENTIONS_USERNAME|"entities.mentions.username"|
+|GEO_PLACE_ID|"geo.place_id"|
+|IN_REPLY_TO_USER_ID|"in_reply_to_user_id"|
+|REFERENCED_TWEETS_ID|"referenced_tweets.id"|
+|REFERENCED_TWEETS_ID_AUTHOR_ID|"referenced_tweets.id.author_id"|
+
+## Enum: MediaField
+
+| Name | Value |
+|---- | -----|
+|ALT_TEXT|"alt_text"|
+|DURATION_MS|"duration_ms"|
+|HEIGHT|"height"|
+|MEDIA_KEY|"media_key"|
+|PREVIEW_IMAGE_URL|"preview_image_url"|
+|PUBLIC_METRICS|"public_metrics"|
+|TYPE|"type"|
+|URL|"url"|
+|VARIANTS|"variants"|
+|WIDTH|"width"|
+
+
+## Enum: PollField
+
+| Name | Value |
+|---- | -----|
+|DURATION_MINUTES|"duration_minutes"|
+|END_DATETIME|"end_datetime"|
+|ID|"id"|
+|OPTIONS|"options"|
+|VOTING_STATUS|"voting_status"|
+
+## Enum: UserField
+
+| Name | Value |
+|---- | -----|
+|CREATED_AT|"created_at"|
+|DESCRIPTION|"description"|
+|ENTITIES|"entities"|
+|ID|"id"|
+|LOCATION|"location"|
+|NAME|"name"|
+|PINNED_TWEET_ID|"pinned_tweet_id"|
+|PROFILE_IMAGE_URL|"profile_image_url"|
+|PROTECTED|"protected"|
+|PUBLIC_METRICS|"public_metrics"|
+|URL|"url"|
+|USERNAME|"username"|
+|VERIFIED|"verified"|
+|WITHHELD|"withheld"|
+
+## Enum: PlaceField
+
+| Name | Value |
+|---- | -----|
+|CONTAINED_WITHIN|"contained_within"|
+|COUNTRY|"country"|
+|COUNTRY_CODE|"country_code"|
+|FULL_NAME|"full_name"|
+|GEO|"geo"|
+|ID|"id"|
+|NAME|"name"|
+|PLACE_TYPE|"place_type"|
\ No newline at end of file
diff --git a/docs/TweetsApi.md b/docs/TweetsApi.md
index bfec075..133e967 100644
--- a/docs/TweetsApi.md
+++ b/docs/TweetsApi.md
@@ -895,15 +895,29 @@ public class Example {
# **sampleStream**
-> StreamingTweetResponse sampleStream().backfillMinutes(backfillMinutes).tweetFields(tweetFields).expansions(expansions).mediaFields(mediaFields).pollFields(pollFields).userFields(userFields).placeFields(placeFields).execute();
+```java
+BufferedSource sampleStream()
+ .parameters(new StreamQueryParameters.Builder()
+ .withBackfillMinutes(backfillMinutes)
+ .withTweetFields(tweetFields)
+ .withExpansions(expansions)
+ .withMediaFields(mediaFields)
+ .withPollFields(pollFields)
+ .withUserFields(userFields)
+ .withPlaceFields(placeFields)
+ .build())
+ .execute();
+```
Sample stream
Streams a deterministic 1% of public Tweets.
### Example
+
```java
// Import classes:
+
import com.twitter.clientlib.ApiClient;
import com.twitter.clientlib.ApiException;
import com.twitter.clientlib.Configuration;
@@ -914,10 +928,15 @@ import com.twitter.clientlib.TwitterCredentialsBearer;
import com.twitter.clientlib.api.TwitterApi;
import com.twitter.clientlib.api.TweetsApi;
+
import java.io.InputStream;
+
import com.google.common.reflect.TypeToken;
-import java.io.BufferedReader;
-import java.io.InputStreamReader;
+
+import com.twitter.clientlib.query.StreamQueryParameters;
+import com.twitter.clientlib.query.model.TweetField;
+import okio.BufferedSource;
+
import java.lang.reflect.Type;
import java.util.List;
import java.util.Set;
@@ -926,76 +945,59 @@ import java.util.HashSet;
import java.time.OffsetDateTime;
public class Example {
- public static void main(String[] args) {
- // Set the credentials based on the API's "security" tag values.
- // Check the API definition in https://api.twitter.com/2/openapi.json
- // When multiple options exist, the SDK supports only "OAuth2UserToken" or "BearerToken"
+ public static void main(String[] args) {
+ // Set the credentials based on the API's "security" tag values.
+ // Check the API definition in https://api.twitter.com/2/openapi.json
+ // When multiple options exist, the SDK supports only "OAuth2UserToken" or "BearerToken"
- // Uncomment and set the credentials configuration
-
- // Configure HTTP bearer authorization:
- // TwitterCredentialsBearer credentials = new TwitterCredentialsBearer(System.getenv("TWITTER_BEARER_TOKEN"));
+ // Uncomment and set the credentials configuration
+
+ // Configure HTTP bearer authorization:
+ // TwitterCredentialsBearer credentials = new TwitterCredentialsBearer(System.getenv("TWITTER_BEARER_TOKEN"));
TwitterApi apiInstance = new TwitterApi(credentials);
- // Set the params values
- Integer backfillMinutes = 56; // Integer | The number of minutes of backfill requested.
- Set tweetFields = new HashSet<>(Arrays.asList()); // Set | A comma separated list of Tweet fields to display.
- Set expansions = new HashSet<>(Arrays.asList()); // Set | A comma separated list of fields to expand.
- Set mediaFields = new HashSet<>(Arrays.asList()); // Set | A comma separated list of Media fields to display.
- Set pollFields = new HashSet<>(Arrays.asList()); // Set | A comma separated list of Poll fields to display.
- Set userFields = new HashSet<>(Arrays.asList()); // Set | A comma separated list of User fields to display.
- Set placeFields = new HashSet<>(Arrays.asList()); // Set | A comma separated list of Place fields to display.
- try {
- InputStream result = apiInstance.tweets().sampleStream()
- .backfillMinutes(backfillMinutes)
- .tweetFields(tweetFields)
- .expansions(expansions)
- .mediaFields(mediaFields)
- .pollFields(pollFields)
- .userFields(userFields)
- .placeFields(placeFields)
- .execute();
- try{
- JSON json = new JSON();
- Type localVarReturnType = new TypeToken(){}.getType();
- BufferedReader reader = new BufferedReader(new InputStreamReader(result));
- String line = reader.readLine();
- while (line != null) {
- if(line.isEmpty()) {
- System.out.println("==> Empty line");
- line = reader.readLine();
- continue;
- }
- Object jsonObject = json.getGson().fromJson(line, localVarReturnType);
- System.out.println(jsonObject != null ? jsonObject.toString() : "Null object");
- line = reader.readLine();
- }
- }catch (Exception e) {
- e.printStackTrace();
- System.out.println(e);
+ try {
+ BufferedSource result = apiInstance.tweets().sampleStream()
+ .parameters(new StreamQueryParameters.Builder()
+ .withBackfillMinutes(56)
+ .withTweetFields(TweetField.AUTHOR_ID, TweetField.ID, TweetField.CREATED_AT)
+ .build())
+ .execute();
+ try {
+ JSON json = new JSON();
+ Type localVarReturnType = new TypeToken() {
+ }.getType();
+ String line = result.readUtf8Line();
+ while (line != null) {
+ if (line.isEmpty()) {
+ System.out.println("==> Empty line");
+ line = result.readUtf8Line();
+ continue;
+ }
+ Object jsonObject = json.getGson().fromJson(line, localVarReturnType);
+ System.out.println(jsonObject != null ? jsonObject.toString() : "Null object");
+ line = result.readUtf8Line();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ System.out.println(e);
}
- } catch (ApiException e) {
- System.err.println("Exception when calling TweetsApi#sampleStream");
- System.err.println("Status code: " + e.getCode());
- System.err.println("Reason: " + e.getResponseBody());
- System.err.println("Response headers: " + e.getResponseHeaders());
- e.printStackTrace();
+ } catch (ApiException e) {
+ System.err.println("Exception when calling TweetsApi#sampleStream");
+ System.err.println("Status code: " + e.getCode());
+ System.err.println("Reason: " + e.getResponseBody());
+ System.err.println("Response headers: " + e.getResponseHeaders());
+ e.printStackTrace();
+ }
}
- }
}
```
### Parameters
-| Name | Type | Description | Notes |
-|------------- | ------------- | ------------- | -------------|
-| **backfillMinutes** | **Integer**| The number of minutes of backfill requested. | [optional] |
-| **tweetFields** | [**Set<String>**](String.md)| A comma separated list of Tweet fields to display. | [optional] [enum: attachments, author_id, context_annotations, conversation_id, created_at, entities, geo, id, in_reply_to_user_id, lang, non_public_metrics, organic_metrics, possibly_sensitive, promoted_metrics, public_metrics, referenced_tweets, reply_settings, source, text, withheld] |
-| **expansions** | [**Set<String>**](String.md)| A comma separated list of fields to expand. | [optional] [enum: attachments.media_keys, attachments.poll_ids, author_id, entities.mentions.username, geo.place_id, in_reply_to_user_id, referenced_tweets.id, referenced_tweets.id.author_id] |
-| **mediaFields** | [**Set<String>**](String.md)| A comma separated list of Media fields to display. | [optional] [enum: alt_text, duration_ms, height, media_key, non_public_metrics, organic_metrics, preview_image_url, promoted_metrics, public_metrics, type, url, variants, width] |
-| **pollFields** | [**Set<String>**](String.md)| A comma separated list of Poll fields to display. | [optional] [enum: duration_minutes, end_datetime, id, options, voting_status] |
-| **userFields** | [**Set<String>**](String.md)| A comma separated list of User fields to display. | [optional] [enum: created_at, description, entities, id, location, name, pinned_tweet_id, profile_image_url, protected, public_metrics, url, username, verified, withheld] |
-| **placeFields** | [**Set<String>**](String.md)| A comma separated list of Place fields to display. | [optional] [enum: contained_within, country, country_code, full_name, geo, id, name, place_type] |
+| Name | Type | Description | Notes |
+|-------|-----------------------------------------------------------------|------------|-------|
+| **parameters** | [**StreamQueryParameters**](StreamQueryParameters.md) | | |
### Return type
@@ -1018,15 +1020,29 @@ public class Example {
# **searchStream**
-> FilteredStreamingTweetResponse searchStream().backfillMinutes(backfillMinutes).tweetFields(tweetFields).expansions(expansions).mediaFields(mediaFields).pollFields(pollFields).userFields(userFields).placeFields(placeFields).execute();
+```java
+FilteredStreamingTweetResponse searchStream()
+ .parameters(new StreamQueryParameters.Builder()
+ .withBackfillMinutes(backfillMinutes)
+ .withTweetFields(tweetFields)
+ .withExpansions(expansions)
+ .withMediaFields(mediaFields)
+ .withPollFields(pollFields)
+ .withUserFields(userFields)
+ .withPlaceFields(placeFields)
+ .build())
+ .execute();
+```
Filtered stream
Streams Tweets matching the stream's active rule set.
### Example
+
```java
// Import classes:
+
import com.twitter.clientlib.ApiClient;
import com.twitter.clientlib.ApiException;
import com.twitter.clientlib.Configuration;
@@ -1037,10 +1053,14 @@ import com.twitter.clientlib.TwitterCredentialsBearer;
import com.twitter.clientlib.api.TwitterApi;
import com.twitter.clientlib.api.TweetsApi;
+
import java.io.InputStream;
+
import com.google.common.reflect.TypeToken;
-import java.io.BufferedReader;
-import java.io.InputStreamReader;
+import com.twitter.clientlib.query.StreamQueryParameters;
+import com.twitter.clientlib.query.model.TweetField;
+import okio.BufferedSource;
+
import java.lang.reflect.Type;
import java.util.List;
import java.util.Set;
@@ -1049,62 +1069,51 @@ import java.util.HashSet;
import java.time.OffsetDateTime;
public class Example {
- public static void main(String[] args) {
- // Set the credentials based on the API's "security" tag values.
- // Check the API definition in https://api.twitter.com/2/openapi.json
- // When multiple options exist, the SDK supports only "OAuth2UserToken" or "BearerToken"
+ public static void main(String[] args) {
+ // Set the credentials based on the API's "security" tag values.
+ // Check the API definition in https://api.twitter.com/2/openapi.json
+ // When multiple options exist, the SDK supports only "OAuth2UserToken" or "BearerToken"
- // Uncomment and set the credentials configuration
-
- // Configure HTTP bearer authorization:
- // TwitterCredentialsBearer credentials = new TwitterCredentialsBearer(System.getenv("TWITTER_BEARER_TOKEN"));
+ // Uncomment and set the credentials configuration
+
+ // Configure HTTP bearer authorization:
+ // TwitterCredentialsBearer credentials = new TwitterCredentialsBearer(System.getenv("TWITTER_BEARER_TOKEN"));
TwitterApi apiInstance = new TwitterApi(credentials);
- // Set the params values
- Integer backfillMinutes = 56; // Integer | The number of minutes of backfill requested.
- Set tweetFields = new HashSet<>(Arrays.asList()); // Set | A comma separated list of Tweet fields to display.
- Set expansions = new HashSet<>(Arrays.asList()); // Set | A comma separated list of fields to expand.
- Set mediaFields = new HashSet<>(Arrays.asList()); // Set | A comma separated list of Media fields to display.
- Set pollFields = new HashSet<>(Arrays.asList()); // Set | A comma separated list of Poll fields to display.
- Set userFields = new HashSet<>(Arrays.asList()); // Set | A comma separated list of User fields to display.
- Set placeFields = new HashSet<>(Arrays.asList()); // Set | A comma separated list of Place fields to display.
- try {
- InputStream result = apiInstance.tweets().searchStream()
- .backfillMinutes(backfillMinutes)
- .tweetFields(tweetFields)
- .expansions(expansions)
- .mediaFields(mediaFields)
- .pollFields(pollFields)
- .userFields(userFields)
- .placeFields(placeFields)
- .execute();
- try{
- JSON json = new JSON();
- Type localVarReturnType = new TypeToken(){}.getType();
- BufferedReader reader = new BufferedReader(new InputStreamReader(result));
- String line = reader.readLine();
- while (line != null) {
- if(line.isEmpty()) {
- System.out.println("==> Empty line");
- line = reader.readLine();
- continue;
- }
- Object jsonObject = json.getGson().fromJson(line, localVarReturnType);
- System.out.println(jsonObject != null ? jsonObject.toString() : "Null object");
- line = reader.readLine();
- }
- }catch (Exception e) {
- e.printStackTrace();
- System.out.println(e);
+ try {
+ BufferedSource result = apiInstance.tweets().searchStream()
+ .parameters(new StreamQueryParameters.Builder()
+ .withBackfillMinutes(56)
+ .withTweetFields(TweetField.AUTHOR_ID, TweetField.ID, TweetField.CREATED_AT)
+ .build())
+ .execute();
+ try {
+ JSON json = new JSON();
+ Type localVarReturnType = new TypeToken() {
+ }.getType();
+ String line = result.readUtf8Line();
+ while (line != null) {
+ if (line.isEmpty()) {
+ System.out.println("==> Empty line");
+ line = result.readUtf8Line();
+ continue;
+ }
+ Object jsonObject = json.getGson().fromJson(line, localVarReturnType);
+ System.out.println(jsonObject != null ? jsonObject.toString() : "Null object");
+ line = result.readUtf8Line();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ System.out.println(e);
}
- } catch (ApiException e) {
- System.err.println("Exception when calling TweetsApi#searchStream");
- System.err.println("Status code: " + e.getCode());
- System.err.println("Reason: " + e.getResponseBody());
- System.err.println("Response headers: " + e.getResponseHeaders());
- e.printStackTrace();
+ } catch (ApiException e) {
+ System.err.println("Exception when calling TweetsApi#searchStream");
+ System.err.println("Status code: " + e.getCode());
+ System.err.println("Reason: " + e.getResponseBody());
+ System.err.println("Response headers: " + e.getResponseHeaders());
+ e.printStackTrace();
+ }
}
- }
}
```
@@ -1112,13 +1121,7 @@ public class Example {
| Name | Type | Description | Notes |
|------------- | ------------- | ------------- | -------------|
-| **backfillMinutes** | **Integer**| The number of minutes of backfill requested. | [optional] |
-| **tweetFields** | [**Set<String>**](String.md)| A comma separated list of Tweet fields to display. | [optional] [enum: attachments, author_id, context_annotations, conversation_id, created_at, entities, geo, id, in_reply_to_user_id, lang, non_public_metrics, organic_metrics, possibly_sensitive, promoted_metrics, public_metrics, referenced_tweets, reply_settings, source, text, withheld] |
-| **expansions** | [**Set<String>**](String.md)| A comma separated list of fields to expand. | [optional] [enum: attachments.media_keys, attachments.poll_ids, author_id, entities.mentions.username, geo.place_id, in_reply_to_user_id, referenced_tweets.id, referenced_tweets.id.author_id] |
-| **mediaFields** | [**Set<String>**](String.md)| A comma separated list of Media fields to display. | [optional] [enum: alt_text, duration_ms, height, media_key, non_public_metrics, organic_metrics, preview_image_url, promoted_metrics, public_metrics, type, url, variants, width] |
-| **pollFields** | [**Set<String>**](String.md)| A comma separated list of Poll fields to display. | [optional] [enum: duration_minutes, end_datetime, id, options, voting_status] |
-| **userFields** | [**Set<String>**](String.md)| A comma separated list of User fields to display. | [optional] [enum: created_at, description, entities, id, location, name, pinned_tweet_id, profile_image_url, protected, public_metrics, url, username, verified, withheld] |
-| **placeFields** | [**Set<String>**](String.md)| A comma separated list of Place fields to display. | [optional] [enum: contained_within, country, country_code, full_name, geo, id, name, place_type] |
+| **parameters** | [**StreamQueryParameters**](StreamQueryParameters.md) | | |
### Return type
diff --git a/docs/TwitterStream.md b/docs/TwitterStream.md
new file mode 100644
index 0000000..332e75c
--- /dev/null
+++ b/docs/TwitterStream.md
@@ -0,0 +1,63 @@
+# TwitterStream
+
+A wrapper for calling the stream endpoints reading the BufferedSource and producing deserialized responses from every line of the BufferedSource.
+
+
+
+# **sampleStream**
+
+```java
+twitterStream.addListener(new TweetListener());
+twitterStream.startSampleStream(new StreamQueryParameters.Builder().build());
+```
+
+The listener must implement this method
+```java
+void onTweetArrival(StreamingTweetResponse streamingTweet);
+```
+
+### Example
+
+```java
+import com.twitter.clientlib.model.*;
+import com.twitter.clientlib.query.StreamQueryParameters;
+import com.twitter.clientlib.query.model.TweetField;
+import com.twitter.clientlib.stream.TweetsStreamListener;
+import com.twitter.clientlib.stream.TwitterStream;
+
+
+public class HelloWorldStreaming {
+
+ public static void main(String[] args) {
+ /**
+ * Set the credentials for the required APIs.
+ * The Java SDK supports TwitterCredentialsOAuth2 & TwitterCredentialsBearer.
+ * Check the 'security' tag of the required APIs in https://api.twitter.com/2/openapi.json in order
+ * to use the right credential object.
+ */
+ TwitterStream twitterStream = new TwitterStream(new TwitterCredentialsBearer(System.getenv("TWITTER_BEARER_TOKEN")));
+ twitterStream.addListener(new Responder());
+
+ twitterStream.startSampleStream(new StreamQueryParameters.Builder()
+ .withTweetFields(TweetField.AUTHOR_ID, TweetField.ID, TweetField.CREATED_AT)
+ .build());
+
+ }
+}
+
+class Responder implements TweetsStreamListener {
+ @Override
+ public void onTweetArrival(StreamingTweetResponse streamingTweet) {
+ if (streamingTweet == null) {
+ System.err.println("Error: actionOnTweetsStream - streamingTweet is null ");
+ return;
+ }
+
+ if (streamingTweet.getErrors() != null) {
+ streamingTweet.getErrors().forEach(System.out::println);
+ } else if (streamingTweet.getData() != null) {
+ System.out.println("New streaming tweet: " + streamingTweet.getData().getText());
+ }
+ }
+}
+```
diff --git a/examples/pom.xml b/examples/pom.xml
index a779e4b..e1867bd 100644
--- a/examples/pom.xml
+++ b/examples/pom.xml
@@ -19,5 +19,10 @@
2.0.0
compile
+
+ org.slf4j
+ slf4j-simple
+ 1.7.5
+
diff --git a/examples/src/main/java/com/twitter/clientlib/HelloWorldStreaming.java b/examples/src/main/java/com/twitter/clientlib/HelloWorldStreaming.java
index c9ed12a..61f1f92 100644
--- a/examples/src/main/java/com/twitter/clientlib/HelloWorldStreaming.java
+++ b/examples/src/main/java/com/twitter/clientlib/HelloWorldStreaming.java
@@ -23,15 +23,11 @@
package com.twitter.clientlib;
-import java.util.HashSet;
-import java.util.Set;
-import java.io.InputStream;
-
-import com.twitter.clientlib.ApiException;
-import com.twitter.clientlib.TwitterCredentialsBearer;
-import com.twitter.clientlib.TweetsStreamListenersExecutor;
-import com.twitter.clientlib.api.TwitterApi;
import com.twitter.clientlib.model.*;
+import com.twitter.clientlib.query.StreamQueryParameters;
+import com.twitter.clientlib.query.model.TweetField;
+import com.twitter.clientlib.stream.TweetsStreamListener;
+import com.twitter.clientlib.stream.TwitterStream;
public class HelloWorldStreaming {
@@ -43,64 +39,19 @@ public static void main(String[] args) {
* Check the 'security' tag of the required APIs in https://api.twitter.com/2/openapi.json in order
* to use the right credential object.
*/
- TwitterApi apiInstance = new TwitterApi(new TwitterCredentialsBearer(System.getenv("TWITTER_BEARER_TOKEN")));
-
- Set tweetFields = new HashSet<>();
- tweetFields.add("author_id");
- tweetFields.add("id");
- tweetFields.add("created_at");
+ TwitterStream twitterStream = new TwitterStream(new TwitterCredentialsBearer(System.getenv("TWITTER_BEARER_TOKEN")));
+ twitterStream.addListener(new Responder());
- try {
- InputStream streamResult = apiInstance.tweets().sampleStream()
- .backfillMinutes(0)
- .tweetFields(tweetFields)
- .execute();
- // sampleStream with TweetsStreamListenersExecutor
- Responder responder = new Responder();
- TweetsStreamListenersExecutor tsle = new TweetsStreamListenersExecutor(streamResult);
- tsle.addListener(responder);
- tsle.executeListeners();
+ twitterStream.startSampleStream(new StreamQueryParameters.Builder()
+ .withTweetFields(TweetField.AUTHOR_ID, TweetField.ID, TweetField.CREATED_AT)
+ .build());
-// // Shutdown TweetsStreamListenersExecutor
-// try {
-// Thread.sleep(20000);
-// tsle.shutdown();
-// } catch (InterruptedException e) {
-// e.printStackTrace();
-// }
-
-// // An example of how to use the streaming directly using the InputStream result (Without TweetsStreamListenersExecutor)
-// try{
-// JSON json = new JSON();
-// Type localVarReturnType = new TypeToken(){}.getType();
-// BufferedReader reader = new BufferedReader(new InputStreamReader(streamResult));
-// String line = reader.readLine();
-// while (line != null) {
-// if(line.isEmpty()) {
-// System.err.println("==> " + line.isEmpty());
-// line = reader.readLine();
-// continue;
-// }
-// Object jsonObject = json.getGson().fromJson(line, localVarReturnType);
-// System.out.println(jsonObject != null ? jsonObject.toString() : "Null object");
-// line = reader.readLine();
-// }
-// }catch (Exception e) {
-// e.printStackTrace();
-// System.out.println(e);
-// }
- } catch (ApiException e) {
- System.err.println("Status code: " + e.getCode());
- System.err.println("Reason: " + e.getResponseBody());
- System.err.println("Response headers: " + e.getResponseHeaders());
- e.printStackTrace();
- }
}
}
-class Responder implements com.twitter.clientlib.TweetsStreamListener {
+class Responder implements TweetsStreamListener {
@Override
- public void actionOnTweetsStream(StreamingTweetResponse streamingTweet) {
+ public void onTweetArrival(StreamingTweetResponse streamingTweet) {
if(streamingTweet == null) {
System.err.println("Error: actionOnTweetsStream - streamingTweet is null ");
return;
diff --git a/examples/src/main/java/com/twitter/clientlib/TweetsStreamListenersExecutor.java b/examples/src/main/java/com/twitter/clientlib/TweetsStreamListenersExecutor.java
deleted file mode 100644
index c3e9439..0000000
--- a/examples/src/main/java/com/twitter/clientlib/TweetsStreamListenersExecutor.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
-Copyright 2020 Twitter, Inc.
-SPDX-License-Identifier: Apache-2.0
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-
-NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
-https://openapi-generator.tech
-Do not edit the class manually.
-*/
-
-
-package com.twitter.clientlib;
-
-
-import java.io.BufferedReader;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.lang.reflect.Type;
-import java.util.ArrayList;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Queue;
-
-import com.google.gson.reflect.TypeToken;
-
-import com.twitter.clientlib.model.StreamingTweetResponse;
-
-public class TweetsStreamListenersExecutor {
- private final ITweetsQueue tweetsQueue;
- private final List listeners = new ArrayList<>();
- private final InputStream stream;
- private volatile boolean isRunning = true;
-
- public TweetsStreamListenersExecutor(InputStream stream) {
- this.tweetsQueue = new LinkedListTweetsQueue();
- this.stream = stream;
- }
-
- public TweetsStreamListenersExecutor(ITweetsQueue tweetsQueue, InputStream stream) {
- this.tweetsQueue = tweetsQueue;
- this.stream = stream;
- }
-
- public void addListener(TweetsStreamListener toAdd) {
- listeners.add(toAdd);
- }
-
- public void executeListeners() {
- if (stream == null) {
- System.out.println("Error: stream is null.");
- return;
- } else if (this.tweetsQueue == null) {
- System.out.println("Error: tweetsQueue is null.");
- return;
- }
-
- TweetsQueuer tweetsQueuer = new TweetsQueuer();
- TweetsListenersExecutor tweetsListenersExecutor = new TweetsListenersExecutor();
- tweetsListenersExecutor.start();
- tweetsQueuer.start();
- }
-
- public synchronized void shutdown() {
- isRunning = false;
- System.out.println("TweetsStreamListenersExecutor is shutting down.");
- }
-
- private class TweetsListenersExecutor extends Thread {
- @Override
- public void run() {
- processTweets();
- }
-
- private void processTweets() {
- StreamingTweetResponse streamingTweet;
- try {
- while (isRunning) {
- streamingTweet = tweetsQueue.poll();
- if (streamingTweet == null) {
- Thread.sleep(100);
- continue;
- }
- for (TweetsStreamListener listener : listeners) {
- listener.actionOnTweetsStream(streamingTweet);
- }
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
-
- private class TweetsQueuer extends Thread {
- @Override
- public void run() {
- queueTweets();
- }
-
- public void queueTweets() {
- String line = null;
- try (BufferedReader reader = new BufferedReader(new InputStreamReader(stream))) {
- while (isRunning) {
- line = reader.readLine();
- if(line == null || line.isEmpty()) {
- Thread.sleep(100);
- continue;
- }
- try {
- tweetsQueue.add(StreamingTweetResponse.fromJson(line));
- } catch (Exception interExcep) {
- interExcep.printStackTrace();
- }
- }
- } catch (Exception e) {
- e.printStackTrace();
- shutdown();
- }
- }
- }
-}
-
-interface ITweetsQueue {
- StreamingTweetResponse poll();
- void add(StreamingTweetResponse streamingTweet);
-}
-
-class LinkedListTweetsQueue implements ITweetsQueue {
- private final Queue tweetsQueue = new LinkedList<>();
-
- @Override
- public StreamingTweetResponse poll() {
- return tweetsQueue.poll();
- }
-
- @Override
- public void add(StreamingTweetResponse streamingTweet) {
- tweetsQueue.add(streamingTweet);
- }
-}
diff --git a/src/main/java/com/twitter/clientlib/ApiClient.java b/src/main/java/com/twitter/clientlib/ApiClient.java
index f682612..c1416eb 100644
--- a/src/main/java/com/twitter/clientlib/ApiClient.java
+++ b/src/main/java/com/twitter/clientlib/ApiClient.java
@@ -29,6 +29,7 @@
import okhttp3.logging.HttpLoggingInterceptor.Level;
import okio.Buffer;
import okio.BufferedSink;
+import okio.BufferedSource;
import okio.Okio;
import org.apache.oltu.oauth2.client.request.OAuthClientRequest.TokenRequestBuilder;
import org.apache.oltu.oauth2.common.message.types.GrantType;
@@ -1099,11 +1100,10 @@ public ApiResponse execute(Call call, Type returnType) throws ApiExceptio
* Execute stream.
*
* @param call a {@link okhttp3.Call} object
- * @param returnType a {@link java.lang.reflect.Type} object
* @return a {@link java.io.InputStream} object
* @throws com.twitter.clientlib.ApiException if any.
*/
- public InputStream executeStream(Call call, Type returnType) throws ApiException {
+ public BufferedSource executeStream(Call call) throws ApiException {
try {
Response response = call.execute();
if (!response.isSuccessful()) {
@@ -1112,7 +1112,7 @@ public InputStream executeStream(Call call, Type returnType) throws ApiException
if (response.body() == null) {
return null;
}
- return response.body().byteStream();
+ return response.body().source();
} catch (IOException e) {
throw new ApiException(e);
}
diff --git a/src/main/java/com/twitter/clientlib/api/TweetsApi.java b/src/main/java/com/twitter/clientlib/api/TweetsApi.java
index c78fa94..d15df00 100644
--- a/src/main/java/com/twitter/clientlib/api/TweetsApi.java
+++ b/src/main/java/com/twitter/clientlib/api/TweetsApi.java
@@ -23,24 +23,15 @@
package com.twitter.clientlib.api;
import com.twitter.clientlib.ApiCallback;
-import com.twitter.clientlib.ApiClient;
-import com.twitter.clientlib.auth.*;
import com.twitter.clientlib.ApiException;
import com.twitter.clientlib.ApiResponse;
-import com.twitter.clientlib.Configuration;
import com.twitter.clientlib.Pair;
-import com.twitter.clientlib.ProgressRequestBody;
-import com.twitter.clientlib.ProgressResponseBody;
-import com.github.scribejava.core.model.OAuth2AccessToken;
import com.google.gson.reflect.TypeToken;
-import java.io.IOException;
-
import com.twitter.clientlib.model.AddOrDeleteRulesRequest;
import com.twitter.clientlib.model.AddOrDeleteRulesResponse;
-import com.twitter.clientlib.model.Error;
import com.twitter.clientlib.model.FilteredStreamingTweetResponse;
import com.twitter.clientlib.model.Get2ListsIdTweetsResponse;
import com.twitter.clientlib.model.Get2SpacesIdBuyersResponse;
@@ -56,10 +47,11 @@
import com.twitter.clientlib.model.Get2UsersIdMentionsResponse;
import com.twitter.clientlib.model.Get2UsersIdTimelinesReverseChronologicalResponse;
import com.twitter.clientlib.model.Get2UsersIdTweetsResponse;
+
+import java.io.InputStream;
import java.time.OffsetDateTime;
-import com.twitter.clientlib.model.Problem;
+
import com.twitter.clientlib.model.RulesLookupResponse;
-import java.util.Set;
import com.twitter.clientlib.model.StreamingTweetResponse;
import com.twitter.clientlib.model.TweetCreateRequest;
import com.twitter.clientlib.model.TweetCreateResponse;
@@ -72,17 +64,16 @@
import com.twitter.clientlib.model.UsersRetweetsCreateRequest;
import com.twitter.clientlib.model.UsersRetweetsCreateResponse;
import com.twitter.clientlib.model.UsersRetweetsDeleteResponse;
+import com.twitter.clientlib.query.StreamQueryParameters;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.Arrays;
-import java.io.InputStream;
-import javax.ws.rs.core.GenericType;
+import java.util.Set;
-import org.apache.commons.lang3.StringUtils;
+import okio.BufferedSource;
public class TweetsApi extends ApiCommon {
@@ -308,7 +299,7 @@ private okhttp3.Call createTweetValidateBeforeCall(TweetCreateRequest tweetCreat
if (tweetCreateRequest == null) {
throw new ApiException("Missing the required parameter 'tweetCreateRequest' when calling createTweet(Async)");
}
-
+
okhttp3.Call localVarCall = createTweetCall(tweetCreateRequest, _callback);
return localVarCall;
@@ -1676,7 +1667,7 @@ private okhttp3.Call hideReplyByIdValidateBeforeCall(TweetHideRequest tweetHideR
if (tweetId == null) {
throw new ApiException("Missing the required parameter 'tweetId' when calling hideReplyById(Async)");
}
-
+
okhttp3.Call localVarCall = hideReplyByIdCall(tweetHideRequest, tweetId, _callback);
return localVarCall;
@@ -2105,7 +2096,7 @@ public okhttp3.Call executeAsync(final ApiCallback _c
public APIlistsIdTweetsRequest listsIdTweets(String id) {
return new APIlistsIdTweetsRequest(id);
}
- private okhttp3.Call sampleStreamCall(Integer backfillMinutes, Set tweetFields, Set expansions, Set mediaFields, Set pollFields, Set userFields, Set placeFields, final ApiCallback _callback) throws ApiException {
+ public okhttp3.Call sampleStreamCall(StreamQueryParameters streamParameters, final ApiCallback _callback) throws ApiException {
Object localVarPostBody = null;
// create path and map variables
@@ -2117,32 +2108,32 @@ private okhttp3.Call sampleStreamCall(Integer backfillMinutes, Set tweet
Map localVarCookieParams = new HashMap();
Map localVarFormParams = new HashMap();
- if (backfillMinutes != null) {
- localVarQueryParams.addAll(localVarApiClient.parameterToPair("backfill_minutes", backfillMinutes));
+ if (streamParameters.getExpansions() != null && !streamParameters.getExpansions().isEmpty()) {
+ localVarCollectionQueryParams.addAll(localVarApiClient.parameterToPairs("csv", "expansions", streamParameters.getExpansions()));
}
- if (tweetFields != null) {
- localVarCollectionQueryParams.addAll(localVarApiClient.parameterToPairs("csv", "tweet.fields", tweetFields));
+ if (streamParameters.getTweetFields() != null && !streamParameters.getTweetFields().isEmpty()) {
+ localVarCollectionQueryParams.addAll(localVarApiClient.parameterToPairs("csv", "tweet.fields", streamParameters.getTweetFields()));
}
- if (expansions != null) {
- localVarCollectionQueryParams.addAll(localVarApiClient.parameterToPairs("csv", "expansions", expansions));
+ if (streamParameters.getUserFields() != null && !streamParameters.getUserFields().isEmpty()) {
+ localVarCollectionQueryParams.addAll(localVarApiClient.parameterToPairs("csv", "user.fields", streamParameters.getUserFields()));
}
- if (mediaFields != null) {
- localVarCollectionQueryParams.addAll(localVarApiClient.parameterToPairs("csv", "media.fields", mediaFields));
+ if (streamParameters.getMediaFields() != null && !streamParameters.getMediaFields().isEmpty()) {
+ localVarCollectionQueryParams.addAll(localVarApiClient.parameterToPairs("csv", "media.fields", streamParameters.getMediaFields()));
}
- if (pollFields != null) {
- localVarCollectionQueryParams.addAll(localVarApiClient.parameterToPairs("csv", "poll.fields", pollFields));
+ if (streamParameters.getPlaceFields() != null && !streamParameters.getPlaceFields().isEmpty()) {
+ localVarCollectionQueryParams.addAll(localVarApiClient.parameterToPairs("csv", "place.fields", streamParameters.getPlaceFields()));
}
- if (userFields != null) {
- localVarCollectionQueryParams.addAll(localVarApiClient.parameterToPairs("csv", "user.fields", userFields));
+ if (streamParameters.getPollFields() != null && !streamParameters.getPollFields().isEmpty()) {
+ localVarCollectionQueryParams.addAll(localVarApiClient.parameterToPairs("csv", "poll.fields", streamParameters.getPollFields()));
}
- if (placeFields != null) {
- localVarCollectionQueryParams.addAll(localVarApiClient.parameterToPairs("csv", "place.fields", placeFields));
+ if (streamParameters.getBackFillMinutes() != null) {
+ localVarQueryParams.addAll(localVarApiClient.parameterToPair("backfill_minutes", streamParameters.getBackFillMinutes()));
}
final String[] localVarAccepts = {
@@ -2166,113 +2157,47 @@ private okhttp3.Call sampleStreamCall(Integer backfillMinutes, Set tweet
}
@SuppressWarnings("rawtypes")
- private okhttp3.Call sampleStreamValidateBeforeCall(Integer backfillMinutes, Set tweetFields, Set expansions, Set mediaFields, Set pollFields, Set userFields, Set placeFields, final ApiCallback _callback) throws ApiException {
+ private okhttp3.Call sampleStreamValidateBeforeCall(StreamQueryParameters streamParameters, final ApiCallback _callback) throws ApiException {
- okhttp3.Call localVarCall = sampleStreamCall(backfillMinutes, tweetFields, expansions, mediaFields, pollFields, userFields, placeFields, _callback);
+ okhttp3.Call localVarCall = sampleStreamCall(streamParameters, _callback);
return localVarCall;
}
-
- private InputStream sampleStreamWithHttpInfo(Integer backfillMinutes, Set tweetFields, Set expansions, Set mediaFields, Set pollFields, Set userFields, Set placeFields) throws ApiException {
- okhttp3.Call localVarCall = sampleStreamValidateBeforeCall(backfillMinutes, tweetFields, expansions, mediaFields, pollFields, userFields, placeFields, null);
+ private BufferedSource sampleStreamWithHttpInfo(StreamQueryParameters streamParameters) throws ApiException {
+ okhttp3.Call localVarCall = sampleStreamValidateBeforeCall(streamParameters, null);
try {
Type localVarReturnType = new TypeToken(){}.getType();
- return localVarApiClient.executeStream(localVarCall, localVarReturnType);
+ return localVarApiClient.executeStream(localVarCall);
} catch (ApiException e) {
e.setErrorObject(localVarApiClient.getJSON().getGson().fromJson(e.getResponseBody(), new TypeToken(){}.getType()));
throw e;
}
}
-
- private okhttp3.Call sampleStreamAsync(Integer backfillMinutes, Set tweetFields, Set expansions, Set mediaFields, Set pollFields, Set userFields, Set placeFields, final ApiCallback _callback) throws ApiException {
- okhttp3.Call localVarCall = sampleStreamValidateBeforeCall(backfillMinutes, tweetFields, expansions, mediaFields, pollFields, userFields, placeFields, _callback);
+ private okhttp3.Call sampleStreamAsync(StreamQueryParameters streamParameters, final ApiCallback _callback) throws ApiException {
+
+ okhttp3.Call localVarCall = sampleStreamValidateBeforeCall(streamParameters, _callback);
Type localVarReturnType = new TypeToken(){}.getType();
localVarApiClient.executeAsync(localVarCall, localVarReturnType, _callback);
return localVarCall;
}
public class APIsampleStreamRequest {
- private Integer backfillMinutes;
- private Set tweetFields;
- private Set expansions;
- private Set mediaFields;
- private Set pollFields;
- private Set userFields;
- private Set placeFields;
+ private StreamQueryParameters parameters;
private APIsampleStreamRequest() {
+ parameters = new StreamQueryParameters.Builder().build();
}
/**
- * Set backfillMinutes
- * @param backfillMinutes The number of minutes of backfill requested. (optional)
- * @return APIsampleStreamRequest
- */
- public APIsampleStreamRequest backfillMinutes(Integer backfillMinutes) {
- this.backfillMinutes = backfillMinutes;
- return this;
- }
-
- /**
- * Set tweetFields
- * @param tweetFields A comma separated list of Tweet fields to display. (optional)
+ * Set parameters
+ * @param queryParameters {@link StreamQueryParameters} The parameters of the request. (optional)
* @return APIsampleStreamRequest
*/
- public APIsampleStreamRequest tweetFields(Set tweetFields) {
- this.tweetFields = tweetFields;
- return this;
- }
-
- /**
- * Set expansions
- * @param expansions A comma separated list of fields to expand. (optional)
- * @return APIsampleStreamRequest
- */
- public APIsampleStreamRequest expansions(Set expansions) {
- this.expansions = expansions;
- return this;
- }
-
- /**
- * Set mediaFields
- * @param mediaFields A comma separated list of Media fields to display. (optional)
- * @return APIsampleStreamRequest
- */
- public APIsampleStreamRequest mediaFields(Set mediaFields) {
- this.mediaFields = mediaFields;
- return this;
- }
-
- /**
- * Set pollFields
- * @param pollFields A comma separated list of Poll fields to display. (optional)
- * @return APIsampleStreamRequest
- */
- public APIsampleStreamRequest pollFields(Set pollFields) {
- this.pollFields = pollFields;
- return this;
- }
-
- /**
- * Set userFields
- * @param userFields A comma separated list of User fields to display. (optional)
- * @return APIsampleStreamRequest
- */
- public APIsampleStreamRequest userFields(Set userFields) {
- this.userFields = userFields;
- return this;
- }
-
- /**
- * Set placeFields
- * @param placeFields A comma separated list of Place fields to display. (optional)
- * @return APIsampleStreamRequest
- */
- public APIsampleStreamRequest placeFields(Set placeFields) {
- this.placeFields = placeFields;
+ public APIsampleStreamRequest parameters(StreamQueryParameters queryParameters) {
+ this.parameters = queryParameters;
return this;
}
@@ -2289,7 +2214,7 @@ public APIsampleStreamRequest placeFields(Set placeFields) {
*/
public okhttp3.Call buildCall(final ApiCallback _callback) throws ApiException {
- return sampleStreamCall(backfillMinutes, tweetFields, expansions, mediaFields, pollFields, userFields, placeFields, _callback);
+ return sampleStreamCall(parameters, _callback);
}
/**
@@ -2303,27 +2228,27 @@ public okhttp3.Call buildCall(final ApiCallback _callback) throws ApiException {
0 | The request has failed. | - |
*/
- public InputStream execute() throws ApiException {
- return sampleStreamWithHttpInfo(backfillMinutes, tweetFields, expansions, mediaFields, pollFields, userFields, placeFields);
+ public BufferedSource execute() throws ApiException {
+ return sampleStreamWithHttpInfo(parameters);
}
/**
- * Calls the API using a retry mechanism to handle rate limits errors.
- *
- */
- public InputStream execute(Integer retries) throws ApiException {
- InputStream localVarResp;
- try{
- localVarResp = execute();
- }
- catch (ApiException e) {
- if(handleRateLimit(e, retries)) {
- return execute(retries - 1);
- } else {
- throw e;
+ * Calls the API using a retry mechanism to handle rate limits errors.
+ *
+ */
+ public BufferedSource execute(Integer retries) throws ApiException {
+ BufferedSource localVarResp;
+ try{
+ localVarResp = execute();
}
- }
- return localVarResp;
+ catch (ApiException e) {
+ if(handleRateLimit(e, retries)) {
+ return execute(retries - 1);
+ } else {
+ throw e;
+ }
+ }
+ return localVarResp;
}
/**
* Execute sampleStream request with HTTP info returned
@@ -2337,9 +2262,9 @@ public InputStream execute(Integer retries) throws ApiException {
*/
- public InputStream executeWithHttpInfo() throws ApiException {
- return sampleStreamWithHttpInfo(backfillMinutes, tweetFields, expansions, mediaFields, pollFields, userFields, placeFields);
- }
+ public BufferedSource executeWithHttpInfo() throws ApiException {
+ return sampleStreamWithHttpInfo(parameters);
+ }
/**
* Execute sampleStream request (asynchronously)
* @param _callback The callback to be executed when the API call finishes
@@ -2353,7 +2278,7 @@ public InputStream executeWithHttpInfo() throws ApiException {
*/
public okhttp3.Call executeAsync(final ApiCallback _callback) throws ApiException {
- return sampleStreamAsync(backfillMinutes, tweetFields, expansions, mediaFields, pollFields, userFields, placeFields, _callback);
+ return sampleStreamAsync(parameters, _callback);
}
}
@@ -2371,7 +2296,7 @@ public okhttp3.Call executeAsync(final ApiCallback _call
public APIsampleStreamRequest sampleStream() {
return new APIsampleStreamRequest();
}
- private okhttp3.Call searchStreamCall(Integer backfillMinutes, Set tweetFields, Set expansions, Set mediaFields, Set pollFields, Set userFields, Set placeFields, final ApiCallback _callback) throws ApiException {
+ public okhttp3.Call searchStreamCall(StreamQueryParameters streamParameters, final ApiCallback _callback) throws ApiException {
Object localVarPostBody = null;
// create path and map variables
@@ -2383,32 +2308,32 @@ private okhttp3.Call searchStreamCall(Integer backfillMinutes, Set tweet
Map localVarCookieParams = new HashMap();
Map localVarFormParams = new HashMap();
- if (backfillMinutes != null) {
- localVarQueryParams.addAll(localVarApiClient.parameterToPair("backfill_minutes", backfillMinutes));
+ if (streamParameters.getExpansions() != null && !streamParameters.getExpansions().isEmpty()) {
+ localVarCollectionQueryParams.addAll(localVarApiClient.parameterToPairs("csv", "expansions", streamParameters.getExpansions()));
}
- if (tweetFields != null) {
- localVarCollectionQueryParams.addAll(localVarApiClient.parameterToPairs("csv", "tweet.fields", tweetFields));
+ if (streamParameters.getTweetFields() != null && !streamParameters.getTweetFields().isEmpty()) {
+ localVarCollectionQueryParams.addAll(localVarApiClient.parameterToPairs("csv", "tweet.fields", streamParameters.getTweetFields()));
}
- if (expansions != null) {
- localVarCollectionQueryParams.addAll(localVarApiClient.parameterToPairs("csv", "expansions", expansions));
+ if (streamParameters.getUserFields() != null && !streamParameters.getUserFields().isEmpty()) {
+ localVarCollectionQueryParams.addAll(localVarApiClient.parameterToPairs("csv", "user.fields", streamParameters.getUserFields()));
}
- if (mediaFields != null) {
- localVarCollectionQueryParams.addAll(localVarApiClient.parameterToPairs("csv", "media.fields", mediaFields));
+ if (streamParameters.getMediaFields() != null && !streamParameters.getMediaFields().isEmpty()) {
+ localVarCollectionQueryParams.addAll(localVarApiClient.parameterToPairs("csv", "media.fields", streamParameters.getMediaFields()));
}
- if (pollFields != null) {
- localVarCollectionQueryParams.addAll(localVarApiClient.parameterToPairs("csv", "poll.fields", pollFields));
+ if (streamParameters.getPlaceFields() != null && !streamParameters.getPlaceFields().isEmpty()) {
+ localVarCollectionQueryParams.addAll(localVarApiClient.parameterToPairs("csv", "place.fields", streamParameters.getPlaceFields()));
}
- if (userFields != null) {
- localVarCollectionQueryParams.addAll(localVarApiClient.parameterToPairs("csv", "user.fields", userFields));
+ if (streamParameters.getPollFields() != null && !streamParameters.getPollFields().isEmpty()) {
+ localVarCollectionQueryParams.addAll(localVarApiClient.parameterToPairs("csv", "poll.fields", streamParameters.getPollFields()));
}
- if (placeFields != null) {
- localVarCollectionQueryParams.addAll(localVarApiClient.parameterToPairs("csv", "place.fields", placeFields));
+ if (streamParameters.getBackFillMinutes() != null) {
+ localVarQueryParams.addAll(localVarApiClient.parameterToPair("backfill_minutes", streamParameters.getBackFillMinutes()));
}
final String[] localVarAccepts = {
@@ -2432,113 +2357,47 @@ private okhttp3.Call searchStreamCall(Integer backfillMinutes, Set tweet
}
@SuppressWarnings("rawtypes")
- private okhttp3.Call searchStreamValidateBeforeCall(Integer backfillMinutes, Set tweetFields, Set expansions, Set mediaFields, Set pollFields, Set userFields, Set placeFields, final ApiCallback _callback) throws ApiException {
+ private okhttp3.Call searchStreamValidateBeforeCall(StreamQueryParameters streamParameters, final ApiCallback _callback) throws ApiException {
- okhttp3.Call localVarCall = searchStreamCall(backfillMinutes, tweetFields, expansions, mediaFields, pollFields, userFields, placeFields, _callback);
+ okhttp3.Call localVarCall = searchStreamCall(streamParameters, _callback);
return localVarCall;
}
-
- private InputStream searchStreamWithHttpInfo(Integer backfillMinutes, Set tweetFields, Set expansions, Set mediaFields, Set pollFields, Set userFields, Set placeFields) throws ApiException {
- okhttp3.Call localVarCall = searchStreamValidateBeforeCall(backfillMinutes, tweetFields, expansions, mediaFields, pollFields, userFields, placeFields, null);
+ private BufferedSource searchStreamWithHttpInfo(StreamQueryParameters queryParameters) throws ApiException {
+ okhttp3.Call localVarCall = searchStreamValidateBeforeCall(queryParameters, null);
try {
Type localVarReturnType = new TypeToken(){}.getType();
- return localVarApiClient.executeStream(localVarCall, localVarReturnType);
+ return localVarApiClient.executeStream(localVarCall);
} catch (ApiException e) {
e.setErrorObject(localVarApiClient.getJSON().getGson().fromJson(e.getResponseBody(), new TypeToken(){}.getType()));
throw e;
}
}
-
- private okhttp3.Call searchStreamAsync(Integer backfillMinutes, Set tweetFields, Set expansions, Set mediaFields, Set pollFields, Set userFields, Set placeFields, final ApiCallback _callback) throws ApiException {
- okhttp3.Call localVarCall = searchStreamValidateBeforeCall(backfillMinutes, tweetFields, expansions, mediaFields, pollFields, userFields, placeFields, _callback);
+ private okhttp3.Call searchStreamAsync(StreamQueryParameters streamParameters, final ApiCallback _callback) throws ApiException {
+
+ okhttp3.Call localVarCall = searchStreamValidateBeforeCall(streamParameters, _callback);
Type localVarReturnType = new TypeToken(){}.getType();
localVarApiClient.executeAsync(localVarCall, localVarReturnType, _callback);
return localVarCall;
}
public class APIsearchStreamRequest {
- private Integer backfillMinutes;
- private Set tweetFields;
- private Set expansions;
- private Set mediaFields;
- private Set pollFields;
- private Set userFields;
- private Set placeFields;
+ private StreamQueryParameters parameters;
private APIsearchStreamRequest() {
+ parameters = new StreamQueryParameters.Builder().build();
}
/**
- * Set backfillMinutes
- * @param backfillMinutes The number of minutes of backfill requested. (optional)
- * @return APIsearchStreamRequest
- */
- public APIsearchStreamRequest backfillMinutes(Integer backfillMinutes) {
- this.backfillMinutes = backfillMinutes;
- return this;
- }
-
- /**
- * Set tweetFields
- * @param tweetFields A comma separated list of Tweet fields to display. (optional)
- * @return APIsearchStreamRequest
- */
- public APIsearchStreamRequest tweetFields(Set tweetFields) {
- this.tweetFields = tweetFields;
- return this;
- }
-
- /**
- * Set expansions
- * @param expansions A comma separated list of fields to expand. (optional)
+ * Set parameters
+ * @param queryParameters {@link StreamQueryParameters} The parameters of the request. (optional)
* @return APIsearchStreamRequest
*/
- public APIsearchStreamRequest expansions(Set expansions) {
- this.expansions = expansions;
- return this;
- }
-
- /**
- * Set mediaFields
- * @param mediaFields A comma separated list of Media fields to display. (optional)
- * @return APIsearchStreamRequest
- */
- public APIsearchStreamRequest mediaFields(Set mediaFields) {
- this.mediaFields = mediaFields;
- return this;
- }
-
- /**
- * Set pollFields
- * @param pollFields A comma separated list of Poll fields to display. (optional)
- * @return APIsearchStreamRequest
- */
- public APIsearchStreamRequest pollFields(Set pollFields) {
- this.pollFields = pollFields;
- return this;
- }
-
- /**
- * Set userFields
- * @param userFields A comma separated list of User fields to display. (optional)
- * @return APIsearchStreamRequest
- */
- public APIsearchStreamRequest userFields(Set userFields) {
- this.userFields = userFields;
- return this;
- }
-
- /**
- * Set placeFields
- * @param placeFields A comma separated list of Place fields to display. (optional)
- * @return APIsearchStreamRequest
- */
- public APIsearchStreamRequest placeFields(Set placeFields) {
- this.placeFields = placeFields;
+ public APIsearchStreamRequest parameters(StreamQueryParameters queryParameters) {
+ this.parameters = queryParameters;
return this;
}
@@ -2555,7 +2414,7 @@ public APIsearchStreamRequest placeFields(Set placeFields) {
*/
public okhttp3.Call buildCall(final ApiCallback _callback) throws ApiException {
- return searchStreamCall(backfillMinutes, tweetFields, expansions, mediaFields, pollFields, userFields, placeFields, _callback);
+ return searchStreamCall(parameters, _callback);
}
/**
@@ -2569,27 +2428,27 @@ public okhttp3.Call buildCall(final ApiCallback _callback) throws ApiException {
0 | The request has failed. | - |
*/
- public InputStream execute() throws ApiException {
- return searchStreamWithHttpInfo(backfillMinutes, tweetFields, expansions, mediaFields, pollFields, userFields, placeFields);
+ public BufferedSource execute() throws ApiException {
+ return searchStreamWithHttpInfo(parameters);
}
/**
- * Calls the API using a retry mechanism to handle rate limits errors.
- *
- */
- public InputStream execute(Integer retries) throws ApiException {
- InputStream localVarResp;
- try{
- localVarResp = execute();
- }
- catch (ApiException e) {
- if(handleRateLimit(e, retries)) {
- return execute(retries - 1);
- } else {
- throw e;
+ * Calls the API using a retry mechanism to handle rate limits errors.
+ *
+ */
+ public BufferedSource execute(Integer retries) throws ApiException {
+ BufferedSource localVarResp;
+ try{
+ localVarResp = execute();
}
- }
- return localVarResp;
+ catch (ApiException e) {
+ if(handleRateLimit(e, retries)) {
+ return execute(retries - 1);
+ } else {
+ throw e;
+ }
+ }
+ return localVarResp;
}
/**
* Execute searchStream request with HTTP info returned
@@ -2602,10 +2461,9 @@ public InputStream execute(Integer retries) throws ApiException {
0 | The request has failed. | - |
*/
-
- public InputStream executeWithHttpInfo() throws ApiException {
- return searchStreamWithHttpInfo(backfillMinutes, tweetFields, expansions, mediaFields, pollFields, userFields, placeFields);
- }
+ public BufferedSource executeWithHttpInfo() throws ApiException {
+ return searchStreamWithHttpInfo(parameters);
+ }
/**
* Execute searchStream request (asynchronously)
* @param _callback The callback to be executed when the API call finishes
@@ -2619,7 +2477,7 @@ public InputStream executeWithHttpInfo() throws ApiException {
*/
public okhttp3.Call executeAsync(final ApiCallback _callback) throws ApiException {
- return searchStreamAsync(backfillMinutes, tweetFields, expansions, mediaFields, pollFields, userFields, placeFields, _callback);
+ return searchStreamAsync(parameters, _callback);
}
}
diff --git a/src/main/java/com/twitter/clientlib/exceptions/AuthenticationException.java b/src/main/java/com/twitter/clientlib/exceptions/AuthenticationException.java
new file mode 100644
index 0000000..11f0313
--- /dev/null
+++ b/src/main/java/com/twitter/clientlib/exceptions/AuthenticationException.java
@@ -0,0 +1,29 @@
+/*
+Copyright 2020 Twitter, Inc.
+SPDX-License-Identifier: Apache-2.0
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+*/
+package com.twitter.clientlib.exceptions;
+
+public class AuthenticationException extends RuntimeException {
+
+ public AuthenticationException(String message) {
+ super(message);
+ }
+
+ public AuthenticationException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/src/main/java/com/twitter/clientlib/exceptions/EmptyStreamTimeoutException.java b/src/main/java/com/twitter/clientlib/exceptions/EmptyStreamTimeoutException.java
new file mode 100644
index 0000000..bf422c3
--- /dev/null
+++ b/src/main/java/com/twitter/clientlib/exceptions/EmptyStreamTimeoutException.java
@@ -0,0 +1,25 @@
+/*
+Copyright 2020 Twitter, Inc.
+SPDX-License-Identifier: Apache-2.0
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+*/
+
+package com.twitter.clientlib.exceptions;
+
+public class EmptyStreamTimeoutException extends RuntimeException {
+ public EmptyStreamTimeoutException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/com/twitter/clientlib/exceptions/StreamException.java b/src/main/java/com/twitter/clientlib/exceptions/StreamException.java
new file mode 100644
index 0000000..f921dd8
--- /dev/null
+++ b/src/main/java/com/twitter/clientlib/exceptions/StreamException.java
@@ -0,0 +1,30 @@
+/*
+Copyright 2020 Twitter, Inc.
+SPDX-License-Identifier: Apache-2.0
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+*/
+
+package com.twitter.clientlib.exceptions;
+
+public class StreamException extends RuntimeException{
+
+ public StreamException(String message) {
+ super(message);
+ }
+
+ public StreamException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/src/main/java/com/twitter/clientlib/exceptions/TooManyRequestsException.java b/src/main/java/com/twitter/clientlib/exceptions/TooManyRequestsException.java
new file mode 100644
index 0000000..705d4b0
--- /dev/null
+++ b/src/main/java/com/twitter/clientlib/exceptions/TooManyRequestsException.java
@@ -0,0 +1,30 @@
+/*
+Copyright 2020 Twitter, Inc.
+SPDX-License-Identifier: Apache-2.0
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+*/
+
+package com.twitter.clientlib.exceptions;
+
+public class TooManyRequestsException extends RuntimeException{
+
+ public TooManyRequestsException(String message) {
+ super(message);
+ }
+
+ public TooManyRequestsException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/src/main/java/com/twitter/clientlib/model/UrlEntity.java b/src/main/java/com/twitter/clientlib/model/UrlEntity.java
index 099e0fd..df9d8d4 100644
--- a/src/main/java/com/twitter/clientlib/model/UrlEntity.java
+++ b/src/main/java/com/twitter/clientlib/model/UrlEntity.java
@@ -23,15 +23,11 @@
package com.twitter.clientlib.model;
import java.util.Objects;
-import java.util.Arrays;
+
import com.google.gson.TypeAdapter;
-import com.google.gson.annotations.JsonAdapter;
import com.google.gson.annotations.SerializedName;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
-import com.twitter.clientlib.model.EntityIndicesInclusiveExclusive;
-import com.twitter.clientlib.model.UrlFields;
-import com.twitter.clientlib.model.UrlImage;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.io.IOException;
@@ -40,22 +36,13 @@
import java.util.List;
import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
-import com.google.gson.JsonDeserializationContext;
-import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
-import com.google.gson.JsonParseException;
import com.google.gson.TypeAdapterFactory;
import com.google.gson.reflect.TypeToken;
-import java.lang.reflect.Type;
-import java.util.HashMap;
import java.util.HashSet;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
import com.twitter.clientlib.JSON;
diff --git a/src/main/java/com/twitter/clientlib/model/URLFields.java b/src/main/java/com/twitter/clientlib/model/UrlFields.java
similarity index 97%
rename from src/main/java/com/twitter/clientlib/model/URLFields.java
rename to src/main/java/com/twitter/clientlib/model/UrlFields.java
index 36ad728..d9040b3 100644
--- a/src/main/java/com/twitter/clientlib/model/URLFields.java
+++ b/src/main/java/com/twitter/clientlib/model/UrlFields.java
@@ -23,13 +23,11 @@
package com.twitter.clientlib.model;
import java.util.Objects;
-import java.util.Arrays;
+
import com.google.gson.TypeAdapter;
-import com.google.gson.annotations.JsonAdapter;
import com.google.gson.annotations.SerializedName;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
-import com.twitter.clientlib.model.UrlImage;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.io.IOException;
@@ -38,22 +36,13 @@
import java.util.List;
import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
-import com.google.gson.JsonDeserializationContext;
-import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
-import com.google.gson.JsonParseException;
import com.google.gson.TypeAdapterFactory;
import com.google.gson.reflect.TypeToken;
-import java.lang.reflect.Type;
-import java.util.HashMap;
import java.util.HashSet;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
import com.twitter.clientlib.JSON;
diff --git a/src/main/java/com/twitter/clientlib/model/URLImage.java b/src/main/java/com/twitter/clientlib/model/UrlImage.java
similarity index 94%
rename from src/main/java/com/twitter/clientlib/model/URLImage.java
rename to src/main/java/com/twitter/clientlib/model/UrlImage.java
index c766943..9c0913d 100644
--- a/src/main/java/com/twitter/clientlib/model/URLImage.java
+++ b/src/main/java/com/twitter/clientlib/model/UrlImage.java
@@ -23,9 +23,8 @@
package com.twitter.clientlib.model;
import java.util.Objects;
-import java.util.Arrays;
+
import com.google.gson.TypeAdapter;
-import com.google.gson.annotations.JsonAdapter;
import com.google.gson.annotations.SerializedName;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
@@ -35,22 +34,12 @@
import java.net.URL;
import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
-import com.google.gson.JsonArray;
-import com.google.gson.JsonDeserializationContext;
-import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
-import com.google.gson.JsonParseException;
import com.google.gson.TypeAdapterFactory;
import com.google.gson.reflect.TypeToken;
-import java.lang.reflect.Type;
-import java.util.HashMap;
import java.util.HashSet;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
import com.twitter.clientlib.JSON;
@@ -72,7 +61,7 @@ public class UrlImage {
@SerializedName(SERIALIZED_NAME_WIDTH)
private Integer width;
- public UrlImage() {
+ public UrlImage() {
}
public UrlImage height(Integer height) {
diff --git a/src/main/java/com/twitter/clientlib/query/StreamQueryParameters.java b/src/main/java/com/twitter/clientlib/query/StreamQueryParameters.java
new file mode 100644
index 0000000..9f74a59
--- /dev/null
+++ b/src/main/java/com/twitter/clientlib/query/StreamQueryParameters.java
@@ -0,0 +1,257 @@
+/*
+Copyright 2020 Twitter, Inc.
+SPDX-License-Identifier: Apache-2.0
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+*/
+
+package com.twitter.clientlib.query;
+
+import com.twitter.clientlib.query.model.*;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class StreamQueryParameters {
+ private List tweetFields;
+ private List expansions;
+ private List mediaFields;
+ private List pollFields;
+ private List userFields;
+ private List placeFields;
+ private Integer backFillMinutes;
+
+ private StreamQueryParameters(Builder builder) {
+ this.tweetFields = builder.tweetFields;
+ this.expansions = builder.expansions;
+ this.mediaFields = builder.mediaFields;
+ this.pollFields = builder.pollFields;
+ this.userFields = builder.userFields;
+ this.placeFields = builder.placeFields;
+ this.backFillMinutes = builder.backFillMinutes;
+ }
+
+ public List getTweetFields() {
+ return tweetFields.stream().map(TweetField::getName).collect(Collectors.toList());
+ }
+
+ public void setTweetFields(List tweetFields) {
+ this.tweetFields = tweetFields;
+ }
+
+ public List getExpansions() {
+ return expansions.stream().map(Expansion::getName).collect(Collectors.toList());
+ }
+
+ public void setExpansions(List expansions) {
+ this.expansions = expansions;
+ }
+
+ public List getMediaFields() {
+ return mediaFields.stream().map(MediaField::getName).collect(Collectors.toList());
+ }
+
+ public void setMediaFields(List mediaFields) {
+ this.mediaFields = mediaFields;
+ }
+
+ public List getPollFields() {
+ return pollFields.stream().map(PollField::getName).collect(Collectors.toList());
+ }
+
+ public void setPollFields(List pollFields) {
+ this.pollFields = pollFields;
+ }
+
+ public List getUserFields() {
+ return userFields.stream().map(UserField::getName).collect(Collectors.toList());
+ }
+
+ public void setUserFields(List userFields) {
+ this.userFields = userFields;
+ }
+
+ public List getPlaceFields() {
+ return placeFields.stream().map(PlaceField::getName).collect(Collectors.toList());
+ }
+
+ public void setPlaceFields(List placeFields) {
+ this.placeFields = placeFields;
+ }
+
+ public Integer getBackFillMinutes() {
+ return backFillMinutes;
+ }
+
+ public void setBackFillMinutes(Integer backFillMinutes) {
+ this.backFillMinutes = backFillMinutes;
+ }
+
+ public static class Builder {
+ private final List tweetFields;
+ private final List expansions;
+ private final List mediaFields;
+ private final List pollFields;
+ private final List userFields;
+ private final List placeFields;
+ private Integer backFillMinutes = 0;
+
+ public Builder() {
+ this.tweetFields = new ArrayList<>();
+ this.expansions = new ArrayList<>();
+ this.mediaFields = new ArrayList<>();
+ this.pollFields = new ArrayList<>();
+ this.userFields = new ArrayList<>();
+ this.placeFields = new ArrayList<>();
+ }
+
+ /**
+ * Set tweetFields
+ * @param tweetFields A comma separated list of Tweet fields to display. (optional)
+ * @return Builder
+ */
+ public Builder withTweetFields(TweetField... tweetFields) {
+ this.tweetFields.addAll(Arrays.asList(tweetFields));
+ return this;
+ }
+
+ /**
+ * Set tweetFields
+ * @param tweetFields A comma separated list of Tweet fields to display. (optional)
+ * @return Builder
+ */
+ public Builder withTweetFields(Collection tweetFields) {
+ this.tweetFields.addAll(tweetFields);
+ return this;
+ }
+
+ /**
+ * Set mediaFields
+ * @param mediaFields A comma separated list of Media fields to display. (optional)
+ * @return Builder
+ */
+ public Builder withMediaFields(MediaField... mediaFields) {
+ this.mediaFields.addAll(Arrays.asList(mediaFields));
+ return this;
+ }
+
+ /**
+ * Set mediaFields
+ * @param mediaFields A comma separated list of Media fields to display. (optional)
+ * @return Builder
+ */
+ public Builder withMediaFields(Collection mediaFields) {
+ this.mediaFields.addAll(mediaFields);
+ return this;
+ }
+
+ /**
+ * Set pollFields
+ * @param pollFields A comma separated list of Poll fields to display. (optional)
+ * @return Builder
+ */
+ public Builder withPollFields(PollField... pollFields) {
+ this.pollFields.addAll(Arrays.asList(pollFields));
+ return this;
+ }
+
+ /**
+ * Set pollFields
+ * @param pollFields A comma separated list of Poll fields to display. (optional)
+ * @return Builder
+ */
+ public Builder withPollFields(Collection pollFields) {
+ this.pollFields.addAll(pollFields);
+ return this;
+ }
+
+ /**
+ * Set userFields
+ * @param userFields A comma separated list of User fields to display. (optional)
+ * @return Builder
+ */
+ public Builder withUserFields(UserField... userFields) {
+ this.userFields.addAll(Arrays.asList(userFields));
+ return this;
+ }
+
+ /**
+ * Set userFields
+ * @param userFields A comma separated list of User fields to display. (optional)
+ * @return Builder
+ */
+ public Builder withUserFields(Collection userFields) {
+ this.userFields.addAll(userFields);
+ return this;
+ }
+
+ /**
+ * Set placeFields
+ * @param placeFields A comma separated list of Place fields to display. (optional)
+ * @return Builder
+ */
+ public Builder withPlaceFields(PlaceField... placeFields) {
+ this.placeFields.addAll(Arrays.asList(placeFields));
+ return this;
+ }
+
+ /**
+ * Set placeFields
+ * @param placeFields A comma separated list of Place fields to display. (optional)
+ * @return Builder
+ */
+ public Builder withPlaceFields(Collection placeFields) {
+ this.placeFields.addAll(placeFields);
+ return this;
+ }
+
+ /**
+ * Set expansions
+ * @param expansions A comma separated list of fields to expand. (optional)
+ * @return Builder
+ */
+ public Builder withExpansions(Expansion... expansions) {
+ this.expansions.addAll(Arrays.asList(expansions));
+ return this;
+ }
+
+ /**
+ * Set expansions
+ * @param expansions A comma separated list of fields to expand. (optional)
+ * @return Builder
+ */
+ public Builder withExpansions(Collection expansions) {
+ this.expansions.addAll(expansions);
+ return this;
+ }
+
+ /**
+ * Set backfillMinutes
+ * @param backfillMinutes The number of minutes of backfill requested. (optional)
+ * @return Builder
+ */
+ public Builder withBackfillMinutes(Integer backFillMinutes) {
+ this.backFillMinutes = backFillMinutes;
+ return this;
+ }
+
+ public StreamQueryParameters build() {
+ return new StreamQueryParameters(this);
+ }
+ }
+}
diff --git a/src/main/java/com/twitter/clientlib/query/model/Expansion.java b/src/main/java/com/twitter/clientlib/query/model/Expansion.java
new file mode 100644
index 0000000..e7c0fa8
--- /dev/null
+++ b/src/main/java/com/twitter/clientlib/query/model/Expansion.java
@@ -0,0 +1,48 @@
+/*
+Copyright 2020 Twitter, Inc.
+SPDX-License-Identifier: Apache-2.0
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+*/
+
+package com.twitter.clientlib.query.model;
+
+import java.util.Arrays;
+import java.util.List;
+
+public enum Expansion {
+ ATTACHMENTS_MEDIA_KEYS("attachments.media_keys"),
+ ATTACHMENTS_POLL_IDS("attachments.poll_ids"),
+ AUTHOR_ID("author_id"),
+ ENTITIES_MENTIONS_USERNAME("entities.mentions.username"),
+ GEO_PLACE_ID("geo.place_id"),
+ IN_REPLY_TO_USER_ID("in_reply_to_user_id"),
+ REFERENCED_TWEETS_ID("referenced_tweets.id"),
+ REFERENCED_TWEETS_ID_AUTHOR_ID("referenced_tweets.id.author_id");
+
+ private final String name;
+
+ Expansion(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public static List all() {
+ return Arrays.asList(Expansion.values());
+ }
+
+}
diff --git a/src/main/java/com/twitter/clientlib/query/model/MediaField.java b/src/main/java/com/twitter/clientlib/query/model/MediaField.java
new file mode 100644
index 0000000..d27d7f0
--- /dev/null
+++ b/src/main/java/com/twitter/clientlib/query/model/MediaField.java
@@ -0,0 +1,50 @@
+/*
+Copyright 2020 Twitter, Inc.
+SPDX-License-Identifier: Apache-2.0
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+*/
+
+package com.twitter.clientlib.query.model;
+
+import java.util.Arrays;
+import java.util.List;
+
+public enum MediaField {
+ ALT_TEXT("alt_text"),
+ DURATION_MS("duration_ms"),
+ HEIGHT("height"),
+ MEDIA_KEY("media_key"),
+ PREVIEW_IMAGE_URL("preview_image_url"),
+ PUBLIC_METRICS("public_metrics"),
+ TYPE("type"),
+ URL("url"),
+ VARIANTS("variants"),
+ WIDTH("width"),;
+
+ private final String name;
+
+ MediaField(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public static List all() {
+ return Arrays.asList(MediaField.values());
+ }
+
+}
diff --git a/src/main/java/com/twitter/clientlib/query/model/PlaceField.java b/src/main/java/com/twitter/clientlib/query/model/PlaceField.java
new file mode 100644
index 0000000..08ddd3a
--- /dev/null
+++ b/src/main/java/com/twitter/clientlib/query/model/PlaceField.java
@@ -0,0 +1,47 @@
+/*
+Copyright 2020 Twitter, Inc.
+SPDX-License-Identifier: Apache-2.0
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+*/
+
+package com.twitter.clientlib.query.model;
+
+import java.util.Arrays;
+import java.util.List;
+
+public enum PlaceField {
+ CONTAINED_WITHIN("contained_within"),
+ COUNTRY("country"),
+ COUNTRY_CODE("country_code"),
+ FULL_NAME("full_name"),
+ GEO("geo"),
+ ID("id"),
+ NAME("name"),
+ PLACE_TYPE("place_type");
+
+ private final String name;
+
+ PlaceField(String name) {
+ this.name = name;
+ }
+
+ public static List all() {
+ return Arrays.asList(PlaceField.values());
+ }
+
+ public String getName() {
+ return name;
+ }
+}
diff --git a/src/main/java/com/twitter/clientlib/query/model/PollField.java b/src/main/java/com/twitter/clientlib/query/model/PollField.java
new file mode 100644
index 0000000..d779f6e
--- /dev/null
+++ b/src/main/java/com/twitter/clientlib/query/model/PollField.java
@@ -0,0 +1,43 @@
+/*
+Copyright 2020 Twitter, Inc.
+SPDX-License-Identifier: Apache-2.0
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+*/
+package com.twitter.clientlib.query.model;
+
+import java.util.Arrays;
+import java.util.List;
+
+public enum PollField {
+ DURATION_MINUTES("duration_minutes"),
+ END_DATETIME("end_datetime"),
+ ID("id"),
+ OPTIONS("options"),
+ VOTING_STATUS("voting_status");
+
+ private final String name;
+
+ PollField(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public static List all() {
+ return Arrays.asList(PollField.values());
+ }
+}
diff --git a/src/main/java/com/twitter/clientlib/query/model/TweetField.java b/src/main/java/com/twitter/clientlib/query/model/TweetField.java
new file mode 100644
index 0000000..7644022
--- /dev/null
+++ b/src/main/java/com/twitter/clientlib/query/model/TweetField.java
@@ -0,0 +1,56 @@
+/*
+Copyright 2020 Twitter, Inc.
+SPDX-License-Identifier: Apache-2.0
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+*/
+package com.twitter.clientlib.query.model;
+
+import java.util.Arrays;
+import java.util.List;
+
+public enum TweetField {
+ ATTACHMENTS("attachments"),
+ AUTHOR_ID("author_id"),
+ CONTEXT_ANNOTATIONS("context_annotations"),
+ CONVERSATION_ID("conversation_id"),
+ CREATED_AT("created_at"),
+ ENTITIES("entities"),
+ GEO("geo"),
+ ID("id"),
+ IN_REPLY_TO_USER_ID("in_reply_to_user_id"),
+ LANG("lang"),
+ POSSIBLE_SENSITIVE("possibly_sensitive"),
+ PUBLIC_METRICS("public_metrics"),
+ REFERENCED_TWEETS("referenced_tweets"),
+ REPLY_SETTINGS("reply_settings"),
+ SOURCE("source"),
+ TEXT("text"),
+ WITHHELD("withheld");
+
+ private final String name;
+
+ TweetField(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public static List all() {
+ return Arrays.asList(TweetField.values());
+ }
+
+}
diff --git a/src/main/java/com/twitter/clientlib/query/model/UserField.java b/src/main/java/com/twitter/clientlib/query/model/UserField.java
new file mode 100644
index 0000000..639d026
--- /dev/null
+++ b/src/main/java/com/twitter/clientlib/query/model/UserField.java
@@ -0,0 +1,52 @@
+/*
+Copyright 2020 Twitter, Inc.
+SPDX-License-Identifier: Apache-2.0
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+*/
+package com.twitter.clientlib.query.model;
+
+import java.util.Arrays;
+import java.util.List;
+
+public enum UserField {
+ CREATED_AT("created_at"),
+ DESCRIPTION("description"),
+ ENTITIES("entities"),
+ ID("id"),
+ LOCATION("location"),
+ NAME("name"),
+ PINNED_TWEET_ID("pinned_tweet_id"),
+ PROFILE_IMAGE_URL("profile_image_url"),
+ PROTECTED("protected"),
+ PUBLIC_METRICS("public_metrics"),
+ URL("url"),
+ USERNAME("username"),
+ VERIFIED("verified"),
+ WITHHELD("withheld");
+
+ private final String name;
+
+ UserField(String name) {
+ this.name = name;
+ }
+
+ public static List all() {
+ return Arrays.asList(UserField.values());
+ }
+
+ public String getName() {
+ return name;
+ }
+}
diff --git a/src/main/java/com/twitter/clientlib/stream/TweetsStreamExecutor.java b/src/main/java/com/twitter/clientlib/stream/TweetsStreamExecutor.java
new file mode 100644
index 0000000..6ee2d1a
--- /dev/null
+++ b/src/main/java/com/twitter/clientlib/stream/TweetsStreamExecutor.java
@@ -0,0 +1,212 @@
+/*
+Copyright 2020 Twitter, Inc.
+SPDX-License-Identifier: Apache-2.0
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+*/
+
+
+package com.twitter.clientlib.stream;
+
+
+import java.io.IOException;
+import java.time.LocalDateTime;
+import java.time.temporal.ChronoUnit;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingDeque;
+import java.util.concurrent.TimeUnit;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+
+import com.twitter.clientlib.exceptions.EmptyStreamTimeoutException;
+import com.twitter.clientlib.model.StreamingTweetResponse;
+import okio.BufferedSource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class TweetsStreamExecutor {
+
+ private static final Logger logger = LoggerFactory.getLogger(TweetsStreamExecutor.class);
+
+ private static final long EMPTY_STREAM_TIMEOUT = 20;
+ private static final int POLL_WAIT = 5;
+
+ private volatile BlockingQueue rawTweets;
+ private volatile BlockingQueue tweets;
+ private volatile boolean isRunning = true;
+ private ExecutorService rawTweetsQueuerService;
+ private ExecutorService deserializationService;
+ private ExecutorService listenersService;
+ private final List listeners = new ArrayList<>();
+ private BufferedSource stream;
+
+ public TweetsStreamExecutor(BufferedSource stream) {
+ this.rawTweets = new LinkedBlockingDeque<>();
+ this.tweets = new LinkedBlockingDeque<>();
+ this.stream = stream;
+ }
+
+ public void addListener(TweetsStreamListener toAdd) {
+ listeners.add(toAdd);
+ }
+
+ public void removeListener(TweetsStreamListener toRemove) {
+ listeners.remove(toRemove);
+ }
+
+ public void start() {
+ if (stream == null) {
+ logger.error("Stream is null. Exiting...");
+ return;
+ }
+ rawTweetsQueuerService = Executors.newSingleThreadExecutor();
+ rawTweetsQueuerService.submit(new RawTweetsQueuer());
+
+ deserializationService = Executors.newSingleThreadExecutor();
+ deserializationService.submit(new DeserializeTweetsTask());
+
+ listenersService = Executors.newSingleThreadExecutor();
+ listenersService.submit(new TweetsListenersTask());
+ }
+
+ public synchronized void shutdown() {
+ logger.info("TweetsStreamListenersExecutor is shutting down.");
+ isRunning = false;
+ shutDownServices();
+ try {
+ terminateServices();
+ stream.close();
+ } catch (InterruptedException ie) {
+ shutDownServices();
+ Thread.currentThread().interrupt();
+ } catch (IOException e) {
+
+ }
+ }
+
+ private void shutDownServices() {
+ rawTweetsQueuerService.shutdown();
+ deserializationService.shutdown();
+ listenersService.shutdown();
+ }
+
+ private void terminateServices() throws InterruptedException {
+ terminateService(rawTweetsQueuerService);
+ terminateService(deserializationService);
+ terminateService(listenersService);
+ }
+ private void terminateService(ExecutorService executorService) throws InterruptedException {
+ if (!executorService.awaitTermination(1500, TimeUnit.MILLISECONDS)) {
+ executorService.shutdownNow();
+ if (!executorService.awaitTermination(1500, TimeUnit.MILLISECONDS))
+ logger.error("Thread pool did not terminate");
+ }
+ }
+
+ private class RawTweetsQueuer implements Runnable {
+
+ private final Logger logger = LoggerFactory.getLogger(RawTweetsQueuer.class);
+
+ @Override
+ public void run() {
+ queueTweets();
+ }
+
+ public void queueTweets() {
+ String line = null;
+ try {
+ boolean emptyResponse = false;
+ LocalDateTime firstEmpty = LocalDateTime.now();
+ while (isRunning) {
+ line = stream.readUtf8Line();
+ if(line == null || line.isEmpty()) {
+ if(!emptyResponse) {
+ firstEmpty = LocalDateTime.now();
+ emptyResponse = true;
+ } else {
+ if(LocalDateTime.now().minus(EMPTY_STREAM_TIMEOUT, ChronoUnit.SECONDS).isAfter(firstEmpty)) {
+ throw new EmptyStreamTimeoutException(String.format("Stream was empty for %d seconds consecutively", EMPTY_STREAM_TIMEOUT));
+ }
+ }
+ continue;
+ }
+ emptyResponse = false;
+ try {
+ rawTweets.put(line);
+ } catch (Exception ignore) {
+
+ }
+ }
+ } catch (Exception e) {
+ logger.error("Something went wrong. Closing stream... {}", e.getMessage());
+ shutdown();
+ }
+ }
+ }
+
+ private class DeserializeTweetsTask implements Runnable {
+
+ private final Logger logger = LoggerFactory.getLogger(DeserializeTweetsTask.class);
+
+ @Override
+ public void run() {
+ while (isRunning) {
+ try {
+ String rawTweet = rawTweets.poll(POLL_WAIT, TimeUnit.MILLISECONDS);
+ if (rawTweet == null) continue;
+ StreamingTweetResponse tweet = StreamingTweetResponse.fromJson(rawTweet);
+ tweets.put(tweet);
+ } catch (InterruptedException ignore) {
+
+ } catch (JsonProcessingException e) {
+ logger.debug("Json could not be parsed");
+ } catch (Exception e) {
+ logger.debug("Exception in deserialization thread: ", e);
+ }
+ }
+ }
+ }
+
+ private class TweetsListenersTask implements Runnable {
+
+ private final Logger logger = LoggerFactory.getLogger(TweetsListenersTask.class);
+ @Override
+ public void run() {
+ processTweets();
+ }
+
+ private void processTweets() {
+ StreamingTweetResponse streamingTweet;
+
+ while (isRunning) {
+ try {
+ streamingTweet = tweets.poll(POLL_WAIT, TimeUnit.MILLISECONDS);
+ if(streamingTweet == null) continue;
+ for (TweetsStreamListener listener : listeners) {
+ listener.onTweetArrival(streamingTweet);
+ }
+ } catch (InterruptedException e) {
+
+ }
+
+ }
+
+ }
+ }
+}
+
diff --git a/examples/src/main/java/com/twitter/clientlib/TweetsStreamListener.java b/src/main/java/com/twitter/clientlib/stream/TweetsStreamListener.java
similarity index 73%
rename from examples/src/main/java/com/twitter/clientlib/TweetsStreamListener.java
rename to src/main/java/com/twitter/clientlib/stream/TweetsStreamListener.java
index 5df0650..8b4e707 100644
--- a/examples/src/main/java/com/twitter/clientlib/TweetsStreamListener.java
+++ b/src/main/java/com/twitter/clientlib/stream/TweetsStreamListener.java
@@ -14,16 +14,13 @@
See the License for the specific language governing permissions and
limitations under the License.
-NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
-https://openapi-generator.tech
-Do not edit the class manually.
*/
-package com.twitter.clientlib;
+package com.twitter.clientlib.stream;
import com.twitter.clientlib.model.StreamingTweetResponse;
public interface TweetsStreamListener {
- void actionOnTweetsStream(StreamingTweetResponse streamingTweet);
+ void onTweetArrival(StreamingTweetResponse streamingTweet);
}
diff --git a/src/main/java/com/twitter/clientlib/stream/TwitterStream.java b/src/main/java/com/twitter/clientlib/stream/TwitterStream.java
new file mode 100644
index 0000000..ac0f312
--- /dev/null
+++ b/src/main/java/com/twitter/clientlib/stream/TwitterStream.java
@@ -0,0 +1,133 @@
+/*
+Copyright 2020 Twitter, Inc.
+SPDX-License-Identifier: Apache-2.0
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+*/
+
+package com.twitter.clientlib.stream;
+
+import com.twitter.clientlib.ApiClient;
+import com.twitter.clientlib.ApiException;
+import com.twitter.clientlib.TwitterCredentialsBearer;
+import com.twitter.clientlib.api.TweetsApi;
+import com.twitter.clientlib.exceptions.AuthenticationException;
+import com.twitter.clientlib.exceptions.StreamException;
+import com.twitter.clientlib.exceptions.TooManyRequestsException;
+import com.twitter.clientlib.query.StreamQueryParameters;
+
+import okio.BufferedSource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.annotation.PreDestroy;
+import java.util.LinkedList;
+import java.util.List;
+
+public class TwitterStream {
+
+ private static final Logger logger = LoggerFactory.getLogger(TwitterStream.class);
+ private final TweetsApi tweets = new TweetsApi();
+
+ private final ApiClient apiClient = new ApiClient();
+
+ private final List listeners = new LinkedList<>();
+
+ private TweetsStreamExecutor executor;
+
+ private int retries;
+
+ public TwitterStream(TwitterCredentialsBearer credentials) {
+ init();
+ apiClient.setTwitterCredentials(credentials);
+ }
+
+ public TwitterStream(int retries) {
+ this.retries = retries;
+ init();
+ }
+
+ private void init() {
+ initBasePath();
+ tweets.setClient(apiClient);
+ }
+
+ /**
+ * Set retries
+ * @param retries the retries for reconnections on 429 status code errors
+ */
+ public void setRetries(int retries) {
+ this.retries = retries;
+ }
+
+ /**
+ * Add listener
+ * @param listener {@link TweetsStreamListener} for 'listening' the tweets returned from the stream
+ */
+ public void addListener(TweetsStreamListener listener) {
+ listeners.add(listener);
+ }
+
+ /**
+ * Remove listener
+ * @param listener {@link TweetsStreamListener} to be removed
+ */
+ public void removeListener(TweetsStreamListener listener) {
+ listeners.remove(listener);
+ }
+
+ /**
+ * Start streaming for sampleSearch
+ * @param streamParameters {@link StreamQueryParameters} the parameters for the request
+ * @return the results are returns through the listeners {@link #addListener(TweetsStreamListener)}
+ */
+ public void startSampleStream(StreamQueryParameters streamParameters) {
+ try {
+ BufferedSource streamResult = tweets.sampleStream().parameters(streamParameters).execute(retries <= 0 ? 1 : retries);
+ executor = new TweetsStreamExecutor(streamResult);
+ listeners.forEach(executor::addListener);
+ executor.start();
+ } catch (ApiException e) {
+ if(e.getCode() == 401) {
+ logger.error("Authentication didn't work");
+ throw new AuthenticationException("Not authenticated. Please check the credentials", e);
+ }
+ if(e.getCode() == 429){
+ /* for this error twitter indicates that to implement a reconnection mechanism
+ * see: https://developer.twitter.com/en/docs/twitter-api/tweets/volume-streams/integrate/handling-disconnections
+ */
+ throw new TooManyRequestsException("Too many requests. Service responded with 429 status code. Consider setting 'retries' or increasing its value");
+ }
+ throw new StreamException("An exception occurred during stream execution ",e);
+ }
+ }
+
+ /**
+ * Closes the threads and performs any other required clean up
+ */
+ public void shutdown() {
+ executor.shutdown();
+ }
+
+ @PreDestroy
+ public void preDestroy() {
+ executor.shutdown();
+ }
+
+ private void initBasePath() {
+ String basePath = System.getenv("TWITTER_API_BASE_PATH");
+ apiClient.setBasePath(basePath != null ? basePath : "https://api.twitter.com");
+ }
+
+}
diff --git a/src/test/java/com/twitter/clientlib/api/TweetsApiTest.java b/src/test/java/com/twitter/clientlib/api/TweetsApiTest.java
index f5e6893..cf7994e 100644
--- a/src/test/java/com/twitter/clientlib/api/TweetsApiTest.java
+++ b/src/test/java/com/twitter/clientlib/api/TweetsApiTest.java
@@ -58,6 +58,8 @@
import com.twitter.clientlib.model.UsersRetweetsCreateRequest;
import com.twitter.clientlib.model.UsersRetweetsCreateResponse;
import com.twitter.clientlib.model.UsersRetweetsDeleteResponse;
+import com.twitter.clientlib.query.StreamQueryParameters;
+import okio.BufferedSource;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
@@ -296,22 +298,7 @@ public void listsIdTweetsTest() throws ApiException {
*/
@Test
public void sampleStreamTest() throws ApiException {
- Integer backfillMinutes = null;
- Set tweetFields = null;
- Set expansions = null;
- Set mediaFields = null;
- Set pollFields = null;
- Set userFields = null;
- Set placeFields = null;
- InputStream response = apiInstance.tweets().sampleStream()
- .backfillMinutes(backfillMinutes)
- .tweetFields(tweetFields)
- .expansions(expansions)
- .mediaFields(mediaFields)
- .pollFields(pollFields)
- .userFields(userFields)
- .placeFields(placeFields)
- .execute();
+ BufferedSource response = apiInstance.tweets().sampleStream().execute();
// TODO: test validations
}
@@ -325,22 +312,7 @@ public void sampleStreamTest() throws ApiException {
*/
@Test
public void searchStreamTest() throws ApiException {
- Integer backfillMinutes = null;
- Set tweetFields = null;
- Set expansions = null;
- Set mediaFields = null;
- Set pollFields = null;
- Set userFields = null;
- Set placeFields = null;
- InputStream response = apiInstance.tweets().searchStream()
- .backfillMinutes(backfillMinutes)
- .tweetFields(tweetFields)
- .expansions(expansions)
- .mediaFields(mediaFields)
- .pollFields(pollFields)
- .userFields(userFields)
- .placeFields(placeFields)
- .execute();
+ BufferedSource response = apiInstance.tweets().searchStream().execute();
// TODO: test validations
}
diff --git a/src/test/java/com/twitter/clientlib/model/UrlEntityTest.java b/src/test/java/com/twitter/clientlib/model/UrlEntityTest.java
index f011ad2..666ccac 100644
--- a/src/test/java/com/twitter/clientlib/model/UrlEntityTest.java
+++ b/src/test/java/com/twitter/clientlib/model/UrlEntityTest.java
@@ -22,21 +22,6 @@
package com.twitter.clientlib.model;
-import com.google.gson.TypeAdapter;
-import com.google.gson.annotations.JsonAdapter;
-import com.google.gson.annotations.SerializedName;
-import com.google.gson.stream.JsonReader;
-import com.google.gson.stream.JsonWriter;
-import com.twitter.clientlib.model.EntityIndicesInclusiveExclusive;
-import com.twitter.clientlib.model.UrlFields;
-import com.twitter.clientlib.model.UrlImage;
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import java.io.IOException;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.List;
-import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
diff --git a/src/test/java/com/twitter/clientlib/model/URLFieldsTest.java b/src/test/java/com/twitter/clientlib/model/UrlFieldsTest.java
similarity index 82%
rename from src/test/java/com/twitter/clientlib/model/URLFieldsTest.java
rename to src/test/java/com/twitter/clientlib/model/UrlFieldsTest.java
index 5fd62e4..699f44f 100644
--- a/src/test/java/com/twitter/clientlib/model/URLFieldsTest.java
+++ b/src/test/java/com/twitter/clientlib/model/UrlFieldsTest.java
@@ -22,19 +22,6 @@
package com.twitter.clientlib.model;
-import com.google.gson.TypeAdapter;
-import com.google.gson.annotations.JsonAdapter;
-import com.google.gson.annotations.SerializedName;
-import com.google.gson.stream.JsonReader;
-import com.google.gson.stream.JsonWriter;
-import com.twitter.clientlib.model.UrlImage;
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import java.io.IOException;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.List;
-import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
diff --git a/src/test/java/com/twitter/clientlib/model/URLImageTest.java b/src/test/java/com/twitter/clientlib/model/UrlImageTest.java
similarity index 78%
rename from src/test/java/com/twitter/clientlib/model/URLImageTest.java
rename to src/test/java/com/twitter/clientlib/model/UrlImageTest.java
index 27deedf..41984a2 100644
--- a/src/test/java/com/twitter/clientlib/model/URLImageTest.java
+++ b/src/test/java/com/twitter/clientlib/model/UrlImageTest.java
@@ -22,16 +22,6 @@
package com.twitter.clientlib.model;
-import com.google.gson.TypeAdapter;
-import com.google.gson.annotations.JsonAdapter;
-import com.google.gson.annotations.SerializedName;
-import com.google.gson.stream.JsonReader;
-import com.google.gson.stream.JsonWriter;
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import java.io.IOException;
-import java.net.URL;
-import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
diff --git a/src/test/java/com/twitter/clientlib/stream/TwitterStreamTest.java b/src/test/java/com/twitter/clientlib/stream/TwitterStreamTest.java
new file mode 100644
index 0000000..d41c35f
--- /dev/null
+++ b/src/test/java/com/twitter/clientlib/stream/TwitterStreamTest.java
@@ -0,0 +1,115 @@
+/*
+Copyright 2020 Twitter, Inc.
+SPDX-License-Identifier: Apache-2.0
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+*/
+
+package com.twitter.clientlib.stream;
+
+import com.twitter.clientlib.TwitterCredentialsBearer;
+import com.twitter.clientlib.integration.ApiTester;
+import com.twitter.clientlib.model.StreamingTweetResponse;
+import com.twitter.clientlib.query.StreamQueryParameters;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+@Disabled
+class TwitterStreamTest extends ApiTester {
+
+ private static TwitterStream twitterStream;
+
+ private TweetsStreamListener courier;
+ private List tweets;
+
+ @BeforeAll
+ public static void beforeAll() {
+ twitterStream = new TwitterStream(new TwitterCredentialsBearer(System.getenv("TWITTER_BEARER_TOKEN")));
+ twitterStream.setRetries(4);
+ }
+
+ @BeforeEach
+ public void setUp() {
+ tweets = new LinkedList<>();
+ courier = new TweetCourier(tweets);
+ twitterStream.addListener(courier);
+ }
+
+ @AfterEach
+ public void tearDown() {
+ twitterStream.removeListener(courier);
+ twitterStream.shutdown();
+ }
+
+ @Test
+ public void shutdown() throws InterruptedException {
+ twitterStream.startSampleStream(new StreamQueryParameters.Builder().build());
+ TimeUnit.SECONDS.sleep(5);
+ assertTrue(tweets.size() > 1);
+ twitterStream.shutdown();
+ }
+
+ @Test
+ public void sampleStream() throws InterruptedException {
+ twitterStream.startSampleStream(new StreamQueryParameters.Builder().build());
+ TimeUnit.SECONDS.sleep(5);
+ assertTrue(tweets.size() > 1);
+ }
+
+ @Test
+ public void sampleStreamAddSecondListener() throws InterruptedException {
+ List tweetsDuplicate = new LinkedList<>();
+ TweetsStreamListener courierDuplicate = new TweetCourier(tweetsDuplicate);
+ twitterStream.addListener(courierDuplicate);
+ twitterStream.startSampleStream(new StreamQueryParameters.Builder().build());
+ TimeUnit.SECONDS.sleep(5);
+ assertTrue(tweets.size() > 1);
+ assertTrue(tweetsDuplicate.size() > 1);
+ assertEquals(tweets.size(), tweetsDuplicate.size());
+ }
+
+ @Test
+ public void sampleStreamAddSecondListenerAndRemove() throws InterruptedException {
+ List tweetsDuplicate = new LinkedList<>();
+ TweetsStreamListener courierDuplicate = new TweetCourier(tweetsDuplicate);
+ twitterStream.addListener(courierDuplicate);
+ twitterStream.removeListener(courierDuplicate);
+ twitterStream.startSampleStream(new StreamQueryParameters.Builder().build());
+ TimeUnit.SECONDS.sleep(5);
+ assertTrue(tweets.size() > 1);
+ assertEquals(0, tweetsDuplicate.size());
+ }
+
+ private class TweetCourier implements TweetsStreamListener {
+
+ private List tweetsList;
+
+ private TweetCourier(List tweetsList) {
+ this.tweetsList = tweetsList;
+ }
+ @Override
+ public void onTweetArrival(StreamingTweetResponse tweet) {
+ tweetsList.add(tweet);
+ }
+ }
+}
\ No newline at end of file