commit
984a99b7cf
File diff suppressed because it is too large
Load Diff
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package com.baeldung;
|
||||
package com.baeldung.timer;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package com.baeldung.scala
|
||||
package com.baeldung.scala.regex
|
||||
|
||||
import org.junit.Test
|
||||
import org.junit.Assert.assertEquals
|
|
@ -14,11 +14,28 @@
|
|||
</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>
|
||||
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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>
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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"/>
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
description = Generates a Controller with form handling
|
||||
model = user
|
|
@ -0,0 +1 @@
|
|||
Temporary file until g8-scaffold will generate "test" directory
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
logs
|
||||
target
|
||||
/.idea
|
||||
/.idea_modules
|
||||
/.classpath
|
||||
/.project
|
||||
/.settings
|
||||
/RUNNING_PID
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
@()
|
||||
|
||||
@main("Welcome to Play") {
|
||||
<h1>Welcome to Play!</h1>
|
||||
}
|
|
@ -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>
|
|
@ -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
|
|
@ -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
|
|
@ -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>
|
|
@ -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)
|
|
@ -0,0 +1 @@
|
|||
sbt.version=1.3.3
|
|
@ -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 |
|
@ -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.");
|
||||
}
|
||||
}
|
2
pom.xml
2
pom.xml
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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>
|
|
@ -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>
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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>
|
|
@ -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!");
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package org.baeldung;
|
||||
package com.baeldung;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
|
@ -1,4 +1,4 @@
|
|||
package org.baeldung;
|
||||
package com.baeldung;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
|
@ -1,4 +1,4 @@
|
|||
package org.baeldung.spring.cloud;
|
||||
package com.baeldung.spring.cloud;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
|
@ -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;
|
|
@ -1,4 +1,4 @@
|
|||
package org.baeldung.spring.cloud;
|
||||
package com.baeldung.spring.cloud;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
|
@ -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;
|
|
@ -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;
|
|
@ -1,4 +1,4 @@
|
|||
package org.baeldung.spring.cloud;
|
||||
package com.baeldung.spring.cloud;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
|
@ -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;
|
|
@ -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;
|
|
@ -1,4 +1,4 @@
|
|||
package org.baeldung.spring.cloud;
|
||||
package com.baeldung.spring.cloud;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
|
@ -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;
|
|
@ -1,4 +1,4 @@
|
|||
package org.baeldung.spring.cloud;
|
||||
package com.baeldung.spring.cloud;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
|
@ -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;
|
|
@ -1,4 +1,4 @@
|
|||
package org.baeldung.spring.cloud;
|
||||
package com.baeldung.spring.cloud;
|
||||
|
||||
import java.util.Date;
|
||||
|
|
@ -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;
|
|
@ -1,4 +1,4 @@
|
|||
package org.baeldung;
|
||||
package com.baeldung;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
|
@ -1,4 +1,4 @@
|
|||
package org.baeldung;
|
||||
package com.baeldung;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
|
@ -1,4 +1,4 @@
|
|||
package org.baeldung;
|
||||
package com.baeldung;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
|
@ -1,4 +1,4 @@
|
|||
package org.baeldung;
|
||||
package com.baeldung;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
|
@ -1,4 +1,4 @@
|
|||
package org.baeldung;
|
||||
package com.baeldung;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
|
@ -1,4 +1,4 @@
|
|||
package org.baeldung;
|
||||
package com.baeldung;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
|
@ -1,4 +1,4 @@
|
|||
package org.baeldung;
|
||||
package com.baeldung;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
|
@ -1,4 +1,4 @@
|
|||
package org.baeldung;
|
||||
package com.baeldung;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
|
@ -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>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package org.baeldung;
|
||||
package com.baeldung;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
|
@ -1,4 +1,4 @@
|
|||
package org.baeldung;
|
||||
package com.baeldung;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
|
@ -1,4 +1,4 @@
|
|||
package org.baeldung;
|
||||
package com.baeldung;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
|
@ -1,4 +1,4 @@
|
|||
package org.baeldung;
|
||||
package com.baeldung;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
|
@ -1,4 +1,4 @@
|
|||
package org.baeldung;
|
||||
package com.baeldung;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package org.baeldung;
|
||||
package com.baeldung;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
|
@ -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;
|
|
@ -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;
|
|
@ -1,4 +1,4 @@
|
|||
package org.baeldung.persistence.model;
|
||||
package com.baeldung.persistence.model;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
|
@ -1,4 +1,4 @@
|
|||
package org.baeldung;
|
||||
package com.baeldung;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
|
@ -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;
|
|
@ -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;
|
||||
|
|
@ -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;
|
|
@ -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>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package org.baeldung;
|
||||
package com.baeldung;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue