Skip to content

Commit

Permalink
Make spring-twitter-function as auto-config
Browse files Browse the repository at this point in the history
* Fix Checkstyle violations in this module
* Make all the Twitter function auto-configurations as conditional on their specific properties
to avoid extra beans not expected in the target application
* Fix README respectively
  • Loading branch information
artembilan committed Jan 10, 2024
1 parent e1874ee commit e2f721b
Show file tree
Hide file tree
Showing 14 changed files with 164 additions and 175 deletions.
46 changes: 18 additions & 28 deletions function/spring-twitter-function/README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,31 @@

This module provides couple of twitter functions that can be reused and composed in other applications.

To use those functions add the following dependency to your POM:
This module exposes auto-configurations for the following beans:

[source,XML]
----
<dependency>
<groupId>org.springframework.cloud.fn</groupId>
<artifactId>twitter-function</artifactId>
<version>${java-functions.version}</version>
</dependency>
----
* `twitterTrendFunction`
* `twitterUsersFunction`
* `twitterGeoFunction`
Each of them are conditional by specific configuration properties.

## 1. Twitter Trend Function

Functions can return either Trends topics or the Locations of the trending topics. The `twitter.trend.trend-query-type` property allows choosing between both types.
Function can return either Trends topics or the Locations of the trending topics.
The `twitter.trend.trend-query-type` property allows choosing between both types.
This property is required to enable the function auto-configuration.

* Trends - `twitter.trend.trend-query-type` is set to `trend`. Leverages the https://developer.twitter.com/en/docs/trends/trends-for-location/api-reference/get-trends-place[Trends API] to return the https://help.twitter.com/en/using-twitter/twitter-trending-faqs[trending topics] near a specific latitude, longitude location.
* Trends - `twitter.trend.trend-query-type` is set to `trend`.
Leverages the https://developer.twitter.com/en/docs/trends/trends-for-location/api-reference/get-trends-place[Trends API] to return the https://help.twitter.com/en/using-twitter/twitter-trending-faqs[trending topics] near a specific latitude, longitude location.
* Trend Locations - the `twitter.trend.trend-query-type` is set `trendLocation`. Retrieve a full or nearby locations list of trending topics by location. If the `latitude`, `longitude` parameters are NOT provided the processor performs the https://developer.twitter.com/en/docs/trends/locations-with-trending-topics/api-reference/get-trends-available[Trends Available API] and returns the locations that Twitter has trending topic information for.
* Trend Locations - the `twitter.trend.trend-query-type` is set `trendLocation`.
Retrieve a full or nearby locations list of trending topics by location. If the `latitude`, `longitude` parameters are NOT provided the processor performs the https://developer.twitter.com/en/docs/trends/locations-with-trending-topics/api-reference/get-trends-available[Trends Available API] and returns the locations that Twitter has trending topic information for.
If the `latitude`, `longitude` parameters are provided the processor performs the https://developer.twitter.com/en/docs/trends/locations-with-trending-topics/api-reference/get-trends-closest[Trends Closest API] and returns the locations that Twitter has trending topic information for, closest to a specified location.
Response is an array of `locations` that encode the location's WOEID and some other human-readable information such as a canonical name and country the location belongs in.

### 1.1 Beans for injection

You can import the `TwitterTrendFunctionConfiguration` in a Spring Boot application and then inject the following bean.

`filterFunction`

You can use `Function<Message<?>, Message<byte[]>> twitterTrendFunction` as a qualifier when injecting.

Once injected, you can use the `apply` method of the `Function` to invoke it and get the result.
Expand All @@ -45,12 +42,11 @@ See this link:src/test/java/org/springframework/cloud/fn/twitter/trend/TwitterTr

### 1.4 Other usage

Leveraging the Spring Cloud Function composability, you can compose the Trend function in your boot app like this:
Leveraging the Spring Cloud Function "composability", you can compose the Trend function in your boot app like this:

[source,Java]
----
@SpringBootApplication
@Import(TwitterTrendFunctionConfiguration.class )
public class MyTwitterTrendBootApp {
public static void main(String[] args) {
Expand Down Expand Up @@ -79,11 +75,9 @@ Some parameters in this method are only required based on the existence of other

NOTE: Limits: 15 requests / 15-min window (user auth).

### 2.1 Beans for injection

You can import the `TwitterGeoFunctionConfiguration` in a Spring Boot application and then inject the following bean.
This function auto-configuration is conditional on `twitter.geo.search.ip != null || (twitter.geo.location.lat != null && twitter.geo.location.lon != null)`

`filterFunction`
### 2.1 Beans for injection

You can use `Function<Message<?>, Message<byte[]>> twitterGeoFunction` as a qualifier when injecting.
Once injected, you can use the `apply` method of the `Function` to invoke it and get the result.
Expand All @@ -96,7 +90,7 @@ For more information on the various options available, please see link:../twitte

### 2.3 Tests

See this link:src/test/java/org/springframework/cloud/fn/twitter/geo/TwitterGeoFunctionTest.java[test suite] for examples of how this function is used.
See this link:src/test/java/org/springframework/cloud/fn/twitter/geo/TwitterGeoFunctionTests.java[test suite] for examples of how this function is used.

### 2.4 Other usage

Expand All @@ -105,7 +99,6 @@ Leveraging the Spring Cloud Function composability, you can compose the Geo func
[source,Java]
----
@SpringBootApplication
@Import(TwitterGeoFunctionConfiguration.class )
public class MyTwitterGeoProcessorBootApp {
public static void main(String[] args) {
Expand All @@ -122,17 +115,14 @@ Uses SpEL expressions to compute the query parameters from the input message.
Use the single quoted literals to set static values (e.g. user-id: '6666, 9999, 10000').

Use `twitter.users.type` property allow to select the query approaches.
This property is required to trigger the `twitterUsersFunction` auto-configuration.

* https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-users-lookup[Users Lookup API] - Returns fully-hydrated user objects for up to 100 users per request, as specified by comma-separated values passed to the `userId` and/or `screenName` parameters. Rate limits: (300 requests / 15-min window)
* https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-users-search[Users Search API] - Relevance-based search interface to public user accounts on Twitter.
Querying by topical interest, full name, company name, location, or other criteria. Exact match searches are not supported. Only the first 1,000 matching results are available. Rate limits:(900 requests / 15-min window)
### 3.1 Beans for injection

You can import the `TwitterUsersFunctionConfiguration` in a Spring Boot application and then inject the following bean.

`filterFunction`

You can use `Function<Message<?>, Message<byte[]>> twitterUsersFunction` as a qualifier when injecting.
Once injected, you can use the `apply` method of the `Function` to invoke it and get the result.

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2020-2020 the original author or authors.
* Copyright 2020-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -27,27 +27,29 @@
import twitter4j.Twitter;
import twitter4j.TwitterException;

import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.fn.common.twitter.TwitterConnectionConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.messaging.Message;

/**
* Auto-configuration for Twitter Geo function.
*
* @author Christian Tzolov
*/
@Configuration
@ConditionalOnExpression("environment['twitter.geo.search.ip'] != null || (environment['twitter.geo.location.lat'] != null && environment['twitter.geo.location.lon'] != null)")
@AutoConfiguration(after = TwitterConnectionConfiguration.class)
@EnableConfigurationProperties(TwitterGeoFunctionProperties.class)
@Import(TwitterConnectionConfiguration.class)
public class TwitterGeoFunctionConfiguration {

private static final Log logger = LogFactory.getLog(TwitterGeoFunctionConfiguration.class);
private static final Log LOGGER = LogFactory.getLog(TwitterGeoFunctionConfiguration.class);

@Bean
public Function<Message<?>, GeoQuery> messageToGeoQueryFunction(TwitterGeoFunctionProperties geoProperties) {
return message -> {
return (message) -> {
String ip = null;
if (geoProperties.getSearch().getIp() != null) {
ip = geoProperties.getSearch().getIp().getValue(message, String.class);
Expand Down Expand Up @@ -76,12 +78,12 @@ public Function<Message<?>, GeoQuery> messageToGeoQueryFunction(TwitterGeoFuncti
@Bean
@ConditionalOnProperty(name = "twitter.geo.search.type", havingValue = "search", matchIfMissing = true)
public Function<GeoQuery, List<Place>> twitterSearchPlacesFunction(Twitter twitter) {
return geoQuery -> {
return (geoQuery) -> {
try {
return twitter.searchPlaces(geoQuery);
}
catch (TwitterException e) {
logger.error("Places Search failed!", e);
catch (TwitterException ex) {
LOGGER.error("Places Search failed!", ex);
}
return null;
};
Expand All @@ -90,12 +92,12 @@ public Function<GeoQuery, List<Place>> twitterSearchPlacesFunction(Twitter twitt
@Bean
@ConditionalOnProperty(name = "twitter.geo.search.type", havingValue = "reverse")
public Function<GeoQuery, List<Place>> twitterReverseGeocodeFunction(Twitter twitter) {
return geoQuery -> {
return (geoQuery) -> {
try {
return twitter.reverseGeoCode(geoQuery);
}
catch (TwitterException e) {
logger.error("Reverse Geocode failed!", e);
catch (TwitterException ex) {
LOGGER.error("Reverse Geocode failed!", ex);
}
return null;
};
Expand All @@ -105,7 +107,7 @@ public Function<GeoQuery, List<Place>> twitterReverseGeocodeFunction(Twitter twi
public Function<Message<?>, Message<byte[]>> twitterGeoFunction(Function<Message<?>, GeoQuery> toGeoQuery,
Function<GeoQuery, List<Place>> places, Function<Object, Message<byte[]>> managedJson) {

return toGeoQuery.andThen(places).andThen(managedJson)::apply;
return toGeoQuery.andThen(places).andThen(managedJson);
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2020-2020 the original author or authors.
* Copyright 2020-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -21,18 +21,17 @@

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.validation.annotation.Validated;

/**
* Configuration properties for Twitter Geo function.
*
* @author Christian Tzolov
*/
@ConfigurationProperties("twitter.geo")
@Validated
public class TwitterGeoFunctionProperties {

private static final Expression DEFAULT_EXPRESSION = new SpelExpressionParser().parseExpression("payload");

public enum GeoType {

/** Geo retrieval type. */
Expand All @@ -51,9 +50,6 @@ public enum GeoType {
*/
private Search search = new Search();

/**
*
*/
private Location location = new Location();

/**
Expand All @@ -68,7 +64,7 @@ public enum GeoType {
* in meters, but it can also take a string that is suffixed with ft to specify feet.
* If this is not passed in, then it is assumed to be 0m. If coming from a device, in
* practice, this value is whatever accuracy the device has measuring its location
* (whether it be coming from a GPS, WiFi triangulation, etc.).
* (whether it be coming from a GPS, Wi-Fi triangulation, etc.).
*/
private String accuracy = null;

Expand All @@ -79,47 +75,47 @@ public enum GeoType {
private String granularity = null;

public Search getSearch() {
return search;
return this.search;
}

public void setSearch(Search search) {
this.search = search;
}

public GeoType getType() {
return type;
return this.type;
}

public void setType(GeoType type) {
this.type = type;
}

public Location getLocation() {
return location;
return this.location;
}

public void setLocation(Location location) {
this.location = location;
}

public int getMaxResults() {
return maxResults;
return this.maxResults;
}

public void setMaxResults(int maxResults) {
this.maxResults = maxResults;
}

public String getAccuracy() {
return accuracy;
return this.accuracy;
}

public void setAccuracy(String accuracy) {
this.accuracy = accuracy;
}

public String getGranularity() {
return granularity;
return this.granularity;
}

public void setGranularity(String granularity) {
Expand All @@ -128,13 +124,12 @@ public void setGranularity(String granularity) {

@AssertTrue(message = "Either the IP or the Location must be set")
public boolean isAtLeastOne() {
return this.getSearch().getIp() == null
^ (this.getLocation().getLat() == null && this.getLocation().getLon() == null);
return getSearch().getIp() == null ^ (getLocation().getLat() == null && getLocation().getLon() == null);
}

@AssertTrue(message = "The IP parameter is applicable only for 'Search' GeoType")
public boolean isIpUsedWithSearchGeoType() {
if (this.getSearch().getIp() != null) {
if (getSearch().getIp() != null) {
return this.type == GeoType.search;
}
return true;
Expand All @@ -154,15 +149,15 @@ public static class Search {
private Expression query = null;

public Expression getIp() {
return ip;
return this.ip;
}

public void setIp(Expression ip) {
this.ip = ip;
}

public Expression getQuery() {
return query;
return this.query;
}

public void setQuery(Expression query) {
Expand All @@ -184,15 +179,15 @@ public static class Location {
private Expression lon;

public Expression getLat() {
return lat;
return this.lat;
}

public void setLat(Expression lat) {
this.lat = lat;
}

public Expression getLon() {
return lon;
return this.lon;
}

public void setLon(Expression lon) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/**
* The Twitter Geo function auto-configuration.
*/
package org.springframework.cloud.fn.twitter.geo;
Loading

0 comments on commit e2f721b

Please sign in to comment.