├── tag-cloud ├── src │ ├── main │ │ ├── resources │ │ │ ├── reflection-config.json │ │ │ ├── application.properties │ │ │ └── META-INF │ │ │ │ └── resources │ │ │ │ ├── static.html │ │ │ │ └── index.html │ │ ├── java │ │ │ └── cz │ │ │ │ └── scholz │ │ │ │ └── tagcloud │ │ │ │ ├── model │ │ │ │ ├── twitter │ │ │ │ │ ├── README.md │ │ │ │ │ ├── Scopes.java │ │ │ │ │ ├── GeoLocation.java │ │ │ │ │ ├── HashtagEntity.java │ │ │ │ │ ├── SymbolEntity.java │ │ │ │ │ ├── RateLimitStatus.java │ │ │ │ │ ├── UserMentionEntity.java │ │ │ │ │ ├── URLEntity.java │ │ │ │ │ ├── Place.java │ │ │ │ │ └── MediaEntity.java │ │ │ │ └── TweetSerde.java │ │ │ │ ├── streams │ │ │ │ ├── PipelineMetadata.java │ │ │ │ ├── TopologyProducer.java │ │ │ │ └── InteractiveQueries.java │ │ │ │ └── rest │ │ │ │ └── TagCloudEndpoint.java │ │ └── docker │ │ │ ├── Dockerfile.native-distroless │ │ │ ├── Dockerfile.native │ │ │ ├── Dockerfile.legacy-jar │ │ │ └── Dockerfile.jvm │ └── test │ │ └── java │ │ └── cz │ │ └── scholz │ │ └── tagcloud │ │ └── streams │ │ └── TopologyProducerTest.java ├── .dockerignore ├── .mvn │ └── wrapper │ │ ├── maven-wrapper.properties │ │ └── MavenWrapperDownloader.java ├── Makefile ├── .gitignore ├── README.md └── pom.xml ├── word-cloud ├── src │ ├── main │ │ ├── resources │ │ │ ├── reflection-config.json │ │ │ ├── application.properties │ │ │ └── META-INF │ │ │ │ └── resources │ │ │ │ ├── static.html │ │ │ │ └── index.html │ │ ├── java │ │ │ └── cz │ │ │ │ └── scholz │ │ │ │ └── wordcloud │ │ │ │ ├── model │ │ │ │ ├── twitter │ │ │ │ │ ├── README.md │ │ │ │ │ ├── Scopes.java │ │ │ │ │ ├── GeoLocation.java │ │ │ │ │ ├── SymbolEntity.java │ │ │ │ │ ├── HashtagEntity.java │ │ │ │ │ ├── RateLimitStatus.java │ │ │ │ │ ├── UserMentionEntity.java │ │ │ │ │ ├── URLEntity.java │ │ │ │ │ ├── Place.java │ │ │ │ │ └── MediaEntity.java │ │ │ │ └── TweetSerde.java │ │ │ │ ├── streams │ │ │ │ ├── PipelineMetadata.java │ │ │ │ ├── InteractiveQueries.java │ │ │ │ └── TopologyProducer.java │ │ │ │ └── rest │ │ │ │ └── WordCloudEndpoint.java │ │ └── docker │ │ │ ├── Dockerfile.native-distroless │ │ │ ├── Dockerfile.native │ │ │ ├── Dockerfile.legacy-jar │ │ │ └── Dockerfile.jvm │ └── test │ │ └── java │ │ └── cz │ │ └── scholz │ │ └── wordcloud │ │ └── streams │ │ └── TopologyProducerTest.java ├── .dockerignore ├── .mvn │ └── wrapper │ │ ├── maven-wrapper.properties │ │ └── MavenWrapperDownloader.java ├── Makefile ├── README.md ├── .gitignore └── pom.xml ├── sentiment-analysis ├── src │ └── main │ │ ├── resources │ │ ├── reflection-config.json │ │ └── application.properties │ │ ├── java │ │ └── cz │ │ │ └── scholz │ │ │ └── sentimentanalysis │ │ │ ├── model │ │ │ ├── twitter │ │ │ │ ├── README.md │ │ │ │ ├── Scopes.java │ │ │ │ ├── GeoLocation.java │ │ │ │ ├── SymbolEntity.java │ │ │ │ ├── HashtagEntity.java │ │ │ │ ├── RateLimitStatus.java │ │ │ │ ├── UserMentionEntity.java │ │ │ │ ├── URLEntity.java │ │ │ │ ├── Place.java │ │ │ │ └── MediaEntity.java │ │ │ └── TweetSerde.java │ │ │ └── streams │ │ │ └── TopologyProducer.java │ │ └── docker │ │ ├── Dockerfile.native-distroless │ │ ├── Dockerfile.native │ │ ├── Dockerfile.legacy-jar │ │ └── Dockerfile.jvm ├── .dockerignore ├── .mvn │ └── wrapper │ │ ├── maven-wrapper.properties │ │ └── MavenWrapperDownloader.java ├── Makefile ├── .gitignore ├── README.md └── pom.xml ├── ad-hoc ├── .dockerignore ├── src │ └── main │ │ ├── java │ │ └── cz │ │ │ └── scholz │ │ │ └── sentimentanalysis │ │ │ ├── model │ │ │ ├── twitter │ │ │ │ ├── README.md │ │ │ │ ├── Scopes.java │ │ │ │ ├── GeoLocation.java │ │ │ │ ├── HashtagEntity.java │ │ │ │ ├── SymbolEntity.java │ │ │ │ ├── RateLimitStatus.java │ │ │ │ ├── UserMentionEntity.java │ │ │ │ ├── URLEntity.java │ │ │ │ ├── Place.java │ │ │ │ └── MediaEntity.java │ │ │ ├── TweetSerde.java │ │ │ └── Aggregation.java │ │ │ └── streams │ │ │ └── TopologyProducer.java │ │ ├── docker │ │ ├── Dockerfile.native-distroless │ │ ├── Dockerfile.native │ │ ├── Dockerfile.legacy-jar │ │ └── Dockerfile.jvm │ │ └── resources │ │ └── application.properties ├── README.md ├── .mvn │ └── wrapper │ │ ├── maven-wrapper.properties │ │ └── MavenWrapperDownloader.java ├── .gitignore └── pom.xml ├── assets ├── word-cloud.png └── sentiment-analysis.png ├── Makefile ├── .gitignore ├── Makefile.java ├── Makefile.docker ├── 20-search.yaml ├── 91-strimzi-search.yaml ├── 92-avfc-search.yaml ├── 90-kafka-search.yaml ├── 10-timeline.yaml ├── 21-alerts.yaml ├── 22-sentiment-analysis.yaml ├── 12-timeline-tag-cloud.yaml └── 11-timeline-word-cloud.yaml /tag-cloud/src/main/resources/reflection-config.json: -------------------------------------------------------------------------------- 1 | [ 2 | 3 | ] 4 | -------------------------------------------------------------------------------- /word-cloud/src/main/resources/reflection-config.json: -------------------------------------------------------------------------------- 1 | [ 2 | 3 | ] 4 | -------------------------------------------------------------------------------- /sentiment-analysis/src/main/resources/reflection-config.json: -------------------------------------------------------------------------------- 1 | [ 2 | 3 | ] 4 | -------------------------------------------------------------------------------- /ad-hoc/.dockerignore: -------------------------------------------------------------------------------- 1 | * 2 | !target/*-runner 3 | !target/*-runner.jar 4 | !target/lib/* 5 | !target/quarkus-app/* -------------------------------------------------------------------------------- /tag-cloud/.dockerignore: -------------------------------------------------------------------------------- 1 | * 2 | !target/*-runner 3 | !target/*-runner.jar 4 | !target/lib/* 5 | !target/quarkus-app/* -------------------------------------------------------------------------------- /word-cloud/.dockerignore: -------------------------------------------------------------------------------- 1 | * 2 | !target/*-runner 3 | !target/*-runner.jar 4 | !target/lib/* 5 | !target/quarkus-app/* -------------------------------------------------------------------------------- /sentiment-analysis/.dockerignore: -------------------------------------------------------------------------------- 1 | * 2 | !target/*-runner 3 | !target/*-runner.jar 4 | !target/lib/* 5 | !target/quarkus-app/* -------------------------------------------------------------------------------- /assets/word-cloud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scholzj/build-your-own-social-media-analytics-with-apache-kafka/HEAD/assets/word-cloud.png -------------------------------------------------------------------------------- /assets/sentiment-analysis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scholzj/build-your-own-social-media-analytics-with-apache-kafka/HEAD/assets/sentiment-analysis.png -------------------------------------------------------------------------------- /tag-cloud/src/main/java/cz/scholz/tagcloud/model/twitter/README.md: -------------------------------------------------------------------------------- 1 | # Twitter model 2 | 3 | A simplified set of POJO classes for deserializing the Twitter statuses we receive from Kafka Connect. -------------------------------------------------------------------------------- /word-cloud/src/main/java/cz/scholz/wordcloud/model/twitter/README.md: -------------------------------------------------------------------------------- 1 | # Twitter model 2 | 3 | A simplified set of POJO classes for deserializing the Twitter statuses we receive from Kafka Connect. -------------------------------------------------------------------------------- /ad-hoc/src/main/java/cz/scholz/sentimentanalysis/model/twitter/README.md: -------------------------------------------------------------------------------- 1 | # Twitter model 2 | 3 | A simplified set of POJO classes for deserializing the Twitter statuses we receive from Kafka Connect. -------------------------------------------------------------------------------- /sentiment-analysis/src/main/java/cz/scholz/sentimentanalysis/model/twitter/README.md: -------------------------------------------------------------------------------- 1 | # Twitter model 2 | 3 | A simplified set of POJO classes for deserializing the Twitter statuses we receive from Kafka Connect. -------------------------------------------------------------------------------- /ad-hoc/README.md: -------------------------------------------------------------------------------- 1 | # Ad-hoc Analysis 2 | 3 | Use this project to do some ad-hoc analysis. 4 | Prepare the Kafka Streams topology for your experiment. 5 | Configure Kafka connection in `./src/main/resources/application.properties` and run `mvn quarkus:dev`. -------------------------------------------------------------------------------- /ad-hoc/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.1/apache-maven-3.8.1-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar 3 | -------------------------------------------------------------------------------- /tag-cloud/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.1/apache-maven-3.8.1-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar 3 | -------------------------------------------------------------------------------- /word-cloud/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.1/apache-maven-3.8.1-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar 3 | -------------------------------------------------------------------------------- /sentiment-analysis/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.1/apache-maven-3.8.1-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar 3 | -------------------------------------------------------------------------------- /tag-cloud/Makefile: -------------------------------------------------------------------------------- 1 | PROJECT_NAME=build-your-own-social-media-analytics-with-apache-kafka-tag-cloud 2 | 3 | all: java_build docker_build docker_push 4 | build: java_build 5 | clean: java_clean 6 | 7 | include ../Makefile.docker 8 | 9 | include ../Makefile.java 10 | 11 | .PHONY: build clean 12 | -------------------------------------------------------------------------------- /word-cloud/Makefile: -------------------------------------------------------------------------------- 1 | PROJECT_NAME=build-your-own-social-media-analytics-with-apache-kafka-word-cloud 2 | 3 | all: java_build docker_build docker_push 4 | build: java_build 5 | clean: java_clean 6 | 7 | include ../Makefile.docker 8 | 9 | include ../Makefile.java 10 | 11 | .PHONY: build clean 12 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | RELEASE_VERSION ?= latest 2 | 3 | SUBDIRS=word-cloud tag-cloud sentiment-analysis 4 | DOCKER_TARGETS=docker_build docker_push docker_tag 5 | 6 | all: $(SUBDIRS) 7 | build: $(SUBDIRS) 8 | clean: $(SUBDIRS) 9 | $(DOCKER_TARGETS): $(SUBDIRS) 10 | 11 | $(SUBDIRS): 12 | $(MAKE) -C $@ $(MAKECMDGOALS) 13 | 14 | .PHONY: all $(SUBDIRS) $(DOCKER_TARGETS) 15 | -------------------------------------------------------------------------------- /sentiment-analysis/Makefile: -------------------------------------------------------------------------------- 1 | PROJECT_NAME=build-your-own-social-media-analytics-with-apache-kafka-sentiment-analysis 2 | 3 | NATIVE_BUILD= 4 | DOCKERFILE?=src/main/docker/Dockerfile.jvm 5 | 6 | all: java_build docker_build docker_push 7 | build: java_build 8 | clean: java_clean 9 | 10 | include ../Makefile.docker 11 | 12 | include ../Makefile.java 13 | 14 | .PHONY: build clean 15 | -------------------------------------------------------------------------------- /tag-cloud/src/main/java/cz/scholz/tagcloud/streams/PipelineMetadata.java: -------------------------------------------------------------------------------- 1 | package cz.scholz.tagcloud.streams; 2 | 3 | import java.util.Set; 4 | 5 | public class PipelineMetadata { 6 | public String host; 7 | public Set partitions; 8 | 9 | public PipelineMetadata(String host, Set partitions) { 10 | this.host = host; 11 | this.partitions = partitions; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /word-cloud/src/main/java/cz/scholz/wordcloud/streams/PipelineMetadata.java: -------------------------------------------------------------------------------- 1 | package cz.scholz.wordcloud.streams; 2 | 3 | import java.util.Set; 4 | 5 | public class PipelineMetadata { 6 | public String host; 7 | public Set partitions; 8 | 9 | public PipelineMetadata(String host, Set partitions) { 10 | this.host = host; 11 | this.partitions = partitions; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.nar 17 | *.ear 18 | *.zip 19 | *.tar.gz 20 | *.rar 21 | 22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 23 | hs_err_pid* 24 | 25 | .DS_Store 26 | 27 | ## Files with real secrets which should not be committed 28 | 00-* 29 | .kubeconfig -------------------------------------------------------------------------------- /tag-cloud/src/main/java/cz/scholz/tagcloud/model/twitter/Scopes.java: -------------------------------------------------------------------------------- 1 | package cz.scholz.tagcloud.model.twitter; 2 | 3 | import io.quarkus.runtime.annotations.RegisterForReflection; 4 | 5 | @RegisterForReflection 6 | public class Scopes { 7 | public String[] placeIds; 8 | 9 | public Scopes() { 10 | } 11 | 12 | public Scopes(String[] placeIds) { 13 | this.placeIds = placeIds; 14 | } 15 | 16 | public String[] getPlaceIds() { 17 | return placeIds; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /word-cloud/src/main/java/cz/scholz/wordcloud/model/twitter/Scopes.java: -------------------------------------------------------------------------------- 1 | package cz.scholz.wordcloud.model.twitter; 2 | 3 | import io.quarkus.runtime.annotations.RegisterForReflection; 4 | 5 | @RegisterForReflection 6 | public class Scopes { 7 | public String[] placeIds; 8 | 9 | public Scopes() { 10 | } 11 | 12 | public Scopes(String[] placeIds) { 13 | this.placeIds = placeIds; 14 | } 15 | 16 | public String[] getPlaceIds() { 17 | return placeIds; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /ad-hoc/src/main/java/cz/scholz/sentimentanalysis/model/twitter/Scopes.java: -------------------------------------------------------------------------------- 1 | package cz.scholz.sentimentanalysis.model.twitter; 2 | 3 | import io.quarkus.runtime.annotations.RegisterForReflection; 4 | 5 | @RegisterForReflection 6 | public class Scopes { 7 | public String[] placeIds; 8 | 9 | public Scopes() { 10 | } 11 | 12 | public Scopes(String[] placeIds) { 13 | this.placeIds = placeIds; 14 | } 15 | 16 | public String[] getPlaceIds() { 17 | return placeIds; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /word-cloud/README.md: -------------------------------------------------------------------------------- 1 | # Word Cloud 2 | 3 | This project uses Quarkus and Kafka Streams to analyze tweets received from Camel Kafka Connector. 4 | It splits them into words and counts the occurrences. 5 | The results are presented using HTTP API and using the Echarts Word Cloud chart. 6 | 7 | ## Build 8 | 9 | Run `make all` to build the container image and push it to a registry. 10 | You can use the environment variables `DOCKER_REGISTRY`, `DOCKER_ORG` and `DOCKER_TAG` to configure the registry where the image will be pushed. -------------------------------------------------------------------------------- /ad-hoc/.gitignore: -------------------------------------------------------------------------------- 1 | #Maven 2 | target/ 3 | pom.xml.tag 4 | pom.xml.releaseBackup 5 | pom.xml.versionsBackup 6 | release.properties 7 | 8 | # Eclipse 9 | .project 10 | .classpath 11 | .settings/ 12 | bin/ 13 | 14 | # IntelliJ 15 | .idea 16 | *.ipr 17 | *.iml 18 | *.iws 19 | 20 | # NetBeans 21 | nb-configuration.xml 22 | 23 | # Visual Studio Code 24 | .vscode 25 | .factorypath 26 | 27 | # OSX 28 | .DS_Store 29 | 30 | # Vim 31 | *.swp 32 | *.swo 33 | 34 | # patch 35 | *.orig 36 | *.rej 37 | 38 | # Local environment 39 | .env 40 | -------------------------------------------------------------------------------- /sentiment-analysis/src/main/java/cz/scholz/sentimentanalysis/model/twitter/Scopes.java: -------------------------------------------------------------------------------- 1 | package cz.scholz.sentimentanalysis.model.twitter; 2 | 3 | import io.quarkus.runtime.annotations.RegisterForReflection; 4 | 5 | @RegisterForReflection 6 | public class Scopes { 7 | public String[] placeIds; 8 | 9 | public Scopes() { 10 | } 11 | 12 | public Scopes(String[] placeIds) { 13 | this.placeIds = placeIds; 14 | } 15 | 16 | public String[] getPlaceIds() { 17 | return placeIds; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /tag-cloud/.gitignore: -------------------------------------------------------------------------------- 1 | #Maven 2 | target/ 3 | pom.xml.tag 4 | pom.xml.releaseBackup 5 | pom.xml.versionsBackup 6 | release.properties 7 | 8 | # Eclipse 9 | .project 10 | .classpath 11 | .settings/ 12 | bin/ 13 | 14 | # IntelliJ 15 | .idea 16 | *.ipr 17 | *.iml 18 | *.iws 19 | 20 | # NetBeans 21 | nb-configuration.xml 22 | 23 | # Visual Studio Code 24 | .vscode 25 | .factorypath 26 | 27 | # OSX 28 | .DS_Store 29 | 30 | # Vim 31 | *.swp 32 | *.swo 33 | 34 | # patch 35 | *.orig 36 | *.rej 37 | 38 | # Local environment 39 | .env 40 | -------------------------------------------------------------------------------- /tag-cloud/README.md: -------------------------------------------------------------------------------- 1 | # Tag Cloud 2 | 3 | This project uses Quarkus and Kafka Streams to analyze tweets received from Camel Kafka Connector. 4 | It finds all hashtags and mentions and counts their occurrences. 5 | The results are presented using HTTP API and using the Echarts Word Cloud chart. 6 | 7 | ## Build 8 | 9 | Run `make all` to build the container image and push it to a registry. 10 | You can use the environment variables `DOCKER_REGISTRY`, `DOCKER_ORG` and `DOCKER_TAG` to configure the registry where the image will be pushed. -------------------------------------------------------------------------------- /word-cloud/.gitignore: -------------------------------------------------------------------------------- 1 | #Maven 2 | target/ 3 | pom.xml.tag 4 | pom.xml.releaseBackup 5 | pom.xml.versionsBackup 6 | release.properties 7 | 8 | # Eclipse 9 | .project 10 | .classpath 11 | .settings/ 12 | bin/ 13 | 14 | # IntelliJ 15 | .idea 16 | *.ipr 17 | *.iml 18 | *.iws 19 | 20 | # NetBeans 21 | nb-configuration.xml 22 | 23 | # Visual Studio Code 24 | .vscode 25 | .factorypath 26 | 27 | # OSX 28 | .DS_Store 29 | 30 | # Vim 31 | *.swp 32 | *.swo 33 | 34 | # patch 35 | *.orig 36 | *.rej 37 | 38 | # Local environment 39 | .env 40 | -------------------------------------------------------------------------------- /sentiment-analysis/.gitignore: -------------------------------------------------------------------------------- 1 | #Maven 2 | target/ 3 | pom.xml.tag 4 | pom.xml.releaseBackup 5 | pom.xml.versionsBackup 6 | release.properties 7 | 8 | # Eclipse 9 | .project 10 | .classpath 11 | .settings/ 12 | bin/ 13 | 14 | # IntelliJ 15 | .idea 16 | *.ipr 17 | *.iml 18 | *.iws 19 | 20 | # NetBeans 21 | nb-configuration.xml 22 | 23 | # Visual Studio Code 24 | .vscode 25 | .factorypath 26 | 27 | # OSX 28 | .DS_Store 29 | 30 | # Vim 31 | *.swp 32 | *.swo 33 | 34 | # patch 35 | *.orig 36 | *.rej 37 | 38 | # Local environment 39 | .env 40 | -------------------------------------------------------------------------------- /Makefile.java: -------------------------------------------------------------------------------- 1 | # Makefile.java contains the shared tasks for building Java applications. This file is 2 | # included into the Makefile files which contain some Java sources which should be build 3 | # (E.g. cluster-controller etc.). 4 | # 5 | 6 | UNAME_S := $(shell uname -s) 7 | ifeq ($(UNAME_S),Darwin) 8 | NATIVE_BUILD?=-Pnative -Dquarkus.native.container-build=true 9 | else 10 | NATIVE_BUILD?=-Pnative 11 | endif 12 | 13 | java_build: 14 | echo "Building JAR file ..." 15 | mvn $(NATIVE_BUILD) package 16 | 17 | java_clean: 18 | echo "Cleaning Maven build ..." 19 | mvn clean 20 | -------------------------------------------------------------------------------- /sentiment-analysis/README.md: -------------------------------------------------------------------------------- 1 | # Sentiment Analysis 2 | 3 | This project uses Quarkus, Kafka Streams and Deep Java Library to analyze sentiment of tweets received from Camel Kafka Connector. 4 | It reads tweets from one topic, decides whether they are _positive_ or _negative_ and if they are above 90%, it forwards them to another topic where they can be picked up by another application. 5 | 6 | ## Build 7 | 8 | Run `make all` to build the container image and push it to a registry. 9 | You can use the environment variables `DOCKER_REGISTRY`, `DOCKER_ORG` and `DOCKER_TAG` to configure the registry where the image will be pushed. -------------------------------------------------------------------------------- /tag-cloud/src/main/java/cz/scholz/tagcloud/model/twitter/GeoLocation.java: -------------------------------------------------------------------------------- 1 | package cz.scholz.tagcloud.model.twitter; 2 | 3 | import io.quarkus.runtime.annotations.RegisterForReflection; 4 | 5 | @RegisterForReflection 6 | public class GeoLocation { 7 | public double latitude; 8 | public double longitude; 9 | 10 | public GeoLocation() { 11 | } 12 | 13 | public GeoLocation(double latitude, double longitude) { 14 | this.latitude = latitude; 15 | this.longitude = longitude; 16 | } 17 | 18 | public double getLatitude() { 19 | return latitude; 20 | } 21 | 22 | public double getLongitude() { 23 | return longitude; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /word-cloud/src/main/java/cz/scholz/wordcloud/model/twitter/GeoLocation.java: -------------------------------------------------------------------------------- 1 | package cz.scholz.wordcloud.model.twitter; 2 | 3 | import io.quarkus.runtime.annotations.RegisterForReflection; 4 | 5 | @RegisterForReflection 6 | public class GeoLocation { 7 | public double latitude; 8 | public double longitude; 9 | 10 | public GeoLocation() { 11 | } 12 | 13 | public GeoLocation(double latitude, double longitude) { 14 | this.latitude = latitude; 15 | this.longitude = longitude; 16 | } 17 | 18 | public double getLatitude() { 19 | return latitude; 20 | } 21 | 22 | public double getLongitude() { 23 | return longitude; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /ad-hoc/src/main/java/cz/scholz/sentimentanalysis/model/twitter/GeoLocation.java: -------------------------------------------------------------------------------- 1 | package cz.scholz.sentimentanalysis.model.twitter; 2 | 3 | import io.quarkus.runtime.annotations.RegisterForReflection; 4 | 5 | @RegisterForReflection 6 | public class GeoLocation { 7 | public double latitude; 8 | public double longitude; 9 | 10 | public GeoLocation() { 11 | } 12 | 13 | public GeoLocation(double latitude, double longitude) { 14 | this.latitude = latitude; 15 | this.longitude = longitude; 16 | } 17 | 18 | public double getLatitude() { 19 | return latitude; 20 | } 21 | 22 | public double getLongitude() { 23 | return longitude; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /sentiment-analysis/src/main/java/cz/scholz/sentimentanalysis/model/twitter/GeoLocation.java: -------------------------------------------------------------------------------- 1 | package cz.scholz.sentimentanalysis.model.twitter; 2 | 3 | import io.quarkus.runtime.annotations.RegisterForReflection; 4 | 5 | @RegisterForReflection 6 | public class GeoLocation { 7 | public double latitude; 8 | public double longitude; 9 | 10 | public GeoLocation() { 11 | } 12 | 13 | public GeoLocation(double latitude, double longitude) { 14 | this.latitude = latitude; 15 | this.longitude = longitude; 16 | } 17 | 18 | public double getLatitude() { 19 | return latitude; 20 | } 21 | 22 | public double getLongitude() { 23 | return longitude; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /ad-hoc/src/main/docker/Dockerfile.native-distroless: -------------------------------------------------------------------------------- 1 | #### 2 | # This Dockerfile is used in order to build a distroless container that runs the Quarkus application in native (no JVM) mode 3 | # 4 | # Before building the container image run: 5 | # 6 | # ./mvnw package -Pnative 7 | # 8 | # Then, build the image with: 9 | # 10 | # docker build -f src/main/docker/Dockerfile.native-distroless -t quarkus/amazon-kms . 11 | # 12 | # Then run the container using: 13 | # 14 | # docker run -i --rm -p 8080:8080 quarkus/amazon-kms 15 | # 16 | ### 17 | FROM quay.io/quarkus/quarkus-distroless-image:1.0 18 | COPY target/*-runner /application 19 | 20 | EXPOSE 8080 21 | USER nonroot 22 | 23 | CMD ["./application", "-Dquarkus.http.host=0.0.0.0"] 24 | -------------------------------------------------------------------------------- /tag-cloud/src/main/docker/Dockerfile.native-distroless: -------------------------------------------------------------------------------- 1 | #### 2 | # This Dockerfile is used in order to build a distroless container that runs the Quarkus application in native (no JVM) mode 3 | # 4 | # Before building the container image run: 5 | # 6 | # ./mvnw package -Pnative 7 | # 8 | # Then, build the image with: 9 | # 10 | # docker build -f src/main/docker/Dockerfile.native-distroless -t quarkus/amazon-kms . 11 | # 12 | # Then run the container using: 13 | # 14 | # docker run -i --rm -p 8080:8080 quarkus/amazon-kms 15 | # 16 | ### 17 | FROM quay.io/quarkus/quarkus-distroless-image:1.0 18 | COPY target/*-runner /application 19 | 20 | EXPOSE 8080 21 | USER nonroot 22 | 23 | CMD ["./application", "-Dquarkus.http.host=0.0.0.0"] 24 | -------------------------------------------------------------------------------- /word-cloud/src/main/docker/Dockerfile.native-distroless: -------------------------------------------------------------------------------- 1 | #### 2 | # This Dockerfile is used in order to build a distroless container that runs the Quarkus application in native (no JVM) mode 3 | # 4 | # Before building the container image run: 5 | # 6 | # ./mvnw package -Pnative 7 | # 8 | # Then, build the image with: 9 | # 10 | # docker build -f src/main/docker/Dockerfile.native-distroless -t quarkus/amazon-kms . 11 | # 12 | # Then run the container using: 13 | # 14 | # docker run -i --rm -p 8080:8080 quarkus/amazon-kms 15 | # 16 | ### 17 | FROM quay.io/quarkus/quarkus-distroless-image:1.0 18 | COPY target/*-runner /application 19 | 20 | EXPOSE 8080 21 | USER nonroot 22 | 23 | CMD ["./application", "-Dquarkus.http.host=0.0.0.0"] 24 | -------------------------------------------------------------------------------- /sentiment-analysis/src/main/docker/Dockerfile.native-distroless: -------------------------------------------------------------------------------- 1 | #### 2 | # This Dockerfile is used in order to build a distroless container that runs the Quarkus application in native (no JVM) mode 3 | # 4 | # Before building the container image run: 5 | # 6 | # ./mvnw package -Pnative 7 | # 8 | # Then, build the image with: 9 | # 10 | # docker build -f src/main/docker/Dockerfile.native-distroless -t quarkus/amazon-kms . 11 | # 12 | # Then run the container using: 13 | # 14 | # docker run -i --rm -p 8080:8080 quarkus/amazon-kms 15 | # 16 | ### 17 | FROM quay.io/quarkus/quarkus-distroless-image:1.0 18 | COPY target/*-runner /application 19 | 20 | EXPOSE 8080 21 | USER nonroot 22 | 23 | CMD ["./application", "-Dquarkus.http.host=0.0.0.0"] 24 | -------------------------------------------------------------------------------- /tag-cloud/src/main/java/cz/scholz/tagcloud/model/twitter/HashtagEntity.java: -------------------------------------------------------------------------------- 1 | package cz.scholz.tagcloud.model.twitter; 2 | 3 | import io.quarkus.runtime.annotations.RegisterForReflection; 4 | 5 | @RegisterForReflection 6 | public class HashtagEntity { 7 | public String text; 8 | public int start = -1; 9 | public int end = -1; 10 | 11 | HashtagEntity() { 12 | } 13 | 14 | public HashtagEntity(String text, int start, int end) { 15 | this.text = text; 16 | this.start = start; 17 | this.end = end; 18 | } 19 | 20 | public String getText() { 21 | return text; 22 | } 23 | 24 | public int getStart() { 25 | return start; 26 | } 27 | 28 | public int getEnd() { 29 | return end; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tag-cloud/src/main/java/cz/scholz/tagcloud/model/twitter/SymbolEntity.java: -------------------------------------------------------------------------------- 1 | package cz.scholz.tagcloud.model.twitter; 2 | 3 | import io.quarkus.runtime.annotations.RegisterForReflection; 4 | 5 | @RegisterForReflection 6 | public class SymbolEntity { 7 | public String text; 8 | public int start = -1; 9 | public int end = -1; 10 | 11 | SymbolEntity() { 12 | } 13 | 14 | public SymbolEntity(String text, int start, int end) { 15 | this.text = text; 16 | this.start = start; 17 | this.end = end; 18 | } 19 | 20 | public String getText() { 21 | return text; 22 | } 23 | 24 | public int getStart() { 25 | return start; 26 | } 27 | 28 | public int getEnd() { 29 | return end; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /word-cloud/src/main/java/cz/scholz/wordcloud/model/twitter/SymbolEntity.java: -------------------------------------------------------------------------------- 1 | package cz.scholz.wordcloud.model.twitter; 2 | 3 | import io.quarkus.runtime.annotations.RegisterForReflection; 4 | 5 | @RegisterForReflection 6 | public class SymbolEntity { 7 | public String text; 8 | public int start = -1; 9 | public int end = -1; 10 | 11 | SymbolEntity() { 12 | } 13 | 14 | public SymbolEntity(String text, int start, int end) { 15 | this.text = text; 16 | this.start = start; 17 | this.end = end; 18 | } 19 | 20 | public String getText() { 21 | return text; 22 | } 23 | 24 | public int getStart() { 25 | return start; 26 | } 27 | 28 | public int getEnd() { 29 | return end; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /word-cloud/src/main/java/cz/scholz/wordcloud/model/twitter/HashtagEntity.java: -------------------------------------------------------------------------------- 1 | package cz.scholz.wordcloud.model.twitter; 2 | 3 | import io.quarkus.runtime.annotations.RegisterForReflection; 4 | 5 | @RegisterForReflection 6 | public class HashtagEntity { 7 | public String text; 8 | public int start = -1; 9 | public int end = -1; 10 | 11 | HashtagEntity() { 12 | } 13 | 14 | public HashtagEntity(String text, int start, int end) { 15 | this.text = text; 16 | this.start = start; 17 | this.end = end; 18 | } 19 | 20 | public String getText() { 21 | return text; 22 | } 23 | 24 | public int getStart() { 25 | return start; 26 | } 27 | 28 | public int getEnd() { 29 | return end; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /ad-hoc/src/main/java/cz/scholz/sentimentanalysis/model/twitter/HashtagEntity.java: -------------------------------------------------------------------------------- 1 | package cz.scholz.sentimentanalysis.model.twitter; 2 | 3 | import io.quarkus.runtime.annotations.RegisterForReflection; 4 | 5 | @RegisterForReflection 6 | public class HashtagEntity { 7 | public String text; 8 | public int start = -1; 9 | public int end = -1; 10 | 11 | HashtagEntity() { 12 | } 13 | 14 | public HashtagEntity(String text, int start, int end) { 15 | this.text = text; 16 | this.start = start; 17 | this.end = end; 18 | } 19 | 20 | public String getText() { 21 | return text; 22 | } 23 | 24 | public int getStart() { 25 | return start; 26 | } 27 | 28 | public int getEnd() { 29 | return end; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /ad-hoc/src/main/java/cz/scholz/sentimentanalysis/model/twitter/SymbolEntity.java: -------------------------------------------------------------------------------- 1 | package cz.scholz.sentimentanalysis.model.twitter; 2 | 3 | import io.quarkus.runtime.annotations.RegisterForReflection; 4 | 5 | @RegisterForReflection 6 | public class SymbolEntity { 7 | public String text; 8 | public int start = -1; 9 | public int end = -1; 10 | 11 | SymbolEntity() { 12 | } 13 | 14 | public SymbolEntity(String text, int start, int end) { 15 | this.text = text; 16 | this.start = start; 17 | this.end = end; 18 | } 19 | 20 | public String getText() { 21 | return text; 22 | } 23 | 24 | public int getStart() { 25 | return start; 26 | } 27 | 28 | public int getEnd() { 29 | return end; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /sentiment-analysis/src/main/java/cz/scholz/sentimentanalysis/model/twitter/SymbolEntity.java: -------------------------------------------------------------------------------- 1 | package cz.scholz.sentimentanalysis.model.twitter; 2 | 3 | import io.quarkus.runtime.annotations.RegisterForReflection; 4 | 5 | @RegisterForReflection 6 | public class SymbolEntity { 7 | public String text; 8 | public int start = -1; 9 | public int end = -1; 10 | 11 | SymbolEntity() { 12 | } 13 | 14 | public SymbolEntity(String text, int start, int end) { 15 | this.text = text; 16 | this.start = start; 17 | this.end = end; 18 | } 19 | 20 | public String getText() { 21 | return text; 22 | } 23 | 24 | public int getStart() { 25 | return start; 26 | } 27 | 28 | public int getEnd() { 29 | return end; 30 | } 31 | } -------------------------------------------------------------------------------- /sentiment-analysis/src/main/java/cz/scholz/sentimentanalysis/model/twitter/HashtagEntity.java: -------------------------------------------------------------------------------- 1 | package cz.scholz.sentimentanalysis.model.twitter; 2 | 3 | import io.quarkus.runtime.annotations.RegisterForReflection; 4 | 5 | @RegisterForReflection 6 | public class HashtagEntity { 7 | public String text; 8 | public int start = -1; 9 | public int end = -1; 10 | 11 | HashtagEntity() { 12 | } 13 | 14 | public HashtagEntity(String text, int start, int end) { 15 | this.text = text; 16 | this.start = start; 17 | this.end = end; 18 | } 19 | 20 | public String getText() { 21 | return text; 22 | } 23 | 24 | public int getStart() { 25 | return start; 26 | } 27 | 28 | public int getEnd() { 29 | return end; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /ad-hoc/src/main/docker/Dockerfile.native: -------------------------------------------------------------------------------- 1 | #### 2 | # This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode 3 | # 4 | # Before building the container image run: 5 | # 6 | # ./mvnw package -Pnative 7 | # 8 | # Then, build the image with: 9 | # 10 | # docker build -f src/main/docker/Dockerfile.native -t quarkus/amazon-kms . 11 | # 12 | # Then run the container using: 13 | # 14 | # docker run -i --rm -p 8080:8080 quarkus/amazon-kms 15 | # 16 | ### 17 | FROM registry.access.redhat.com/ubi8/ubi-minimal:8.3 18 | WORKDIR /work/ 19 | RUN chown 1001 /work \ 20 | && chmod "g+rwX" /work \ 21 | && chown 1001:root /work 22 | COPY --chown=1001:root target/*-runner /work/application 23 | 24 | EXPOSE 8080 25 | USER 1001 26 | 27 | CMD ["./application", "-Dquarkus.http.host=0.0.0.0"] 28 | -------------------------------------------------------------------------------- /tag-cloud/src/main/docker/Dockerfile.native: -------------------------------------------------------------------------------- 1 | #### 2 | # This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode 3 | # 4 | # Before building the container image run: 5 | # 6 | # ./mvnw package -Pnative 7 | # 8 | # Then, build the image with: 9 | # 10 | # docker build -f src/main/docker/Dockerfile.native -t quarkus/amazon-kms . 11 | # 12 | # Then run the container using: 13 | # 14 | # docker run -i --rm -p 8080:8080 quarkus/amazon-kms 15 | # 16 | ### 17 | FROM registry.access.redhat.com/ubi8/ubi-minimal:8.3 18 | WORKDIR /work/ 19 | RUN chown 1001 /work \ 20 | && chmod "g+rwX" /work \ 21 | && chown 1001:root /work 22 | COPY --chown=1001:root target/*-runner /work/application 23 | 24 | EXPOSE 8080 25 | USER 1001 26 | 27 | CMD ["./application", "-Dquarkus.http.host=0.0.0.0"] 28 | -------------------------------------------------------------------------------- /word-cloud/src/main/docker/Dockerfile.native: -------------------------------------------------------------------------------- 1 | #### 2 | # This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode 3 | # 4 | # Before building the container image run: 5 | # 6 | # ./mvnw package -Pnative 7 | # 8 | # Then, build the image with: 9 | # 10 | # docker build -f src/main/docker/Dockerfile.native -t quarkus/amazon-kms . 11 | # 12 | # Then run the container using: 13 | # 14 | # docker run -i --rm -p 8080:8080 quarkus/amazon-kms 15 | # 16 | ### 17 | FROM registry.access.redhat.com/ubi8/ubi-minimal:8.3 18 | WORKDIR /work/ 19 | RUN chown 1001 /work \ 20 | && chmod "g+rwX" /work \ 21 | && chown 1001:root /work 22 | COPY --chown=1001:root target/*-runner /work/application 23 | 24 | EXPOSE 8080 25 | USER 1001 26 | 27 | CMD ["./application", "-Dquarkus.http.host=0.0.0.0"] 28 | -------------------------------------------------------------------------------- /sentiment-analysis/src/main/docker/Dockerfile.native: -------------------------------------------------------------------------------- 1 | #### 2 | # This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode 3 | # 4 | # Before building the container image run: 5 | # 6 | # ./mvnw package -Pnative 7 | # 8 | # Then, build the image with: 9 | # 10 | # docker build -f src/main/docker/Dockerfile.native -t quarkus/amazon-kms . 11 | # 12 | # Then run the container using: 13 | # 14 | # docker run -i --rm -p 8080:8080 quarkus/amazon-kms 15 | # 16 | ### 17 | FROM registry.access.redhat.com/ubi8/ubi-minimal:8.3 18 | WORKDIR /work/ 19 | RUN chown 1001 /work \ 20 | && chmod "g+rwX" /work \ 21 | && chown 1001:root /work 22 | COPY --chown=1001:root target/*-runner /work/application 23 | 24 | EXPOSE 8080 25 | USER 1001 26 | 27 | CMD ["./application", "-Dquarkus.http.host=0.0.0.0"] 28 | -------------------------------------------------------------------------------- /Makefile.docker: -------------------------------------------------------------------------------- 1 | DOCKERFILE ?= src/main/docker/Dockerfile.native-distroless 2 | DOCKER_REGISTRY ?= ghcr.io 3 | DOCKER_ORG ?= $(USER) 4 | DOCKER_TAG ?= latest 5 | DOCKER_VERSION_ARG ?= 1.0.0-SNAPSHOT 6 | 7 | all: docker_build docker_push 8 | 9 | docker_build: 10 | echo "Building Docker image ..." 11 | docker build --build-arg version=$(DOCKER_VERSION_ARG) -t $(PROJECT_NAME):$(DOCKER_TAG) -f $(DOCKERFILE) . 12 | 13 | docker_tag: 14 | echo "Tagging $(PROJECT_NAME):$(DOCKER_TAG) to $(DOCKER_REGISTRY)/$(DOCKER_ORG)/$(PROJECT_NAME):$(DOCKER_TAG) ..." 15 | docker tag $(PROJECT_NAME):$(DOCKER_TAG) $(DOCKER_REGISTRY)/$(DOCKER_ORG)/$(PROJECT_NAME):$(DOCKER_TAG) 16 | 17 | docker_push: docker_tag 18 | echo "Pushing $(DOCKER_REGISTRY)/$(DOCKER_ORG)/$(PROJECT_NAME):$(DOCKER_TAG) ..." 19 | docker push $(DOCKER_REGISTRY)/$(DOCKER_ORG)/$(PROJECT_NAME):$(DOCKER_TAG) -------------------------------------------------------------------------------- /word-cloud/src/test/java/cz/scholz/wordcloud/streams/TopologyProducerTest.java: -------------------------------------------------------------------------------- 1 | package cz.scholz.wordcloud.streams; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static org.hamcrest.MatcherAssert.assertThat; 6 | import static org.hamcrest.Matchers.is; 7 | 8 | public class TopologyProducerTest { 9 | @Test 10 | public void testSpecialCharactersRemoval() { 11 | assertThat(TopologyProducer.stripSpecialCharacters("#avfc"), is("avfc")); 12 | assertThat(TopologyProducer.stripSpecialCharacters("@jakub"), is("jakub")); 13 | assertThat(TopologyProducer.stripSpecialCharacters("@jakub:"), is("jakub")); 14 | assertThat(TopologyProducer.stripSpecialCharacters("@jakub..."), is("jakub")); 15 | assertThat(TopologyProducer.stripSpecialCharacters("etc..."), is("etc")); 16 | assertThat(TopologyProducer.stripSpecialCharacters("...."), is("")); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tag-cloud/src/test/java/cz/scholz/tagcloud/streams/TopologyProducerTest.java: -------------------------------------------------------------------------------- 1 | package cz.scholz.tagcloud.streams; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | import static org.hamcrest.MatcherAssert.assertThat; 6 | import static org.hamcrest.Matchers.is; 7 | 8 | public class TopologyProducerTest { 9 | @Test 10 | public void testSpecialCharactersRemoval() { 11 | assertThat(TopologyProducer.stripSpecialCharactersFromTheEnd("#avfc"), is("#avfc")); 12 | assertThat(TopologyProducer.stripSpecialCharactersFromTheEnd("@jakub"), is("@jakub")); 13 | assertThat(TopologyProducer.stripSpecialCharactersFromTheEnd("@jakub:"), is("@jakub")); 14 | assertThat(TopologyProducer.stripSpecialCharactersFromTheEnd("@jakub..."), is("@jakub")); 15 | assertThat(TopologyProducer.stripSpecialCharactersFromTheEnd("etc..."), is("etc")); 16 | assertThat(TopologyProducer.stripSpecialCharactersFromTheEnd("...."), is("")); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tag-cloud/src/main/java/cz/scholz/tagcloud/model/twitter/RateLimitStatus.java: -------------------------------------------------------------------------------- 1 | package cz.scholz.tagcloud.model.twitter; 2 | 3 | import io.quarkus.runtime.annotations.RegisterForReflection; 4 | 5 | @RegisterForReflection 6 | public class RateLimitStatus { 7 | public int remaining; 8 | public int limit; 9 | public int resetTimeInSeconds; 10 | public int secondsUntilReset; 11 | 12 | public RateLimitStatus() { 13 | } 14 | 15 | public RateLimitStatus(int remaining, int limit, int resetTimeInSeconds, int secondsUntilReset) { 16 | this.remaining = remaining; 17 | this.limit = limit; 18 | this.resetTimeInSeconds = resetTimeInSeconds; 19 | this.secondsUntilReset = secondsUntilReset; 20 | } 21 | 22 | public int getRemaining() { 23 | return remaining; 24 | } 25 | 26 | public int getLimit() { 27 | return limit; 28 | } 29 | 30 | public int getResetTimeInSeconds() { 31 | return resetTimeInSeconds; 32 | } 33 | 34 | public int getSecondsUntilReset() { 35 | return secondsUntilReset; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /word-cloud/src/main/java/cz/scholz/wordcloud/model/twitter/RateLimitStatus.java: -------------------------------------------------------------------------------- 1 | package cz.scholz.wordcloud.model.twitter; 2 | 3 | import io.quarkus.runtime.annotations.RegisterForReflection; 4 | 5 | @RegisterForReflection 6 | public class RateLimitStatus { 7 | public int remaining; 8 | public int limit; 9 | public int resetTimeInSeconds; 10 | public int secondsUntilReset; 11 | 12 | public RateLimitStatus() { 13 | } 14 | 15 | public RateLimitStatus(int remaining, int limit, int resetTimeInSeconds, int secondsUntilReset) { 16 | this.remaining = remaining; 17 | this.limit = limit; 18 | this.resetTimeInSeconds = resetTimeInSeconds; 19 | this.secondsUntilReset = secondsUntilReset; 20 | } 21 | 22 | public int getRemaining() { 23 | return remaining; 24 | } 25 | 26 | public int getLimit() { 27 | return limit; 28 | } 29 | 30 | public int getResetTimeInSeconds() { 31 | return resetTimeInSeconds; 32 | } 33 | 34 | public int getSecondsUntilReset() { 35 | return secondsUntilReset; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /ad-hoc/src/main/java/cz/scholz/sentimentanalysis/model/twitter/RateLimitStatus.java: -------------------------------------------------------------------------------- 1 | package cz.scholz.sentimentanalysis.model.twitter; 2 | 3 | import io.quarkus.runtime.annotations.RegisterForReflection; 4 | 5 | @RegisterForReflection 6 | public class RateLimitStatus { 7 | public int remaining; 8 | public int limit; 9 | public int resetTimeInSeconds; 10 | public int secondsUntilReset; 11 | 12 | public RateLimitStatus() { 13 | } 14 | 15 | public RateLimitStatus(int remaining, int limit, int resetTimeInSeconds, int secondsUntilReset) { 16 | this.remaining = remaining; 17 | this.limit = limit; 18 | this.resetTimeInSeconds = resetTimeInSeconds; 19 | this.secondsUntilReset = secondsUntilReset; 20 | } 21 | 22 | public int getRemaining() { 23 | return remaining; 24 | } 25 | 26 | public int getLimit() { 27 | return limit; 28 | } 29 | 30 | public int getResetTimeInSeconds() { 31 | return resetTimeInSeconds; 32 | } 33 | 34 | public int getSecondsUntilReset() { 35 | return secondsUntilReset; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /sentiment-analysis/src/main/java/cz/scholz/sentimentanalysis/model/twitter/RateLimitStatus.java: -------------------------------------------------------------------------------- 1 | package cz.scholz.sentimentanalysis.model.twitter; 2 | 3 | import io.quarkus.runtime.annotations.RegisterForReflection; 4 | 5 | @RegisterForReflection 6 | public class RateLimitStatus { 7 | public int remaining; 8 | public int limit; 9 | public int resetTimeInSeconds; 10 | public int secondsUntilReset; 11 | 12 | public RateLimitStatus() { 13 | } 14 | 15 | public RateLimitStatus(int remaining, int limit, int resetTimeInSeconds, int secondsUntilReset) { 16 | this.remaining = remaining; 17 | this.limit = limit; 18 | this.resetTimeInSeconds = resetTimeInSeconds; 19 | this.secondsUntilReset = secondsUntilReset; 20 | } 21 | 22 | public int getRemaining() { 23 | return remaining; 24 | } 25 | 26 | public int getLimit() { 27 | return limit; 28 | } 29 | 30 | public int getResetTimeInSeconds() { 31 | return resetTimeInSeconds; 32 | } 33 | 34 | public int getSecondsUntilReset() { 35 | return secondsUntilReset; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /tag-cloud/src/main/java/cz/scholz/tagcloud/model/twitter/UserMentionEntity.java: -------------------------------------------------------------------------------- 1 | package cz.scholz.tagcloud.model.twitter; 2 | 3 | import io.quarkus.runtime.annotations.RegisterForReflection; 4 | 5 | @RegisterForReflection 6 | public class UserMentionEntity { 7 | public String text; 8 | public String name; 9 | public String screenName; 10 | public long id; 11 | public int start = -1; 12 | public int end = -1; 13 | 14 | UserMentionEntity() { 15 | } 16 | 17 | public UserMentionEntity(String text, String name, String screenName, long id, int start, int end) { 18 | this.text = text; 19 | this.name = name; 20 | this.screenName = screenName; 21 | this.id = id; 22 | this.start = start; 23 | this.end = end; 24 | } 25 | 26 | public String getText() { 27 | return text; 28 | } 29 | 30 | public String getName() { 31 | return name; 32 | } 33 | 34 | public String getScreenName() { 35 | return screenName; 36 | } 37 | 38 | public long getId() { 39 | return id; 40 | } 41 | 42 | public int getStart() { 43 | return start; 44 | } 45 | 46 | public int getEnd() { 47 | return end; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /word-cloud/src/main/java/cz/scholz/wordcloud/model/twitter/UserMentionEntity.java: -------------------------------------------------------------------------------- 1 | package cz.scholz.wordcloud.model.twitter; 2 | 3 | import io.quarkus.runtime.annotations.RegisterForReflection; 4 | 5 | @RegisterForReflection 6 | public class UserMentionEntity { 7 | public String text; 8 | public String name; 9 | public String screenName; 10 | public long id; 11 | public int start = -1; 12 | public int end = -1; 13 | 14 | UserMentionEntity() { 15 | } 16 | 17 | public UserMentionEntity(String text, String name, String screenName, long id, int start, int end) { 18 | this.text = text; 19 | this.name = name; 20 | this.screenName = screenName; 21 | this.id = id; 22 | this.start = start; 23 | this.end = end; 24 | } 25 | 26 | public String getText() { 27 | return text; 28 | } 29 | 30 | public String getName() { 31 | return name; 32 | } 33 | 34 | public String getScreenName() { 35 | return screenName; 36 | } 37 | 38 | public long getId() { 39 | return id; 40 | } 41 | 42 | public int getStart() { 43 | return start; 44 | } 45 | 46 | public int getEnd() { 47 | return end; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /20-search.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kafka.strimzi.io/v1beta2 2 | kind: KafkaTopic 3 | metadata: 4 | name: twitter-search 5 | labels: 6 | strimzi.io/cluster: my-cluster 7 | spec: 8 | partitions: 1 9 | replicas: 3 10 | config: 11 | retention.ms: 2629800000 12 | segment.bytes: 107374182 13 | --- 14 | 15 | apiVersion: kafka.strimzi.io/v1beta2 16 | kind: KafkaConnector 17 | metadata: 18 | name: twitter-search 19 | labels: 20 | strimzi.io/cluster: my-connect 21 | spec: 22 | class: CamelTwittersearchSourceConnector 23 | tasksMax: 1 24 | config: 25 | topics: twitter-search 26 | camel.source.path.keywords: "#BYOSMA" 27 | # Twitter account 28 | camel.source.endpoint.consumerKey: ${env:TWITTER_CONSUMER_KEY} 29 | camel.source.endpoint.consumerSecret: ${env:TWITTER_CONSUMER_SECRET} 30 | camel.source.endpoint.accessToken: ${env:TWITTER_ACCESS_TOKEN} 31 | camel.source.endpoint.accessTokenSecret: ${env:TWITTER_ACCESS_TOKEN_SECRET} 32 | # Converting 33 | camel.source.marshal: json-jackson 34 | key.converter: org.apache.kafka.connect.storage.StringConverter 35 | value.converter: org.apache.kafka.connect.converters.ByteArrayConverter 36 | key.converter.schemas.enable: false 37 | value.converter.schemas.enable: false -------------------------------------------------------------------------------- /ad-hoc/src/main/java/cz/scholz/sentimentanalysis/model/twitter/UserMentionEntity.java: -------------------------------------------------------------------------------- 1 | package cz.scholz.sentimentanalysis.model.twitter; 2 | 3 | import io.quarkus.runtime.annotations.RegisterForReflection; 4 | 5 | @RegisterForReflection 6 | public class UserMentionEntity { 7 | public String text; 8 | public String name; 9 | public String screenName; 10 | public long id; 11 | public int start = -1; 12 | public int end = -1; 13 | 14 | UserMentionEntity() { 15 | } 16 | 17 | public UserMentionEntity(String text, String name, String screenName, long id, int start, int end) { 18 | this.text = text; 19 | this.name = name; 20 | this.screenName = screenName; 21 | this.id = id; 22 | this.start = start; 23 | this.end = end; 24 | } 25 | 26 | public String getText() { 27 | return text; 28 | } 29 | 30 | public String getName() { 31 | return name; 32 | } 33 | 34 | public String getScreenName() { 35 | return screenName; 36 | } 37 | 38 | public long getId() { 39 | return id; 40 | } 41 | 42 | public int getStart() { 43 | return start; 44 | } 45 | 46 | public int getEnd() { 47 | return end; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /tag-cloud/src/main/java/cz/scholz/tagcloud/model/twitter/URLEntity.java: -------------------------------------------------------------------------------- 1 | package cz.scholz.tagcloud.model.twitter; 2 | 3 | import io.quarkus.runtime.annotations.RegisterForReflection; 4 | 5 | @RegisterForReflection 6 | public class URLEntity { 7 | public String text; 8 | public String url; 9 | public String expandedURL; 10 | public String displayURL; 11 | public int start = -1; 12 | public int end = -1; 13 | 14 | URLEntity() { 15 | } 16 | 17 | public URLEntity(String text, String url, String expandedURL, String displayURL, int start, int end) { 18 | this.text = text; 19 | this.url = url; 20 | this.expandedURL = expandedURL; 21 | this.displayURL = displayURL; 22 | this.start = start; 23 | this.end = end; 24 | } 25 | 26 | public String getText() { 27 | return text; 28 | } 29 | 30 | public String getUrl() { 31 | return url; 32 | } 33 | 34 | public String getExpandedURL() { 35 | return expandedURL; 36 | } 37 | 38 | public String getDisplayURL() { 39 | return displayURL; 40 | } 41 | 42 | public int getStart() { 43 | return start; 44 | } 45 | 46 | public int getEnd() { 47 | return end; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /sentiment-analysis/src/main/java/cz/scholz/sentimentanalysis/model/twitter/UserMentionEntity.java: -------------------------------------------------------------------------------- 1 | package cz.scholz.sentimentanalysis.model.twitter; 2 | 3 | import io.quarkus.runtime.annotations.RegisterForReflection; 4 | 5 | @RegisterForReflection 6 | public class UserMentionEntity { 7 | public String text; 8 | public String name; 9 | public String screenName; 10 | public long id; 11 | public int start = -1; 12 | public int end = -1; 13 | 14 | UserMentionEntity() { 15 | } 16 | 17 | public UserMentionEntity(String text, String name, String screenName, long id, int start, int end) { 18 | this.text = text; 19 | this.name = name; 20 | this.screenName = screenName; 21 | this.id = id; 22 | this.start = start; 23 | this.end = end; 24 | } 25 | 26 | public String getText() { 27 | return text; 28 | } 29 | 30 | public String getName() { 31 | return name; 32 | } 33 | 34 | public String getScreenName() { 35 | return screenName; 36 | } 37 | 38 | public long getId() { 39 | return id; 40 | } 41 | 42 | public int getStart() { 43 | return start; 44 | } 45 | 46 | public int getEnd() { 47 | return end; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /word-cloud/src/main/java/cz/scholz/wordcloud/model/twitter/URLEntity.java: -------------------------------------------------------------------------------- 1 | package cz.scholz.wordcloud.model.twitter; 2 | 3 | import io.quarkus.runtime.annotations.RegisterForReflection; 4 | 5 | @RegisterForReflection 6 | public class URLEntity { 7 | public String text; 8 | public String url; 9 | public String expandedURL; 10 | public String displayURL; 11 | public int start = -1; 12 | public int end = -1; 13 | 14 | URLEntity() { 15 | } 16 | 17 | public URLEntity(String text, String url, String expandedURL, String displayURL, int start, int end) { 18 | this.text = text; 19 | this.url = url; 20 | this.expandedURL = expandedURL; 21 | this.displayURL = displayURL; 22 | this.start = start; 23 | this.end = end; 24 | } 25 | 26 | public String getText() { 27 | return text; 28 | } 29 | 30 | public String getUrl() { 31 | return url; 32 | } 33 | 34 | public String getExpandedURL() { 35 | return expandedURL; 36 | } 37 | 38 | public String getDisplayURL() { 39 | return displayURL; 40 | } 41 | 42 | public int getStart() { 43 | return start; 44 | } 45 | 46 | public int getEnd() { 47 | return end; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /ad-hoc/src/main/java/cz/scholz/sentimentanalysis/model/twitter/URLEntity.java: -------------------------------------------------------------------------------- 1 | package cz.scholz.sentimentanalysis.model.twitter; 2 | 3 | import io.quarkus.runtime.annotations.RegisterForReflection; 4 | 5 | @RegisterForReflection 6 | public class URLEntity { 7 | public String text; 8 | public String url; 9 | public String expandedURL; 10 | public String displayURL; 11 | public int start = -1; 12 | public int end = -1; 13 | 14 | URLEntity() { 15 | } 16 | 17 | public URLEntity(String text, String url, String expandedURL, String displayURL, int start, int end) { 18 | this.text = text; 19 | this.url = url; 20 | this.expandedURL = expandedURL; 21 | this.displayURL = displayURL; 22 | this.start = start; 23 | this.end = end; 24 | } 25 | 26 | public String getText() { 27 | return text; 28 | } 29 | 30 | public String getUrl() { 31 | return url; 32 | } 33 | 34 | public String getExpandedURL() { 35 | return expandedURL; 36 | } 37 | 38 | public String getDisplayURL() { 39 | return displayURL; 40 | } 41 | 42 | public int getStart() { 43 | return start; 44 | } 45 | 46 | public int getEnd() { 47 | return end; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /sentiment-analysis/src/main/java/cz/scholz/sentimentanalysis/model/twitter/URLEntity.java: -------------------------------------------------------------------------------- 1 | package cz.scholz.sentimentanalysis.model.twitter; 2 | 3 | import io.quarkus.runtime.annotations.RegisterForReflection; 4 | 5 | @RegisterForReflection 6 | public class URLEntity { 7 | public String text; 8 | public String url; 9 | public String expandedURL; 10 | public String displayURL; 11 | public int start = -1; 12 | public int end = -1; 13 | 14 | URLEntity() { 15 | } 16 | 17 | public URLEntity(String text, String url, String expandedURL, String displayURL, int start, int end) { 18 | this.text = text; 19 | this.url = url; 20 | this.expandedURL = expandedURL; 21 | this.displayURL = displayURL; 22 | this.start = start; 23 | this.end = end; 24 | } 25 | 26 | public String getText() { 27 | return text; 28 | } 29 | 30 | public String getUrl() { 31 | return url; 32 | } 33 | 34 | public String getExpandedURL() { 35 | return expandedURL; 36 | } 37 | 38 | public String getDisplayURL() { 39 | return displayURL; 40 | } 41 | 42 | public int getStart() { 43 | return start; 44 | } 45 | 46 | public int getEnd() { 47 | return end; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /91-strimzi-search.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kafka.strimzi.io/v1beta2 2 | kind: KafkaTopic 3 | metadata: 4 | name: strimzi-search 5 | labels: 6 | strimzi.io/cluster: my-cluster 7 | spec: 8 | partitions: 1 9 | replicas: 3 10 | config: 11 | retention.ms: 2629800000 12 | segment.bytes: 107374182 13 | --- 14 | 15 | apiVersion: kafka.strimzi.io/v1beta2 16 | kind: KafkaConnector 17 | metadata: 18 | name: strimzi-search 19 | labels: 20 | strimzi.io/cluster: my-connect 21 | spec: 22 | class: CamelTwittersearchSourceConnector 23 | tasksMax: 1 24 | config: 25 | topics: strimzi-search 26 | # Searchs for mentions of the Strimzi project 27 | camel.source.path.keywords: strimzi 28 | # Twitter account 29 | camel.source.endpoint.consumerKey: ${env:TWITTER_CONSUMER_KEY} 30 | camel.source.endpoint.consumerSecret: ${env:TWITTER_CONSUMER_SECRET} 31 | camel.source.endpoint.accessToken: ${env:TWITTER_ACCESS_TOKEN} 32 | camel.source.endpoint.accessTokenSecret: ${env:TWITTER_ACCESS_TOKEN_SECRET} 33 | # Converting 34 | camel.source.marshal: json-jackson 35 | key.converter: org.apache.kafka.connect.storage.StringConverter 36 | value.converter: org.apache.kafka.connect.converters.ByteArrayConverter 37 | key.converter.schemas.enable: false 38 | value.converter.schemas.enable: false -------------------------------------------------------------------------------- /92-avfc-search.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kafka.strimzi.io/v1beta2 2 | kind: KafkaTopic 3 | metadata: 4 | name: avfc-search 5 | labels: 6 | strimzi.io/cluster: my-cluster 7 | spec: 8 | partitions: 1 9 | replicas: 3 10 | config: 11 | retention.ms: 2629800000 12 | segment.bytes: 107374182 13 | --- 14 | 15 | apiVersion: kafka.strimzi.io/v1beta2 16 | kind: KafkaConnector 17 | metadata: 18 | name: avfc-search 19 | labels: 20 | strimzi.io/cluster: my-connect 21 | spec: 22 | class: CamelTwittersearchSourceConnector 23 | tasksMax: 1 24 | config: 25 | topics: avfc-search 26 | # Searches for Aston Ville Football Club 27 | camel.source.path.keywords: "AVFC OR \"Aston Villa\"" 28 | # Twitter account 29 | camel.source.endpoint.consumerKey: ${env:TWITTER_CONSUMER_KEY} 30 | camel.source.endpoint.consumerSecret: ${env:TWITTER_CONSUMER_SECRET} 31 | camel.source.endpoint.accessToken: ${env:TWITTER_ACCESS_TOKEN} 32 | camel.source.endpoint.accessTokenSecret: ${env:TWITTER_ACCESS_TOKEN_SECRET} 33 | # Converting 34 | camel.source.marshal: json-jackson 35 | key.converter: org.apache.kafka.connect.storage.StringConverter 36 | value.converter: org.apache.kafka.connect.converters.ByteArrayConverter 37 | key.converter.schemas.enable: false 38 | value.converter.schemas.enable: false -------------------------------------------------------------------------------- /90-kafka-search.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kafka.strimzi.io/v1beta2 2 | kind: KafkaTopic 3 | metadata: 4 | name: kafka-search 5 | labels: 6 | strimzi.io/cluster: my-cluster 7 | spec: 8 | partitions: 1 9 | replicas: 3 10 | config: 11 | retention.ms: 2629800000 12 | segment.bytes: 107374182 13 | --- 14 | 15 | apiVersion: kafka.strimzi.io/v1beta2 16 | kind: KafkaConnector 17 | metadata: 18 | name: kafka-search 19 | labels: 20 | strimzi.io/cluster: my-connect 21 | spec: 22 | class: CamelTwittersearchSourceConnector 23 | tasksMax: 1 24 | config: 25 | topics: kafka-search 26 | #searchs fos Apache Kafka mentions 27 | camel.source.path.keywords: "#apachekafka OR \"Apache Kafka\" OR #kafka" 28 | # Twitter account 29 | camel.source.endpoint.consumerKey: ${env:TWITTER_CONSUMER_KEY} 30 | camel.source.endpoint.consumerSecret: ${env:TWITTER_CONSUMER_SECRET} 31 | camel.source.endpoint.accessToken: ${env:TWITTER_ACCESS_TOKEN} 32 | camel.source.endpoint.accessTokenSecret: ${env:TWITTER_ACCESS_TOKEN_SECRET} 33 | # Converting 34 | camel.source.marshal: json-jackson 35 | key.converter: org.apache.kafka.connect.storage.StringConverter 36 | value.converter: org.apache.kafka.connect.converters.ByteArrayConverter 37 | key.converter.schemas.enable: false 38 | value.converter.schemas.enable: false 39 | -------------------------------------------------------------------------------- /10-timeline.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kafka.strimzi.io/v1beta2 2 | kind: KafkaTopic 3 | metadata: 4 | name: twitter-timeline 5 | labels: 6 | strimzi.io/cluster: my-cluster 7 | spec: 8 | partitions: 1 9 | replicas: 3 10 | config: 11 | retention.ms: 2629800000 12 | segment.bytes: 107374182 13 | min.insync.replicas: 2 14 | --- 15 | 16 | apiVersion: kafka.strimzi.io/v1beta2 17 | kind: KafkaConnector 18 | metadata: 19 | name: twitter-timeline 20 | labels: 21 | strimzi.io/cluster: my-connect 22 | spec: 23 | class: CamelTwittertimelineSourceConnector 24 | tasksMax: 1 25 | config: 26 | topics: twitter-timeline 27 | camel.source.path.timelineType: home 28 | camel.source.endpoint.delay: 300000 29 | # Twitter account 30 | camel.source.endpoint.consumerKey: ${env:TWITTER_CONSUMER_KEY} 31 | camel.source.endpoint.consumerSecret: ${env:TWITTER_CONSUMER_SECRET} 32 | camel.source.endpoint.accessToken: ${env:TWITTER_ACCESS_TOKEN} 33 | camel.source.endpoint.accessTokenSecret: ${env:TWITTER_ACCESS_TOKEN_SECRET} 34 | # Converting 35 | camel.source.marshal: json-jackson 36 | key.converter: org.apache.kafka.connect.converters.ByteArrayConverter 37 | value.converter: org.apache.kafka.connect.converters.ByteArrayConverter 38 | key.converter.schemas.enable: false 39 | value.converter.schemas.enable: false -------------------------------------------------------------------------------- /tag-cloud/src/main/java/cz/scholz/tagcloud/rest/TagCloudEndpoint.java: -------------------------------------------------------------------------------- 1 | package cz.scholz.tagcloud.rest; 2 | 3 | import cz.scholz.tagcloud.streams.PipelineMetadata; 4 | import cz.scholz.tagcloud.streams.InteractiveQueries; 5 | 6 | import javax.enterprise.context.ApplicationScoped; 7 | import javax.inject.Inject; 8 | import javax.ws.rs.Consumes; 9 | import javax.ws.rs.GET; 10 | import javax.ws.rs.Path; 11 | import javax.ws.rs.PathParam; 12 | import javax.ws.rs.Produces; 13 | import javax.ws.rs.core.MediaType; 14 | import javax.ws.rs.core.Response; 15 | import java.util.List; 16 | import java.util.Map; 17 | 18 | @ApplicationScoped 19 | @Path("/api") 20 | public class TagCloudEndpoint { 21 | @Inject 22 | InteractiveQueries interactiveQueries; 23 | 24 | @GET 25 | @Path("/all-time/top/{count}") 26 | @Consumes(MediaType.APPLICATION_JSON) 27 | @Produces(MediaType.APPLICATION_JSON) 28 | public Response getAllTimeTopWords(@PathParam("count") int count) { 29 | Map result = interactiveQueries.getAllTimeHighest(count); 30 | 31 | return Response.ok(result).build(); 32 | } 33 | 34 | @GET 35 | @Path("/all-time/meta-data") 36 | @Produces(MediaType.APPLICATION_JSON) 37 | public List getAllTimeMetaData() { 38 | return interactiveQueries.getAllTimeMetaData(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /word-cloud/src/main/java/cz/scholz/wordcloud/rest/WordCloudEndpoint.java: -------------------------------------------------------------------------------- 1 | package cz.scholz.wordcloud.rest; 2 | 3 | import cz.scholz.wordcloud.streams.PipelineMetadata; 4 | import cz.scholz.wordcloud.streams.InteractiveQueries; 5 | 6 | import javax.enterprise.context.ApplicationScoped; 7 | import javax.inject.Inject; 8 | import javax.ws.rs.Consumes; 9 | import javax.ws.rs.GET; 10 | import javax.ws.rs.Path; 11 | import javax.ws.rs.PathParam; 12 | import javax.ws.rs.Produces; 13 | import javax.ws.rs.core.MediaType; 14 | import javax.ws.rs.core.Response; 15 | import java.util.List; 16 | import java.util.Map; 17 | 18 | @ApplicationScoped 19 | @Path("/api") 20 | public class WordCloudEndpoint { 21 | @Inject 22 | InteractiveQueries interactiveQueries; 23 | 24 | @GET 25 | @Path("/all-time/top/{count}") 26 | @Consumes(MediaType.APPLICATION_JSON) 27 | @Produces(MediaType.APPLICATION_JSON) 28 | public Response getAllTimeTopWords(@PathParam("count") int count) { 29 | Map result = interactiveQueries.getAllTimeHighest(count); 30 | 31 | return Response.ok(result).build(); 32 | } 33 | 34 | @GET 35 | @Path("/all-time/meta-data") 36 | @Produces(MediaType.APPLICATION_JSON) 37 | public List getAllTimeMetaData() { 38 | return interactiveQueries.getAllTimeMetaData(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /ad-hoc/src/main/java/cz/scholz/sentimentanalysis/streams/TopologyProducer.java: -------------------------------------------------------------------------------- 1 | package cz.scholz.sentimentanalysis.streams; 2 | 3 | import cz.scholz.sentimentanalysis.model.Aggregation; 4 | import cz.scholz.sentimentanalysis.model.TweetSerde; 5 | import io.quarkus.kafka.client.serialization.ObjectMapperSerde; 6 | import org.apache.kafka.common.serialization.Serdes; 7 | import org.apache.kafka.streams.StreamsBuilder; 8 | import org.apache.kafka.streams.Topology; 9 | import org.apache.kafka.streams.kstream.Consumed; 10 | import org.apache.kafka.streams.kstream.Grouped; 11 | import org.apache.kafka.streams.kstream.Materialized; 12 | import org.jboss.logging.Logger; 13 | 14 | import javax.enterprise.context.ApplicationScoped; 15 | import javax.enterprise.inject.Produces; 16 | 17 | @ApplicationScoped 18 | public class TopologyProducer { 19 | private static final Logger LOG = Logger.getLogger(TopologyProducer.class); 20 | 21 | private static final String SOURCE_TOPIC = "twitter-timeline"; 22 | 23 | @Produces 24 | public Topology buildTopology() { 25 | final TweetSerde tweetSerde = new TweetSerde(); 26 | final ObjectMapperSerde aggregationSerde = new ObjectMapperSerde<>(Aggregation.class); 27 | final StreamsBuilder builder = new StreamsBuilder(); 28 | 29 | builder.stream(SOURCE_TOPIC, Consumed.with(Serdes.ByteArray(), tweetSerde)) 30 | .filter((key, value) -> value.getRetweetedStatus() == null) 31 | .groupBy((key, value) -> 1, Grouped.with(Serdes.Integer(), tweetSerde)) 32 | .aggregate( 33 | Aggregation::new, 34 | (aggKey, newValue, oldValue) -> oldValue.aggregate(newValue), 35 | Materialized.with(Serdes.Integer(), aggregationSerde) 36 | ) 37 | .toStream() 38 | .peek((key, value) -> LOG.infov("{0}", value)); 39 | 40 | return builder.build(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /ad-hoc/src/main/docker/Dockerfile.legacy-jar: -------------------------------------------------------------------------------- 1 | #### 2 | # This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode 3 | # 4 | # Before building the container image run: 5 | # 6 | # ./mvnw package -Dquarkus.package.type=legacy-jar 7 | # 8 | # Then, build the image with: 9 | # 10 | # docker build -f src/main/docker/Dockerfile.legacy-jar -t quarkus/amazon-kms-legacy-jar . 11 | # 12 | # Then run the container using: 13 | # 14 | # docker run -i --rm -p 8080:8080 quarkus/amazon-kms-legacy-jar 15 | # 16 | # If you want to include the debug port into your docker image 17 | # you will have to expose the debug port (default 5005) like this : EXPOSE 8080 5050 18 | # 19 | # Then run the container using : 20 | # 21 | # docker run -i --rm -p 8080:8080 -p 5005:5005 -e JAVA_ENABLE_DEBUG="true" quarkus/amazon-kms-legacy-jar 22 | # 23 | ### 24 | FROM registry.access.redhat.com/ubi8/ubi-minimal:8.3 25 | 26 | ARG JAVA_PACKAGE=java-11-openjdk-headless 27 | ARG RUN_JAVA_VERSION=1.3.8 28 | ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' 29 | # Install java and the run-java script 30 | # Also set up permissions for user `1001` 31 | RUN microdnf install curl ca-certificates ${JAVA_PACKAGE} \ 32 | && microdnf update \ 33 | && microdnf clean all \ 34 | && mkdir /deployments \ 35 | && chown 1001 /deployments \ 36 | && chmod "g+rwX" /deployments \ 37 | && chown 1001:root /deployments \ 38 | && curl https://repo1.maven.org/maven2/io/fabric8/run-java-sh/${RUN_JAVA_VERSION}/run-java-sh-${RUN_JAVA_VERSION}-sh.sh -o /deployments/run-java.sh \ 39 | && chown 1001 /deployments/run-java.sh \ 40 | && chmod 540 /deployments/run-java.sh \ 41 | && echo "securerandom.source=file:/dev/urandom" >> /etc/alternatives/jre/lib/security/java.security 42 | 43 | # Configure the JAVA_OPTIONS, you can add -XshowSettings:vm to also display the heap size. 44 | ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" 45 | COPY target/lib/* /deployments/lib/ 46 | COPY target/*-runner.jar /deployments/app.jar 47 | 48 | EXPOSE 8080 49 | USER 1001 50 | 51 | ENTRYPOINT [ "/deployments/run-java.sh" ] 52 | -------------------------------------------------------------------------------- /tag-cloud/src/main/docker/Dockerfile.legacy-jar: -------------------------------------------------------------------------------- 1 | #### 2 | # This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode 3 | # 4 | # Before building the container image run: 5 | # 6 | # ./mvnw package -Dquarkus.package.type=legacy-jar 7 | # 8 | # Then, build the image with: 9 | # 10 | # docker build -f src/main/docker/Dockerfile.legacy-jar -t quarkus/amazon-kms-legacy-jar . 11 | # 12 | # Then run the container using: 13 | # 14 | # docker run -i --rm -p 8080:8080 quarkus/amazon-kms-legacy-jar 15 | # 16 | # If you want to include the debug port into your docker image 17 | # you will have to expose the debug port (default 5005) like this : EXPOSE 8080 5050 18 | # 19 | # Then run the container using : 20 | # 21 | # docker run -i --rm -p 8080:8080 -p 5005:5005 -e JAVA_ENABLE_DEBUG="true" quarkus/amazon-kms-legacy-jar 22 | # 23 | ### 24 | FROM registry.access.redhat.com/ubi8/ubi-minimal:8.3 25 | 26 | ARG JAVA_PACKAGE=java-11-openjdk-headless 27 | ARG RUN_JAVA_VERSION=1.3.8 28 | ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' 29 | # Install java and the run-java script 30 | # Also set up permissions for user `1001` 31 | RUN microdnf install curl ca-certificates ${JAVA_PACKAGE} \ 32 | && microdnf update \ 33 | && microdnf clean all \ 34 | && mkdir /deployments \ 35 | && chown 1001 /deployments \ 36 | && chmod "g+rwX" /deployments \ 37 | && chown 1001:root /deployments \ 38 | && curl https://repo1.maven.org/maven2/io/fabric8/run-java-sh/${RUN_JAVA_VERSION}/run-java-sh-${RUN_JAVA_VERSION}-sh.sh -o /deployments/run-java.sh \ 39 | && chown 1001 /deployments/run-java.sh \ 40 | && chmod 540 /deployments/run-java.sh \ 41 | && echo "securerandom.source=file:/dev/urandom" >> /etc/alternatives/jre/lib/security/java.security 42 | 43 | # Configure the JAVA_OPTIONS, you can add -XshowSettings:vm to also display the heap size. 44 | ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" 45 | COPY target/lib/* /deployments/lib/ 46 | COPY target/*-runner.jar /deployments/app.jar 47 | 48 | EXPOSE 8080 49 | USER 1001 50 | 51 | ENTRYPOINT [ "/deployments/run-java.sh" ] 52 | -------------------------------------------------------------------------------- /word-cloud/src/main/docker/Dockerfile.legacy-jar: -------------------------------------------------------------------------------- 1 | #### 2 | # This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode 3 | # 4 | # Before building the container image run: 5 | # 6 | # ./mvnw package -Dquarkus.package.type=legacy-jar 7 | # 8 | # Then, build the image with: 9 | # 10 | # docker build -f src/main/docker/Dockerfile.legacy-jar -t quarkus/amazon-kms-legacy-jar . 11 | # 12 | # Then run the container using: 13 | # 14 | # docker run -i --rm -p 8080:8080 quarkus/amazon-kms-legacy-jar 15 | # 16 | # If you want to include the debug port into your docker image 17 | # you will have to expose the debug port (default 5005) like this : EXPOSE 8080 5050 18 | # 19 | # Then run the container using : 20 | # 21 | # docker run -i --rm -p 8080:8080 -p 5005:5005 -e JAVA_ENABLE_DEBUG="true" quarkus/amazon-kms-legacy-jar 22 | # 23 | ### 24 | FROM registry.access.redhat.com/ubi8/ubi-minimal:8.3 25 | 26 | ARG JAVA_PACKAGE=java-11-openjdk-headless 27 | ARG RUN_JAVA_VERSION=1.3.8 28 | ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' 29 | # Install java and the run-java script 30 | # Also set up permissions for user `1001` 31 | RUN microdnf install curl ca-certificates ${JAVA_PACKAGE} \ 32 | && microdnf update \ 33 | && microdnf clean all \ 34 | && mkdir /deployments \ 35 | && chown 1001 /deployments \ 36 | && chmod "g+rwX" /deployments \ 37 | && chown 1001:root /deployments \ 38 | && curl https://repo1.maven.org/maven2/io/fabric8/run-java-sh/${RUN_JAVA_VERSION}/run-java-sh-${RUN_JAVA_VERSION}-sh.sh -o /deployments/run-java.sh \ 39 | && chown 1001 /deployments/run-java.sh \ 40 | && chmod 540 /deployments/run-java.sh \ 41 | && echo "securerandom.source=file:/dev/urandom" >> /etc/alternatives/jre/lib/security/java.security 42 | 43 | # Configure the JAVA_OPTIONS, you can add -XshowSettings:vm to also display the heap size. 44 | ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" 45 | COPY target/lib/* /deployments/lib/ 46 | COPY target/*-runner.jar /deployments/app.jar 47 | 48 | EXPOSE 8080 49 | USER 1001 50 | 51 | ENTRYPOINT [ "/deployments/run-java.sh" ] 52 | -------------------------------------------------------------------------------- /tag-cloud/src/main/java/cz/scholz/tagcloud/model/TweetSerde.java: -------------------------------------------------------------------------------- 1 | package cz.scholz.tagcloud.model; 2 | 3 | import com.fasterxml.jackson.core.JsonProcessingException; 4 | import com.fasterxml.jackson.databind.ObjectMapper; 5 | import cz.scholz.tagcloud.model.twitter.Tweet; 6 | import org.apache.kafka.common.serialization.Deserializer; 7 | import org.apache.kafka.common.serialization.Serde; 8 | import org.apache.kafka.common.serialization.Serializer; 9 | import org.jboss.logging.Logger; 10 | 11 | import java.io.IOException; 12 | 13 | public class TweetSerde implements Serde { 14 | private static final Logger LOG = Logger.getLogger(TweetSerde.class); 15 | 16 | final ObjectMapper mapper; 17 | 18 | private final TweetSerializer serializer; 19 | private final TweetDeserializer deserializer; 20 | 21 | public TweetSerde() { 22 | mapper = new ObjectMapper(); 23 | serializer = new TweetSerializer(); 24 | deserializer = new TweetDeserializer(); 25 | } 26 | 27 | @Override 28 | public Serializer serializer() { 29 | return serializer; 30 | } 31 | 32 | @Override 33 | public Deserializer deserializer() { 34 | return deserializer; 35 | } 36 | 37 | final class TweetSerializer implements Serializer { 38 | @Override 39 | public byte[] serialize(String topic, Tweet data) { 40 | try { 41 | return mapper.writeValueAsBytes(data); 42 | } catch (JsonProcessingException e) { 43 | throw new RuntimeException("Failed to serialize tweet", e); 44 | } 45 | } 46 | } 47 | 48 | final class TweetDeserializer implements Deserializer { 49 | @Override 50 | public Tweet deserialize(String topic, byte[] data) { 51 | try { 52 | return mapper.readValue(data, Tweet.class); 53 | } catch (IOException e) { 54 | LOG.errorv("Failed to deserialize Tweet from JSON: {0}", new String(data)); 55 | throw new RuntimeException("Failed to deserialize tweet", e); 56 | } 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /ad-hoc/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | # Enable SSL support 2 | quarkus.ssl.native=true 3 | 4 | # Enable CORS to be able to use the APi from browsers 5 | quarkus.http.cors=true 6 | 7 | # Disable Quarkus Continuous testing and Kafka Dev Service 8 | quarkus.test.continuous-testing=disabled 9 | quarkus.kafka.devservices.enabled=false 10 | 11 | # Quarkus logging configuration 12 | quarkus.log.file.enable=false 13 | quarkus.log.console.enable=true 14 | quarkus.log.console.format=%d{yyyy-MM-dd HH:mm:ss,SSS} %-5p [%c{3.}] (%t) %s%e%n 15 | quarkus.log.console.level=INFO 16 | 17 | # Kafka Streams configuration 18 | quarkus.kafka-streams.bootstrap-servers=192.168.1.86:30331 19 | quarkus.kafka-streams.application-id=ad-hoc 20 | quarkus.kafka-streams.topics=twitter-timeline 21 | quarkus.kafka-streams.security.protocol=PLAINTEXT 22 | quarkus.kafka-streams.sasl.mechanism="" 23 | quarkus.kafka-streams.sasl.jaas-config="" 24 | quarkus.kafka-streams.ssl.truststore.type=PKCS12 25 | quarkus.kafka-streams.ssl.truststore.location= 26 | quarkus.kafka-streams.ssl.truststore.password= 27 | quarkus.kafka-streams.ssl.truststore.certificates= 28 | quarkus.kafka-streams.ssl.keystore.type=PKCS12 29 | quarkus.kafka-streams.ssl.keystore.location= 30 | quarkus.kafka-streams.ssl.keystore.password= 31 | quarkus.kafka-streams.ssl.keystore.key= 32 | quarkus.kafka-streams.ssl.keystore.certificate-chain= 33 | quarkus.kafka-streams.ssl.endpoint-identification-algorithm=HTTPS 34 | quarkus.kafka-streams.sasl.login-callback-handler-class= 35 | quarkus.kafka-streams.cache.max.bytes.buffering=10240 36 | quarkus.kafka-streams.commit.interval.ms=1000 37 | quarkus.kafka-streams.metadata.max.age.ms=500 38 | quarkus.kafka-streams.auto.offset.reset=earliest 39 | quarkus.kafka-streams.metrics.recording.level=DEBUG 40 | quarkus.kafka-streams.consumer.heartbeat.interval.ms=200 41 | # Use sub-folder of embedded broker, so it gets cleaned by KafkaResource between re-runs 42 | # This does not work for native tests, manually clean-up /tmp/kafka-streams/temperature-aggregator 43 | #%test.kafka-streams.state.dir=target/data/kafka-data/stores 44 | 45 | # Disable health checks 46 | quarkus.kafka-streams.health.enabled=false 47 | -------------------------------------------------------------------------------- /sentiment-analysis/src/main/docker/Dockerfile.legacy-jar: -------------------------------------------------------------------------------- 1 | #### 2 | # This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode 3 | # 4 | # Before building the container image run: 5 | # 6 | # ./mvnw package -Dquarkus.package.type=legacy-jar 7 | # 8 | # Then, build the image with: 9 | # 10 | # docker build -f src/main/docker/Dockerfile.legacy-jar -t quarkus/amazon-kms-legacy-jar . 11 | # 12 | # Then run the container using: 13 | # 14 | # docker run -i --rm -p 8080:8080 quarkus/amazon-kms-legacy-jar 15 | # 16 | # If you want to include the debug port into your docker image 17 | # you will have to expose the debug port (default 5005) like this : EXPOSE 8080 5050 18 | # 19 | # Then run the container using : 20 | # 21 | # docker run -i --rm -p 8080:8080 -p 5005:5005 -e JAVA_ENABLE_DEBUG="true" quarkus/amazon-kms-legacy-jar 22 | # 23 | ### 24 | FROM registry.access.redhat.com/ubi8/ubi-minimal:8.3 25 | 26 | ARG JAVA_PACKAGE=java-11-openjdk-headless 27 | ARG RUN_JAVA_VERSION=1.3.8 28 | ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' 29 | # Install java and the run-java script 30 | # Also set up permissions for user `1001` 31 | RUN microdnf install curl ca-certificates ${JAVA_PACKAGE} \ 32 | && microdnf update \ 33 | && microdnf clean all \ 34 | && mkdir /deployments \ 35 | && chown 1001 /deployments \ 36 | && chmod "g+rwX" /deployments \ 37 | && chown 1001:root /deployments \ 38 | && curl https://repo1.maven.org/maven2/io/fabric8/run-java-sh/${RUN_JAVA_VERSION}/run-java-sh-${RUN_JAVA_VERSION}-sh.sh -o /deployments/run-java.sh \ 39 | && chown 1001 /deployments/run-java.sh \ 40 | && chmod 540 /deployments/run-java.sh \ 41 | && echo "securerandom.source=file:/dev/urandom" >> /etc/alternatives/jre/lib/security/java.security 42 | 43 | # Configure the JAVA_OPTIONS, you can add -XshowSettings:vm to also display the heap size. 44 | ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" 45 | COPY target/lib/* /deployments/lib/ 46 | COPY target/*-runner.jar /deployments/app.jar 47 | 48 | EXPOSE 8080 49 | USER 1001 50 | 51 | ENTRYPOINT [ "/deployments/run-java.sh" ] 52 | -------------------------------------------------------------------------------- /tag-cloud/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | # Enable SSL support 2 | quarkus.ssl.native=true 3 | 4 | # Enable CORS to be able to use the APi from browsers 5 | quarkus.http.cors=true 6 | 7 | # Disable Quarkus Continuous testing and Kafka Dev Service 8 | quarkus.test.continuous-testing=disabled 9 | quarkus.kafka.devservices.enabled=false 10 | 11 | # Quarkus logging configuration 12 | quarkus.log.file.enable=false 13 | quarkus.log.console.enable=true 14 | quarkus.log.console.format=%d{yyyy-MM-dd HH:mm:ss,SSS} %-5p [%c{3.}] (%t) %s%e%n 15 | quarkus.log.console.level=INFO 16 | 17 | # Kafka Streams configuration 18 | quarkus.kafka-streams.bootstrap-servers=localhost:9092 19 | quarkus.kafka-streams.application-id=tag-cloud 20 | quarkus.kafka-streams.topics=twitter-timeline 21 | quarkus.kafka-streams.security.protocol=PLAINTEXT 22 | quarkus.kafka-streams.sasl.mechanism="" 23 | quarkus.kafka-streams.sasl.jaas-config="" 24 | quarkus.kafka-streams.ssl.truststore.type=PKCS12 25 | quarkus.kafka-streams.ssl.truststore.location= 26 | quarkus.kafka-streams.ssl.truststore.password= 27 | quarkus.kafka-streams.ssl.truststore.certificates= 28 | quarkus.kafka-streams.ssl.keystore.type=PKCS12 29 | quarkus.kafka-streams.ssl.keystore.location= 30 | quarkus.kafka-streams.ssl.keystore.password= 31 | quarkus.kafka-streams.ssl.keystore.key= 32 | quarkus.kafka-streams.ssl.keystore.certificate-chain= 33 | quarkus.kafka-streams.ssl.endpoint-identification-algorithm=HTTPS 34 | quarkus.kafka-streams.sasl.login-callback-handler-class= 35 | quarkus.kafka-streams.cache.max.bytes.buffering=10240 36 | quarkus.kafka-streams.commit.interval.ms=1000 37 | quarkus.kafka-streams.metadata.max.age.ms=500 38 | quarkus.kafka-streams.auto.offset.reset=earliest 39 | quarkus.kafka-streams.metrics.recording.level=DEBUG 40 | quarkus.kafka-streams.consumer.heartbeat.interval.ms=200 41 | # Use sub-folder of embedded broker, so it gets cleaned by KafkaResource between re-runs 42 | # This does not work for native tests, manually clean-up /tmp/kafka-streams/temperature-aggregator 43 | #%test.kafka-streams.state.dir=target/data/kafka-data/stores 44 | 45 | # Disable health checks 46 | quarkus.kafka-streams.health.enabled=false 47 | -------------------------------------------------------------------------------- /word-cloud/src/main/java/cz/scholz/wordcloud/model/TweetSerde.java: -------------------------------------------------------------------------------- 1 | package cz.scholz.wordcloud.model; 2 | 3 | import com.fasterxml.jackson.core.JsonProcessingException; 4 | import com.fasterxml.jackson.databind.ObjectMapper; 5 | import cz.scholz.wordcloud.model.twitter.Tweet; 6 | import org.apache.kafka.common.serialization.Deserializer; 7 | import org.apache.kafka.common.serialization.Serde; 8 | import org.apache.kafka.common.serialization.Serializer; 9 | import org.jboss.logging.Logger; 10 | 11 | import java.io.IOException; 12 | 13 | public class TweetSerde implements Serde { 14 | private static final Logger LOG = Logger.getLogger(TweetSerde.class); 15 | 16 | final ObjectMapper mapper; 17 | 18 | private final TweetSerializer serializer; 19 | private final TweetDeserializer deserializer; 20 | 21 | public TweetSerde() { 22 | mapper = new ObjectMapper(); 23 | serializer = new TweetSerializer(); 24 | deserializer = new TweetDeserializer(); 25 | } 26 | 27 | @Override 28 | public Serializer serializer() { 29 | return serializer; 30 | } 31 | 32 | @Override 33 | public Deserializer deserializer() { 34 | return deserializer; 35 | } 36 | 37 | final class TweetSerializer implements Serializer { 38 | @Override 39 | public byte[] serialize(String topic, Tweet data) { 40 | try { 41 | return mapper.writeValueAsBytes(data); 42 | } catch (JsonProcessingException e) { 43 | throw new RuntimeException("Failed to serialize tweet", e); 44 | } 45 | } 46 | } 47 | 48 | final class TweetDeserializer implements Deserializer { 49 | @Override 50 | public Tweet deserialize(String topic, byte[] data) { 51 | try { 52 | return mapper.readValue(data, Tweet.class); 53 | } catch (IOException e) { 54 | LOG.errorv("Failed to deserialize Tweet from JSON: {0}", new String(data)); 55 | throw new RuntimeException("Failed to deserialize tweet", e); 56 | } 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /word-cloud/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | # Enable SSL support 2 | quarkus.ssl.native=true 3 | 4 | # Enable CORS to be able to use the APi from browsers 5 | quarkus.http.cors=true 6 | 7 | # Disable Quarkus Continuous testing and Kafka Dev Service 8 | quarkus.test.continuous-testing=disabled 9 | quarkus.kafka.devservices.enabled=false 10 | 11 | # Quarkus logging configuration 12 | quarkus.log.file.enable=false 13 | quarkus.log.console.enable=true 14 | quarkus.log.console.format=%d{yyyy-MM-dd HH:mm:ss,SSS} %-5p [%c{3.}] (%t) %s%e%n 15 | quarkus.log.console.level=INFO 16 | 17 | # Kafka Streams configuration 18 | quarkus.kafka-streams.bootstrap-servers=localhost:9092 19 | quarkus.kafka-streams.application-id=word-cloud 20 | quarkus.kafka-streams.topics=twitter-timeline 21 | quarkus.kafka-streams.security.protocol=PLAINTEXT 22 | quarkus.kafka-streams.sasl.mechanism="" 23 | quarkus.kafka-streams.sasl.jaas-config="" 24 | quarkus.kafka-streams.ssl.truststore.type=PKCS12 25 | quarkus.kafka-streams.ssl.truststore.location= 26 | quarkus.kafka-streams.ssl.truststore.password= 27 | quarkus.kafka-streams.ssl.truststore.certificates= 28 | quarkus.kafka-streams.ssl.keystore.type=PKCS12 29 | quarkus.kafka-streams.ssl.keystore.location= 30 | quarkus.kafka-streams.ssl.keystore.password= 31 | quarkus.kafka-streams.ssl.keystore.key= 32 | quarkus.kafka-streams.ssl.keystore.certificate-chain= 33 | quarkus.kafka-streams.ssl.endpoint-identification-algorithm=HTTPS 34 | quarkus.kafka-streams.sasl.login-callback-handler-class= 35 | quarkus.kafka-streams.cache.max.bytes.buffering=10240 36 | quarkus.kafka-streams.commit.interval.ms=1000 37 | quarkus.kafka-streams.metadata.max.age.ms=500 38 | quarkus.kafka-streams.auto.offset.reset=earliest 39 | quarkus.kafka-streams.metrics.recording.level=DEBUG 40 | quarkus.kafka-streams.consumer.heartbeat.interval.ms=200 41 | # Use sub-folder of embedded broker, so it gets cleaned by KafkaResource between re-runs 42 | # This does not work for native tests, manually clean-up /tmp/kafka-streams/temperature-aggregator 43 | #%test.kafka-streams.state.dir=target/data/kafka-data/stores 44 | 45 | # Disable health checks 46 | quarkus.kafka-streams.health.enabled=false 47 | -------------------------------------------------------------------------------- /ad-hoc/src/main/java/cz/scholz/sentimentanalysis/model/TweetSerde.java: -------------------------------------------------------------------------------- 1 | package cz.scholz.sentimentanalysis.model; 2 | 3 | import com.fasterxml.jackson.core.JsonProcessingException; 4 | import com.fasterxml.jackson.databind.ObjectMapper; 5 | import cz.scholz.sentimentanalysis.model.twitter.Tweet; 6 | import org.apache.kafka.common.serialization.Deserializer; 7 | import org.apache.kafka.common.serialization.Serde; 8 | import org.apache.kafka.common.serialization.Serializer; 9 | import org.jboss.logging.Logger; 10 | 11 | import java.io.IOException; 12 | 13 | public class TweetSerde implements Serde { 14 | private static final Logger LOG = Logger.getLogger(TweetSerde.class); 15 | 16 | final ObjectMapper mapper; 17 | 18 | private final TweetSerializer serializer; 19 | private final TweetDeserializer deserializer; 20 | 21 | public TweetSerde() { 22 | mapper = new ObjectMapper(); 23 | serializer = new TweetSerializer(); 24 | deserializer = new TweetDeserializer(); 25 | } 26 | 27 | @Override 28 | public Serializer serializer() { 29 | return serializer; 30 | } 31 | 32 | @Override 33 | public Deserializer deserializer() { 34 | return deserializer; 35 | } 36 | 37 | final class TweetSerializer implements Serializer { 38 | @Override 39 | public byte[] serialize(String topic, Tweet data) { 40 | try { 41 | return mapper.writeValueAsBytes(data); 42 | } catch (JsonProcessingException e) { 43 | throw new RuntimeException("Failed to serialize tweet", e); 44 | } 45 | } 46 | } 47 | 48 | final class TweetDeserializer implements Deserializer { 49 | @Override 50 | public Tweet deserialize(String topic, byte[] data) { 51 | try { 52 | return mapper.readValue(data, Tweet.class); 53 | } catch (IOException e) { 54 | LOG.errorv("Failed to deserialize Tweet from JSON: {0}", new String(data)); 55 | throw new RuntimeException("Failed to deserialize tweet", e); 56 | } 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /sentiment-analysis/src/main/java/cz/scholz/sentimentanalysis/model/TweetSerde.java: -------------------------------------------------------------------------------- 1 | package cz.scholz.sentimentanalysis.model; 2 | 3 | import com.fasterxml.jackson.core.JsonProcessingException; 4 | import com.fasterxml.jackson.databind.ObjectMapper; 5 | import cz.scholz.sentimentanalysis.model.twitter.Tweet; 6 | import org.apache.kafka.common.serialization.Deserializer; 7 | import org.apache.kafka.common.serialization.Serde; 8 | import org.apache.kafka.common.serialization.Serializer; 9 | import org.jboss.logging.Logger; 10 | 11 | import java.io.IOException; 12 | 13 | public class TweetSerde implements Serde { 14 | private static final Logger LOG = Logger.getLogger(TweetSerde.class); 15 | 16 | final ObjectMapper mapper; 17 | 18 | private final TweetSerializer serializer; 19 | private final TweetDeserializer deserializer; 20 | 21 | public TweetSerde() { 22 | mapper = new ObjectMapper(); 23 | serializer = new TweetSerializer(); 24 | deserializer = new TweetDeserializer(); 25 | } 26 | 27 | @Override 28 | public Serializer serializer() { 29 | return serializer; 30 | } 31 | 32 | @Override 33 | public Deserializer deserializer() { 34 | return deserializer; 35 | } 36 | 37 | final class TweetSerializer implements Serializer { 38 | @Override 39 | public byte[] serialize(String topic, Tweet data) { 40 | try { 41 | return mapper.writeValueAsBytes(data); 42 | } catch (JsonProcessingException e) { 43 | throw new RuntimeException("Failed to serialize tweet", e); 44 | } 45 | } 46 | } 47 | 48 | final class TweetDeserializer implements Deserializer { 49 | @Override 50 | public Tweet deserialize(String topic, byte[] data) { 51 | try { 52 | return mapper.readValue(data, Tweet.class); 53 | } catch (IOException e) { 54 | LOG.errorv("Failed to deserialize Tweet from JSON: {0}", new String(data)); 55 | throw new RuntimeException("Failed to deserialize tweet", e); 56 | } 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /sentiment-analysis/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | # Enable SSL support 2 | quarkus.ssl.native=true 3 | 4 | # Enable CORS to be able to use the APi from browsers 5 | quarkus.http.cors=true 6 | 7 | # Disable Quarkus Continuous testing and Kafka Dev Service 8 | quarkus.test.continuous-testing=disabled 9 | quarkus.kafka.devservices.enabled=false 10 | 11 | # Quarkus logging configuration 12 | quarkus.log.file.enable=false 13 | quarkus.log.console.enable=true 14 | quarkus.log.console.format=%d{yyyy-MM-dd HH:mm:ss,SSS} %-5p [%c{3.}] (%t) %s%e%n 15 | quarkus.log.console.level=INFO 16 | 17 | # Kafka Streams configuration 18 | quarkus.kafka-streams.bootstrap-servers=localhost:9092 19 | quarkus.kafka-streams.application-id=sentiment-analysis 20 | quarkus.kafka-streams.topics=twitter-search,twitter-alerts 21 | quarkus.kafka-streams.security.protocol=PLAINTEXT 22 | quarkus.kafka-streams.sasl.mechanism="" 23 | quarkus.kafka-streams.sasl.jaas-config="" 24 | quarkus.kafka-streams.ssl.truststore.type=PKCS12 25 | quarkus.kafka-streams.ssl.truststore.location= 26 | quarkus.kafka-streams.ssl.truststore.password= 27 | quarkus.kafka-streams.ssl.truststore.certificates= 28 | quarkus.kafka-streams.ssl.keystore.type=PKCS12 29 | quarkus.kafka-streams.ssl.keystore.location= 30 | quarkus.kafka-streams.ssl.keystore.password= 31 | quarkus.kafka-streams.ssl.keystore.key= 32 | quarkus.kafka-streams.ssl.keystore.certificate-chain= 33 | quarkus.kafka-streams.ssl.endpoint-identification-algorithm=HTTPS 34 | quarkus.kafka-streams.sasl.login-callback-handler-class= 35 | quarkus.kafka-streams.cache.max.bytes.buffering=10240 36 | quarkus.kafka-streams.commit.interval.ms=1000 37 | quarkus.kafka-streams.metadata.max.age.ms=500 38 | quarkus.kafka-streams.auto.offset.reset=earliest 39 | quarkus.kafka-streams.metrics.recording.level=DEBUG 40 | quarkus.kafka-streams.consumer.heartbeat.interval.ms=200 41 | # Use sub-folder of embedded broker, so it gets cleaned by KafkaResource between re-runs 42 | # This does not work for native tests, manually clean-up /tmp/kafka-streams/temperature-aggregator 43 | #%test.kafka-streams.state.dir=target/data/kafka-data/stores 44 | 45 | # Disable health checks 46 | quarkus.kafka-streams.health.enabled=false 47 | -------------------------------------------------------------------------------- /21-alerts.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kafka.strimzi.io/v1beta2 2 | kind: KafkaTopic 3 | metadata: 4 | name: twitter-alerts 5 | labels: 6 | strimzi.io/cluster: my-cluster 7 | spec: 8 | partitions: 1 9 | replicas: 3 10 | config: 11 | retention.ms: 2629800000 12 | segment.bytes: 107374182 13 | --- 14 | 15 | apiVersion: kafka.strimzi.io/v1beta2 16 | kind: KafkaConnector 17 | metadata: 18 | name: twitter-alerts 19 | labels: 20 | strimzi.io/cluster: my-connect 21 | spec: 22 | class: CamelTwittertimelineSinkConnector 23 | tasksMax: 1 24 | config: 25 | topics: twitter-alerts 26 | camel.sink.path.timelineType: user 27 | # Twitter account 28 | camel.sink.endpoint.consumerKey: ${env:TWITTER2_CONSUMER_KEY} 29 | camel.sink.endpoint.consumerSecret: ${env:TWITTER2_CONSUMER_SECRET} 30 | camel.sink.endpoint.accessToken: ${env:TWITTER2_ACCESS_TOKEN} 31 | camel.sink.endpoint.accessTokenSecret: ${env:TWITTER2_ACCESS_TOKEN_SECRET} 32 | # Converting 33 | key.converter: org.apache.kafka.connect.storage.StringConverter 34 | value.converter: org.apache.kafka.connect.storage.StringConverter 35 | key.converter.schemas.enable: false 36 | value.converter.schemas.enable: false 37 | --- 38 | 39 | # Can be used to send the alerts as direct messages instead of sending it as re-tweets to the timeline 40 | # apiVersion: kafka.strimzi.io/v1beta2 41 | # kind: KafkaConnector 42 | # metadata: 43 | # name: twitter-alerts 44 | # labels: 45 | # strimzi.io/cluster: my-connect 46 | # spec: 47 | # class: CamelTwitterdirectmessageSinkConnector 48 | # tasksMax: 1 49 | # config: 50 | # topics: twitter-alerts 51 | # # User to send the alert DM to 52 | # camel.sink.path.user: "7246595" 53 | # # Twitter account 54 | # camel.sink.endpoint.consumerKey: ${env:TWITTER_CONSUMER_KEY} 55 | # camel.sink.endpoint.consumerSecret: ${env:TWITTER_CONSUMER_SECRET} 56 | # camel.sink.endpoint.accessToken: ${env:TWITTER_ACCESS_TOKEN} 57 | # camel.sink.endpoint.accessTokenSecret: ${env:TWITTER_ACCESS_TOKEN_SECRET} 58 | # # Converting 59 | # key.converter: org.apache.kafka.connect.storage.StringConverter 60 | # value.converter: org.apache.kafka.connect.storage.StringConverter 61 | # key.converter.schemas.enable: false 62 | # value.converter.schemas.enable: false -------------------------------------------------------------------------------- /ad-hoc/src/main/docker/Dockerfile.jvm: -------------------------------------------------------------------------------- 1 | #### 2 | # This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode 3 | # 4 | # Before building the container image run: 5 | # 6 | # ./mvnw package 7 | # 8 | # Then, build the image with: 9 | # 10 | # docker build -f src/main/docker/Dockerfile.jvm -t quarkus/amazon-kms-jvm . 11 | # 12 | # Then run the container using: 13 | # 14 | # docker run -i --rm -p 8080:8080 quarkus/amazon-kms-jvm 15 | # 16 | # If you want to include the debug port into your docker image 17 | # you will have to expose the debug port (default 5005) like this : EXPOSE 8080 5050 18 | # 19 | # Then run the container using : 20 | # 21 | # docker run -i --rm -p 8080:8080 -p 5005:5005 -e JAVA_ENABLE_DEBUG="true" quarkus/amazon-kms-jvm 22 | # 23 | ### 24 | FROM registry.access.redhat.com/ubi8/ubi-minimal:8.3 25 | 26 | ARG JAVA_PACKAGE=java-11-openjdk-headless 27 | ARG RUN_JAVA_VERSION=1.3.8 28 | ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' 29 | # Install java and the run-java script 30 | # Also set up permissions for user `1001` 31 | RUN microdnf install curl ca-certificates ${JAVA_PACKAGE} \ 32 | && microdnf update \ 33 | && microdnf clean all \ 34 | && mkdir /deployments \ 35 | && chown 1001 /deployments \ 36 | && chmod "g+rwX" /deployments \ 37 | && chown 1001:root /deployments \ 38 | && curl https://repo1.maven.org/maven2/io/fabric8/run-java-sh/${RUN_JAVA_VERSION}/run-java-sh-${RUN_JAVA_VERSION}-sh.sh -o /deployments/run-java.sh \ 39 | && chown 1001 /deployments/run-java.sh \ 40 | && chmod 540 /deployments/run-java.sh \ 41 | && echo "securerandom.source=file:/dev/urandom" >> /etc/alternatives/jre/lib/security/java.security 42 | 43 | # Configure the JAVA_OPTIONS, you can add -XshowSettings:vm to also display the heap size. 44 | ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" 45 | # We make four distinct layers so if there are application changes the library layers can be re-used 46 | COPY --chown=1001 target/quarkus-app/lib/ /deployments/lib/ 47 | COPY --chown=1001 target/quarkus-app/*.jar /deployments/ 48 | COPY --chown=1001 target/quarkus-app/app/ /deployments/app/ 49 | COPY --chown=1001 target/quarkus-app/quarkus/ /deployments/quarkus/ 50 | 51 | EXPOSE 8080 52 | USER 1001 53 | 54 | ENTRYPOINT [ "/deployments/run-java.sh" ] 55 | -------------------------------------------------------------------------------- /tag-cloud/src/main/docker/Dockerfile.jvm: -------------------------------------------------------------------------------- 1 | #### 2 | # This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode 3 | # 4 | # Before building the container image run: 5 | # 6 | # ./mvnw package 7 | # 8 | # Then, build the image with: 9 | # 10 | # docker build -f src/main/docker/Dockerfile.jvm -t quarkus/amazon-kms-jvm . 11 | # 12 | # Then run the container using: 13 | # 14 | # docker run -i --rm -p 8080:8080 quarkus/amazon-kms-jvm 15 | # 16 | # If you want to include the debug port into your docker image 17 | # you will have to expose the debug port (default 5005) like this : EXPOSE 8080 5050 18 | # 19 | # Then run the container using : 20 | # 21 | # docker run -i --rm -p 8080:8080 -p 5005:5005 -e JAVA_ENABLE_DEBUG="true" quarkus/amazon-kms-jvm 22 | # 23 | ### 24 | FROM registry.access.redhat.com/ubi8/ubi-minimal:8.3 25 | 26 | ARG JAVA_PACKAGE=java-11-openjdk-headless 27 | ARG RUN_JAVA_VERSION=1.3.8 28 | ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' 29 | # Install java and the run-java script 30 | # Also set up permissions for user `1001` 31 | RUN microdnf install curl ca-certificates ${JAVA_PACKAGE} \ 32 | && microdnf update \ 33 | && microdnf clean all \ 34 | && mkdir /deployments \ 35 | && chown 1001 /deployments \ 36 | && chmod "g+rwX" /deployments \ 37 | && chown 1001:root /deployments \ 38 | && curl https://repo1.maven.org/maven2/io/fabric8/run-java-sh/${RUN_JAVA_VERSION}/run-java-sh-${RUN_JAVA_VERSION}-sh.sh -o /deployments/run-java.sh \ 39 | && chown 1001 /deployments/run-java.sh \ 40 | && chmod 540 /deployments/run-java.sh \ 41 | && echo "securerandom.source=file:/dev/urandom" >> /etc/alternatives/jre/lib/security/java.security 42 | 43 | # Configure the JAVA_OPTIONS, you can add -XshowSettings:vm to also display the heap size. 44 | ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" 45 | # We make four distinct layers so if there are application changes the library layers can be re-used 46 | COPY --chown=1001 target/quarkus-app/lib/ /deployments/lib/ 47 | COPY --chown=1001 target/quarkus-app/*.jar /deployments/ 48 | COPY --chown=1001 target/quarkus-app/app/ /deployments/app/ 49 | COPY --chown=1001 target/quarkus-app/quarkus/ /deployments/quarkus/ 50 | 51 | EXPOSE 8080 52 | USER 1001 53 | 54 | ENTRYPOINT [ "/deployments/run-java.sh" ] 55 | -------------------------------------------------------------------------------- /word-cloud/src/main/docker/Dockerfile.jvm: -------------------------------------------------------------------------------- 1 | #### 2 | # This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode 3 | # 4 | # Before building the container image run: 5 | # 6 | # ./mvnw package 7 | # 8 | # Then, build the image with: 9 | # 10 | # docker build -f src/main/docker/Dockerfile.jvm -t quarkus/amazon-kms-jvm . 11 | # 12 | # Then run the container using: 13 | # 14 | # docker run -i --rm -p 8080:8080 quarkus/amazon-kms-jvm 15 | # 16 | # If you want to include the debug port into your docker image 17 | # you will have to expose the debug port (default 5005) like this : EXPOSE 8080 5050 18 | # 19 | # Then run the container using : 20 | # 21 | # docker run -i --rm -p 8080:8080 -p 5005:5005 -e JAVA_ENABLE_DEBUG="true" quarkus/amazon-kms-jvm 22 | # 23 | ### 24 | FROM registry.access.redhat.com/ubi8/ubi-minimal:8.3 25 | 26 | ARG JAVA_PACKAGE=java-11-openjdk-headless 27 | ARG RUN_JAVA_VERSION=1.3.8 28 | ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' 29 | # Install java and the run-java script 30 | # Also set up permissions for user `1001` 31 | RUN microdnf install curl ca-certificates ${JAVA_PACKAGE} \ 32 | && microdnf update \ 33 | && microdnf clean all \ 34 | && mkdir /deployments \ 35 | && chown 1001 /deployments \ 36 | && chmod "g+rwX" /deployments \ 37 | && chown 1001:root /deployments \ 38 | && curl https://repo1.maven.org/maven2/io/fabric8/run-java-sh/${RUN_JAVA_VERSION}/run-java-sh-${RUN_JAVA_VERSION}-sh.sh -o /deployments/run-java.sh \ 39 | && chown 1001 /deployments/run-java.sh \ 40 | && chmod 540 /deployments/run-java.sh \ 41 | && echo "securerandom.source=file:/dev/urandom" >> /etc/alternatives/jre/lib/security/java.security 42 | 43 | # Configure the JAVA_OPTIONS, you can add -XshowSettings:vm to also display the heap size. 44 | ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" 45 | # We make four distinct layers so if there are application changes the library layers can be re-used 46 | COPY --chown=1001 target/quarkus-app/lib/ /deployments/lib/ 47 | COPY --chown=1001 target/quarkus-app/*.jar /deployments/ 48 | COPY --chown=1001 target/quarkus-app/app/ /deployments/app/ 49 | COPY --chown=1001 target/quarkus-app/quarkus/ /deployments/quarkus/ 50 | 51 | EXPOSE 8080 52 | USER 1001 53 | 54 | ENTRYPOINT [ "/deployments/run-java.sh" ] 55 | -------------------------------------------------------------------------------- /sentiment-analysis/src/main/docker/Dockerfile.jvm: -------------------------------------------------------------------------------- 1 | #### 2 | # This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode 3 | # 4 | # Before building the container image run: 5 | # 6 | # ./mvnw package 7 | # 8 | # Then, build the image with: 9 | # 10 | # docker build -f src/main/docker/Dockerfile.jvm -t quarkus/amazon-kms-jvm . 11 | # 12 | # Then run the container using: 13 | # 14 | # docker run -i --rm -p 8080:8080 quarkus/amazon-kms-jvm 15 | # 16 | # If you want to include the debug port into your docker image 17 | # you will have to expose the debug port (default 5005) like this : EXPOSE 8080 5050 18 | # 19 | # Then run the container using : 20 | # 21 | # docker run -i --rm -p 8080:8080 -p 5005:5005 -e JAVA_ENABLE_DEBUG="true" quarkus/amazon-kms-jvm 22 | # 23 | ### 24 | FROM registry.access.redhat.com/ubi8/ubi-minimal:8.3 25 | 26 | ARG JAVA_PACKAGE=java-11-openjdk-headless 27 | ARG RUN_JAVA_VERSION=1.3.8 28 | ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' 29 | # Install java and the run-java script 30 | # Also set up permissions for user `1001` 31 | RUN microdnf install curl ca-certificates ${JAVA_PACKAGE} \ 32 | && microdnf update \ 33 | && microdnf clean all \ 34 | && mkdir /deployments \ 35 | && chown 1001 /deployments \ 36 | && chmod "g+rwX" /deployments \ 37 | && chown 1001:root /deployments \ 38 | && curl https://repo1.maven.org/maven2/io/fabric8/run-java-sh/${RUN_JAVA_VERSION}/run-java-sh-${RUN_JAVA_VERSION}-sh.sh -o /deployments/run-java.sh \ 39 | && chown 1001 /deployments/run-java.sh \ 40 | && chmod 540 /deployments/run-java.sh \ 41 | && echo "securerandom.source=file:/dev/urandom" >> /etc/alternatives/jre/lib/security/java.security 42 | 43 | # Configure the JAVA_OPTIONS, you can add -XshowSettings:vm to also display the heap size. 44 | ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" 45 | # We make four distinct layers so if there are application changes the library layers can be re-used 46 | COPY --chown=1001 target/quarkus-app/lib/ /deployments/lib/ 47 | COPY --chown=1001 target/quarkus-app/*.jar /deployments/ 48 | COPY --chown=1001 target/quarkus-app/app/ /deployments/app/ 49 | COPY --chown=1001 target/quarkus-app/quarkus/ /deployments/quarkus/ 50 | 51 | EXPOSE 8080 52 | USER 1001 53 | 54 | ENTRYPOINT [ "/deployments/run-java.sh" ] 55 | -------------------------------------------------------------------------------- /ad-hoc/src/main/java/cz/scholz/sentimentanalysis/model/Aggregation.java: -------------------------------------------------------------------------------- 1 | package cz.scholz.sentimentanalysis.model; 2 | 3 | import cz.scholz.sentimentanalysis.model.twitter.Tweet; 4 | 5 | import java.math.BigDecimal; 6 | import java.math.RoundingMode; 7 | 8 | public class Aggregation { 9 | public int countWithMedia = 0; 10 | public int countWithoutMedia = 0; 11 | public double avgRetweetsWithMedia = 0; 12 | public double avgRetweetsWithoutMedia = 0; 13 | public double sumRetweetsWithMedia = 0; 14 | public double sumRetweetsWithoutMedia = 0; 15 | 16 | public Aggregation() { 17 | } 18 | 19 | public int getCountWithMedia() { 20 | return countWithMedia; 21 | } 22 | 23 | public int getCountWithoutMedia() { 24 | return countWithoutMedia; 25 | } 26 | 27 | public double getAvgRetweetsWithMedia() { 28 | return avgRetweetsWithMedia; 29 | } 30 | 31 | public double getAvgRetweetsWithoutMedia() { 32 | return avgRetweetsWithoutMedia; 33 | } 34 | 35 | public double getSumRetweetsWithMedia() { 36 | return sumRetweetsWithMedia; 37 | } 38 | 39 | public double getSumRetweetsWithoutMedia() { 40 | return sumRetweetsWithoutMedia; 41 | } 42 | 43 | public Aggregation aggregate(Tweet tweet) { 44 | if (tweet.mediaEntities != null 45 | && tweet.mediaEntities.length > 0) { 46 | // Has media 47 | increaseWithMedia(tweet.getRetweetCount()); 48 | } else { 49 | // Does not have media 50 | increaseWithoutMedia(tweet.getRetweetCount()); 51 | } 52 | 53 | return this; 54 | } 55 | 56 | private void increaseWithMedia(int retweets) { 57 | countWithMedia++; 58 | sumRetweetsWithMedia += retweets; 59 | avgRetweetsWithMedia = BigDecimal.valueOf(sumRetweetsWithMedia / countWithMedia).setScale(1, RoundingMode.HALF_UP).doubleValue(); 60 | } 61 | 62 | private void increaseWithoutMedia(int retweets) { 63 | countWithoutMedia++; 64 | sumRetweetsWithoutMedia += retweets; 65 | avgRetweetsWithoutMedia = BigDecimal.valueOf(sumRetweetsWithoutMedia / countWithoutMedia).setScale(1, RoundingMode.HALF_UP).doubleValue(); 66 | } 67 | 68 | @Override 69 | public String toString() { 70 | return "We have so far:\n\t" + 71 | countWithMedia + " tweets with media with average " + avgRetweetsWithMedia + " retweets\n\t" + 72 | countWithoutMedia + " tweets without media with average " + avgRetweetsWithoutMedia + " retweets\n\t"; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /word-cloud/src/main/resources/META-INF/resources/static.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Word Cloud 5 | 6 | 7 | 8 | 9 | 10 | 22 | 23 | 24 | 30 | 31 |
32 | 33 | 86 | 87 | -------------------------------------------------------------------------------- /tag-cloud/src/main/resources/META-INF/resources/static.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Tag Cloud 5 | 6 | 7 | 8 | 9 | 10 | 22 | 23 | 24 | 30 | 31 |
32 | 33 | 86 | 87 | -------------------------------------------------------------------------------- /tag-cloud/src/main/java/cz/scholz/tagcloud/streams/TopologyProducer.java: -------------------------------------------------------------------------------- 1 | package cz.scholz.tagcloud.streams; 2 | 3 | import cz.scholz.tagcloud.model.TweetSerde; 4 | import org.apache.kafka.common.serialization.Serdes; 5 | import org.apache.kafka.streams.StreamsBuilder; 6 | import org.apache.kafka.streams.Topology; 7 | import org.apache.kafka.streams.kstream.Consumed; 8 | import org.apache.kafka.streams.kstream.Grouped; 9 | import org.apache.kafka.streams.kstream.Materialized; 10 | import org.apache.kafka.streams.state.KeyValueBytesStoreSupplier; 11 | import org.apache.kafka.streams.state.Stores; 12 | import org.eclipse.microprofile.config.inject.ConfigProperty; 13 | 14 | import javax.enterprise.context.ApplicationScoped; 15 | import javax.enterprise.inject.Produces; 16 | import java.util.Arrays; 17 | import java.util.List; 18 | 19 | @ApplicationScoped 20 | public class TopologyProducer { 21 | static final String TAG_CLOUD_STORE = "tag-cloud-store"; 22 | 23 | @ConfigProperty(name = "quarkus.kafka-streams.topics") 24 | String tweetsTopic; 25 | 26 | @Produces 27 | public Topology buildTopology() { 28 | final TweetSerde tweetSerde = new TweetSerde(); 29 | final KeyValueBytesStoreSupplier storeSupplier = Stores.persistentKeyValueStore(TAG_CLOUD_STORE); 30 | 31 | final StreamsBuilder builder = new StreamsBuilder(); 32 | 33 | builder.stream(tweetsTopic, Consumed.with(Serdes.ByteArray(), tweetSerde)) 34 | .flatMapValues(value -> { 35 | if (value.getRetweetedStatus() != null) { 36 | return List.of(value.getRetweetedStatus().getText()); 37 | } else if (value.getQuotedStatus() != null) { 38 | return List.of(value.getQuotedStatus().getText(), value.getText()); 39 | } else { 40 | return List.of(value.getText()); 41 | } 42 | }) 43 | .flatMapValues(value -> Arrays.asList(value.toLowerCase().split("\\s+"))) 44 | .filter((key, value) -> value != null && (value.startsWith("#") || value.startsWith("@"))) 45 | .mapValues(TopologyProducer::stripSpecialCharactersFromTheEnd) 46 | .filter((key, value) -> !value.isEmpty()) 47 | .groupBy((key, value) -> value, Grouped.with(Serdes.String(), Serdes.String())) 48 | .count(Materialized.as(storeSupplier) 49 | .withKeySerde(Serdes.String()) 50 | .withValueSerde(Serdes.Long())); 51 | 52 | return builder.build(); 53 | } 54 | 55 | /** 56 | * Strips special characters from the end of the word. This removes things such as ":" or "." etc. 57 | * 58 | * @param word The word which should be striped 59 | * 60 | * @return The striped word 61 | */ 62 | static String stripSpecialCharactersFromTheEnd(String word) { 63 | return word.replaceAll("\\W+$", ""); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /22-sentiment-analysis.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kafka.strimzi.io/v1beta2 2 | kind: KafkaUser 3 | metadata: 4 | name: sentiment-analysis 5 | labels: 6 | strimzi.io/cluster: my-cluster 7 | spec: 8 | authentication: 9 | type: tls 10 | authorization: 11 | type: simple 12 | acls: 13 | # Source topic 14 | - resource: 15 | type: topic 16 | name: twitter-search 17 | operation: Read 18 | # Group used by the Kafka Streams app 19 | - resource: 20 | type: group 21 | name: sentiment-analysis 22 | operation: Read 23 | # Target topic 24 | - resource: 25 | type: topic 26 | name: twitter-alerts 27 | operation: Write 28 | --- 29 | 30 | apiVersion: apps/v1 31 | kind: Deployment 32 | metadata: 33 | labels: 34 | app: sentiment-analysis 35 | name: sentiment-analysis 36 | spec: 37 | replicas: 1 38 | selector: 39 | matchLabels: 40 | app: sentiment-analysis 41 | template: 42 | metadata: 43 | labels: 44 | app: sentiment-analysis 45 | spec: 46 | containers: 47 | - name: sentiment-analysis 48 | image: ghcr.io/scholzj/build-your-own-social-media-analytics-with-apache-kafka-sentiment-analysis:latest 49 | env: 50 | - name: QUARKUS_KAFKA_STREAMS_BOOTSTRAP_SERVERS 51 | value: my-cluster-kafka-bootstrap:9093 52 | - name: QUARKUS_KAFKA_STREAMS_APPLICATION_ID 53 | value: sentiment-analysis 54 | - name: QUARKUS_KAFKA_STREAMS_SECURITY_PROTOCOL 55 | value: SSL 56 | - name: QUARKUS_KAFKA_STREAMS_SSL_TRUSTSTORE_TYPE 57 | value: PKCS12 58 | - name: QUARKUS_KAFKA_STREAMS_SSL_TRUSTSTORE_LOCATION 59 | value: /etc/truststore/ca.p12 60 | - name: QUARKUS_KAFKA_STREAMS_SSL_TRUSTSTORE_PASSWORD 61 | valueFrom: 62 | secretKeyRef: 63 | name: my-cluster-cluster-ca-cert 64 | key: ca.password 65 | - name: QUARKUS_KAFKA_STREAMS_SSL_KEYSTORE_TYPE 66 | value: PKCS12 67 | - name: QUARKUS_KAFKA_STREAMS_SSL_KEYSTORE_LOCATION 68 | value: /etc/keystore/user.p12 69 | - name: QUARKUS_KAFKA_STREAMS_SSL_KEYSTORE_PASSWORD 70 | valueFrom: 71 | secretKeyRef: 72 | name: sentiment-analysis 73 | key: user.password 74 | volumeMounts: 75 | - name: truststore 76 | mountPath: "/etc/truststore" 77 | readOnly: true 78 | - name: keystore 79 | mountPath: "/etc/keystore" 80 | readOnly: true 81 | volumes: 82 | - name: truststore 83 | secret: 84 | secretName: my-cluster-cluster-ca-cert 85 | items: 86 | - key: ca.p12 87 | path: ca.p12 88 | - name: keystore 89 | secret: 90 | secretName: sentiment-analysis 91 | items: 92 | - key: user.p12 93 | path: user.p12 94 | --- 95 | -------------------------------------------------------------------------------- /tag-cloud/src/main/java/cz/scholz/tagcloud/streams/InteractiveQueries.java: -------------------------------------------------------------------------------- 1 | package cz.scholz.tagcloud.streams; 2 | 3 | import java.util.List; 4 | import java.util.Map; 5 | import java.util.TreeSet; 6 | import java.util.stream.Collectors; 7 | 8 | import javax.enterprise.context.ApplicationScoped; 9 | import javax.inject.Inject; 10 | 11 | import org.apache.kafka.common.TopicPartition; 12 | import org.apache.kafka.streams.KafkaStreams; 13 | import org.apache.kafka.streams.KeyValue; 14 | import org.apache.kafka.streams.StoreQueryParameters; 15 | import org.apache.kafka.streams.errors.InvalidStateStoreException; 16 | import org.apache.kafka.streams.state.KeyValueIterator; 17 | import org.apache.kafka.streams.state.QueryableStoreTypes; 18 | import org.apache.kafka.streams.state.ReadOnlyKeyValueStore; 19 | import org.jboss.logging.Logger; 20 | 21 | @ApplicationScoped 22 | public class InteractiveQueries { 23 | private static final Logger LOG = Logger.getLogger(InteractiveQueries.class); 24 | 25 | @Inject 26 | KafkaStreams streams; 27 | 28 | public Map getAllTimeHighest(int count) { 29 | LOG.infov("Finding all-time top {0} words", count); 30 | return getHighestN(count, TopologyProducer.TAG_CLOUD_STORE); 31 | } 32 | 33 | private Map getHighestN(int count, String storeName) { 34 | //noinspection ComparatorMethodParameterNotUsed 35 | TreeSet> topResults = new TreeSet<>((w1, w2) -> w1.value > w2.value ? 1 : -1); 36 | KeyValueIterator all = getTagCloudStore(storeName).all(); 37 | 38 | while (all.hasNext()) { 39 | KeyValue next = all.next(); 40 | topResults.add(next); 41 | 42 | if (topResults.size() > count) { 43 | topResults.pollFirst(); 44 | } 45 | } 46 | 47 | return topResults.stream().collect(Collectors.toMap(keyValue -> keyValue.key, keyValue -> keyValue.value)); 48 | } 49 | 50 | private ReadOnlyKeyValueStore getTagCloudStore(String storeName) { 51 | while (true) { 52 | try { 53 | return streams.store(StoreQueryParameters.fromNameAndType(storeName, QueryableStoreTypes.keyValueStore())); 54 | } catch (InvalidStateStoreException e) { 55 | // store not ready yet 56 | } 57 | } 58 | } 59 | 60 | public List getAllTimeMetaData() { 61 | return getMetaData(TopologyProducer.TAG_CLOUD_STORE); 62 | } 63 | 64 | private List getMetaData(String storeName) { 65 | return streams.streamsMetadataForStore(storeName) 66 | .stream() 67 | .map(m -> new PipelineMetadata( 68 | m.hostInfo().host() + ":" + m.hostInfo().port(), 69 | m.topicPartitions() 70 | .stream() 71 | .map(TopicPartition::toString) 72 | .collect(Collectors.toSet()))) 73 | .collect(Collectors.toList()); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /word-cloud/src/main/java/cz/scholz/wordcloud/streams/InteractiveQueries.java: -------------------------------------------------------------------------------- 1 | package cz.scholz.wordcloud.streams; 2 | 3 | import org.apache.kafka.common.TopicPartition; 4 | import org.apache.kafka.streams.KafkaStreams; 5 | import org.apache.kafka.streams.KeyValue; 6 | import org.apache.kafka.streams.StoreQueryParameters; 7 | import org.apache.kafka.streams.errors.InvalidStateStoreException; 8 | import org.apache.kafka.streams.state.KeyValueIterator; 9 | import org.apache.kafka.streams.state.QueryableStoreTypes; 10 | import org.apache.kafka.streams.state.ReadOnlyKeyValueStore; 11 | import org.jboss.logging.Logger; 12 | 13 | import javax.enterprise.context.ApplicationScoped; 14 | import javax.inject.Inject; 15 | import java.util.List; 16 | import java.util.Map; 17 | import java.util.TreeSet; 18 | import java.util.stream.Collectors; 19 | 20 | @ApplicationScoped 21 | public class InteractiveQueries { 22 | private static final Logger LOG = Logger.getLogger(InteractiveQueries.class); 23 | 24 | @Inject 25 | KafkaStreams streams; 26 | 27 | public Map getAllTimeHighest(int count) { 28 | LOG.infov("Finding all-time top {0} words", count); 29 | return getHighestN(count, TopologyProducer.WORD_CLOUD_STORE); 30 | } 31 | 32 | private Map getHighestN(int count, String storeName) { 33 | //noinspection ComparatorMethodParameterNotUsed 34 | TreeSet> topResults = new TreeSet<>((w1, w2) -> w1.value > w2.value ? 1 : -1); 35 | KeyValueIterator all = getWordCloudStore(storeName).all(); 36 | 37 | while (all.hasNext()) { 38 | KeyValue next = all.next(); 39 | topResults.add(next); 40 | 41 | if (topResults.size() > count) { 42 | topResults.pollFirst(); 43 | } 44 | } 45 | 46 | all.close(); 47 | 48 | return topResults.stream().collect(Collectors.toMap(keyValue -> keyValue.key, keyValue -> keyValue.value)); 49 | } 50 | 51 | private ReadOnlyKeyValueStore getWordCloudStore(String storeName) { 52 | while (true) { 53 | try { 54 | return streams.store(StoreQueryParameters.fromNameAndType(storeName, QueryableStoreTypes.keyValueStore())); 55 | } catch (InvalidStateStoreException e) { 56 | // store not ready yet 57 | } 58 | } 59 | } 60 | 61 | public List getAllTimeMetaData() { 62 | return getMetaData(TopologyProducer.WORD_CLOUD_STORE); 63 | } 64 | 65 | private List getMetaData(String storeName) { 66 | return streams.streamsMetadataForStore(storeName) 67 | .stream() 68 | .map(m -> new PipelineMetadata( 69 | m.hostInfo().host() + ":" + m.hostInfo().port(), 70 | m.topicPartitions() 71 | .stream() 72 | .map(TopicPartition::toString) 73 | .collect(Collectors.toSet()))) 74 | .collect(Collectors.toList()); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /tag-cloud/src/main/resources/META-INF/resources/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Tag Cloud 5 | 6 | 7 | 8 | 9 | 10 | 22 | 23 | 24 | 30 | 31 |
32 | 33 | 92 | 93 | -------------------------------------------------------------------------------- /word-cloud/src/main/resources/META-INF/resources/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Word Cloud 5 | 6 | 7 | 8 | 9 | 10 | 22 | 23 | 24 | 30 | 31 |
32 | 33 | 92 | 93 | -------------------------------------------------------------------------------- /tag-cloud/src/main/java/cz/scholz/tagcloud/model/twitter/Place.java: -------------------------------------------------------------------------------- 1 | package cz.scholz.tagcloud.model.twitter; 2 | 3 | import io.quarkus.runtime.annotations.RegisterForReflection; 4 | 5 | @RegisterForReflection 6 | public class Place { 7 | public RateLimitStatus rateLimitStatus; 8 | public int accessLevel = 0; 9 | public String name; 10 | public String streetAddress; 11 | public String countryCode; 12 | public String id; 13 | public String country; 14 | public String placeType; 15 | public String url; 16 | public String fullName; 17 | public String boundingBoxType; 18 | public GeoLocation[][] boundingBoxCoordinates; 19 | public String geometryType; 20 | public GeoLocation[][] geometryCoordinates; 21 | public Place[] containedWithIn; 22 | 23 | public Place() { 24 | } 25 | 26 | public Place(RateLimitStatus rateLimitStatus, int accessLevel, String name, String streetAddress, String countryCode, String id, String country, String placeType, String url, String fullName, String boundingBoxType, GeoLocation[][] boundingBoxCoordinates, String geometryType, GeoLocation[][] geometryCoordinates, Place[] containedWithIn) { 27 | this.rateLimitStatus = rateLimitStatus; 28 | this.accessLevel = accessLevel; 29 | this.name = name; 30 | this.streetAddress = streetAddress; 31 | this.countryCode = countryCode; 32 | this.id = id; 33 | this.country = country; 34 | this.placeType = placeType; 35 | this.url = url; 36 | this.fullName = fullName; 37 | this.boundingBoxType = boundingBoxType; 38 | this.boundingBoxCoordinates = boundingBoxCoordinates; 39 | this.geometryType = geometryType; 40 | this.geometryCoordinates = geometryCoordinates; 41 | this.containedWithIn = containedWithIn; 42 | } 43 | 44 | public RateLimitStatus getRateLimitStatus() { 45 | return rateLimitStatus; 46 | } 47 | 48 | public int getAccessLevel() { 49 | return accessLevel; 50 | } 51 | 52 | public String getName() { 53 | return name; 54 | } 55 | 56 | public String getStreetAddress() { 57 | return streetAddress; 58 | } 59 | 60 | public String getCountryCode() { 61 | return countryCode; 62 | } 63 | 64 | public String getId() { 65 | return id; 66 | } 67 | 68 | public String getCountry() { 69 | return country; 70 | } 71 | 72 | public String getPlaceType() { 73 | return placeType; 74 | } 75 | 76 | public String getUrl() { 77 | return url; 78 | } 79 | 80 | public String getFullName() { 81 | return fullName; 82 | } 83 | 84 | public String getBoundingBoxType() { 85 | return boundingBoxType; 86 | } 87 | 88 | public GeoLocation[][] getBoundingBoxCoordinates() { 89 | return boundingBoxCoordinates; 90 | } 91 | 92 | public String getGeometryType() { 93 | return geometryType; 94 | } 95 | 96 | public GeoLocation[][] getGeometryCoordinates() { 97 | return geometryCoordinates; 98 | } 99 | 100 | public Place[] getContainedWithIn() { 101 | return containedWithIn; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /word-cloud/src/main/java/cz/scholz/wordcloud/model/twitter/Place.java: -------------------------------------------------------------------------------- 1 | package cz.scholz.wordcloud.model.twitter; 2 | 3 | import io.quarkus.runtime.annotations.RegisterForReflection; 4 | 5 | @RegisterForReflection 6 | public class Place { 7 | public RateLimitStatus rateLimitStatus; 8 | public int accessLevel = 0; 9 | public String name; 10 | public String streetAddress; 11 | public String countryCode; 12 | public String id; 13 | public String country; 14 | public String placeType; 15 | public String url; 16 | public String fullName; 17 | public String boundingBoxType; 18 | public GeoLocation[][] boundingBoxCoordinates; 19 | public String geometryType; 20 | public GeoLocation[][] geometryCoordinates; 21 | public Place[] containedWithIn; 22 | 23 | public Place() { 24 | } 25 | 26 | public Place(RateLimitStatus rateLimitStatus, int accessLevel, String name, String streetAddress, String countryCode, String id, String country, String placeType, String url, String fullName, String boundingBoxType, GeoLocation[][] boundingBoxCoordinates, String geometryType, GeoLocation[][] geometryCoordinates, Place[] containedWithIn) { 27 | this.rateLimitStatus = rateLimitStatus; 28 | this.accessLevel = accessLevel; 29 | this.name = name; 30 | this.streetAddress = streetAddress; 31 | this.countryCode = countryCode; 32 | this.id = id; 33 | this.country = country; 34 | this.placeType = placeType; 35 | this.url = url; 36 | this.fullName = fullName; 37 | this.boundingBoxType = boundingBoxType; 38 | this.boundingBoxCoordinates = boundingBoxCoordinates; 39 | this.geometryType = geometryType; 40 | this.geometryCoordinates = geometryCoordinates; 41 | this.containedWithIn = containedWithIn; 42 | } 43 | 44 | public RateLimitStatus getRateLimitStatus() { 45 | return rateLimitStatus; 46 | } 47 | 48 | public int getAccessLevel() { 49 | return accessLevel; 50 | } 51 | 52 | public String getName() { 53 | return name; 54 | } 55 | 56 | public String getStreetAddress() { 57 | return streetAddress; 58 | } 59 | 60 | public String getCountryCode() { 61 | return countryCode; 62 | } 63 | 64 | public String getId() { 65 | return id; 66 | } 67 | 68 | public String getCountry() { 69 | return country; 70 | } 71 | 72 | public String getPlaceType() { 73 | return placeType; 74 | } 75 | 76 | public String getUrl() { 77 | return url; 78 | } 79 | 80 | public String getFullName() { 81 | return fullName; 82 | } 83 | 84 | public String getBoundingBoxType() { 85 | return boundingBoxType; 86 | } 87 | 88 | public GeoLocation[][] getBoundingBoxCoordinates() { 89 | return boundingBoxCoordinates; 90 | } 91 | 92 | public String getGeometryType() { 93 | return geometryType; 94 | } 95 | 96 | public GeoLocation[][] getGeometryCoordinates() { 97 | return geometryCoordinates; 98 | } 99 | 100 | public Place[] getContainedWithIn() { 101 | return containedWithIn; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /ad-hoc/src/main/java/cz/scholz/sentimentanalysis/model/twitter/Place.java: -------------------------------------------------------------------------------- 1 | package cz.scholz.sentimentanalysis.model.twitter; 2 | 3 | import io.quarkus.runtime.annotations.RegisterForReflection; 4 | 5 | @RegisterForReflection 6 | public class Place { 7 | public RateLimitStatus rateLimitStatus; 8 | public int accessLevel = 0; 9 | public String name; 10 | public String streetAddress; 11 | public String countryCode; 12 | public String id; 13 | public String country; 14 | public String placeType; 15 | public String url; 16 | public String fullName; 17 | public String boundingBoxType; 18 | public GeoLocation[][] boundingBoxCoordinates; 19 | public String geometryType; 20 | public GeoLocation[][] geometryCoordinates; 21 | public Place[] containedWithIn; 22 | 23 | public Place() { 24 | } 25 | 26 | public Place(RateLimitStatus rateLimitStatus, int accessLevel, String name, String streetAddress, String countryCode, String id, String country, String placeType, String url, String fullName, String boundingBoxType, GeoLocation[][] boundingBoxCoordinates, String geometryType, GeoLocation[][] geometryCoordinates, Place[] containedWithIn) { 27 | this.rateLimitStatus = rateLimitStatus; 28 | this.accessLevel = accessLevel; 29 | this.name = name; 30 | this.streetAddress = streetAddress; 31 | this.countryCode = countryCode; 32 | this.id = id; 33 | this.country = country; 34 | this.placeType = placeType; 35 | this.url = url; 36 | this.fullName = fullName; 37 | this.boundingBoxType = boundingBoxType; 38 | this.boundingBoxCoordinates = boundingBoxCoordinates; 39 | this.geometryType = geometryType; 40 | this.geometryCoordinates = geometryCoordinates; 41 | this.containedWithIn = containedWithIn; 42 | } 43 | 44 | public RateLimitStatus getRateLimitStatus() { 45 | return rateLimitStatus; 46 | } 47 | 48 | public int getAccessLevel() { 49 | return accessLevel; 50 | } 51 | 52 | public String getName() { 53 | return name; 54 | } 55 | 56 | public String getStreetAddress() { 57 | return streetAddress; 58 | } 59 | 60 | public String getCountryCode() { 61 | return countryCode; 62 | } 63 | 64 | public String getId() { 65 | return id; 66 | } 67 | 68 | public String getCountry() { 69 | return country; 70 | } 71 | 72 | public String getPlaceType() { 73 | return placeType; 74 | } 75 | 76 | public String getUrl() { 77 | return url; 78 | } 79 | 80 | public String getFullName() { 81 | return fullName; 82 | } 83 | 84 | public String getBoundingBoxType() { 85 | return boundingBoxType; 86 | } 87 | 88 | public GeoLocation[][] getBoundingBoxCoordinates() { 89 | return boundingBoxCoordinates; 90 | } 91 | 92 | public String getGeometryType() { 93 | return geometryType; 94 | } 95 | 96 | public GeoLocation[][] getGeometryCoordinates() { 97 | return geometryCoordinates; 98 | } 99 | 100 | public Place[] getContainedWithIn() { 101 | return containedWithIn; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /sentiment-analysis/src/main/java/cz/scholz/sentimentanalysis/model/twitter/Place.java: -------------------------------------------------------------------------------- 1 | package cz.scholz.sentimentanalysis.model.twitter; 2 | 3 | import io.quarkus.runtime.annotations.RegisterForReflection; 4 | 5 | @RegisterForReflection 6 | public class Place { 7 | public RateLimitStatus rateLimitStatus; 8 | public int accessLevel = 0; 9 | public String name; 10 | public String streetAddress; 11 | public String countryCode; 12 | public String id; 13 | public String country; 14 | public String placeType; 15 | public String url; 16 | public String fullName; 17 | public String boundingBoxType; 18 | public GeoLocation[][] boundingBoxCoordinates; 19 | public String geometryType; 20 | public GeoLocation[][] geometryCoordinates; 21 | public Place[] containedWithIn; 22 | 23 | public Place() { 24 | } 25 | 26 | public Place(RateLimitStatus rateLimitStatus, int accessLevel, String name, String streetAddress, String countryCode, String id, String country, String placeType, String url, String fullName, String boundingBoxType, GeoLocation[][] boundingBoxCoordinates, String geometryType, GeoLocation[][] geometryCoordinates, Place[] containedWithIn) { 27 | this.rateLimitStatus = rateLimitStatus; 28 | this.accessLevel = accessLevel; 29 | this.name = name; 30 | this.streetAddress = streetAddress; 31 | this.countryCode = countryCode; 32 | this.id = id; 33 | this.country = country; 34 | this.placeType = placeType; 35 | this.url = url; 36 | this.fullName = fullName; 37 | this.boundingBoxType = boundingBoxType; 38 | this.boundingBoxCoordinates = boundingBoxCoordinates; 39 | this.geometryType = geometryType; 40 | this.geometryCoordinates = geometryCoordinates; 41 | this.containedWithIn = containedWithIn; 42 | } 43 | 44 | public RateLimitStatus getRateLimitStatus() { 45 | return rateLimitStatus; 46 | } 47 | 48 | public int getAccessLevel() { 49 | return accessLevel; 50 | } 51 | 52 | public String getName() { 53 | return name; 54 | } 55 | 56 | public String getStreetAddress() { 57 | return streetAddress; 58 | } 59 | 60 | public String getCountryCode() { 61 | return countryCode; 62 | } 63 | 64 | public String getId() { 65 | return id; 66 | } 67 | 68 | public String getCountry() { 69 | return country; 70 | } 71 | 72 | public String getPlaceType() { 73 | return placeType; 74 | } 75 | 76 | public String getUrl() { 77 | return url; 78 | } 79 | 80 | public String getFullName() { 81 | return fullName; 82 | } 83 | 84 | public String getBoundingBoxType() { 85 | return boundingBoxType; 86 | } 87 | 88 | public GeoLocation[][] getBoundingBoxCoordinates() { 89 | return boundingBoxCoordinates; 90 | } 91 | 92 | public String getGeometryType() { 93 | return geometryType; 94 | } 95 | 96 | public GeoLocation[][] getGeometryCoordinates() { 97 | return geometryCoordinates; 98 | } 99 | 100 | public Place[] getContainedWithIn() { 101 | return containedWithIn; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /word-cloud/src/main/java/cz/scholz/wordcloud/streams/TopologyProducer.java: -------------------------------------------------------------------------------- 1 | package cz.scholz.wordcloud.streams; 2 | 3 | import cz.scholz.wordcloud.model.TweetSerde; 4 | import org.apache.kafka.common.serialization.Serdes; 5 | import org.apache.kafka.streams.StreamsBuilder; 6 | import org.apache.kafka.streams.Topology; 7 | import org.apache.kafka.streams.kstream.Consumed; 8 | import org.apache.kafka.streams.kstream.Grouped; 9 | import org.apache.kafka.streams.kstream.Materialized; 10 | import org.apache.kafka.streams.state.KeyValueBytesStoreSupplier; 11 | import org.apache.kafka.streams.state.Stores; 12 | import org.eclipse.microprofile.config.inject.ConfigProperty; 13 | import org.jboss.logging.Logger; 14 | 15 | import javax.enterprise.context.ApplicationScoped; 16 | import javax.enterprise.inject.Produces; 17 | import java.util.Arrays; 18 | import java.util.List; 19 | 20 | @ApplicationScoped 21 | public class TopologyProducer { 22 | private static final Logger LOG = Logger.getLogger(TopologyProducer.class); 23 | 24 | static final List IGNORED_WORDS = List.of("about", "then", "than", "this", "that", "from", "with", "been", 25 | "more", "your", "should", "it's", "i've", "have", "will", "here", "come", "some", "when", "that's", "what", 26 | "like", "just", "they", "their", "many", "which", "give", "them", "first", "today", "time", "last", "live", 27 | "over", "going", "after", "look", "could", "back", "join", "next"); 28 | 29 | static final String WORD_CLOUD_STORE = "word-cloud-store"; 30 | 31 | @ConfigProperty(name = "quarkus.kafka-streams.topics") 32 | String tweetsTopic; 33 | 34 | @Produces 35 | public Topology buildTopology() { 36 | final TweetSerde tweetSerde = new TweetSerde(); 37 | final KeyValueBytesStoreSupplier storeSupplier = Stores.persistentKeyValueStore(WORD_CLOUD_STORE); 38 | 39 | final StreamsBuilder builder = new StreamsBuilder(); 40 | 41 | builder.stream(tweetsTopic, Consumed.with(Serdes.ByteArray(), tweetSerde)) 42 | .flatMapValues(value -> { 43 | if (value.getRetweetedStatus() != null) { 44 | return List.of(value.getRetweetedStatus().getText()); 45 | } else if (value.getQuotedStatus() != null) { 46 | return List.of(value.getQuotedStatus().getText(), value.getText()); 47 | } else { 48 | return List.of(value.getText()); 49 | } 50 | }) 51 | .flatMapValues(value -> Arrays.asList(value.toLowerCase().split("\\s+"))) 52 | .filter((key, value) -> 53 | value.length() > 3 // Longer than 3 characters 54 | && !IGNORED_WORDS.contains(value) // Not on an ignored words list 55 | && !value.startsWith("http://") // Not an HTTP link 56 | && !value.startsWith("https://") // Not an HTTPS link 57 | ) 58 | .mapValues(TopologyProducer::stripSpecialCharacters) 59 | .filter((key, value) -> !value.isEmpty()) 60 | .groupBy((key, value) -> value, Grouped.with(Serdes.String(), Serdes.String())) 61 | .count(Materialized.as(storeSupplier) 62 | .withKeySerde(Serdes.String()) 63 | .withValueSerde(Serdes.Long())); 64 | 65 | return builder.build(); 66 | } 67 | 68 | /** 69 | * Strips special characters from the start or end of the word. This removes things such as ":" or "." etc. 70 | * 71 | * @param word The word which should be striped 72 | * 73 | * @return The striped word 74 | */ 75 | static String stripSpecialCharacters(String word) { 76 | return word.replaceAll("^\\W+", "").replaceAll("\\W+$", ""); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /sentiment-analysis/src/main/java/cz/scholz/sentimentanalysis/streams/TopologyProducer.java: -------------------------------------------------------------------------------- 1 | package cz.scholz.sentimentanalysis.streams; 2 | 3 | import ai.djl.Application; 4 | import ai.djl.MalformedModelException; 5 | import ai.djl.inference.Predictor; 6 | import ai.djl.modality.Classifications; 7 | import ai.djl.repository.zoo.Criteria; 8 | import ai.djl.repository.zoo.ModelNotFoundException; 9 | import ai.djl.repository.zoo.ModelZoo; 10 | import ai.djl.translate.TranslateException; 11 | import cz.scholz.sentimentanalysis.model.TweetSerde; 12 | import org.apache.kafka.common.serialization.Serdes; 13 | import org.apache.kafka.streams.StreamsBuilder; 14 | import org.apache.kafka.streams.Topology; 15 | import org.apache.kafka.streams.kstream.Consumed; 16 | import org.apache.kafka.streams.kstream.Produced; 17 | import org.jboss.logging.Logger; 18 | 19 | import javax.enterprise.context.ApplicationScoped; 20 | import javax.enterprise.inject.Produces; 21 | import java.io.IOException; 22 | import java.util.List; 23 | import java.util.Locale; 24 | 25 | @ApplicationScoped 26 | public class TopologyProducer { 27 | private static final Logger LOG = Logger.getLogger(TopologyProducer.class); 28 | 29 | private static final String SOURCE_TOPIC = "twitter-search"; 30 | private static final String TARGET_TOPIC = "twitter-alerts"; 31 | 32 | private static Predictor predictor; 33 | 34 | @Produces 35 | public Topology buildTopology() { 36 | final TweetSerde tweetSerde = new TweetSerde(); 37 | try { 38 | Criteria criteria = Criteria.builder() 39 | .optApplication(Application.NLP.SENTIMENT_ANALYSIS) 40 | .setTypes(String.class, Classifications.class) 41 | .build(); 42 | predictor = ModelZoo.loadModel(criteria).newPredictor(); 43 | } catch (IOException | ModelNotFoundException | MalformedModelException e) { 44 | LOG.error("Failed to load model", e); 45 | throw new RuntimeException("Failed to load model", e); 46 | } 47 | 48 | final StreamsBuilder builder = new StreamsBuilder(); 49 | 50 | builder.stream(SOURCE_TOPIC, Consumed.with(Serdes.ByteArray(), tweetSerde)) 51 | .flatMapValues(value -> { 52 | if (value.getRetweetedStatus() != null) { 53 | // We ignore retweets => we do not want alert for every retweet 54 | return List.of(); 55 | } else { 56 | String tweet = value.getText(); 57 | 58 | try { 59 | Classifications classifications = predictor.predict(tweet); 60 | 61 | String statusUrl = "https://twitter.com/" + value.getUser().getScreenName() + "/status/" + value.getId(); 62 | String alert = String.format("The following tweet was classified as %s with %2.2f%% probability: %s", 63 | classifications.best().getClassName().toLowerCase(Locale.ENGLISH), 64 | classifications.best().getProbability() * 100, 65 | statusUrl); 66 | 67 | // We care nly about strong results where probability is > 50% 68 | if (classifications.best().getProbability() > 0.50) { 69 | LOG.infov("Tweeting: {0}", alert); 70 | return List.of(alert); 71 | } else { 72 | LOG.infov("Not tweeting: {0}", alert); 73 | return List.of(); 74 | } 75 | } catch (TranslateException e) { 76 | LOG.errorv("Failed to classify the tweet {0}", value); 77 | return List.of(); 78 | } 79 | } 80 | }) 81 | .peek((key, value) -> LOG.infov("{0}", value)) 82 | .to(TARGET_TOPIC, Produced.with(Serdes.ByteArray(), Serdes.String())); 83 | 84 | return builder.build(); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /12-timeline-tag-cloud.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kafka.strimzi.io/v1beta2 2 | kind: KafkaUser 3 | metadata: 4 | name: timeline-tag-cloud 5 | labels: 6 | strimzi.io/cluster: my-cluster 7 | spec: 8 | authentication: 9 | type: tls 10 | authorization: 11 | type: simple 12 | acls: 13 | # Source topic 14 | - resource: 15 | type: topic 16 | name: twitter-timeline 17 | operation: Read 18 | # Group used by the Kafka Streams app 19 | - resource: 20 | type: group 21 | name: timeline-tag-cloud 22 | operation: Read 23 | # Streams topics 24 | - resource: 25 | type: topic 26 | name: timeline-tag-cloud- 27 | patternType: prefix 28 | operation: Write 29 | - resource: 30 | type: topic 31 | name: timeline-tag-cloud- 32 | patternType: prefix 33 | operation: Read 34 | - resource: 35 | type: topic 36 | name: timeline-tag-cloud- 37 | patternType: prefix 38 | operation: Create 39 | --- 40 | 41 | apiVersion: apps/v1 42 | kind: Deployment 43 | metadata: 44 | labels: 45 | app: timeline-tag-cloud 46 | name: timeline-tag-cloud 47 | spec: 48 | replicas: 1 49 | selector: 50 | matchLabels: 51 | app: timeline-tag-cloud 52 | template: 53 | metadata: 54 | labels: 55 | app: timeline-tag-cloud 56 | spec: 57 | containers: 58 | - name: timeline-tag-cloud 59 | image: ghcr.io/scholzj/build-your-own-social-media-analytics-with-apache-kafka-tag-cloud:latest 60 | env: 61 | - name: QUARKUS_KAFKA_STREAMS_BOOTSTRAP_SERVERS 62 | value: my-cluster-kafka-bootstrap:9093 63 | - name: QUARKUS_KAFKA_STREAMS_APPLICATION_ID 64 | value: timeline-tag-cloud 65 | - name: QUARKUS_KAFKA_STREAMS_TOPICS 66 | value: twitter-timeline 67 | - name: QUARKUS_KAFKA_STREAMS_SECURITY_PROTOCOL 68 | value: SSL 69 | - name: QUARKUS_KAFKA_STREAMS_SSL_TRUSTSTORE_TYPE 70 | value: PKCS12 71 | - name: QUARKUS_KAFKA_STREAMS_SSL_TRUSTSTORE_LOCATION 72 | value: /etc/truststore/ca.p12 73 | - name: QUARKUS_KAFKA_STREAMS_SSL_TRUSTSTORE_PASSWORD 74 | valueFrom: 75 | secretKeyRef: 76 | name: my-cluster-cluster-ca-cert 77 | key: ca.password 78 | - name: QUARKUS_KAFKA_STREAMS_SSL_KEYSTORE_TYPE 79 | value: PKCS12 80 | - name: QUARKUS_KAFKA_STREAMS_SSL_KEYSTORE_LOCATION 81 | value: /etc/keystore/user.p12 82 | - name: QUARKUS_KAFKA_STREAMS_SSL_KEYSTORE_PASSWORD 83 | valueFrom: 84 | secretKeyRef: 85 | name: timeline-tag-cloud 86 | key: user.password 87 | volumeMounts: 88 | - name: truststore 89 | mountPath: "/etc/truststore" 90 | readOnly: true 91 | - name: keystore 92 | mountPath: "/etc/keystore" 93 | readOnly: true 94 | ports: 95 | - containerPort: 8080 96 | volumes: 97 | - name: truststore 98 | secret: 99 | secretName: my-cluster-cluster-ca-cert 100 | items: 101 | - key: ca.p12 102 | path: ca.p12 103 | - name: keystore 104 | secret: 105 | secretName: timeline-tag-cloud 106 | items: 107 | - key: user.p12 108 | path: user.p12 109 | --- 110 | 111 | apiVersion: v1 112 | kind: Service 113 | metadata: 114 | name: timeline-tag-cloud 115 | spec: 116 | selector: 117 | app: timeline-tag-cloud 118 | ports: 119 | - protocol: TCP 120 | port: 8080 121 | targetPort: 8080 122 | --- 123 | 124 | apiVersion: networking.k8s.io/v1 125 | kind: Ingress 126 | metadata: 127 | name: timeline-tag-cloud 128 | annotations: 129 | nginx.ingress.kubernetes.io/rewrite-target: /$2 130 | spec: 131 | ingressClassName: nginx 132 | rules: 133 | - host: social.p50 134 | http: 135 | paths: 136 | - path: /timeline-tag-cloud(/|$)(.*) 137 | pathType: Prefix 138 | backend: 139 | service: 140 | name: timeline-tag-cloud 141 | port: 142 | number: 8080 143 | -------------------------------------------------------------------------------- /11-timeline-word-cloud.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kafka.strimzi.io/v1beta2 2 | kind: KafkaUser 3 | metadata: 4 | name: timeline-word-cloud 5 | labels: 6 | strimzi.io/cluster: my-cluster 7 | spec: 8 | authentication: 9 | type: tls 10 | authorization: 11 | type: simple 12 | acls: 13 | # Source topic 14 | - resource: 15 | type: topic 16 | name: twitter-timeline 17 | operation: Read 18 | # Group used by the Kafka Streams app 19 | - resource: 20 | type: group 21 | name: timeline-word-cloud 22 | operation: Read 23 | # Streams topics 24 | - resource: 25 | type: topic 26 | name: timeline-word-cloud- 27 | patternType: prefix 28 | operation: Write 29 | - resource: 30 | type: topic 31 | name: timeline-word-cloud- 32 | patternType: prefix 33 | operation: Read 34 | - resource: 35 | type: topic 36 | name: timeline-word-cloud- 37 | patternType: prefix 38 | operation: Create 39 | --- 40 | 41 | apiVersion: apps/v1 42 | kind: Deployment 43 | metadata: 44 | labels: 45 | app: timeline-word-cloud 46 | name: timeline-word-cloud 47 | spec: 48 | replicas: 1 49 | selector: 50 | matchLabels: 51 | app: timeline-word-cloud 52 | template: 53 | metadata: 54 | labels: 55 | app: timeline-word-cloud 56 | spec: 57 | containers: 58 | - name: timeline-word-cloud 59 | image: ghcr.io/scholzj/build-your-own-social-media-analytics-with-apache-kafka-word-cloud:latest 60 | env: 61 | - name: QUARKUS_KAFKA_STREAMS_BOOTSTRAP_SERVERS 62 | value: my-cluster-kafka-bootstrap:9093 63 | - name: QUARKUS_KAFKA_STREAMS_APPLICATION_ID 64 | value: timeline-word-cloud 65 | - name: QUARKUS_KAFKA_STREAMS_TOPICS 66 | value: twitter-timeline 67 | - name: QUARKUS_KAFKA_STREAMS_SECURITY_PROTOCOL 68 | value: SSL 69 | - name: QUARKUS_KAFKA_STREAMS_SSL_TRUSTSTORE_TYPE 70 | value: PKCS12 71 | - name: QUARKUS_KAFKA_STREAMS_SSL_TRUSTSTORE_LOCATION 72 | value: /etc/truststore/ca.p12 73 | - name: QUARKUS_KAFKA_STREAMS_SSL_TRUSTSTORE_PASSWORD 74 | valueFrom: 75 | secretKeyRef: 76 | name: my-cluster-cluster-ca-cert 77 | key: ca.password 78 | - name: QUARKUS_KAFKA_STREAMS_SSL_KEYSTORE_TYPE 79 | value: PKCS12 80 | - name: QUARKUS_KAFKA_STREAMS_SSL_KEYSTORE_LOCATION 81 | value: /etc/keystore/user.p12 82 | - name: QUARKUS_KAFKA_STREAMS_SSL_KEYSTORE_PASSWORD 83 | valueFrom: 84 | secretKeyRef: 85 | name: timeline-word-cloud 86 | key: user.password 87 | volumeMounts: 88 | - name: truststore 89 | mountPath: "/etc/truststore" 90 | readOnly: true 91 | - name: keystore 92 | mountPath: "/etc/keystore" 93 | readOnly: true 94 | ports: 95 | - containerPort: 8080 96 | volumes: 97 | - name: truststore 98 | secret: 99 | secretName: my-cluster-cluster-ca-cert 100 | items: 101 | - key: ca.p12 102 | path: ca.p12 103 | - name: keystore 104 | secret: 105 | secretName: timeline-word-cloud 106 | items: 107 | - key: user.p12 108 | path: user.p12 109 | --- 110 | 111 | apiVersion: v1 112 | kind: Service 113 | metadata: 114 | name: timeline-word-cloud 115 | spec: 116 | selector: 117 | app: timeline-word-cloud 118 | ports: 119 | - protocol: TCP 120 | port: 8080 121 | targetPort: 8080 122 | --- 123 | 124 | apiVersion: networking.k8s.io/v1 125 | kind: Ingress 126 | metadata: 127 | name: timeline-word-cloud 128 | annotations: 129 | nginx.ingress.kubernetes.io/rewrite-target: /$2 130 | spec: 131 | ingressClassName: nginx 132 | rules: 133 | - host: social.p50 134 | http: 135 | paths: 136 | - path: /timeline-word-cloud(/|$)(.*) 137 | pathType: Prefix 138 | backend: 139 | service: 140 | name: timeline-word-cloud 141 | port: 142 | number: 8080 143 | -------------------------------------------------------------------------------- /tag-cloud/src/main/java/cz/scholz/tagcloud/model/twitter/MediaEntity.java: -------------------------------------------------------------------------------- 1 | package cz.scholz.tagcloud.model.twitter; 2 | 3 | import io.quarkus.runtime.annotations.RegisterForReflection; 4 | 5 | import java.util.Map; 6 | 7 | @RegisterForReflection 8 | public class MediaEntity { 9 | public String text; 10 | public int start = -1; 11 | public int end = -1; 12 | public long id; 13 | public String url; 14 | public String mediaURL; 15 | public String mediaURLHttps; 16 | public String expandedURL; 17 | public String displayURL; 18 | public Map sizes; 19 | public String type; 20 | public int videoAspectRatioWidth; 21 | public int videoAspectRatioHeight; 22 | public long videoDurationMillis; 23 | public Variant[] videoVariants; 24 | public String extAltText; 25 | 26 | MediaEntity() { 27 | } 28 | 29 | public MediaEntity(String text, int start, int end, long id, String url, String mediaURL, String mediaURLHttps, String expandedURL, String displayURL, Map sizes, String type, int videoAspectRatioWidth, int videoAspectRatioHeight, long videoDurationMillis, Variant[] videoVariants, String extAltText) { 30 | this.text = text; 31 | this.start = start; 32 | this.end = end; 33 | this.id = id; 34 | this.url = url; 35 | this.mediaURL = mediaURL; 36 | this.mediaURLHttps = mediaURLHttps; 37 | this.expandedURL = expandedURL; 38 | this.displayURL = displayURL; 39 | this.sizes = sizes; 40 | this.type = type; 41 | this.videoAspectRatioWidth = videoAspectRatioWidth; 42 | this.videoAspectRatioHeight = videoAspectRatioHeight; 43 | this.videoDurationMillis = videoDurationMillis; 44 | this.videoVariants = videoVariants; 45 | this.extAltText = extAltText; 46 | } 47 | 48 | public String getText() { 49 | return text; 50 | } 51 | 52 | public int getStart() { 53 | return start; 54 | } 55 | 56 | public int getEnd() { 57 | return end; 58 | } 59 | 60 | public long getId() { 61 | return id; 62 | } 63 | 64 | public String getUrl() { 65 | return url; 66 | } 67 | 68 | public String getMediaURL() { 69 | return mediaURL; 70 | } 71 | 72 | public String getMediaURLHttps() { 73 | return mediaURLHttps; 74 | } 75 | 76 | public String getExpandedURL() { 77 | return expandedURL; 78 | } 79 | 80 | public String getDisplayURL() { 81 | return displayURL; 82 | } 83 | 84 | public Map getSizes() { 85 | return sizes; 86 | } 87 | 88 | public String getType() { 89 | return type; 90 | } 91 | 92 | public int getVideoAspectRatioWidth() { 93 | return videoAspectRatioWidth; 94 | } 95 | 96 | public int getVideoAspectRatioHeight() { 97 | return videoAspectRatioHeight; 98 | } 99 | 100 | public long getVideoDurationMillis() { 101 | return videoDurationMillis; 102 | } 103 | 104 | public Variant[] getVideoVariants() { 105 | return videoVariants; 106 | } 107 | 108 | public String getExtAltText() { 109 | return extAltText; 110 | } 111 | 112 | @RegisterForReflection 113 | public static class Variant { 114 | public int bitrate; 115 | public String contentType; 116 | public String url; 117 | 118 | Variant() { 119 | } 120 | 121 | public Variant(int bitrate, String contentType, String url) { 122 | this.bitrate = bitrate; 123 | this.contentType = contentType; 124 | this.url = url; 125 | } 126 | 127 | public int getBitrate() { 128 | return bitrate; 129 | } 130 | 131 | public String getContentType() { 132 | return contentType; 133 | } 134 | 135 | public String getUrl() { 136 | return url; 137 | } 138 | } 139 | 140 | @RegisterForReflection 141 | public static class Size { 142 | int width; 143 | int height; 144 | int resize; 145 | 146 | Size() { 147 | } 148 | 149 | public Size(int width, int height, int resize) { 150 | this.width = width; 151 | this.height = height; 152 | this.resize = resize; 153 | } 154 | 155 | public int getWidth() { 156 | return width; 157 | } 158 | 159 | public int getHeight() { 160 | return height; 161 | } 162 | 163 | public int getResize() { 164 | return resize; 165 | } 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /word-cloud/src/main/java/cz/scholz/wordcloud/model/twitter/MediaEntity.java: -------------------------------------------------------------------------------- 1 | package cz.scholz.wordcloud.model.twitter; 2 | 3 | import io.quarkus.runtime.annotations.RegisterForReflection; 4 | 5 | import java.util.Map; 6 | 7 | @RegisterForReflection 8 | public class MediaEntity { 9 | public String text; 10 | public int start = -1; 11 | public int end = -1; 12 | public long id; 13 | public String url; 14 | public String mediaURL; 15 | public String mediaURLHttps; 16 | public String expandedURL; 17 | public String displayURL; 18 | public Map sizes; 19 | public String type; 20 | public int videoAspectRatioWidth; 21 | public int videoAspectRatioHeight; 22 | public long videoDurationMillis; 23 | public Variant[] videoVariants; 24 | public String extAltText; 25 | 26 | MediaEntity() { 27 | } 28 | 29 | public MediaEntity(String text, int start, int end, long id, String url, String mediaURL, String mediaURLHttps, String expandedURL, String displayURL, Map sizes, String type, int videoAspectRatioWidth, int videoAspectRatioHeight, long videoDurationMillis, Variant[] videoVariants, String extAltText) { 30 | this.text = text; 31 | this.start = start; 32 | this.end = end; 33 | this.id = id; 34 | this.url = url; 35 | this.mediaURL = mediaURL; 36 | this.mediaURLHttps = mediaURLHttps; 37 | this.expandedURL = expandedURL; 38 | this.displayURL = displayURL; 39 | this.sizes = sizes; 40 | this.type = type; 41 | this.videoAspectRatioWidth = videoAspectRatioWidth; 42 | this.videoAspectRatioHeight = videoAspectRatioHeight; 43 | this.videoDurationMillis = videoDurationMillis; 44 | this.videoVariants = videoVariants; 45 | this.extAltText = extAltText; 46 | } 47 | 48 | public String getText() { 49 | return text; 50 | } 51 | 52 | public int getStart() { 53 | return start; 54 | } 55 | 56 | public int getEnd() { 57 | return end; 58 | } 59 | 60 | public long getId() { 61 | return id; 62 | } 63 | 64 | public String getUrl() { 65 | return url; 66 | } 67 | 68 | public String getMediaURL() { 69 | return mediaURL; 70 | } 71 | 72 | public String getMediaURLHttps() { 73 | return mediaURLHttps; 74 | } 75 | 76 | public String getExpandedURL() { 77 | return expandedURL; 78 | } 79 | 80 | public String getDisplayURL() { 81 | return displayURL; 82 | } 83 | 84 | public Map getSizes() { 85 | return sizes; 86 | } 87 | 88 | public String getType() { 89 | return type; 90 | } 91 | 92 | public int getVideoAspectRatioWidth() { 93 | return videoAspectRatioWidth; 94 | } 95 | 96 | public int getVideoAspectRatioHeight() { 97 | return videoAspectRatioHeight; 98 | } 99 | 100 | public long getVideoDurationMillis() { 101 | return videoDurationMillis; 102 | } 103 | 104 | public Variant[] getVideoVariants() { 105 | return videoVariants; 106 | } 107 | 108 | public String getExtAltText() { 109 | return extAltText; 110 | } 111 | 112 | @RegisterForReflection 113 | public static class Variant { 114 | public int bitrate; 115 | public String contentType; 116 | public String url; 117 | 118 | Variant() { 119 | } 120 | 121 | public Variant(int bitrate, String contentType, String url) { 122 | this.bitrate = bitrate; 123 | this.contentType = contentType; 124 | this.url = url; 125 | } 126 | 127 | public int getBitrate() { 128 | return bitrate; 129 | } 130 | 131 | public String getContentType() { 132 | return contentType; 133 | } 134 | 135 | public String getUrl() { 136 | return url; 137 | } 138 | } 139 | 140 | @RegisterForReflection 141 | public static class Size { 142 | int width; 143 | int height; 144 | int resize; 145 | 146 | Size() { 147 | } 148 | 149 | public Size(int width, int height, int resize) { 150 | this.width = width; 151 | this.height = height; 152 | this.resize = resize; 153 | } 154 | 155 | public int getWidth() { 156 | return width; 157 | } 158 | 159 | public int getHeight() { 160 | return height; 161 | } 162 | 163 | public int getResize() { 164 | return resize; 165 | } 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /ad-hoc/src/main/java/cz/scholz/sentimentanalysis/model/twitter/MediaEntity.java: -------------------------------------------------------------------------------- 1 | package cz.scholz.sentimentanalysis.model.twitter; 2 | 3 | import io.quarkus.runtime.annotations.RegisterForReflection; 4 | 5 | import java.util.Map; 6 | 7 | @RegisterForReflection 8 | public class MediaEntity { 9 | public String text; 10 | public int start = -1; 11 | public int end = -1; 12 | public long id; 13 | public String url; 14 | public String mediaURL; 15 | public String mediaURLHttps; 16 | public String expandedURL; 17 | public String displayURL; 18 | public Map sizes; 19 | public String type; 20 | public int videoAspectRatioWidth; 21 | public int videoAspectRatioHeight; 22 | public long videoDurationMillis; 23 | public Variant[] videoVariants; 24 | public String extAltText; 25 | 26 | MediaEntity() { 27 | } 28 | 29 | public MediaEntity(String text, int start, int end, long id, String url, String mediaURL, String mediaURLHttps, String expandedURL, String displayURL, Map sizes, String type, int videoAspectRatioWidth, int videoAspectRatioHeight, long videoDurationMillis, Variant[] videoVariants, String extAltText) { 30 | this.text = text; 31 | this.start = start; 32 | this.end = end; 33 | this.id = id; 34 | this.url = url; 35 | this.mediaURL = mediaURL; 36 | this.mediaURLHttps = mediaURLHttps; 37 | this.expandedURL = expandedURL; 38 | this.displayURL = displayURL; 39 | this.sizes = sizes; 40 | this.type = type; 41 | this.videoAspectRatioWidth = videoAspectRatioWidth; 42 | this.videoAspectRatioHeight = videoAspectRatioHeight; 43 | this.videoDurationMillis = videoDurationMillis; 44 | this.videoVariants = videoVariants; 45 | this.extAltText = extAltText; 46 | } 47 | 48 | public String getText() { 49 | return text; 50 | } 51 | 52 | public int getStart() { 53 | return start; 54 | } 55 | 56 | public int getEnd() { 57 | return end; 58 | } 59 | 60 | public long getId() { 61 | return id; 62 | } 63 | 64 | public String getUrl() { 65 | return url; 66 | } 67 | 68 | public String getMediaURL() { 69 | return mediaURL; 70 | } 71 | 72 | public String getMediaURLHttps() { 73 | return mediaURLHttps; 74 | } 75 | 76 | public String getExpandedURL() { 77 | return expandedURL; 78 | } 79 | 80 | public String getDisplayURL() { 81 | return displayURL; 82 | } 83 | 84 | public Map getSizes() { 85 | return sizes; 86 | } 87 | 88 | public String getType() { 89 | return type; 90 | } 91 | 92 | public int getVideoAspectRatioWidth() { 93 | return videoAspectRatioWidth; 94 | } 95 | 96 | public int getVideoAspectRatioHeight() { 97 | return videoAspectRatioHeight; 98 | } 99 | 100 | public long getVideoDurationMillis() { 101 | return videoDurationMillis; 102 | } 103 | 104 | public Variant[] getVideoVariants() { 105 | return videoVariants; 106 | } 107 | 108 | public String getExtAltText() { 109 | return extAltText; 110 | } 111 | 112 | @RegisterForReflection 113 | public static class Variant { 114 | public int bitrate; 115 | public String contentType; 116 | public String url; 117 | 118 | Variant() { 119 | } 120 | 121 | public Variant(int bitrate, String contentType, String url) { 122 | this.bitrate = bitrate; 123 | this.contentType = contentType; 124 | this.url = url; 125 | } 126 | 127 | public int getBitrate() { 128 | return bitrate; 129 | } 130 | 131 | public String getContentType() { 132 | return contentType; 133 | } 134 | 135 | public String getUrl() { 136 | return url; 137 | } 138 | } 139 | 140 | @RegisterForReflection 141 | public static class Size { 142 | int width; 143 | int height; 144 | int resize; 145 | 146 | Size() { 147 | } 148 | 149 | public Size(int width, int height, int resize) { 150 | this.width = width; 151 | this.height = height; 152 | this.resize = resize; 153 | } 154 | 155 | public int getWidth() { 156 | return width; 157 | } 158 | 159 | public int getHeight() { 160 | return height; 161 | } 162 | 163 | public int getResize() { 164 | return resize; 165 | } 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /sentiment-analysis/src/main/java/cz/scholz/sentimentanalysis/model/twitter/MediaEntity.java: -------------------------------------------------------------------------------- 1 | package cz.scholz.sentimentanalysis.model.twitter; 2 | 3 | import io.quarkus.runtime.annotations.RegisterForReflection; 4 | 5 | import java.util.Map; 6 | 7 | @RegisterForReflection 8 | public class MediaEntity { 9 | public String text; 10 | public int start = -1; 11 | public int end = -1; 12 | public long id; 13 | public String url; 14 | public String mediaURL; 15 | public String mediaURLHttps; 16 | public String expandedURL; 17 | public String displayURL; 18 | public Map sizes; 19 | public String type; 20 | public int videoAspectRatioWidth; 21 | public int videoAspectRatioHeight; 22 | public long videoDurationMillis; 23 | public Variant[] videoVariants; 24 | public String extAltText; 25 | 26 | MediaEntity() { 27 | } 28 | 29 | public MediaEntity(String text, int start, int end, long id, String url, String mediaURL, String mediaURLHttps, String expandedURL, String displayURL, Map sizes, String type, int videoAspectRatioWidth, int videoAspectRatioHeight, long videoDurationMillis, Variant[] videoVariants, String extAltText) { 30 | this.text = text; 31 | this.start = start; 32 | this.end = end; 33 | this.id = id; 34 | this.url = url; 35 | this.mediaURL = mediaURL; 36 | this.mediaURLHttps = mediaURLHttps; 37 | this.expandedURL = expandedURL; 38 | this.displayURL = displayURL; 39 | this.sizes = sizes; 40 | this.type = type; 41 | this.videoAspectRatioWidth = videoAspectRatioWidth; 42 | this.videoAspectRatioHeight = videoAspectRatioHeight; 43 | this.videoDurationMillis = videoDurationMillis; 44 | this.videoVariants = videoVariants; 45 | this.extAltText = extAltText; 46 | } 47 | 48 | public String getText() { 49 | return text; 50 | } 51 | 52 | public int getStart() { 53 | return start; 54 | } 55 | 56 | public int getEnd() { 57 | return end; 58 | } 59 | 60 | public long getId() { 61 | return id; 62 | } 63 | 64 | public String getUrl() { 65 | return url; 66 | } 67 | 68 | public String getMediaURL() { 69 | return mediaURL; 70 | } 71 | 72 | public String getMediaURLHttps() { 73 | return mediaURLHttps; 74 | } 75 | 76 | public String getExpandedURL() { 77 | return expandedURL; 78 | } 79 | 80 | public String getDisplayURL() { 81 | return displayURL; 82 | } 83 | 84 | public Map getSizes() { 85 | return sizes; 86 | } 87 | 88 | public String getType() { 89 | return type; 90 | } 91 | 92 | public int getVideoAspectRatioWidth() { 93 | return videoAspectRatioWidth; 94 | } 95 | 96 | public int getVideoAspectRatioHeight() { 97 | return videoAspectRatioHeight; 98 | } 99 | 100 | public long getVideoDurationMillis() { 101 | return videoDurationMillis; 102 | } 103 | 104 | public Variant[] getVideoVariants() { 105 | return videoVariants; 106 | } 107 | 108 | public String getExtAltText() { 109 | return extAltText; 110 | } 111 | 112 | @RegisterForReflection 113 | public static class Variant { 114 | public int bitrate; 115 | public String contentType; 116 | public String url; 117 | 118 | Variant() { 119 | } 120 | 121 | public Variant(int bitrate, String contentType, String url) { 122 | this.bitrate = bitrate; 123 | this.contentType = contentType; 124 | this.url = url; 125 | } 126 | 127 | public int getBitrate() { 128 | return bitrate; 129 | } 130 | 131 | public String getContentType() { 132 | return contentType; 133 | } 134 | 135 | public String getUrl() { 136 | return url; 137 | } 138 | } 139 | 140 | @RegisterForReflection 141 | public static class Size { 142 | int width; 143 | int height; 144 | int resize; 145 | 146 | Size() { 147 | } 148 | 149 | public Size(int width, int height, int resize) { 150 | this.width = width; 151 | this.height = height; 152 | this.resize = resize; 153 | } 154 | 155 | public int getWidth() { 156 | return width; 157 | } 158 | 159 | public int getHeight() { 160 | return height; 161 | } 162 | 163 | public int getResize() { 164 | return resize; 165 | } 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /ad-hoc/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | cz.scholz 7 | ad-hoc 8 | 1.0.0-SNAPSHOT 9 | 10 | 3.0.0-M5 11 | 11 12 | 11 13 | 2.9.1.Final 14 | quarkus-bom 15 | io.quarkus 16 | 2.9.1.Final 17 | UTF-8 18 | UTF-8 19 | 20 | 21 | 22 | 23 | ${quarkus.platform.group-id} 24 | ${quarkus.platform.artifact-id} 25 | ${quarkus.platform.version} 26 | pom 27 | import 28 | 29 | 30 | 31 | 32 | 33 | io.quarkus 34 | quarkus-resteasy 35 | 36 | 37 | io.quarkus 38 | quarkus-resteasy-jackson 39 | 40 | 41 | io.quarkus 42 | quarkus-kafka-streams 43 | 44 | 45 | io.quarkus 46 | quarkus-junit5 47 | test 48 | 49 | 50 | 51 | 52 | 53 | io.quarkus 54 | quarkus-maven-plugin 55 | ${quarkus-plugin.version} 56 | 57 | 58 | 59 | build 60 | 61 | 62 | 63 | 64 | 65 | maven-surefire-plugin 66 | ${surefire-plugin.version} 67 | 68 | 69 | org.jboss.logmanager.LogManager 70 | ${maven.home} 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | native 79 | 80 | 81 | native 82 | 83 | 84 | 85 | native 86 | 87 | 88 | 89 | 90 | maven-failsafe-plugin 91 | ${surefire-plugin.version} 92 | 93 | 94 | 95 | integration-test 96 | verify 97 | 98 | 99 | 100 | 101 | ${project.build.directory}/${project.build.finalName}-runner 102 | 103 | org.jboss.logmanager.LogManager 104 | 105 | ${maven.home} 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | -------------------------------------------------------------------------------- /ad-hoc/.mvn/wrapper/MavenWrapperDownloader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2007-present the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import java.net.*; 17 | import java.io.*; 18 | import java.nio.channels.*; 19 | import java.util.Properties; 20 | 21 | public class MavenWrapperDownloader { 22 | 23 | private static final String WRAPPER_VERSION = "0.5.6"; 24 | /** 25 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. 26 | */ 27 | private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" 28 | + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; 29 | 30 | /** 31 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to 32 | * use instead of the default one. 33 | */ 34 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH = 35 | ".mvn/wrapper/maven-wrapper.properties"; 36 | 37 | /** 38 | * Path where the maven-wrapper.jar will be saved to. 39 | */ 40 | private static final String MAVEN_WRAPPER_JAR_PATH = 41 | ".mvn/wrapper/maven-wrapper.jar"; 42 | 43 | /** 44 | * Name of the property which should be used to override the default download url for the wrapper. 45 | */ 46 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; 47 | 48 | public static void main(String args[]) { 49 | System.out.println("- Downloader started"); 50 | File baseDirectory = new File(args[0]); 51 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); 52 | 53 | // If the maven-wrapper.properties exists, read it and check if it contains a custom 54 | // wrapperUrl parameter. 55 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); 56 | String url = DEFAULT_DOWNLOAD_URL; 57 | if(mavenWrapperPropertyFile.exists()) { 58 | FileInputStream mavenWrapperPropertyFileInputStream = null; 59 | try { 60 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); 61 | Properties mavenWrapperProperties = new Properties(); 62 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); 63 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); 64 | } catch (IOException e) { 65 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); 66 | } finally { 67 | try { 68 | if(mavenWrapperPropertyFileInputStream != null) { 69 | mavenWrapperPropertyFileInputStream.close(); 70 | } 71 | } catch (IOException e) { 72 | // Ignore ... 73 | } 74 | } 75 | } 76 | System.out.println("- Downloading from: " + url); 77 | 78 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); 79 | if(!outputFile.getParentFile().exists()) { 80 | if(!outputFile.getParentFile().mkdirs()) { 81 | System.out.println( 82 | "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); 83 | } 84 | } 85 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); 86 | try { 87 | downloadFileFromURL(url, outputFile); 88 | System.out.println("Done"); 89 | System.exit(0); 90 | } catch (Throwable e) { 91 | System.out.println("- Error downloading"); 92 | e.printStackTrace(); 93 | System.exit(1); 94 | } 95 | } 96 | 97 | private static void downloadFileFromURL(String urlString, File destination) throws Exception { 98 | if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { 99 | String username = System.getenv("MVNW_USERNAME"); 100 | char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); 101 | Authenticator.setDefault(new Authenticator() { 102 | @Override 103 | protected PasswordAuthentication getPasswordAuthentication() { 104 | return new PasswordAuthentication(username, password); 105 | } 106 | }); 107 | } 108 | URL website = new URL(urlString); 109 | ReadableByteChannel rbc; 110 | rbc = Channels.newChannel(website.openStream()); 111 | FileOutputStream fos = new FileOutputStream(destination); 112 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); 113 | fos.close(); 114 | rbc.close(); 115 | } 116 | 117 | } 118 | -------------------------------------------------------------------------------- /tag-cloud/.mvn/wrapper/MavenWrapperDownloader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2007-present the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import java.net.*; 17 | import java.io.*; 18 | import java.nio.channels.*; 19 | import java.util.Properties; 20 | 21 | public class MavenWrapperDownloader { 22 | 23 | private static final String WRAPPER_VERSION = "0.5.6"; 24 | /** 25 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. 26 | */ 27 | private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" 28 | + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; 29 | 30 | /** 31 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to 32 | * use instead of the default one. 33 | */ 34 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH = 35 | ".mvn/wrapper/maven-wrapper.properties"; 36 | 37 | /** 38 | * Path where the maven-wrapper.jar will be saved to. 39 | */ 40 | private static final String MAVEN_WRAPPER_JAR_PATH = 41 | ".mvn/wrapper/maven-wrapper.jar"; 42 | 43 | /** 44 | * Name of the property which should be used to override the default download url for the wrapper. 45 | */ 46 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; 47 | 48 | public static void main(String args[]) { 49 | System.out.println("- Downloader started"); 50 | File baseDirectory = new File(args[0]); 51 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); 52 | 53 | // If the maven-wrapper.properties exists, read it and check if it contains a custom 54 | // wrapperUrl parameter. 55 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); 56 | String url = DEFAULT_DOWNLOAD_URL; 57 | if(mavenWrapperPropertyFile.exists()) { 58 | FileInputStream mavenWrapperPropertyFileInputStream = null; 59 | try { 60 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); 61 | Properties mavenWrapperProperties = new Properties(); 62 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); 63 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); 64 | } catch (IOException e) { 65 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); 66 | } finally { 67 | try { 68 | if(mavenWrapperPropertyFileInputStream != null) { 69 | mavenWrapperPropertyFileInputStream.close(); 70 | } 71 | } catch (IOException e) { 72 | // Ignore ... 73 | } 74 | } 75 | } 76 | System.out.println("- Downloading from: " + url); 77 | 78 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); 79 | if(!outputFile.getParentFile().exists()) { 80 | if(!outputFile.getParentFile().mkdirs()) { 81 | System.out.println( 82 | "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); 83 | } 84 | } 85 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); 86 | try { 87 | downloadFileFromURL(url, outputFile); 88 | System.out.println("Done"); 89 | System.exit(0); 90 | } catch (Throwable e) { 91 | System.out.println("- Error downloading"); 92 | e.printStackTrace(); 93 | System.exit(1); 94 | } 95 | } 96 | 97 | private static void downloadFileFromURL(String urlString, File destination) throws Exception { 98 | if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { 99 | String username = System.getenv("MVNW_USERNAME"); 100 | char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); 101 | Authenticator.setDefault(new Authenticator() { 102 | @Override 103 | protected PasswordAuthentication getPasswordAuthentication() { 104 | return new PasswordAuthentication(username, password); 105 | } 106 | }); 107 | } 108 | URL website = new URL(urlString); 109 | ReadableByteChannel rbc; 110 | rbc = Channels.newChannel(website.openStream()); 111 | FileOutputStream fos = new FileOutputStream(destination); 112 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); 113 | fos.close(); 114 | rbc.close(); 115 | } 116 | 117 | } 118 | -------------------------------------------------------------------------------- /word-cloud/.mvn/wrapper/MavenWrapperDownloader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2007-present the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import java.net.*; 17 | import java.io.*; 18 | import java.nio.channels.*; 19 | import java.util.Properties; 20 | 21 | public class MavenWrapperDownloader { 22 | 23 | private static final String WRAPPER_VERSION = "0.5.6"; 24 | /** 25 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. 26 | */ 27 | private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" 28 | + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; 29 | 30 | /** 31 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to 32 | * use instead of the default one. 33 | */ 34 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH = 35 | ".mvn/wrapper/maven-wrapper.properties"; 36 | 37 | /** 38 | * Path where the maven-wrapper.jar will be saved to. 39 | */ 40 | private static final String MAVEN_WRAPPER_JAR_PATH = 41 | ".mvn/wrapper/maven-wrapper.jar"; 42 | 43 | /** 44 | * Name of the property which should be used to override the default download url for the wrapper. 45 | */ 46 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; 47 | 48 | public static void main(String args[]) { 49 | System.out.println("- Downloader started"); 50 | File baseDirectory = new File(args[0]); 51 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); 52 | 53 | // If the maven-wrapper.properties exists, read it and check if it contains a custom 54 | // wrapperUrl parameter. 55 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); 56 | String url = DEFAULT_DOWNLOAD_URL; 57 | if(mavenWrapperPropertyFile.exists()) { 58 | FileInputStream mavenWrapperPropertyFileInputStream = null; 59 | try { 60 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); 61 | Properties mavenWrapperProperties = new Properties(); 62 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); 63 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); 64 | } catch (IOException e) { 65 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); 66 | } finally { 67 | try { 68 | if(mavenWrapperPropertyFileInputStream != null) { 69 | mavenWrapperPropertyFileInputStream.close(); 70 | } 71 | } catch (IOException e) { 72 | // Ignore ... 73 | } 74 | } 75 | } 76 | System.out.println("- Downloading from: " + url); 77 | 78 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); 79 | if(!outputFile.getParentFile().exists()) { 80 | if(!outputFile.getParentFile().mkdirs()) { 81 | System.out.println( 82 | "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); 83 | } 84 | } 85 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); 86 | try { 87 | downloadFileFromURL(url, outputFile); 88 | System.out.println("Done"); 89 | System.exit(0); 90 | } catch (Throwable e) { 91 | System.out.println("- Error downloading"); 92 | e.printStackTrace(); 93 | System.exit(1); 94 | } 95 | } 96 | 97 | private static void downloadFileFromURL(String urlString, File destination) throws Exception { 98 | if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { 99 | String username = System.getenv("MVNW_USERNAME"); 100 | char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); 101 | Authenticator.setDefault(new Authenticator() { 102 | @Override 103 | protected PasswordAuthentication getPasswordAuthentication() { 104 | return new PasswordAuthentication(username, password); 105 | } 106 | }); 107 | } 108 | URL website = new URL(urlString); 109 | ReadableByteChannel rbc; 110 | rbc = Channels.newChannel(website.openStream()); 111 | FileOutputStream fos = new FileOutputStream(destination); 112 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); 113 | fos.close(); 114 | rbc.close(); 115 | } 116 | 117 | } 118 | -------------------------------------------------------------------------------- /sentiment-analysis/.mvn/wrapper/MavenWrapperDownloader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2007-present the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | import java.net.*; 17 | import java.io.*; 18 | import java.nio.channels.*; 19 | import java.util.Properties; 20 | 21 | public class MavenWrapperDownloader { 22 | 23 | private static final String WRAPPER_VERSION = "0.5.6"; 24 | /** 25 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. 26 | */ 27 | private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" 28 | + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; 29 | 30 | /** 31 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to 32 | * use instead of the default one. 33 | */ 34 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH = 35 | ".mvn/wrapper/maven-wrapper.properties"; 36 | 37 | /** 38 | * Path where the maven-wrapper.jar will be saved to. 39 | */ 40 | private static final String MAVEN_WRAPPER_JAR_PATH = 41 | ".mvn/wrapper/maven-wrapper.jar"; 42 | 43 | /** 44 | * Name of the property which should be used to override the default download url for the wrapper. 45 | */ 46 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; 47 | 48 | public static void main(String args[]) { 49 | System.out.println("- Downloader started"); 50 | File baseDirectory = new File(args[0]); 51 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); 52 | 53 | // If the maven-wrapper.properties exists, read it and check if it contains a custom 54 | // wrapperUrl parameter. 55 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); 56 | String url = DEFAULT_DOWNLOAD_URL; 57 | if(mavenWrapperPropertyFile.exists()) { 58 | FileInputStream mavenWrapperPropertyFileInputStream = null; 59 | try { 60 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); 61 | Properties mavenWrapperProperties = new Properties(); 62 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); 63 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); 64 | } catch (IOException e) { 65 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); 66 | } finally { 67 | try { 68 | if(mavenWrapperPropertyFileInputStream != null) { 69 | mavenWrapperPropertyFileInputStream.close(); 70 | } 71 | } catch (IOException e) { 72 | // Ignore ... 73 | } 74 | } 75 | } 76 | System.out.println("- Downloading from: " + url); 77 | 78 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); 79 | if(!outputFile.getParentFile().exists()) { 80 | if(!outputFile.getParentFile().mkdirs()) { 81 | System.out.println( 82 | "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); 83 | } 84 | } 85 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); 86 | try { 87 | downloadFileFromURL(url, outputFile); 88 | System.out.println("Done"); 89 | System.exit(0); 90 | } catch (Throwable e) { 91 | System.out.println("- Error downloading"); 92 | e.printStackTrace(); 93 | System.exit(1); 94 | } 95 | } 96 | 97 | private static void downloadFileFromURL(String urlString, File destination) throws Exception { 98 | if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { 99 | String username = System.getenv("MVNW_USERNAME"); 100 | char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); 101 | Authenticator.setDefault(new Authenticator() { 102 | @Override 103 | protected PasswordAuthentication getPasswordAuthentication() { 104 | return new PasswordAuthentication(username, password); 105 | } 106 | }); 107 | } 108 | URL website = new URL(urlString); 109 | ReadableByteChannel rbc; 110 | rbc = Channels.newChannel(website.openStream()); 111 | FileOutputStream fos = new FileOutputStream(destination); 112 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); 113 | fos.close(); 114 | rbc.close(); 115 | } 116 | 117 | } 118 | -------------------------------------------------------------------------------- /tag-cloud/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | cz.scholz 7 | tag-cloud 8 | 1.0.0-SNAPSHOT 9 | 10 | 3.0.0-M5 11 | 11 12 | 11 13 | 2.9.1.Final 14 | quarkus-bom 15 | io.quarkus 16 | 2.9.1.Final 17 | UTF-8 18 | UTF-8 19 | 20 | 21 | 22 | 23 | ${quarkus.platform.group-id} 24 | ${quarkus.platform.artifact-id} 25 | ${quarkus.platform.version} 26 | pom 27 | import 28 | 29 | 30 | 31 | 32 | 33 | io.quarkus 34 | quarkus-resteasy 35 | 36 | 37 | io.quarkus 38 | quarkus-resteasy-jackson 39 | 40 | 41 | io.quarkus 42 | quarkus-kafka-streams 43 | 44 | 45 | io.quarkus 46 | quarkus-junit5 47 | test 48 | 49 | 50 | io.rest-assured 51 | rest-assured 52 | test 53 | 54 | 55 | 56 | 57 | 58 | io.quarkus 59 | quarkus-maven-plugin 60 | ${quarkus-plugin.version} 61 | 62 | 63 | 64 | build 65 | 66 | 67 | 68 | 69 | 70 | maven-surefire-plugin 71 | ${surefire-plugin.version} 72 | 73 | 74 | org.jboss.logmanager.LogManager 75 | ${maven.home} 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | native 84 | 85 | 86 | native 87 | 88 | 89 | 90 | native 91 | -H:ReflectionConfigurationFiles=reflection-config.json 92 | 93 | 94 | 95 | 96 | 97 | maven-failsafe-plugin 98 | ${surefire-plugin.version} 99 | 100 | 101 | 102 | integration-test 103 | verify 104 | 105 | 106 | 107 | 108 | ${project.build.directory}/${project.build.finalName}-runner 109 | 110 | org.jboss.logmanager.LogManager 111 | 112 | ${maven.home} 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | -------------------------------------------------------------------------------- /word-cloud/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | cz.scholz 7 | word-cloud 8 | 1.0.0-SNAPSHOT 9 | 10 | 3.0.0-M5 11 | 11 12 | 11 13 | 2.9.1.Final 14 | quarkus-bom 15 | io.quarkus 16 | 2.9.1.Final 17 | UTF-8 18 | UTF-8 19 | 20 | 21 | 22 | 23 | ${quarkus.platform.group-id} 24 | ${quarkus.platform.artifact-id} 25 | ${quarkus.platform.version} 26 | pom 27 | import 28 | 29 | 30 | 31 | 32 | 33 | io.quarkus 34 | quarkus-resteasy 35 | 36 | 37 | io.quarkus 38 | quarkus-resteasy-jackson 39 | 40 | 41 | io.quarkus 42 | quarkus-kafka-streams 43 | 44 | 45 | io.quarkus 46 | quarkus-junit5 47 | test 48 | 49 | 50 | io.rest-assured 51 | rest-assured 52 | test 53 | 54 | 55 | 56 | 57 | 58 | io.quarkus 59 | quarkus-maven-plugin 60 | ${quarkus-plugin.version} 61 | 62 | 63 | 64 | build 65 | 66 | 67 | 68 | 69 | 70 | maven-surefire-plugin 71 | ${surefire-plugin.version} 72 | 73 | 74 | org.jboss.logmanager.LogManager 75 | ${maven.home} 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | native 84 | 85 | 86 | native 87 | 88 | 89 | 90 | native 91 | -H:ReflectionConfigurationFiles=reflection-config.json 92 | 93 | 94 | 95 | 96 | 97 | maven-failsafe-plugin 98 | ${surefire-plugin.version} 99 | 100 | 101 | 102 | integration-test 103 | verify 104 | 105 | 106 | 107 | 108 | ${project.build.directory}/${project.build.finalName}-runner 109 | 110 | org.jboss.logmanager.LogManager 111 | 112 | ${maven.home} 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | -------------------------------------------------------------------------------- /sentiment-analysis/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | cz.scholz 7 | sentiment-analysis 8 | 1.0.0-SNAPSHOT 9 | 10 | 3.0.0-M5 11 | 11 12 | 11 13 | 2.9.1.Final 14 | quarkus-bom 15 | io.quarkus 16 | 2.9.1.Final 17 | 0.16.0 18 | 1.10.0 19 | UTF-8 20 | UTF-8 21 | 22 | 23 | 24 | 25 | ${quarkus.platform.group-id} 26 | ${quarkus.platform.artifact-id} 27 | ${quarkus.platform.version} 28 | pom 29 | import 30 | 31 | 32 | 33 | 34 | 35 | io.quarkus 36 | quarkus-resteasy 37 | 38 | 39 | io.quarkus 40 | quarkus-resteasy-jackson 41 | 42 | 43 | io.quarkus 44 | quarkus-kafka-streams 45 | 46 | 47 | ai.djl 48 | api 49 | ${ai-djl.version} 50 | 51 | 52 | ai.djl 53 | model-zoo 54 | ${ai-djl.version} 55 | 56 | 57 | ai.djl.pytorch 58 | pytorch-engine 59 | ${ai-djl.version} 60 | 61 | 62 | ai.djl.pytorch 63 | pytorch-model-zoo 64 | ${ai-djl.version} 65 | 66 | 67 | 68 | ai.djl.pytorch 69 | pytorch-native-cpu 70 | linux-x86_64 71 | runtime 72 | ${ai-djl-pytorch.version} 73 | 74 | 75 | io.quarkus 76 | quarkus-junit5 77 | test 78 | 79 | 80 | io.rest-assured 81 | rest-assured 82 | test 83 | 84 | 85 | 86 | 87 | 88 | io.quarkus 89 | quarkus-maven-plugin 90 | ${quarkus-plugin.version} 91 | 92 | 93 | 94 | build 95 | 96 | 97 | 98 | 99 | 100 | maven-surefire-plugin 101 | ${surefire-plugin.version} 102 | 103 | 104 | org.jboss.logmanager.LogManager 105 | ${maven.home} 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | native 114 | 115 | 116 | native 117 | 118 | 119 | 120 | native 121 | -H:ReflectionConfigurationFiles=reflection-config.json 122 | 123 | 124 | 125 | 126 | maven-failsafe-plugin 127 | ${surefire-plugin.version} 128 | 129 | 130 | 131 | integration-test 132 | verify 133 | 134 | 135 | 136 | 137 | ${project.build.directory}/${project.build.finalName}-runner 138 | 139 | org.jboss.logmanager.LogManager 140 | 141 | ${maven.home} 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | --------------------------------------------------------------------------------