diff --git a/core-java-modules/core-java-annotations/README.md b/core-java-modules/core-java-annotations/README.md
index 18f5589771..a8a9ac3b16 100644
--- a/core-java-modules/core-java-annotations/README.md
+++ b/core-java-modules/core-java-annotations/README.md
@@ -12,3 +12,4 @@
- [Efficient Word Frequency Calculator in Java](https://www.baeldung.com/java-word-frequency)
- [Why Missing Annotations Don’t Cause ClassNotFoundException](https://www.baeldung.com/classnotfoundexception-missing-annotation)
- [Valid @SuppressWarnings Warning Names](https://www.baeldung.com/java-suppresswarnings-valid-names)
+- [Get a Field’s Annotations Using Reflection](https://www.baeldung.com/java-get-field-annotations)
diff --git a/maven-modules/maven-generate-war/README.md b/maven-modules/maven-generate-war/README.md
new file mode 100644
index 0000000000..1e74a087ae
--- /dev/null
+++ b/maven-modules/maven-generate-war/README.md
@@ -0,0 +1,3 @@
+### Relevant Articles:
+
+- [Generate a WAR File in Maven](https://www.baeldung.com/maven-generate-war-file)
diff --git a/persistence-modules/spring-data-cassandra/pom.xml b/persistence-modules/spring-data-cassandra/pom.xml
index d21541abf8..e2b47ce024 100644
--- a/persistence-modules/spring-data-cassandra/pom.xml
+++ b/persistence-modules/spring-data-cassandra/pom.xml
@@ -16,46 +16,15 @@
- org.springframework.data
- spring-data-cassandra
- ${org.springframework.data.version}
-
-
- org.springframework
- spring-core
- ${spring.version}
-
-
- commons-logging
- commons-logging
-
-
-
-
- org.springframework
- spring-beans
- ${spring.version}
-
-
- org.springframework
- spring-context
- ${spring.version}
+ org.springframework.boot
+ spring-boot-starter-data-cassandra
+ ${spring-boot-starter-data-cassandra.version}
org.springframework
spring-aop
${spring.version}
-
- org.springframework
- spring-expression
- ${spring.version}
-
-
- org.springframework
- spring-tx
- ${spring.version}
-
org.springframework
spring-test
@@ -91,17 +60,10 @@
-
- com.datastax.cassandra
- cassandra-driver-core
- ${cassandra-driver-core.version}
- true
-
- 1.3.2.RELEASE
- 2.1.5
+ 1.3.2.RELEASE
2.1.9.2
2.1.9.2
2.0-0
diff --git a/persistence-modules/spring-jdbc/README.md b/persistence-modules/spring-jdbc/README.md
index 1433344b7a..437a1312da 100644
--- a/persistence-modules/spring-jdbc/README.md
+++ b/persistence-modules/spring-jdbc/README.md
@@ -4,3 +4,4 @@
- [Spring JDBC](https://www.baeldung.com/spring-jdbc-jdbctemplate)
- [Spring JdbcTemplate Unit Testing](https://www.baeldung.com/spring-jdbctemplate-testing)
- [Using a List of Values in a JdbcTemplate IN Clause](https://www.baeldung.com/spring-jdbctemplate-in-list)
+- [Obtaining Auto-generated Keys in Spring JDBC](https://www.baeldung.com/spring-jdbc-autogenerated-keys)
diff --git a/persistence-modules/spring-jpa/README.md b/persistence-modules/spring-jpa/README.md
index 937890cd13..db70259005 100644
--- a/persistence-modules/spring-jpa/README.md
+++ b/persistence-modules/spring-jpa/README.md
@@ -6,7 +6,6 @@
- [Sorting with JPA](https://www.baeldung.com/jpa-sort)
- [Self-Contained Testing Using an In-Memory Database](https://www.baeldung.com/spring-jpa-test-in-memory-database)
- [A Guide to Spring AbstractRoutingDatasource](https://www.baeldung.com/spring-abstract-routing-data-source)
-- [Obtaining Auto-generated Keys in Spring JDBC](https://www.baeldung.com/spring-jdbc-autogenerated-keys)
- [Spring Data Annotations](http://www.baeldung.com/spring-data-annotations)
- More articles: [[next -->]](/spring-jpa-2)
diff --git a/quarkus-vs-springboot/README.md b/quarkus-vs-springboot/README.md
index 35fc8eb5eb..05eaabb923 100644
--- a/quarkus-vs-springboot/README.md
+++ b/quarkus-vs-springboot/README.md
@@ -92,4 +92,8 @@ Then, once again, you can also run both application and DB from docker, using:
docker-compose -f src/main/docker/quarkus.yml up
```
-Now you have all you need to reproduce the tests with your machine.
\ No newline at end of file
+Now you have all you need to reproduce the tests with your machine.
+
+### Relevant Articles:
+
+- [Spring Boot vs Quarkus](https://www.baeldung.com/spring-boot-vs-quarkus)
diff --git a/ratpack/src/main/java/com/baeldung/model/Quote.java b/ratpack/src/main/java/com/baeldung/model/Quote.java
new file mode 100644
index 0000000000..009a85fa11
--- /dev/null
+++ b/ratpack/src/main/java/com/baeldung/model/Quote.java
@@ -0,0 +1,107 @@
+package com.baeldung.model;
+
+import java.time.Instant;
+
+public class Quote {
+
+ private Instant ts;
+ private String symbol;
+ private double value;
+
+ public Quote() {}
+
+
+ public Quote(Instant ts, String symbol, double value) {
+ this.ts = ts;
+ this.symbol = symbol;
+ this.value = value;
+ }
+
+
+ /**
+ * @return the ts
+ */
+ public Instant getTs() {
+ return ts;
+ }
+
+ /**
+ * @param ts the ts to set
+ */
+ public void setTs(Instant ts) {
+ this.ts = ts;
+ }
+
+ /**
+ * @return the symbol
+ */
+ public String getSymbol() {
+ return symbol;
+ }
+
+ /**
+ * @param symbol the symbol to set
+ */
+ public void setSymbol(String symbol) {
+ this.symbol = symbol;
+ }
+
+ /**
+ * @return the value
+ */
+ public double getValue() {
+ return value;
+ }
+
+ /**
+ * @param value the value to set
+ */
+ public void setValue(double value) {
+ this.value = value;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((symbol == null) ? 0 : symbol.hashCode());
+ result = prime * result + ((ts == null) ? 0 : ts.hashCode());
+ long temp;
+ temp = Double.doubleToLongBits(value);
+ result = prime * result + (int) (temp ^ (temp >>> 32));
+ return result;
+ }
+
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ Quote other = (Quote) obj;
+ if (symbol == null) {
+ if (other.symbol != null)
+ return false;
+ } else if (!symbol.equals(other.symbol))
+ return false;
+ if (ts == null) {
+ if (other.ts != null)
+ return false;
+ } else if (!ts.equals(other.ts))
+ return false;
+ if (Double.doubleToLongBits(value) != Double.doubleToLongBits(other.value))
+ return false;
+ return true;
+ }
+
+
+ @Override
+ public String toString() {
+ return "Quote [ts=" + ts + ", symbol=" + symbol + ", value=" + value + "]";
+ }
+
+
+}
diff --git a/ratpack/src/main/java/com/baeldung/rxjava/service/QuotesService.java b/ratpack/src/main/java/com/baeldung/rxjava/service/QuotesService.java
new file mode 100644
index 0000000000..7c073ee1de
--- /dev/null
+++ b/ratpack/src/main/java/com/baeldung/rxjava/service/QuotesService.java
@@ -0,0 +1,44 @@
+package com.baeldung.rxjava.service;
+
+import java.time.Duration;
+import java.time.Instant;
+import java.util.Random;
+import java.util.concurrent.ScheduledExecutorService;
+
+import org.reactivestreams.Publisher;
+
+import com.baeldung.model.Quote;
+
+import ratpack.stream.Streams;
+
+public class QuotesService {
+
+ private final ScheduledExecutorService executorService;
+ private static Random rnd = new Random();
+ private static String[] symbols = new String[] {
+ "MSFT",
+ "ORCL",
+ "GOOG",
+ "AAPL",
+ "CSCO"
+ };
+
+ public QuotesService(ScheduledExecutorService executorService) {
+ this.executorService = executorService;
+ }
+
+ public Publisher newTicker() {
+ return Streams.periodically(executorService, Duration.ofSeconds(2), (t) -> {
+
+ return randomQuote();
+ });
+ }
+
+ private static Quote randomQuote() {
+ return new Quote (
+ Instant.now(),
+ symbols[rnd.nextInt(symbols.length)],
+ Math.round(rnd.nextDouble()*100)
+ );
+ }
+}
diff --git a/ratpack/src/main/java/com/baeldung/spring/EmbedRatpackStreamsApp.java b/ratpack/src/main/java/com/baeldung/spring/EmbedRatpackStreamsApp.java
new file mode 100644
index 0000000000..dc66efbecb
--- /dev/null
+++ b/ratpack/src/main/java/com/baeldung/spring/EmbedRatpackStreamsApp.java
@@ -0,0 +1,206 @@
+package com.baeldung.spring;
+
+import java.util.Random;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.reactivestreams.Publisher;
+import org.reactivestreams.Subscriber;
+import org.reactivestreams.Subscription;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Bean;
+
+import com.baeldung.model.Quote;
+import com.baeldung.rxjava.service.QuotesService;
+
+import groovy.util.logging.Slf4j;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import ratpack.func.Action;
+import ratpack.handling.Chain;
+import ratpack.http.ResponseChunks;
+import ratpack.http.Status;
+import ratpack.server.ServerConfig;
+import ratpack.spring.config.EnableRatpack;
+import ratpack.sse.ServerSentEvents;
+import ratpack.stream.Streams;
+import ratpack.stream.TransformablePublisher;
+import ratpack.websocket.WebSockets;
+import rx.subscriptions.Subscriptions;
+
+/**
+ * @author psevestre
+ */
+@SpringBootApplication
+@EnableRatpack
+public class EmbedRatpackStreamsApp {
+
+ private static final Logger log = LoggerFactory.getLogger(EmbedRatpackStreamsApp.class);
+
+ @Autowired
+ private QuotesService quotesService;
+
+ private AtomicLong idSeq = new AtomicLong(0);
+
+
+ @Bean
+ public ScheduledExecutorService executorService() {
+ return Executors.newScheduledThreadPool(1);
+ }
+
+ @Bean
+ public QuotesService quotesService(ScheduledExecutorService executor) {
+ return new QuotesService(executor);
+ }
+
+ @Bean
+ public Action quotes() {
+ ServerSentEvents sse = ServerSentEvents.serverSentEvents(quotesService.newTicker(), (evt) -> {
+ evt
+ .id(Long.toString(idSeq.incrementAndGet()))
+ .event("quote")
+ .data( q -> q.toString());
+ });
+
+ return chain -> chain.get("quotes", ctx -> ctx.render(sse));
+ }
+
+ @Bean
+ public Action quotesWS() {
+ Publisher pub = Streams.transformable(quotesService.newTicker())
+ .map(Quote::toString);
+ return chain -> chain.get("quotes-ws", ctx -> WebSockets.websocketBroadcast(ctx, pub));
+ }
+
+ @Bean
+ public Action uploadFile() {
+
+ return chain -> chain.post("upload", ctx -> {
+ TransformablePublisher extends ByteBuf> pub = ctx.getRequest().getBodyStream();
+ pub.subscribe(new Subscriber() {
+ private Subscription sub;
+ @Override
+ public void onSubscribe(Subscription sub) {
+ this.sub = sub;
+ sub.request(1);
+ }
+
+ @Override
+ public void onNext(ByteBuf t) {
+ try {
+ int len = t.readableBytes();
+ log.info("Got {} bytes", len);
+
+ // Do something useful with data
+
+ // Request next chunk
+ sub.request(1);
+ }
+ finally {
+ // DO NOT FORGET to RELEASE !
+ t.release();
+ }
+ }
+
+ @Override
+ public void onError(Throwable t) {
+ ctx.getResponse().status(500);
+ }
+
+ @Override
+ public void onComplete() {
+ ctx.getResponse().status(202);
+ }
+ });
+ });
+ }
+
+ @Bean
+ public Action download() {
+ return chain -> chain.get("download", ctx -> {
+ ctx.getResponse().sendStream(new RandomBytesPublisher(1024,512));
+ });
+ }
+
+ @Bean
+ public Action downloadChunks() {
+ return chain -> chain.get("downloadChunks", ctx -> {
+ ctx.render(ResponseChunks.bufferChunks("application/octetstream",
+ new RandomBytesPublisher(1024,512)));
+ });
+ }
+
+ @Bean
+ public ServerConfig ratpackServerConfig() {
+ return ServerConfig
+ .builder()
+ .findBaseDir("public")
+ .build();
+ }
+
+ public static void main(String[] args) {
+ SpringApplication.run(EmbedRatpackStreamsApp.class, args);
+ }
+
+
+ public static class RandomBytesPublisher implements Publisher {
+
+ private int bufCount;
+ private int bufSize;
+ private Random rnd = new Random();
+
+
+ RandomBytesPublisher(int bufCount, int bufSize) {
+ this.bufCount = bufCount;
+ this.bufSize = bufSize;
+ }
+
+ @Override
+ public void subscribe(Subscriber super ByteBuf> s) {
+ s.onSubscribe(new Subscription() {
+
+ private boolean cancelled = false;
+ private boolean recurse;
+ private long requested = 0;
+
+ @Override
+ public void request(long n) {
+ if ( bufCount == 0 ) {
+ s.onComplete();
+ return;
+ }
+
+ requested += n;
+ if ( recurse ) {
+ return;
+ }
+
+ recurse = true;
+ try {
+ while ( requested-- > 0 && !cancelled && bufCount-- > 0 ) {
+ byte[] data = new byte[bufSize];
+ rnd.nextBytes(data);
+ ByteBuf buf = Unpooled.wrappedBuffer(data);
+ s.onNext(buf);
+ }
+ }
+ finally {
+ recurse = false;
+ }
+ }
+
+ @Override
+ public void cancel() {
+ cancelled = true;
+ }
+ });
+
+ }
+ }
+
+}
diff --git a/ratpack/src/test/java/com/baeldung/ratpack/CompliantPublisher.java b/ratpack/src/test/java/com/baeldung/ratpack/CompliantPublisher.java
new file mode 100644
index 0000000000..5526a630ff
--- /dev/null
+++ b/ratpack/src/test/java/com/baeldung/ratpack/CompliantPublisher.java
@@ -0,0 +1,63 @@
+package com.baeldung.ratpack;
+
+import org.reactivestreams.Publisher;
+import org.reactivestreams.Subscriber;
+import org.reactivestreams.Subscription;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+// Non-thread safe !!!
+class CompliantPublisher implements Publisher {
+ String name;
+
+ private static final Logger log = LoggerFactory.getLogger(CompliantPublisher.class);
+ private long available;
+
+
+ public CompliantPublisher(long available) {
+ this.available = available;
+ }
+
+ @Override
+ public void subscribe(Subscriber super Integer> subscriber) {
+ log.info("subscribe");
+ subscriber.onSubscribe(new CompliantSubscription(subscriber));
+
+ }
+
+
+ private class CompliantSubscription implements Subscription {
+
+ private Subscriber super Integer> subscriber;
+ private int recurseLevel;
+ private long requested;
+ private boolean cancelled;
+
+ public CompliantSubscription(Subscriber super Integer> subscriber) {
+ this.subscriber = subscriber;
+ }
+
+ @Override
+ public void request(long n) {
+ log.info("request: requested={}, available={}", n, available);
+ requested += n;
+ if ( recurseLevel > 0 ) {
+ return;
+ }
+
+ recurseLevel++;
+ for (int i = 0 ; i < (requested) && !cancelled && available > 0 ; i++, available-- ) {
+ subscriber.onNext(i);
+ }
+ subscriber.onComplete();
+ }
+
+ @Override
+ public void cancel() {
+ cancelled = true;
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/ratpack/src/test/java/com/baeldung/ratpack/LoggingSubscriber.java b/ratpack/src/test/java/com/baeldung/ratpack/LoggingSubscriber.java
new file mode 100644
index 0000000000..0d58b7c05e
--- /dev/null
+++ b/ratpack/src/test/java/com/baeldung/ratpack/LoggingSubscriber.java
@@ -0,0 +1,67 @@
+package com.baeldung.ratpack;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import org.reactivestreams.Subscriber;
+import org.reactivestreams.Subscription;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public class LoggingSubscriber implements Subscriber {
+ private static final Logger log = LoggerFactory.getLogger(LoggingSubscriber.class);
+
+ private Subscription subscription;
+ private long requested;
+ private long received;
+ private CountDownLatch finished = new CountDownLatch(1);
+
+ @Override
+ public void onComplete() {
+ log.info("onComplete: sub={}", subscription.hashCode());
+ finished.countDown();
+ }
+
+ @Override
+ public void onError(Throwable t) {
+ log.error("Error: sub={}, message={}", subscription.hashCode(), t.getMessage(),t);
+ finished.countDown();
+ }
+
+ @Override
+ public void onNext(T value) {
+ log.info("onNext: sub={}, value={}", subscription.hashCode(), value);
+ this.received++;
+ this.requested++;
+ subscription.request(1);
+ }
+
+ @Override
+ public void onSubscribe(Subscription sub) {
+ log.info("onSubscribe: sub={}", sub.hashCode());
+ this.subscription = sub;
+ this.received = 0;
+ this.requested = 1;
+ sub.request(1);
+ }
+
+
+ public long getRequested() {
+ return requested;
+ }
+
+ public long getReceived() {
+ return received;
+ }
+
+ public void block() {
+ try {
+ finished.await(10, TimeUnit.SECONDS);
+ }
+ catch(InterruptedException iex) {
+ throw new RuntimeException(iex);
+ }
+ }
+
+}
diff --git a/ratpack/src/test/java/com/baeldung/ratpack/NonCompliantPublisher.java b/ratpack/src/test/java/com/baeldung/ratpack/NonCompliantPublisher.java
new file mode 100644
index 0000000000..03b94d429d
--- /dev/null
+++ b/ratpack/src/test/java/com/baeldung/ratpack/NonCompliantPublisher.java
@@ -0,0 +1,46 @@
+package com.baeldung.ratpack;
+
+import org.reactivestreams.Publisher;
+import org.reactivestreams.Subscriber;
+import org.reactivestreams.Subscription;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public class NonCompliantPublisher implements Publisher {
+
+ private static final Logger log = LoggerFactory.getLogger(NonCompliantPublisher.class);
+
+ @Override
+ public void subscribe(Subscriber super Integer> subscriber) {
+ log.info("subscribe");
+ subscriber.onSubscribe(new NonCompliantSubscription(subscriber));
+ }
+
+ private class NonCompliantSubscription implements Subscription {
+ private Subscriber super Integer> subscriber;
+ private int recurseLevel = 0;
+
+ public NonCompliantSubscription(Subscriber super Integer> subscriber) {
+ this.subscriber = subscriber;
+ }
+
+ @Override
+ public void request(long n) {
+ log.info("request: n={}", n);
+ if ( recurseLevel > 0 ) {
+ return;
+ }
+
+ recurseLevel++;
+ for (int i = 0 ; i < (n + 5) ; i ++ ) {
+ subscriber.onNext(i);
+ }
+ subscriber.onComplete();
+ }
+
+ @Override
+ public void cancel() {
+ }
+ }
+}
\ No newline at end of file
diff --git a/ratpack/src/test/java/com/baeldung/ratpack/RatpackStreamsUnitTest.java b/ratpack/src/test/java/com/baeldung/ratpack/RatpackStreamsUnitTest.java
new file mode 100644
index 0000000000..54cc71c328
--- /dev/null
+++ b/ratpack/src/test/java/com/baeldung/ratpack/RatpackStreamsUnitTest.java
@@ -0,0 +1,140 @@
+package com.baeldung.ratpack;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.time.Duration;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+
+import org.junit.jupiter.api.Test;
+import org.reactivestreams.Publisher;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import ratpack.exec.ExecResult;
+import ratpack.func.Action;
+import ratpack.stream.StreamEvent;
+import ratpack.stream.Streams;
+import ratpack.stream.TransformablePublisher;
+import ratpack.test.exec.ExecHarness;
+
+public class RatpackStreamsUnitTest {
+
+ private static Logger log = LoggerFactory.getLogger(RatpackStreamsUnitTest.class);
+
+ @Test
+ public void whenPublish_thenSuccess() {
+
+ Publisher pub = Streams.publish(Arrays.asList("hello", "hello again"));
+ LoggingSubscriber sub = new LoggingSubscriber();
+ pub.subscribe(sub);
+ sub.block();
+ }
+
+
+ @Test
+ public void whenYield_thenSuccess() {
+
+ Publisher pub = Streams.yield((t) -> {
+ return t.getRequestNum() < 5 ? "hello" : null;
+ });
+
+ LoggingSubscriber sub = new LoggingSubscriber();
+ pub.subscribe(sub);
+ sub.block();
+ assertEquals(5, sub.getReceived());
+ }
+
+ @Test
+ public void whenPeriodic_thenSuccess() {
+ ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
+ Publisher pub = Streams.periodically(executor, Duration.ofSeconds(1), (t) -> {
+ return t < 5 ? String.format("hello %d",t): null;
+ });
+
+ LoggingSubscriber sub = new LoggingSubscriber();
+ pub.subscribe(sub);
+ sub.block();
+ assertEquals(5, sub.getReceived());
+ }
+
+ @Test
+ public void whenMap_thenSuccess() throws Exception {
+
+ TransformablePublisher pub = Streams.yield( t -> {
+ return t.getRequestNum() < 5 ? t.getRequestNum() : null;
+ })
+ .map(v -> String.format("item %d", v));
+
+ ExecResult> result = ExecHarness.yieldSingle((c) -> pub.toList() );
+ assertTrue("should succeed", result.isSuccess());
+ assertEquals("should have 5 items",5,result.getValue().size());
+ }
+
+ @Test
+ public void whenNonCompliantPublisherWithBuffer_thenSuccess() throws Exception {
+
+ TransformablePublisher pub = Streams.transformable(new NonCompliantPublisher())
+ .wiretap(new LoggingAction("before buffer"))
+ .buffer()
+ .wiretap(new LoggingAction("after buffer"))
+ .take(1);
+
+ LoggingSubscriber sub = new LoggingSubscriber<>();
+ pub.subscribe(sub);
+ sub.block();
+ }
+
+ @Test
+ public void whenNonCompliantPublisherWithoutBuffer_thenSuccess() throws Exception {
+ TransformablePublisher pub = Streams.transformable(new NonCompliantPublisher())
+ .wiretap(new LoggingAction(""))
+ .take(1);
+
+ LoggingSubscriber sub = new LoggingSubscriber<>();
+ pub.subscribe(sub);
+ sub.block();
+ }
+
+@Test
+public void whenCompliantPublisherWithoutBatch_thenSuccess() throws Exception {
+
+ TransformablePublisher pub = Streams.transformable(new CompliantPublisher(10))
+ .wiretap(new LoggingAction(""));
+
+ LoggingSubscriber sub = new LoggingSubscriber<>();
+ pub.subscribe(sub);
+ sub.block();
+}
+
+@Test
+public void whenCompliantPublisherWithBatch_thenSuccess() throws Exception {
+
+ TransformablePublisher pub = Streams.transformable(new CompliantPublisher(10))
+ .wiretap(new LoggingAction("before batch"))
+ .batch(5, Action.noop())
+ .wiretap(new LoggingAction("after batch"));
+
+ LoggingSubscriber sub = new LoggingSubscriber<>();
+ pub.subscribe(sub);
+ sub.block();
+}
+
+ private static class LoggingAction implements Action>{
+ private final String label;
+
+ public LoggingAction(String label) {
+ this.label = label;
+ }
+
+ @Override
+ public void execute(StreamEvent e) throws Exception {
+ log.info("{}: event={}", label,e);
+ }
+
+ }
+
+}
diff --git a/spring-5/src/main/java/com/baeldung/jdbc/autogenkey/repository/MessageRepositoryJDBCTemplate.java b/spring-5/src/main/java/com/baeldung/jdbc/autogenkey/repository/MessageRepositoryJDBCTemplate.java
deleted file mode 100644
index cf0dbe4681..0000000000
--- a/spring-5/src/main/java/com/baeldung/jdbc/autogenkey/repository/MessageRepositoryJDBCTemplate.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package com.baeldung.jdbc.autogenkey.repository;
-
-import java.sql.PreparedStatement;
-
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.jdbc.core.JdbcTemplate;
-import org.springframework.jdbc.support.GeneratedKeyHolder;
-import org.springframework.jdbc.support.KeyHolder;
-import org.springframework.stereotype.Repository;
-
-@Repository
-public class MessageRepositoryJDBCTemplate {
-
- @Autowired
- JdbcTemplate jdbcTemplate;
-
- final String INSERT_MESSAGE_SQL = "insert into sys_message (message) values(?) ";
-
- public long insert(final String message) {
-
- KeyHolder keyHolder = new GeneratedKeyHolder();
-
- jdbcTemplate.update(connection -> {
- PreparedStatement ps = connection.prepareStatement(INSERT_MESSAGE_SQL);
- ps.setString(1, message);
- return ps;
- }, keyHolder);
-
- return (long) keyHolder.getKey();
- }
-
- final String SELECT_BY_ID = "select message from sys_message where id = ?";
-
- public String getMessageById(long id) {
- return this.jdbcTemplate.queryForObject(SELECT_BY_ID, String.class, new Object[] { id });
- }
-
-}
diff --git a/spring-5/src/main/java/com/baeldung/jdbc/autogenkey/repository/MessageRepositorySimpleJDBCInsert.java b/spring-5/src/main/java/com/baeldung/jdbc/autogenkey/repository/MessageRepositorySimpleJDBCInsert.java
deleted file mode 100644
index 022ea29ed6..0000000000
--- a/spring-5/src/main/java/com/baeldung/jdbc/autogenkey/repository/MessageRepositorySimpleJDBCInsert.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package com.baeldung.jdbc.autogenkey.repository;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.sql.DataSource;
-
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
-import org.springframework.stereotype.Repository;
-
-@Repository
-public class MessageRepositorySimpleJDBCInsert {
-
- SimpleJdbcInsert messageInsert;
-
- @Autowired
- public MessageRepositorySimpleJDBCInsert(DataSource dataSource) {
- messageInsert = new SimpleJdbcInsert(dataSource).withTableName("sys_message").usingGeneratedKeyColumns("id");
- }
-
- public long insert(String message) {
- Map parameters = new HashMap(1);
- parameters.put("message", message);
- Number newId = messageInsert.executeAndReturnKey(parameters);
- return (long) newId;
- }
-
-}
diff --git a/spring-5/src/main/resources/autogenkey-db.properties b/spring-5/src/main/resources/autogenkey-db.properties
deleted file mode 100644
index 3e1a088dc1..0000000000
--- a/spring-5/src/main/resources/autogenkey-db.properties
+++ /dev/null
@@ -1,9 +0,0 @@
-spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_ON_EXIT=FALSE
-spring.datasource.username=sa
-spring.datasource.password=
-spring.datasource.driverClassName=org.h2.Driver
-spring.jpa.hibernate.ddl-auto=create
-spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect
-
-spring.datasource.initialize=true
-spring.datasource.schema=classpath:autogenkey-schema.sql
diff --git a/spring-5/src/main/resources/autogenkey-schema.sql b/spring-5/src/main/resources/autogenkey-schema.sql
deleted file mode 100644
index 925b27143c..0000000000
--- a/spring-5/src/main/resources/autogenkey-schema.sql
+++ /dev/null
@@ -1,5 +0,0 @@
-CREATE TABLE IF NOT EXISTS sys_message (
- id bigint(20) NOT NULL AUTO_INCREMENT,
- message varchar(100) NOT NULL,
- PRIMARY KEY (id)
-);
\ No newline at end of file
diff --git a/spring-5/src/test/java/com/baeldung/jdbc/autogenkey/GetAutoGenKeyByJDBCIntTest.java b/spring-5/src/test/java/com/baeldung/jdbc/autogenkey/GetAutoGenKeyByJDBCIntTest.java
deleted file mode 100644
index 14d2fb736b..0000000000
--- a/spring-5/src/test/java/com/baeldung/jdbc/autogenkey/GetAutoGenKeyByJDBCIntTest.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package com.baeldung.jdbc.autogenkey;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
-import org.springframework.context.annotation.ComponentScan;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.context.annotation.PropertySource;
-import org.springframework.test.context.junit4.SpringRunner;
-
-import com.baeldung.jdbc.autogenkey.repository.MessageRepositoryJDBCTemplate;
-import com.baeldung.jdbc.autogenkey.repository.MessageRepositorySimpleJDBCInsert;
-
-@RunWith(SpringRunner.class)
-@Ignore
-public class GetAutoGenKeyByJDBCIntTest {
-
- @Configuration
- @EnableAutoConfiguration
- @PropertySource("classpath:autogenkey-db.properties")
- @ComponentScan(basePackages = { "com.baeldung.jdbc.autogenkey.repository" })
- public static class SpringConfig {
-
- }
-
- @Autowired
- MessageRepositorySimpleJDBCInsert messageRepositorySimpleJDBCInsert;
-
- @Autowired
- MessageRepositoryJDBCTemplate messageRepositoryJDBCTemplate;
-
- final String MESSAGE_CONTENT = "Test";
-
- @Test
- public void insertJDBC_whenLoadMessageByKey_thenGetTheSameMessage() {
- long key = messageRepositoryJDBCTemplate.insert(MESSAGE_CONTENT);
- String loadedMessage = messageRepositoryJDBCTemplate.getMessageById(key);
-
- assertEquals(MESSAGE_CONTENT, loadedMessage);
-
- }
-
- @Test
- public void insertSimpleInsert_whenLoadMessageKey_thenGetTheSameMessage() {
- long key = messageRepositorySimpleJDBCInsert.insert(MESSAGE_CONTENT);
- String loadedMessage = messageRepositoryJDBCTemplate.getMessageById(key);
-
- assertEquals(MESSAGE_CONTENT, loadedMessage);
- }
-
-}
diff --git a/spring-security-modules/spring-security-web-mvc-custom/pom.xml b/spring-security-modules/spring-security-web-mvc-custom/pom.xml
index 539f83d7b8..533a1bf83d 100644
--- a/spring-security-modules/spring-security-web-mvc-custom/pom.xml
+++ b/spring-security-modules/spring-security-web-mvc-custom/pom.xml
@@ -175,6 +175,7 @@
19.0
+ 3.2.2
1.6.1
diff --git a/spring-security-modules/spring-security-web-mvc-custom/src/main/java/com/baeldung/web/interceptor/LoggerInterceptor.java b/spring-security-modules/spring-security-web-mvc-custom/src/main/java/com/baeldung/web/interceptor/LoggerInterceptor.java
index b54fda5a82..669e4cb3c5 100644
--- a/spring-security-modules/spring-security-web-mvc-custom/src/main/java/com/baeldung/web/interceptor/LoggerInterceptor.java
+++ b/spring-security-modules/spring-security-web-mvc-custom/src/main/java/com/baeldung/web/interceptor/LoggerInterceptor.java
@@ -1,16 +1,18 @@
package com.baeldung.web.interceptor;
-import com.google.common.base.Strings;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.web.servlet.ModelAndView;
-import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
+import java.util.Enumeration;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import java.util.Enumeration;
-public class LoggerInterceptor extends HandlerInterceptorAdapter {
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.servlet.HandlerInterceptor;
+import org.springframework.web.servlet.ModelAndView;
+
+import com.google.common.base.Strings;
+
+public class LoggerInterceptor implements HandlerInterceptor {
private static Logger log = LoggerFactory.getLogger(LoggerInterceptor.class);
@@ -50,7 +52,8 @@ public class LoggerInterceptor extends HandlerInterceptorAdapter {
if (posted.length() > 1)
posted.append("&");
final String curr = (String) e.nextElement();
- posted.append(curr).append("=");
+ posted.append(curr)
+ .append("=");
if (curr.contains("password") || curr.contains("answer") || curr.contains("pwd")) {
posted.append("*****");
} else {
diff --git a/spring-security-modules/spring-security-web-mvc-custom/src/main/java/com/baeldung/web/interceptor/SessionTimerInterceptor.java b/spring-security-modules/spring-security-web-mvc-custom/src/main/java/com/baeldung/web/interceptor/SessionTimerInterceptor.java
index 38e852305c..e7decc262f 100644
--- a/spring-security-modules/spring-security-web-mvc-custom/src/main/java/com/baeldung/web/interceptor/SessionTimerInterceptor.java
+++ b/spring-security-modules/spring-security-web-mvc-custom/src/main/java/com/baeldung/web/interceptor/SessionTimerInterceptor.java
@@ -8,10 +8,10 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
-import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
-public class SessionTimerInterceptor extends HandlerInterceptorAdapter {
+public class SessionTimerInterceptor implements HandlerInterceptor {
private static Logger log = LoggerFactory.getLogger(SessionTimerInterceptor.class);
@@ -30,7 +30,8 @@ public class SessionTimerInterceptor extends HandlerInterceptorAdapter {
request.setAttribute("executionTime", startTime);
if (UserInterceptor.isUserLogged()) {
session = request.getSession();
- log.info("Time since last request in this session: {} ms", System.currentTimeMillis() - request.getSession().getLastAccessedTime());
+ log.info("Time since last request in this session: {} ms", System.currentTimeMillis() - request.getSession()
+ .getLastAccessedTime());
if (System.currentTimeMillis() - session.getLastAccessedTime() > MAX_INACTIVE_SESSION_TIME) {
log.warn("Logging out, due to inactive session");
SecurityContextHolder.clearContext();
diff --git a/spring-security-modules/spring-security-web-mvc-custom/src/main/java/com/baeldung/web/interceptor/UserInterceptor.java b/spring-security-modules/spring-security-web-mvc-custom/src/main/java/com/baeldung/web/interceptor/UserInterceptor.java
index cd64a20842..ad80571be6 100644
--- a/spring-security-modules/spring-security-web-mvc-custom/src/main/java/com/baeldung/web/interceptor/UserInterceptor.java
+++ b/spring-security-modules/spring-security-web-mvc-custom/src/main/java/com/baeldung/web/interceptor/UserInterceptor.java
@@ -1,18 +1,18 @@
package com.baeldung.web.interceptor;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.security.core.context.SecurityContextHolder;
-import org.springframework.web.servlet.ModelAndView;
-import org.springframework.web.servlet.SmartView;
-import org.springframework.web.servlet.View;
-import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
-
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
-public class UserInterceptor extends HandlerInterceptorAdapter {
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.web.servlet.HandlerInterceptor;
+import org.springframework.web.servlet.ModelAndView;
+import org.springframework.web.servlet.SmartView;
+import org.springframework.web.servlet.View;
+
+public class UserInterceptor implements HandlerInterceptor {
private static Logger log = LoggerFactory.getLogger(UserInterceptor.class);
@@ -44,7 +44,9 @@ public class UserInterceptor extends HandlerInterceptorAdapter {
*/
private void addToModelUserDetails(HttpSession session) {
log.info("================= addToModelUserDetails ============================");
- String loggedUsername = SecurityContextHolder.getContext().getAuthentication().getName();
+ String loggedUsername = SecurityContextHolder.getContext()
+ .getAuthentication()
+ .getName();
session.setAttribute("username", loggedUsername);
log.info("user(" + loggedUsername + ") session : " + session);
log.info("================= addToModelUserDetails ============================");
@@ -56,7 +58,9 @@ public class UserInterceptor extends HandlerInterceptorAdapter {
*/
private void addToModelUserDetails(ModelAndView model) {
log.info("================= addToModelUserDetails ============================");
- String loggedUsername = SecurityContextHolder.getContext().getAuthentication().getName();
+ String loggedUsername = SecurityContextHolder.getContext()
+ .getAuthentication()
+ .getName();
model.addObject("loggedUsername", loggedUsername);
log.trace("session : " + model.getModel());
log.info("================= addToModelUserDetails ============================");
@@ -76,7 +80,10 @@ public class UserInterceptor extends HandlerInterceptorAdapter {
public static boolean isUserLogged() {
try {
- return !SecurityContextHolder.getContext().getAuthentication().getName().equals("anonymousUser");
+ return !SecurityContextHolder.getContext()
+ .getAuthentication()
+ .getName()
+ .equals("anonymousUser");
} catch (Exception e) {
return false;
}