Merge pull request #39 from eugenp/master

update
This commit is contained in:
Maiklins 2020-02-26 15:32:54 +01:00 committed by GitHub
commit 984a99b7cf
194 changed files with 1746 additions and 10245 deletions

View File

@ -11,5 +11,5 @@ This module contains articles about core Java input and output (IO)
- [List Files in a Directory in Java](https://www.baeldung.com/java-list-directory-files)
- [Java Append Data to a File](https://www.baeldung.com/java-append-to-file)
- [How to Copy a File with Java](https://www.baeldung.com/java-copy-file)
- [Create a Directory in Java](https://www.baeldung.com/java-create-directory)
- [Create a Directory in Java](https://www.baeldung.com/java-create-directory)
- [[<-- Prev]](/core-java-modules/core-java-io)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,148 @@
package com.baeldung.lock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.channels.NonReadableChannelException;
import java.nio.channels.NonWritableChannelException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
public class FileLocks {
private static final Logger LOG = LoggerFactory.getLogger(FileLocks.class);
// Write locks
/**
* Trying to get an exclusive lock on a read-only FileChannel won't work.
*/
static void getExclusiveLockFromInputStream() throws IOException {
Path path = Files.createTempFile("foo", "txt");
try (FileInputStream fis = new FileInputStream(path.toFile());
FileLock lock = fis.getChannel()
.lock()) {
LOG.debug("This won't happen");
} catch (NonWritableChannelException e) {
LOG.error("The channel obtained through a FileInputStream isn't writable. You can't obtain an exclusive lock on it!");
throw e;
}
}
/**
* Gets an exclusive lock from a RandomAccessFile. Works because the file is writable.
* @param from beginning of the locked region
* @param size how many bytes to lock
* @return A lock object representing the newly-acquired lock
* @throws IOException if there is a problem creating the temporary file
*/
static FileLock getExclusiveLockFromRandomAccessFile(long from, long size) throws IOException {
Path path = Files.createTempFile("foo", "txt");
try (RandomAccessFile file = new RandomAccessFile(path.toFile(), "rw");
FileLock lock = file.getChannel()
.lock(from, size, false)) {
if (lock.isValid()) {
LOG.debug("This is a valid exclusive lock");
return lock;
}
return null;
} catch (Exception e) {
LOG.error(e.getMessage());
}
return null;
}
/**
* Acquires an exclusive lock on a file region.
* @param from beginning of the locked region
* @param size how many bytes to lock
* @return A lock object representing the newly-acquired lock
* @throws IOException if there is a problem creating the temporary file
*/
static FileLock getExclusiveLockFromFileChannelOpen(long from, long size) throws IOException {
Path path = Files.createTempFile("foo", "txt");
try (FileChannel channel = FileChannel.open(path, StandardOpenOption.APPEND); FileLock lock = channel.lock(from, size, false)) {
String text = "Hello, world.";
ByteBuffer buffer = ByteBuffer.allocate(text.length() + System.lineSeparator()
.length());
buffer.put((text + System.lineSeparator()).getBytes(StandardCharsets.UTF_8));
buffer.flip();
while (buffer.hasRemaining()) {
channel.write(buffer, channel.size());
}
LOG.debug("This was written to the file");
Files.lines(path)
.forEach(LOG::debug);
return lock;
}
}
// Read locks
/**
* Trying to get a shared lock on a write-only FileChannel won't work.
*/
static void getReadLockFromOutputStream() throws IOException {
Path path = Files.createTempFile("foo", "txt");
try (FileOutputStream fis = new FileOutputStream(path.toFile());
FileLock lock = fis.getChannel()
.lock(0, Long.MAX_VALUE, true)) {
LOG.debug("This won't happen");
} catch (NonReadableChannelException e) {
LOG.error("The channel obtained through a FileOutputStream isn't readable. " + "You can't obtain an shared lock on it!");
throw e;
}
}
/**
* Gets a lock from an <tt>InputStream</tt>.
* @param from beginning of the locked region
* @param size how many bytes to lock
* @return A lock object representing the newly-acquired lock
* @throws IOException if there is a problem creating the temporary file
*/
static FileLock getReadLockFromInputStream(long from, long size) throws IOException {
Path path = Files.createTempFile("foo", "txt");
try (FileInputStream fis = new FileInputStream(path.toFile());
FileLock lock = fis.getChannel()
.lock(from, size, true)) {
if (lock.isValid()) {
LOG.debug("This is a valid shared lock");
return lock;
}
return null;
}
}
/**
* Gets an exclusive lock from a RandomAccessFile. Works because the file is readable.
* @param from beginning of the locked region
* @param size how many bytes to lock
* @return A lock object representing the newly-acquired lock
* @throws IOException if there is a problem creating the temporary file
*/
static FileLock getReadLockFromRandomAccessFile(long from, long size) throws IOException {
Path path = Files.createTempFile("foo", "txt");
try (RandomAccessFile file = new RandomAccessFile(path.toFile(), "r"); // could also be "rw", but "r" is sufficient for reading
FileLock lock = file.getChannel()
.lock(from, size, true)) {
if (lock.isValid()) {
LOG.debug("This is a valid shared lock");
return lock;
}
} catch (Exception e) {
LOG.error(e.getMessage());
}
return null;
}
}

View File

@ -0,0 +1,54 @@
package com.baeldung.lock;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.io.IOException;
import java.nio.channels.FileLock;
import java.nio.channels.NonReadableChannelException;
import java.nio.channels.NonWritableChannelException;
import org.junit.jupiter.api.Test;
class FileLocksUnitTest {
@Test
void givenAnInputStream_whenGetWriteLock_thenThrowNonWritableChannelException() {
assertThrows(NonWritableChannelException.class, () -> FileLocks.getExclusiveLockFromInputStream());
}
@Test
void givenARandomAccessFileWithReadWriteAccess_whenGetWriteLock_thenLock() throws IOException {
FileLock lock = FileLocks.getExclusiveLockFromRandomAccessFile(0, 10);
assertNotNull(lock);
assertFalse(lock.isShared());
}
@Test
void givenAPath_whenGetExclusiveLock_thenLock() throws IOException {
FileLock lock = FileLocks.getExclusiveLockFromFileChannelOpen(0, 10);
assertNotNull(lock);
assertFalse(lock.isShared());
}
@Test
void givenAFileOutputStream_whenGetSharedLock_thenThrowNonReadableChannelException() {
assertThrows(NonReadableChannelException.class, FileLocks::getReadLockFromOutputStream);
}
@Test
void givenAnInputStream_whenGetSharedLock_thenLock() throws IOException {
FileLock lock = FileLocks.getReadLockFromInputStream(0, 10);
assertNotNull(lock);
assertTrue(lock.isShared());
}
@Test
void givenARandomAccessFile_whenGetSharedLock_thenLock() throws IOException {
FileLock lock = FileLocks.getReadLockFromRandomAccessFile(0, 10);
assertNotNull(lock);
assertTrue(lock.isShared());
}
}

View File

@ -11,7 +11,7 @@
- [Introduction to Java Serialization](http://www.baeldung.com/java-serialization)
- [Guide to UUID in Java](http://www.baeldung.com/java-uuid)
- [Creating a Java Compiler Plugin](http://www.baeldung.com/java-build-compiler-plugin)
- [Quick Guide to Java Stack](http://www.baeldung.com/java-stack)
- [Quick Guide to the Java Stack](http://www.baeldung.com/java-stack)
- [Compiling Java *.class Files with javac](http://www.baeldung.com/javac)
- [Introduction to Javadoc](http://www.baeldung.com/javadoc)
- [Guide to the Externalizable Interface in Java](http://www.baeldung.com/java-externalizable)

View File

@ -1,4 +1,4 @@
package com.baeldung;
package com.baeldung.timer;
import org.junit.Test;
import org.slf4j.Logger;

View File

@ -5,4 +5,5 @@ This module contains articles about Kotlin core features.
### Relevant articles:
- [Working with Dates in Kotlin](https://www.baeldung.com/kotlin-dates)
- [Kotlin Ternary Conditional Operator](https://www.baeldung.com/kotlin-ternary-operator)
- [Sequences in Kotlin](https://www.baeldung.com/kotlin/sequences)
- [[<-- Prev]](/core-kotlin-modules/core-kotlin)

View File

@ -13,4 +13,7 @@ This module contains articles about Kotlin core features.
- [Implementing a Binary Tree in Kotlin](https://www.baeldung.com/kotlin-binary-tree)
- [JUnit 5 for Kotlin Developers](https://www.baeldung.com/junit-5-kotlin)
- [Converting Kotlin Data Class from JSON using GSON](https://www.baeldung.com/kotlin-json-convert-data-class)
- [Fuel HTTP Library with Kotlin](https://www.baeldung.com/kotlin-fuel)
- [Introduction to Kovenant Library for Kotlin](https://www.baeldung.com/kotlin-kovenant)
- [Dependency Injection for Kotlin with Injekt](https://www.baeldung.com/kotlin-dependency-injection-with-injekt)
- [[More --> ]](/core-kotlin-modules/core-kotlin-2)

View File

@ -5,3 +5,4 @@ This module contains articles about Scala's core features
### Relevant Articles:
- [Introduction to Scala](https://www.baeldung.com/scala-intro)
- [Regular Expressions in Scala](https://www.baeldung.com/scala/regular-expressions)

View File

@ -0,0 +1,82 @@
package com.baeldung.scala
import org.junit.Assert.assertEquals
import org.junit.Test
class HigherOrderFunctionsExamplesUnitTest {
@Test
def whenCallingMapWithAnonymousFunction_thenTransformationIsApplied() = {
val expected = Seq("sir Alex Ferguson", "sir Bobby Charlton", "sir Frank Lampard")
val names = Seq("Alex Ferguson", "Bobby Charlton", "Frank Lampard")
val sirNames = names.map(name => "sir " + name)
assertEquals(expected, sirNames)
}
@Test
def whenCallingMapWithDefined_thenTransformationIsApplied() = {
val expected = Seq("sir Alex Ferguson", "sir Bobby Charlton", "sir Frank Lampard")
val names = Seq("Alex Ferguson", "Bobby Charlton", "Frank Lampard")
def prefixWithSir(name: String) = "sir " + name
val sirNames = names.map(prefixWithSir)
assertEquals(expected, sirNames)
}
@Test
def whenCallingFilter_thenUnecessaryElementsAreRemoved() = {
val expected = Seq("John O'Shea", "John Hartson")
val names = Seq("John O'Shea", "Aiden McGeady", "John Hartson")
val johns = names.filter(name => name.matches("^John .*"))
assertEquals(expected, johns)
}
@Test
def whenCallingReduce_thenProperSumIsCalculated() = {
val expected = 2750
val earnings = Seq(1000, 1300, 450)
val sumEarnings = earnings.reduce((acc, x) => acc + x)
assertEquals(expected, sumEarnings)
}
@Test
def whenCallingFold_thenNumberOfWordsShouldBeCalculated() = {
val expected = 6
val strings = Seq("bunch of words", "just me", "it")
val sumEarnings = strings.foldLeft(0)((acc, x) => acc + x.split(" ").size)
assertEquals(expected, sumEarnings)
}
@Test
def whenCallingOwnHigherOrderFunction_thenProperFunctionIsReturned() = {
def mathOperation(name: String): (Int, Int) => Int = (x: Int, y: Int) => {
name match {
case "addition" => x + y
case "multiplication" => x * y
case "division" => x/y
case "subtraction" => x - y
}
}
def add: (Int, Int) => Int = mathOperation("addition")
def mul: (Int, Int) => Int = mathOperation("multiplication")
def div: (Int, Int) => Int = mathOperation("division")
def sub: (Int, Int) => Int = mathOperation("subtraction")
assertEquals(15, add(10, 5))
assertEquals(50, mul(10, 5))
assertEquals(2, div(10, 5))
assertEquals(5, sub(10, 5))
}
}

View File

@ -1,4 +1,4 @@
package com.baeldung.scala
package com.baeldung.scala.regex
import org.junit.Test
import org.junit.Assert.assertEquals

View File

@ -12,15 +12,32 @@
<version>0.0.1-SNAPSHOT</version>
<relativePath>../parent-java</relativePath>
</parent>
<dependencies>
<dependency>
<dependency>
<groupId>it.unimi.dsi</groupId>
<artifactId>dsiutils</artifactId>
<version>${dsiutils.version}</version>
</dependency>
<dependency>
<groupId>io.vavr</groupId>
<artifactId>vavr</artifactId>
<version>${vavr.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>${assertj.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>java-numbers-3</finalName>
<resources>
@ -33,6 +50,9 @@
<properties>
<dsiutils.version>2.6.0</dsiutils.version>
<vavr.version>0.10.2</vavr.version>
<commons.version>3.9</commons.version>
<assertj.version>3.6.1</assertj.version>
</properties>
</project>

View File

@ -0,0 +1,149 @@
package com.baeldung.parsedouble;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.Optional;
import org.apache.commons.lang3.math.NumberUtils;
import org.junit.Test;
import com.google.common.base.MoreObjects;
import com.google.common.primitives.Doubles;
import io.vavr.control.Try;
public class StringToDoubleParserUnitTest {
@Test
public void givenNullValue_whenParseStringToDouble_thenDefaultNaNValueIsReturned() {
assertThat(parseStringToDouble(null)).isNaN();
}
@Test
public void givenEmptyStringValue_whenParseStringToDouble_thenDefaultNaNValueIsReturned() {
assertThat(parseStringToDouble("")).isNaN();
}
@Test
public void givenStringValue_whenParseStringToDouble_thenDoubleValueIsReturned() {
assertThat(parseStringToDouble("1")).isEqualTo(1.0d);
}
@Test
public void givenStringValue_whenParseStringToDoubleWithDefault_thenDoubleValueIsReturned() {
assertThat(parseStringToDouble("1", 2.0d)).isEqualTo(1.0d);
}
@Test
public void givenEmptyStringValue_whenParseStringToDoubleWithDefault_thenDefaultValueIsReturned() {
assertThat(parseStringToDouble("", 1.0d)).isEqualTo(1.0d);
}
@Test
public void givenNullValue_whenParseStringToDoubleWithDefault_thenDefaultValueIsReturned() {
assertThat(parseStringToDouble(null, 1.0d)).isEqualTo(1.0d);
}
@Test
public void givenStringValue_whenParseStringToOptionalDouble_thenOptionalValueIsReturned() {
assertThat(parseStringToOptionalDouble("1")).isEqualTo(Optional.of(1.0d));
}
@Test
public void givenNullValue_whenParseStringToOptionalDouble_thenOptionalValueIsEmpty() {
assertThat(parseStringToOptionalDouble(null)).isEqualTo(Optional.empty());
}
@Test
public void givenEmptyStringValue_whenParseStringToOptionalDouble_thenOptionalValueIsEmpty() {
assertThat(parseStringToOptionalDouble("")).isEqualTo(Optional.empty());
}
@Test
public void givenEmptyStringValue_whenParseStringToOptionalDouble_thenDefaulOptionalValueIsReturned() {
assertThat(parseStringToOptionalDouble("").orElse(1.0d)).isEqualTo(1.0d);
}
@Test
public void givenNullValue_whenParseStringToOptionalDouble_thenDefaulOptionalValueIsReturned() {
assertThat(parseStringToOptionalDouble(null).orElse(1.0d)).isEqualTo(1.0d);
}
@Test
public void givenStringValue_whenTryStringToDouble_thenDoubleValueIsReturned() {
assertThat(tryStringToDouble("1", 2.0d)).isEqualTo(1.0d);
}
@Test
public void givenNullValue_whenTryStringToDoubleWithDefault_thenDoubleValueIsReturned() {
assertThat(tryStringToDouble(null, 2.0d)).isEqualTo(2.0d);
}
@Test
public void givenEmptyStringValue_whenTryStringToDoubleWithDefault_thenDoubleValueIsReturned() {
assertThat(tryStringToDouble("", 2.0d)).isEqualTo(2.0d);
}
@Test
public void givenTwoStringValues_whenTryParseFirstNonNull_thenDoubleValueIsReturned() {
assertThat(Doubles.tryParse(MoreObjects.firstNonNull("1.0", "2.0"))).isEqualTo(1.0d);
}
@Test
public void givenNullStringValue_whenTryParseFirstNonNull_thenSecondDoubleValueIsReturned() {
assertThat(Doubles.tryParse(MoreObjects.firstNonNull(null, "2.0"))).isEqualTo(2.0d);
}
@Test
public void givenEmptyStringValue_whenTryParseFirstNonNull_thenNullIsReturned() {
assertThat(Doubles.tryParse(MoreObjects.firstNonNull("", "2.0"))).isEqualTo(null);
}
@Test
public void givenStringValue_whenToDouble_thenDoubleValueIsReturned() {
assertThat(NumberUtils.toDouble("1.0")).isEqualTo(1.0d);
}
@Test
public void givenNullValue_whenToDouble_thenLibraryDefaultDoubleValueIsReturned() {
String nullString = null;
assertThat(NumberUtils.toDouble(nullString)).isEqualTo(0.0d);
}
@Test
public void givenEmptyStringValue_whenToDouble_thenLibraryDefaultDoubleValueIsReturned() {
assertThat(NumberUtils.toDouble("")).isEqualTo(0.0d);
}
@Test
public void givenEmptyStringValue_whenToDoubleWithDefault_thenDoubleValueIsReturned() {
assertThat(NumberUtils.toDouble("", 2.0d)).isEqualTo(2.0d);
}
@Test
public void givenNullValue_whenToDoubleWithDefault_thenDoubleValueIsReturned() {
String nullString = null;
assertThat(NumberUtils.toDouble(nullString, 2.0d)).isEqualTo(2.0d);
}
@Test
public void givenStringValue_whenToDoubleWithDefault_thenDoubleValueIsReturned() {
assertThat(NumberUtils.toDouble("1.0", 2.0d)).isEqualTo(1.0d);
}
private static Optional<Double> parseStringToOptionalDouble(String value) {
return value == null || value.isEmpty() ? Optional.empty() : Optional.of(Double.valueOf(value));
}
private static double parseStringToDouble(String value) {
return value == null || value.isEmpty() ? Double.NaN : Double.parseDouble(value);
}
private static double parseStringToDouble(String value, double defaultValue) {
return value == null || value.isEmpty() ? defaultValue : Double.parseDouble(value);
}
private static double tryStringToDouble(String value, double defaultValue) {
return Try.of(() -> Double.parseDouble(value)).getOrElse(defaultValue);
}
}

View File

@ -36,12 +36,12 @@
<profiles>
<profile>
<id>default-tools.jar</id>
<id>default-profile</id>
<activation>
<property>
<name>java.vendor</name>
<value>Oracle Corporation</value>
</property>
<activeByDefault>true</activeByDefault>
<file>
<exists>${java.home}/../lib/tools.jar</exists>
</file>
</activation>
<dependencies>
<dependency>
@ -53,6 +53,24 @@
</dependency>
</dependencies>
</profile>
<profile>
<id>mac-profile</id>
<activation>
<activeByDefault>false</activeByDefault>
<file>
<exists>${java.home}/../Classes/classes.jar</exists>
</file>
</activation>
<dependencies>
<dependency>
<groupId>com.sun</groupId>
<artifactId>tools</artifactId>
<version>${java.version}</version>
<scope>system</scope>
<systemPath>${java.home}/../Classes/classes.jar</systemPath>
</dependency>
</dependencies>
</profile>
</profiles>
<properties>

View File

@ -0,0 +1,43 @@
package controllers;
import play.data.Form;
import play.data.FormFactory;
import play.mvc.Controller;
import play.mvc.Result;
import javax.inject.Inject;
// Add the following to conf/routes
/*
GET /$model;format="camel"$ controllers.$model;format="Camel"$Controller.$model;format="camel"$Get
POST /$model;format="camel"$ controllers.$model;format="Camel"$Controller.$model;format="camel"$Post
*/
/**
* $model;format="Camel"$ form controller for Play Java
*/
public class $model;format="Camel"$Controller extends Controller {
private final Form<$model;format="Camel"$Data> $model;format="camel"$Form;
@Inject
public $model;format="Camel"$Controller(FormFactory formFactory) {
this.$model;format="camel"$Form = formFactory.form($model;format="Camel"$Data.class);
}
public Result $model;format="camel"$Get() {
return ok(views.html.$model;format="camel"$.form.render($model;format="camel"$Form));
}
public Result $model;format="camel"$Post() {
Form<$model;format="Camel"$Data> boundForm = $model;format="camel"$Form.bindFromRequest();
if (boundForm.hasErrors()) {
return badRequest(views.html.$model;format="camel"$.form.render(boundForm));
} else {
$model;format="Camel"$Data $model;format="camel"$ = boundForm.get();
flash("success", "$model;format="Camel"$ " + $model;format="camel"$);
return redirect(routes.$model;format="Camel"$Controller.$model;format="camel"$Get());
}
}
}

View File

@ -0,0 +1,37 @@
package controllers;
import play.data.validation.Constraints;
public class $model;format="Camel"$Data {
@Constraints.Required
private String name;
@Constraints.Required
private Integer age;
public $model;format="Camel"$Data() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return String.format("$model;format="Camel"$Data(%s, %s)", name, age);
}
}

View File

@ -0,0 +1,12 @@
@($model;format="camel"$Form: Form[$model;format="Camel"$Data])
<h1>$model;format="camel"$ form</h1>
@flash.getOrDefault("success", "")
@helper.form(action = routes.$model;format="Camel"$Controller.$model;format="camel"$Post()) {
@helper.CSRF.formField
@helper.inputText($model;format="camel"$Form("name"))
@helper.inputText($model;format="camel"$Form("age"))
<input type="submit" value="submit"/>
}

View File

@ -0,0 +1,2 @@
description = Generates a Controller with form handling
model = user

View File

@ -0,0 +1 @@
Temporary file until g8-scaffold will generate "test" directory

View File

@ -0,0 +1,50 @@
package controllers;
import org.junit.Test;
import play.Application;
import play.filters.csrf.*;
import play.inject.guice.GuiceApplicationBuilder;
import play.mvc.*;
import play.test.WithApplication;
import java.util.HashMap;
import static org.junit.Assert.assertEquals;
import static play.mvc.Http.RequestBuilder;
import static play.mvc.Http.Status.OK;
import static play.test.Helpers.*;
import static play.api.test.CSRFTokenHelper.*;
public class $model;format="Camel"$ControllerTest extends WithApplication {
@Override
protected Application provideApplication() {
return new GuiceApplicationBuilder().build();
}
@Test
public void test$model;format="Camel"$Get() {
RequestBuilder request = new RequestBuilder()
.method(GET)
.uri("/$model;format="camel"$");
Result result = route(app, request);
assertEquals(OK, result.status());
}
@Test
public void test$model;format="Camel"$Post() {
HashMap<String, String> formData = new HashMap<>();
formData.put("name", "play");
formData.put("age", "4");
RequestBuilder request = addCSRFToken(new RequestBuilder()
.header(Http.HeaderNames.HOST, "localhost")
.method(POST)
.bodyForm(formData)
.uri("/$model;format="camel"$"));
Result result = route(app, request);
assertEquals(SEE_OTHER, result.status());
}
}

8
play-framework/async-http/.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
logs
target
/.idea
/.idea_modules
/.classpath
/.project
/.settings
/RUNNING_PID

View File

@ -0,0 +1,38 @@
package controllers;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.ImmutableMap;
import java.util.Collections;
import java.util.Map;
import play.mvc.Controller;
import play.mvc.Http;
import play.mvc.Result;
/**
* This controller contains an action to handle HTTP requests to the application's home page.
*/
public class HomeController extends Controller {
/**
* An action that renders an HTML page with a welcome message. The configuration in the
* <code>routes</code> file means that this method will be called when the application receives
* a
* <code>GET</code> request with a path of <code>/</code>.
*/
public Result index(Http.Request request) throws JsonProcessingException {
return ok(printStats(request));
}
private String printStats(Http.Request request) throws JsonProcessingException {
Map<String, String[]> stringMap = request.body()
.asFormUrlEncoded();
Map<String, Object> map = ImmutableMap.of(
"Result", "ok",
"GetParams", request.queryString(),
"PostParams", stringMap == null ? Collections.emptyMap() : stringMap,
"Headers", request.getHeaders().toMap()
);
return new ObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(map);
}
}

View File

@ -0,0 +1,5 @@
@()
@main("Welcome to Play") {
<h1>Welcome to Play!</h1>
}

View File

@ -0,0 +1,24 @@
@*
* This template is called from the `index` template. This template
* handles the rendering of the page header and body tags. It takes
* two arguments, a `String` for the title of the page and an `Html`
* object to insert into the body of the page.
*@
@(title: String)(content: Html)
<!DOCTYPE html>
<html lang="en">
<head>
@* Here's where we render the page title `String`. *@
<title>@title</title>
<link rel="stylesheet" media="screen" href="@routes.Assets.versioned("stylesheets/main.css")">
<link rel="shortcut icon" type="image/png" href="@routes.Assets.versioned("images/favicon.png")">
</head>
<body>
@* And here's where we render the `Html` object containing
* the page content. *@
@content
<script src="@routes.Assets.versioned("javascripts/main.js")" type="text/javascript"></script>
</body>
</html>

View File

@ -0,0 +1,12 @@
name := """async"""
organization := "com.example"
version := "1.0-SNAPSHOT"
lazy val root = (project in file(".")).enablePlugins(PlayJava)
scalaVersion := "2.13.1"
// comment out the original line
libraryDependencies += guice
libraryDependencies += javaWs

View File

@ -0,0 +1,11 @@
# This is the main configuration file for the application.
# https://www.playframework.com/documentation/latest/ConfigFile
play.ws.followRedirects=false
play.ws.useragent=MyPlayApplication
play.ws.compressionEnabled=true
# time to wait for the connection to be established
play.ws.timeout.connection=30.seconds
# time to wait for data after the connection is open
play.ws.timeout.idle=30.seconds
# max time available to complete the request
play.ws.timeout.request=300.seconds

View File

@ -0,0 +1,36 @@
<!-- https://www.playframework.com/documentation/latest/SettingsLogger -->
<configuration>
<conversionRule conversionWord="coloredLevel" converterClass="play.api.libs.logback.ColoredLevel" />
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>${application.home:-.}/logs/application.log</file>
<encoder>
<pattern>%date [%level] from %logger in %thread - %message%n%xException</pattern>
</encoder>
</appender>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%coloredLevel %logger{15} - %message%n%xException{10}</pattern>
</encoder>
</appender>
<appender name="ASYNCFILE" class="ch.qos.logback.classic.AsyncAppender">
<appender-ref ref="FILE" />
</appender>
<appender name="ASYNCSTDOUT" class="ch.qos.logback.classic.AsyncAppender">
<appender-ref ref="STDOUT" />
</appender>
<logger name="play" level="INFO" />
<logger name="application" level="DEBUG" />
<logger name="controllers" level="DEBUG" />
<root level="WARN">
<appender-ref ref="ASYNCFILE" />
<appender-ref ref="ASYNCSTDOUT" />
</root>
</configuration>

View File

@ -0,0 +1,10 @@
# Routes
# This file defines all application routes (Higher priority routes first)
# ~~~~
# An example controller showing a sample home page
GET / controllers.HomeController.index(request: Request)
POST / controllers.HomeController.index(request: Request)
# Map static resources from the /public folder to the /assets URL path
GET /assets/*file controllers.Assets.versioned(path="/public", file: Asset)

View File

@ -0,0 +1 @@
sbt.version=1.3.3

View File

@ -0,0 +1,7 @@
// The Play plugin
addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.7.3")
// Defines scaffolding (found under .g8 folder)
// http://www.foundweekends.org/giter8/scaffolding.html
// sbt "g8Scaffold form"
addSbtPlugin("org.foundweekends.giter8" % "sbt-giter8-scaffold" % "0.11.0")

Binary file not shown.

After

Width:  |  Height:  |  Size: 687 B

View File

@ -0,0 +1,232 @@
package controllers;
import static java.time.temporal.ChronoUnit.SECONDS;
import static org.junit.Assert.assertEquals;
import static play.mvc.Http.Status.SERVICE_UNAVAILABLE;
import akka.Done;
import akka.actor.ActorSystem;
import akka.stream.ActorMaterializer;
import akka.stream.javadsl.Sink;
import akka.util.ByteString;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Duration;
import java.util.OptionalInt;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.IntStream;
import org.apache.http.HttpStatus;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import play.Application;
import play.inject.guice.GuiceApplicationBuilder;
import play.libs.concurrent.Futures;
import play.libs.ws.WSClient;
import play.libs.ws.WSResponse;
import play.libs.ws.ahc.AhcCurlRequestLogger;
import play.mvc.Result;
import play.mvc.Results;
import play.test.WithServer;
public class HomeControllerTest extends WithServer {
private final Logger log = LoggerFactory.getLogger(HomeControllerTest.class);
private String url;
private int port;
@Override
protected Application provideApplication() {
return new GuiceApplicationBuilder().build();
}
@Before
public void setup() {
OptionalInt optHttpsPort = testServer.getRunningHttpsPort();
if (optHttpsPort.isPresent()) {
port = optHttpsPort.getAsInt();
url = "https://localhost:" + port;
} else {
port = testServer.getRunningHttpPort()
.getAsInt();
url = "http://localhost:" + port;
}
}
@Test
public void givenASingleGetRequestWhenResponseThenBlockWithCompletableAndLog()
throws Exception {
WSClient ws = play.test.WSTestClient.newClient(port);
WSResponse wsResponse = ws.url(url)
.setRequestFilter(new AhcCurlRequestLogger())
.addHeader("key", "value")
.addQueryParameter("num", "" + 1)
.get()
.toCompletableFuture()
.get();
log.debug("Thread#" + Thread.currentThread()
.getId() + " Request complete: Response code = "
+ wsResponse.getStatus()
+ " | Response: " + wsResponse.getBody() + " | Current Time:"
+ System.currentTimeMillis());
assert (HttpStatus.SC_OK == wsResponse.getStatus());
}
@Test
public void givenASingleGetRequestWhenResponseThenLog() throws Exception {
CountDownLatch latch = new CountDownLatch(1);
WSClient ws = play.test.WSTestClient.newClient(port);
ws.url(url)
.setRequestFilter(new AhcCurlRequestLogger())
.addHeader("key", "value")
.addQueryParameter("num", "" + 1)
.get()
.thenAccept(r -> {
log.debug("Thread#" + Thread.currentThread()
.getId() + " Request complete: Response code = "
+ r.getStatus()
+ " | Response: " + r.getBody() + " | Current Time:" + System.currentTimeMillis());
latch.countDown();
});
log.debug(
"Waiting for requests to be completed. Current Time: " + System.currentTimeMillis());
latch.await(5, TimeUnit.SECONDS );
assertEquals(0, latch.getCount());
log.debug("All requests have been completed. Exiting test.");
}
@Test
public void givenASinglePostRequestWhenResponseThenLog() throws Exception {
CountDownLatch latch = new CountDownLatch(1);
WSClient ws = play.test.WSTestClient.newClient(port);
ws.url(url)
.setContentType("application/x-www-form-urlencoded")
.post("key1=value1&key2=value2")
.thenAccept(r -> {
log.debug("Thread#" + Thread.currentThread()
.getId() + " Request complete: Response code = "
+ r.getStatus()
+ " | Response: " + r.getBody() + " | Current Time:" + System.currentTimeMillis());
latch.countDown();
});
log.debug(
"Waiting for requests to be completed. Current Time: " + System.currentTimeMillis());
latch.await(5, TimeUnit.SECONDS );
assertEquals(0, latch.getCount());
log.debug("All requests have been completed. Exiting test.");
}
@Test
public void givenMultipleRequestsWhenResponseThenLog() throws Exception {
CountDownLatch latch = new CountDownLatch(100);
WSClient ws = play.test.WSTestClient.newClient(port);
IntStream.range(0, 100)
.parallel()
.forEach(num ->
ws.url(url)
.setRequestFilter(new AhcCurlRequestLogger())
.addHeader("key", "value")
.addQueryParameter("num", "" + num)
.get()
.thenAccept(r -> {
log.debug(
"Thread#" + num + " Request complete: Response code = " + r.getStatus()
+ " | Response: " + r.getBody() + " | Current Time:"
+ System.currentTimeMillis());
latch.countDown();
})
);
log.debug(
"Waiting for requests to be completed. Current Time: " + System.currentTimeMillis());
latch.await(5, TimeUnit.SECONDS );
assertEquals(0, latch.getCount());
log.debug("All requests have been completed. Exiting test.");
}
@Test
public void givenLongResponseWhenTimeoutThenHandle() throws Exception {
CountDownLatch latch = new CountDownLatch(1);
WSClient ws = play.test.WSTestClient.newClient(port);
Futures futures = app.injector()
.instanceOf(Futures.class);
CompletionStage<Result> f = futures.timeout(
ws.url(url)
.setRequestTimeout(Duration.of(1, SECONDS))
.get()
.thenApply(result -> {
try {
Thread.sleep(2000L);
return Results.ok();
} catch (InterruptedException e) {
return Results.status(
SERVICE_UNAVAILABLE);
}
}), 1L, TimeUnit.SECONDS
);
CompletionStage<Object> res = f.handleAsync((result, e) -> {
if (e != null) {
log.error("Exception thrown", e);
latch.countDown();
return e.getCause();
} else {
return result;
}
});
res.thenAccept(result -> assertEquals(TimeoutException.class, result));
log.debug(
"Waiting for requests to be completed. Current Time: " + System.currentTimeMillis());
latch.await(5, TimeUnit.SECONDS );
assertEquals(0, latch.getCount());
log.debug("All requests have been completed. Exiting test.");
}
@Test
public void givenMultigigabyteResponseConsumeWithStreams() throws Exception {
CountDownLatch latch = new CountDownLatch(1);
final ActorSystem system = ActorSystem.create();
final ActorMaterializer materializer = ActorMaterializer.create(system);
final Path path = Files.createTempFile("tmp_", ".out");
WSClient ws = play.test.WSTestClient.newClient(port);
log.info("Starting test server on url: " + url);
ws.url(url)
.stream()
.thenAccept(
response -> {
try {
OutputStream outputStream = java.nio.file.Files.newOutputStream(path);
Sink<ByteString, CompletionStage<Done>> outputWriter =
Sink.foreach(bytes -> {
log.info("Reponse: " + bytes.utf8String());
outputStream.write(bytes.toArray());
});
response.getBodyAsSource()
.runWith(outputWriter, materializer);
} catch (IOException e) {
log.error("An error happened while opening the output stream", e);
}
})
.whenComplete((value, error) -> latch.countDown());
log.debug(
"Waiting for requests to be completed. Current Time: " + System.currentTimeMillis());
latch.await(5, TimeUnit.SECONDS );
assertEquals(0, latch.getCount());
log.debug("All requests have been completed. Exiting test.");
}
}

View File

@ -639,7 +639,6 @@
<module>spring-batch</module>
<module>spring-bom</module>
<module>spring-boot-modules</module>
<module>spring-boot-parent</module>
<module>spring-boot-rest</module>
<module>spring-caching</module>
@ -1141,7 +1140,6 @@
<module>spring-batch</module>
<module>spring-bom</module>
<module>spring-boot-modules</module>
<module>spring-boot-parent</module>
<module>spring-boot-rest</module>
<module>spring-caching</module>

View File

@ -0,0 +1,11 @@
package com.baeldung.springamqp.exponentialbackoff;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ExponentialBackoffApp {
public static void main(String[] args) {
SpringApplication.run(ExponentialBackoffApp.class, args);
}
}

View File

@ -0,0 +1,21 @@
package com.baeldung.springamqp.exponentialbackoff;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.retry.RejectAndDontRequeueRecoverer;
public class ObservableRejectAndDontRequeueRecoverer extends RejectAndDontRequeueRecoverer {
private Runnable observer;
@Override
public void recover(Message message, Throwable cause) {
if(observer != null) {
observer.run();
}
super.recover(message, cause);
}
void setObserver(Runnable observer){
this.observer = observer;
}
}

View File

@ -0,0 +1,162 @@
package com.baeldung.springamqp.exponentialbackoff;
import org.aopalliance.aop.Advice;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.AmqpAdmin;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.QueueBuilder;
import org.springframework.amqp.rabbit.annotation.EnableRabbit;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.config.RetryInterceptorBuilder;
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.retry.interceptor.RetryOperationsInterceptor;
import com.rabbitmq.client.Channel;
@EnableRabbit
@Configuration
public class RabbitConfiguration {
private static Logger logger = LoggerFactory.getLogger(RabbitConfiguration.class);
@Bean
public ConnectionFactory connectionFactory() {
return new CachingConnectionFactory("localhost");
}
@Bean
public AmqpAdmin amqpAdmin() {
return new RabbitAdmin(connectionFactory());
}
@Bean
public RabbitTemplate rabbitTemplate() {
return new RabbitTemplate(connectionFactory());
}
@Bean
public Queue blockingQueue() {
return QueueBuilder.nonDurable("blocking-queue")
.build();
}
@Bean
public Queue nonBlockingQueue() {
return QueueBuilder.nonDurable("non-blocking-queue")
.build();
}
@Bean
public Queue retryWaitEndedQueue() {
return QueueBuilder.nonDurable("retry-wait-ended-queue")
.build();
}
@Bean
public Queue retryQueue1() {
return QueueBuilder.nonDurable("retry-queue-1")
.deadLetterExchange("")
.deadLetterRoutingKey("retry-wait-ended-queue")
.build();
}
@Bean
public Queue retryQueue2() {
return QueueBuilder.nonDurable("retry-queue-2")
.deadLetterExchange("")
.deadLetterRoutingKey("retry-wait-ended-queue")
.build();
}
@Bean
public Queue retryQueue3() {
return QueueBuilder.nonDurable("retry-queue-3")
.deadLetterExchange("")
.deadLetterRoutingKey("retry-wait-ended-queue")
.build();
}
@Bean
public RetryQueues retryQueues() {
return new RetryQueues(1000, 3.0, 10000, retryQueue1(), retryQueue2(), retryQueue3());
}
@Bean
public ObservableRejectAndDontRequeueRecoverer observableRecoverer() {
return new ObservableRejectAndDontRequeueRecoverer();
}
@Bean
public RetryOperationsInterceptor retryInterceptor() {
return RetryInterceptorBuilder.stateless()
.backOffOptions(1000, 3.0, 10000)
.maxAttempts(5)
.recoverer(observableRecoverer())
.build();
}
@Bean
public RetryQueuesInterceptor retryQueuesInterceptor(RabbitTemplate rabbitTemplate, RetryQueues retryQueues) {
return new RetryQueuesInterceptor(rabbitTemplate, retryQueues);
}
@Bean
public SimpleRabbitListenerContainerFactory defaultContainerFactory(ConnectionFactory connectionFactory) {
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
factory.setConnectionFactory(connectionFactory);
return factory;
}
@Bean
public SimpleRabbitListenerContainerFactory retryContainerFactory(ConnectionFactory connectionFactory, RetryOperationsInterceptor retryInterceptor) {
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
factory.setConnectionFactory(connectionFactory);
Advice[] adviceChain = { retryInterceptor };
factory.setAdviceChain(adviceChain);
return factory;
}
@Bean
public SimpleRabbitListenerContainerFactory retryQueuesContainerFactory(ConnectionFactory connectionFactory, RetryQueuesInterceptor retryInterceptor) {
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
factory.setConnectionFactory(connectionFactory);
Advice[] adviceChain = { retryInterceptor };
factory.setAdviceChain(adviceChain);
return factory;
}
@RabbitListener(queues = "blocking-queue", containerFactory = "retryContainerFactory")
public void consumeBlocking(String payload) throws Exception {
logger.info("Processing message from blocking-queue: {}", payload);
throw new Exception("exception occured!");
}
@RabbitListener(queues = "non-blocking-queue", containerFactory = "retryQueuesContainerFactory", ackMode = "MANUAL")
public void consumeNonBlocking(String payload) throws Exception {
logger.info("Processing message from non-blocking-queue: {}", payload);
throw new Exception("Error occured!");
}
@RabbitListener(queues = "retry-wait-ended-queue", containerFactory = "defaultContainerFactory")
public void consumeRetryWaitEndedMessage(String payload, Message message, Channel channel) throws Exception {
MessageProperties props = message.getMessageProperties();
rabbitTemplate().convertAndSend(props.getHeader("x-original-exchange"), props.getHeader("x-original-routing-key"), message);
}
}

View File

@ -0,0 +1,34 @@
package com.baeldung.springamqp.exponentialbackoff;
import org.springframework.amqp.core.Queue;
public class RetryQueues {
private Queue[] queues;
private long initialInterval;
private double factor;
private long maxWait;
public RetryQueues(long initialInterval, double factor, long maxWait, Queue... queues) {
this.queues = queues;
this.initialInterval = initialInterval;
this.factor = factor;
this.maxWait = maxWait;
}
public boolean retriesExhausted(int retry) {
return retry >= queues.length;
}
public String getQueueName(int retry) {
return queues[retry].getName();
}
public long getTimeToWait(int retry) {
double time = initialInterval * Math.pow(factor, (double) retry);
if (time > maxWait) {
return maxWait;
}
return (long) time;
}
}

View File

@ -0,0 +1,109 @@
package com.baeldung.springamqp.exponentialbackoff;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import com.rabbitmq.client.Channel;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
public class RetryQueuesInterceptor implements MethodInterceptor {
private RabbitTemplate rabbitTemplate;
private RetryQueues retryQueues;
private Runnable observer;
public RetryQueuesInterceptor(RabbitTemplate rabbitTemplate, RetryQueues retryQueues) {
this.rabbitTemplate = rabbitTemplate;
this.retryQueues = retryQueues;
}
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
return tryConsume(invocation, this::ack, (mac, e) -> {
try {
int retryCount = tryGetRetryCountOrFail(mac, e);
sendToNextRetryQueue(mac, retryCount);
} catch (Throwable t) {
if (observer != null) {
observer.run();
}
throw new RuntimeException(t);
}
});
}
void setObserver(Runnable observer) {
this.observer = observer;
}
private Object tryConsume(MethodInvocation invocation, Consumer<MessageAndChannel> successHandler, BiConsumer<MessageAndChannel, Throwable> errorHandler) throws Throwable {
MessageAndChannel mac = new MessageAndChannel((Message) invocation.getArguments()[1], (Channel) invocation.getArguments()[0]);
Object ret = null;
try {
ret = invocation.proceed();
successHandler.accept(mac);
} catch (Throwable e) {
errorHandler.accept(mac, e);
}
return ret;
}
private void ack(MessageAndChannel mac) {
try {
mac.channel.basicAck(mac.message.getMessageProperties()
.getDeliveryTag(), false);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private int tryGetRetryCountOrFail(MessageAndChannel mac, Throwable originalError) throws Throwable {
MessageProperties props = mac.message.getMessageProperties();
String xRetriedCountHeader = (String) props.getHeader("x-retried-count");
final int xRetriedCount = xRetriedCountHeader == null ? 0 : Integer.valueOf(xRetriedCountHeader);
if (retryQueues.retriesExhausted(xRetriedCount)) {
mac.channel.basicReject(props.getDeliveryTag(), false);
throw originalError;
}
return xRetriedCount;
}
private void sendToNextRetryQueue(MessageAndChannel mac, int retryCount) throws Exception {
String retryQueueName = retryQueues.getQueueName(retryCount);
rabbitTemplate.convertAndSend(retryQueueName, mac.message, m -> {
MessageProperties props = m.getMessageProperties();
props.setExpiration(String.valueOf(retryQueues.getTimeToWait(retryCount)));
props.setHeader("x-retried-count", String.valueOf(retryCount + 1));
props.setHeader("x-original-exchange", props.getReceivedExchange());
props.setHeader("x-original-routing-key", props.getReceivedRoutingKey());
return m;
});
mac.channel.basicReject(mac.message.getMessageProperties()
.getDeliveryTag(), false);
}
private class MessageAndChannel {
private Message message;
private Channel channel;
private MessageAndChannel(Message message, Channel channel) {
this.message = message;
this.channel = channel;
}
}
}

View File

@ -0,0 +1,58 @@
package com.baeldung.springamqp.exponentialbackoff;
import java.util.concurrent.CountDownLatch;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* This live test requires:
*
* - A running RabbitMQ instance on localhost (e.g. docker run -p 5672:5672 -p 15672:15672 --name rabbit rabbitmq:3-management)
*
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { RabbitConfiguration.class })
public class ExponentialBackoffLiveTest {
@Autowired
private RabbitTemplate rabbitTemplate;
@Autowired
private ObservableRejectAndDontRequeueRecoverer observableRecoverer;
@Autowired
private RetryQueuesInterceptor retryQueues;
@Test
public void whenSendToBlockingQueue_thenAllMessagesProcessed() throws Exception {
int nb = 2;
CountDownLatch latch = new CountDownLatch(nb);
observableRecoverer.setObserver(() -> latch.countDown());
for (int i = 1; i <= nb; i++) {
rabbitTemplate.convertAndSend("blocking-queue", "blocking message " + i);
}
latch.await();
}
@Test
public void whenSendToNonBlockingQueue_thenAllMessageProcessed() throws Exception {
int nb = 2;
CountDownLatch latch = new CountDownLatch(nb);
retryQueues.setObserver(() -> latch.countDown());
for (int i = 1; i <= nb; i++) {
rabbitTemplate.convertAndSend("non-blocking-queue", "non-blocking message " + i);
}
latch.await();
}
}

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include
resource="org/springframework/boot/logging/logback/base.xml" />
<logger name="org.springframework" level="INFO" />
</configuration>

View File

@ -43,6 +43,7 @@
<module>spring-boot-mvc-2</module>
<module>spring-boot-mvc-birt</module>
<module>spring-boot-nashorn</module>
<module>spring-boot-parent</module>
<module>spring-boot-performance</module>
<module>spring-boot-properties</module>
<module>spring-boot-property-exp</module>

View File

@ -16,11 +16,12 @@ import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;
public class Swagger2Config {
@Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2).select()
.apis(RequestHandlerSelectors.basePackage("com.baeldung.swagger2boot.controller"))
.paths(PathSelectors.regex("/.*"))
.build()
.apiInfo(apiEndPointsInfo());
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any())
.build()
.apiInfo(apiEndPointsInfo());
}
private ApiInfo apiEndPointsInfo() {

View File

@ -0,0 +1,39 @@
package com.baeldung.swagger2boot.controller;
import com.baeldung.swagger2boot.model.Foo;
import com.baeldung.swagger2boot.model.User;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import javax.websocket.server.PathParam;
import static org.apache.commons.lang3.RandomStringUtils.randomNumeric;
@Controller
public class UserController {
public UserController() {
super();
} //@formatter:off
@RequestMapping(method = RequestMethod.POST, value = "/createUser", produces = "application/json; charset=UTF-8")
@ResponseStatus(HttpStatus.CREATED)
@ResponseBody
@ApiOperation(value = "Create user",
notes = "This method creates a new user")
public User createUser(@ApiParam(
name = "firstName",
type = "String",
value = "First Name of the user",
example = "Vatsal",
required = true) @RequestParam String firstName) { //@formatter:on
User user = new User(firstName);
return user;
}
}

View File

@ -0,0 +1,28 @@
package com.baeldung.swagger2boot.model;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
@ApiModel
public class User {
@ApiModelProperty(value = "first name of the user", name = "firstName", dataType = "String", example = "Vatsal")
String firstName;
public User() {
super();
}
public User(final String firstName) {
super();
this.firstName = firstName;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
}

View File

@ -10,10 +10,9 @@
<description>spring-boot-parent</description>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-modules</artifactId>
<groupId>com.baeldung.spring-boot-modules</groupId>
<artifactId>spring-boot-modules</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>..</relativePath>
</parent>
<modules>

View File

@ -1,11 +1,11 @@
package com.baeldung.requestresponsebody;
import com.baeldung.services.ExampleService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
@ -34,4 +34,18 @@ public class ExamplePostController {
log.debug("POST received - serializing LoginForm: " + loginForm.getPassword() + " " + loginForm.getUsername());
return new ResponseTransfer("Thanks For Posting!!!");
}
@PostMapping(value = "/content", produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public ResponseTransfer postResponseJsonContent(@RequestBody LoginForm loginForm) {
log.debug("POST received - serializing LoginForm: " + loginForm.getPassword() + " " + loginForm.getUsername());
return new ResponseTransfer("JSON Content!");
}
@PostMapping(value = "/content", produces = MediaType.APPLICATION_XML_VALUE)
@ResponseBody
public ResponseTransfer postResponseXmlContent(@RequestBody LoginForm loginForm) {
log.debug("POST received - serializing LoginForm: " + loginForm.getPassword() + " " + loginForm.getUsername());
return new ResponseTransfer("XML Content!");
}
}

View File

@ -1,4 +1,4 @@
package org.baeldung;
package com.baeldung;
import org.junit.Test;
import org.junit.runner.RunWith;

View File

@ -2,7 +2,7 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.baeldung.spring.cloud</groupId>
<groupId>com.baeldung.spring.cloud</groupId>
<artifactId>batch-job</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>batch-job</name>

View File

@ -1,4 +1,4 @@
package org.baeldung.spring.cloud;
package com.baeldung.spring.cloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

View File

@ -1,39 +1,39 @@
package org.baeldung.spring.cloud;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableBatchProcessing
public class JobConfiguration {
private static final Log logger = LogFactory.getLog(JobConfiguration.class);
@Autowired
public JobBuilderFactory jobBuilderFactory;
@Autowired
public StepBuilderFactory stepBuilderFactory;
@Bean
public Job job() {
return jobBuilderFactory.get("job").start(stepBuilderFactory.get("jobStep1").tasklet(new Tasklet() {
@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
logger.info("Job was run");
return RepeatStatus.FINISHED;
}
}).build()).build();
}
}
package com.baeldung.spring.cloud;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableBatchProcessing
public class JobConfiguration {
private static final Log logger = LogFactory.getLog(JobConfiguration.class);
@Autowired
public JobBuilderFactory jobBuilderFactory;
@Autowired
public StepBuilderFactory stepBuilderFactory;
@Bean
public Job job() {
return jobBuilderFactory.get("job").start(stepBuilderFactory.get("jobStep1").tasklet(new Tasklet() {
@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
logger.info("Job was run");
return RepeatStatus.FINISHED;
}
}).build()).build();
}
}

View File

@ -1,6 +1,6 @@
package org.baeldung;
package com.baeldung;
import org.baeldung.spring.cloud.JobConfiguration;
import com.baeldung.spring.cloud.JobConfiguration;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;

View File

@ -1,4 +1,4 @@
package org.baeldung.spring.cloud;
package com.baeldung.spring.cloud;
import org.junit.Test;
import org.junit.runner.RunWith;

View File

@ -1,4 +1,4 @@
package org.baeldung.spring.cloud;
package com.baeldung.spring.cloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

View File

@ -1,6 +1,6 @@
package org.baeldung;
package com.baeldung;
import org.baeldung.spring.cloud.DataFlowServerApplication;
import com.baeldung.spring.cloud.DataFlowServerApplication;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;

View File

@ -1,4 +1,4 @@
package org.baeldung.spring.cloud;
package com.baeldung.spring.cloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

View File

@ -1,6 +1,6 @@
package org.baeldung;
package com.baeldung;
import org.baeldung.spring.cloud.DataFlowShellApplication;
import com.baeldung.spring.cloud.DataFlowShellApplication;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;

View File

@ -1,6 +1,6 @@
package org.baeldung;
package com.baeldung;
import org.baeldung.spring.cloud.LogSinkApplication;
import com.baeldung.spring.cloud.LogSinkApplication;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;

View File

@ -1,6 +1,6 @@
package org.baeldung;
package com.baeldung;
import org.baeldung.spring.cloud.TimeProcessorApplication;
import com.baeldung.spring.cloud.TimeProcessorApplication;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;

View File

@ -1,6 +1,6 @@
package org.baeldung;
package com.baeldung;
import org.baeldung.spring.cloud.TimeSourceApplication;
import com.baeldung.spring.cloud.TimeSourceApplication;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;

View File

@ -1,4 +1,4 @@
package org.baeldung;
package com.baeldung;
import org.junit.Test;
import org.junit.runner.RunWith;

View File

@ -1,4 +1,4 @@
package org.baeldung;
package com.baeldung;
import org.junit.Test;
import org.junit.runner.RunWith;

View File

@ -2,7 +2,7 @@
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.baeldung</groupId>
<groupId>com.baeldung</groupId>
<artifactId>spring-cloud-consul</artifactId>
<name>spring-cloud-consul</name>
<packaging>jar</packaging>

View File

@ -2,7 +2,7 @@
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.baeldung</groupId>
<groupId>com.baeldung</groupId>
<artifactId>spring-cloud-rest</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>spring-cloud-rest</name>

View File

@ -2,7 +2,7 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.baeldung</groupId>
<groupId>com.baeldung</groupId>
<artifactId>spring-cloud-rest-books-api</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-cloud-rest-books-api</name>

View File

@ -1,4 +1,4 @@
package org.baeldung;
package com.baeldung;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

View File

@ -1,4 +1,4 @@
package org.baeldung;
package com.baeldung;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
import org.springframework.session.web.context.AbstractHttpSessionApplicationInitializer;

View File

@ -1,6 +1,6 @@
package org.baeldung.persistence.dao;
package com.baeldung.persistence.dao;
import org.baeldung.persistence.model.Book;
import com.baeldung.persistence.model.Book;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.repository.CrudRepository;

View File

@ -1,4 +1,4 @@
package org.baeldung.persistence.model;
package com.baeldung.persistence.model;
import javax.persistence.Column;
import javax.persistence.Entity;

View File

@ -1,14 +1,16 @@
package org.baeldung;
package com.baeldung;
import static io.restassured.RestAssured.preemptive;
import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic;
import static org.apache.commons.lang3.RandomStringUtils.randomNumeric;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import com.baeldung.BooksApiApplication;
import io.restassured.RestAssured;
import io.restassured.response.Response;
import org.baeldung.persistence.model.Book;
import com.baeldung.persistence.model.Book;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

View File

@ -1,7 +1,10 @@
package org.baeldung;
package com.baeldung;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import com.baeldung.BooksApiApplication;
import com.baeldung.SessionConfig;
import io.restassured.RestAssured;
import io.restassured.response.Response;

View File

@ -1,5 +1,6 @@
package org.baeldung;
package com.baeldung;
import com.baeldung.BooksApiApplication;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;

View File

@ -2,7 +2,7 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.baeldung</groupId>
<groupId>com.baeldung</groupId>
<artifactId>spring-cloud-rest-config-server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-cloud-rest-config-server</name>

Some files were not shown because too many files have changed in this diff Show More