From 29194d18e1bdff5fe39ac9db3ce56b5f2001e8aa Mon Sep 17 00:00:00 2001 From: Azhwani Date: Sun, 12 Sep 2021 13:13:51 +0200 Subject: [PATCH 1/7] init commit --- .../spring-security-web-mvc-custom/pom.xml | 1 + .../web/interceptor/LoggerInterceptor.java | 19 +++++++----- .../interceptor/SessionTimerInterceptor.java | 7 +++-- .../web/interceptor/UserInterceptor.java | 31 ++++++++++++------- 4 files changed, 35 insertions(+), 23 deletions(-) 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; } From d4dbc6a526ea171e895f7a8375746929dc1eb774 Mon Sep 17 00:00:00 2001 From: johnA1331 <53036378+johnA1331@users.noreply.github.com> Date: Wed, 13 Oct 2021 23:45:08 +0800 Subject: [PATCH 2/7] Create README.md --- maven-modules/maven-generate-war/README.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 maven-modules/maven-generate-war/README.md 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) From 68e0a1a0940d860bd8be711bd2a802af77f64d1e Mon Sep 17 00:00:00 2001 From: johnA1331 <53036378+johnA1331@users.noreply.github.com> Date: Wed, 13 Oct 2021 23:47:53 +0800 Subject: [PATCH 3/7] Update README.md --- quarkus-vs-springboot/README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) 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) From d64b8f1b2cc5397a74a315f5c5815f2ecd6c1864 Mon Sep 17 00:00:00 2001 From: johnA1331 <53036378+johnA1331@users.noreply.github.com> Date: Wed, 13 Oct 2021 23:55:55 +0800 Subject: [PATCH 4/7] Update README.md --- core-java-modules/core-java-annotations/README.md | 1 + 1 file changed, 1 insertion(+) 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) From 47abbf654b5bee31721b9d40d0115471b114142d Mon Sep 17 00:00:00 2001 From: psevestre Date: Thu, 14 Oct 2021 01:04:19 -0300 Subject: [PATCH 5/7] BAEL-772 Reactive Streams API with Ratpack (#11328) * [BAEL-4849] Article code * [BAEL-4968] Article code * [BAEL-4968] Article code * [BAEL-4968] Article code * [BAEL-4968] Remove extra comments * [BAEL-4020] Article code * [BAEL-722] Article code --- .../main/java/com/baeldung/model/Quote.java | 107 +++++++++ .../rxjava/service/QuotesService.java | 44 ++++ .../spring/EmbedRatpackStreamsApp.java | 206 ++++++++++++++++++ .../baeldung/ratpack/CompliantPublisher.java | 63 ++++++ .../baeldung/ratpack/LoggingSubscriber.java | 67 ++++++ .../ratpack/NonCompliantPublisher.java | 46 ++++ .../ratpack/RatpackStreamsUnitTest.java | 140 ++++++++++++ 7 files changed, 673 insertions(+) create mode 100644 ratpack/src/main/java/com/baeldung/model/Quote.java create mode 100644 ratpack/src/main/java/com/baeldung/rxjava/service/QuotesService.java create mode 100644 ratpack/src/main/java/com/baeldung/spring/EmbedRatpackStreamsApp.java create mode 100644 ratpack/src/test/java/com/baeldung/ratpack/CompliantPublisher.java create mode 100644 ratpack/src/test/java/com/baeldung/ratpack/LoggingSubscriber.java create mode 100644 ratpack/src/test/java/com/baeldung/ratpack/NonCompliantPublisher.java create mode 100644 ratpack/src/test/java/com/baeldung/ratpack/RatpackStreamsUnitTest.java 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 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 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 subscriber) { + log.info("subscribe"); + subscriber.onSubscribe(new CompliantSubscription(subscriber)); + + } + + + private class CompliantSubscription implements Subscription { + + private Subscriber subscriber; + private int recurseLevel; + private long requested; + private boolean cancelled; + + public CompliantSubscription(Subscriber 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 subscriber) { + log.info("subscribe"); + subscriber.onSubscribe(new NonCompliantSubscription(subscriber)); + } + + private class NonCompliantSubscription implements Subscription { + private Subscriber subscriber; + private int recurseLevel = 0; + + public NonCompliantSubscription(Subscriber 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); + } + + } + +} From 47b27beae07d1fea2f1b4524a73dd9cb750aac43 Mon Sep 17 00:00:00 2001 From: Rafael Lopez Date: Thu, 14 Oct 2021 17:16:56 -0400 Subject: [PATCH 6/7] JAVA-2595: Update Cassandra articles --- .../spring-data-cassandra/pom.xml | 46 ++----------------- 1 file changed, 4 insertions(+), 42 deletions(-) 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 From b63d7cc057c287b4c8ecb9b0ca384b9ac8886825 Mon Sep 17 00:00:00 2001 From: Shashank Date: Fri, 15 Oct 2021 08:56:39 +0530 Subject: [PATCH 7/7] autogen key code cleanup --- persistence-modules/spring-jdbc/README.md | 1 + persistence-modules/spring-jpa/README.md | 1 - .../MessageRepositoryJDBCTemplate.java | 38 ------------- .../MessageRepositorySimpleJDBCInsert.java | 29 ---------- .../main/resources/autogenkey-db.properties | 9 --- .../src/main/resources/autogenkey-schema.sql | 5 -- .../GetAutoGenKeyByJDBCIntTest.java | 55 ------------------- 7 files changed, 1 insertion(+), 137 deletions(-) delete mode 100644 spring-5/src/main/java/com/baeldung/jdbc/autogenkey/repository/MessageRepositoryJDBCTemplate.java delete mode 100644 spring-5/src/main/java/com/baeldung/jdbc/autogenkey/repository/MessageRepositorySimpleJDBCInsert.java delete mode 100644 spring-5/src/main/resources/autogenkey-db.properties delete mode 100644 spring-5/src/main/resources/autogenkey-schema.sql delete mode 100644 spring-5/src/test/java/com/baeldung/jdbc/autogenkey/GetAutoGenKeyByJDBCIntTest.java 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/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); - } - -}