This commit is contained in:
Jonathan Cook 2020-04-09 10:09:45 +02:00
commit f630aeed0b
171 changed files with 2295 additions and 225 deletions

View File

@ -0,0 +1,56 @@
package com.baeldung.java14.helpfulnullpointerexceptions;
public class HelpfulNullPointerException {
public static void main(String[] args) {
Employee employee = null;
employee.getName();
}
public String getEmployeeEmailAddress(Employee employee) {
String emailAddress = employee.getPersonalDetails().getEmailAddress().toLowerCase();
return emailAddress;
}
static class Employee {
String name;
PersonalDetails personalDetails;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public PersonalDetails getPersonalDetails() {
return personalDetails;
}
public void setPersonalDetails(PersonalDetails personalDetails) {
this.personalDetails = personalDetails;
}
}
static class PersonalDetails {
String emailAddress;
String phone;
public String getEmailAddress() {
return emailAddress;
}
public void setEmailAddress(String emailAddress) {
this.emailAddress = emailAddress;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
}
}

View File

@ -0,0 +1,37 @@
package com.baeldung.java14.helpfulnullpointerexceptions;
import org.junit.Test;
import static com.baeldung.java14.helpfulnullpointerexceptions.HelpfulNullPointerException.Employee;
import static com.baeldung.java14.helpfulnullpointerexceptions.HelpfulNullPointerException.PersonalDetails;
import static org.assertj.core.api.Assertions.assertThat;
public class HelpfulNullPointerExceptionUnitTest {
@Test (expected = NullPointerException.class)
public void givenAnEmptyPersonalDetails_whenEmailAddressIsAccessed_thenThrowNPE() {
var helpfulNPE = new HelpfulNullPointerException();
var employee = new Employee();
employee.setName("Eduard");
employee.setPersonalDetails(new PersonalDetails());
helpfulNPE.getEmployeeEmailAddress(employee);
}
@Test
public void givenCompletePersonalDetails_whenEmailAddressIsAccessed_thenSuccess() {
var helpfulNPE = new HelpfulNullPointerException();
var emailAddress = "eduard@gmx.com";
var employee = new Employee();
employee.setName("Eduard");
var personalDetails = new PersonalDetails();
personalDetails.setEmailAddress(emailAddress.toUpperCase());
personalDetails.setPhone("1234");
employee.setPersonalDetails(personalDetails);
assertThat(helpfulNPE.getEmployeeEmailAddress(employee)).isEqualTo(emailAddress);
}
}

View File

@ -0,0 +1,25 @@
package com.baeldung.concurrent.volatilekeyword;
public class TaskRunner {
private static int number;
private volatile static boolean ready;
private static class Reader extends Thread {
@Override
public void run() {
while (!ready) {
Thread.yield();
}
System.out.println(number);
}
}
public static void main(String[] args) {
new Reader().start();
number = 42;
ready = true;
}
}

View File

@ -1,18 +1,17 @@
package com.baeldung.java8;
import static org.hamcrest.Matchers.equalTo;
import com.baeldung.java8.entity.Human;
import com.google.common.collect.Lists;
import com.google.common.primitives.Ints;
import org.junit.Assert;
import org.junit.Test;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import org.junit.Assert;
import org.junit.Test;
import com.baeldung.java8.entity.Human;
import com.google.common.collect.Lists;
import com.google.common.primitives.Ints;
import static org.hamcrest.Matchers.equalTo;
public class Java8SortUnitTest {
@ -113,11 +112,11 @@ public class Java8SortUnitTest {
humans.sort(Comparator.comparing(Human::getName));
Assert.assertThat(humans.get(0), equalTo(new Human("Jack", 12)));
}
@Test
public final void givenStreamNaturalOrdering_whenSortingEntitiesByName_thenCorrectlySorted() {
final List<String> letters = Lists.newArrayList("B", "A", "C");
final List<String> sortedLetters = letters.stream().sorted().collect(Collectors.toList());
Assert.assertThat(sortedLetters.get(0), equalTo("A"));
}
@ -126,7 +125,7 @@ public class Java8SortUnitTest {
public final void givenStreamCustomOrdering_whenSortingEntitiesByName_thenCorrectlySorted() {
final List<Human> humans = Lists.newArrayList(new Human("Sarah", 10), new Human("Jack", 12));
final Comparator<Human> nameComparator = (h1, h2) -> h1.getName().compareTo(h2.getName());
final List<Human> sortedHumans = humans.stream().sorted(nameComparator).collect(Collectors.toList());
Assert.assertThat(sortedHumans.get(0), equalTo(new Human("Jack", 12)));
}
@ -164,4 +163,48 @@ public class Java8SortUnitTest {
Assert.assertThat(reverseSortedHumans.get(0), equalTo(new Human("Sarah", 10)));
}
@Test(expected = NullPointerException.class)
public final void givenANullElement_whenSortingEntitiesByName_thenThrowsNPE() {
final List<Human> humans = Lists.newArrayList(null, new Human("Jack", 12));
humans.sort((h1, h2) -> h1.getName().compareTo(h2.getName()));
}
@Test
public final void givenANullElement_whenSortingEntitiesByNameManually_thenMovesTheNullToLast() {
final List<Human> humans = Lists.newArrayList(null, new Human("Jack", 12), null);
humans.sort((h1, h2) -> {
if (h1 == null) return h2 == null ? 0 : 1;
else if (h2 == null) return -1;
return h1.getName().compareTo(h2.getName());
});
Assert.assertNotNull(humans.get(0));
Assert.assertNull(humans.get(1));
Assert.assertNull(humans.get(2));
}
@Test
public final void givenANullElement_whenSortingEntitiesByName_thenMovesTheNullToLast() {
final List<Human> humans = Lists.newArrayList(null, new Human("Jack", 12), null);
humans.sort(Comparator.nullsLast(Comparator.comparing(Human::getName)));
Assert.assertNotNull(humans.get(0));
Assert.assertNull(humans.get(1));
Assert.assertNull(humans.get(2));
}
@Test
public final void givenANullElement_whenSortingEntitiesByName_thenMovesTheNullToStart() {
final List<Human> humans = Lists.newArrayList(null, new Human("Jack", 12), null);
humans.sort(Comparator.nullsFirst(Comparator.comparing(Human::getName)));
Assert.assertNull(humans.get(0));
Assert.assertNull(humans.get(1));
Assert.assertNotNull(humans.get(2));
}
}

View File

@ -1,8 +1,12 @@
package com.baeldung.comparelong;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatCode;
import org.junit.Test;
import java.util.Objects;
public class CompareLongUnitTest {
@Test
@ -32,6 +36,33 @@ public class CompareLongUnitTest {
assertThat(l1.equals(l2)).isTrue();
}
@Test
public void givenLongValuesLessThan128_whenUsingObjectsEquals_thenSuccess() {
Long l1 = 127L;
Long l2 = 127L;
assertThat(Objects.equals(l1, l2)).isTrue();
}
@Test
public void givenLongValuesGreaterOrEqualsThan128_whenUsingObjectsEquals_thenSuccess() {
Long l1 = 128L;
Long l2 = 128L;
assertThat(Objects.equals(l1, l2)).isTrue();
}
@Test
public void givenNullReference_whenUsingObjectsEquals_thenNoException() {
Long l1 = null;
Long l2 = 128L;
assertThatCode(() -> Objects.equals(l1, l2)).doesNotThrowAnyException();
}
@Test
public void givenLongValuesGreaterOrEqualsThan128_whenUsingComparisonOperator_andLongValue_thenSuccess() {

View File

@ -1,3 +1,11 @@
## Core Java Security
This module contains articles about core Java Security
### Relevant Articles:
- [Guide To The Java Authentication And Authorization Service (JAAS)](https://www.baeldung.com/java-authentication-authorization-service)
- [MD5 Hashing in Java](http://www.baeldung.com/java-md5)
- [Hashing a Password in Java](https://www.baeldung.com/java-password-hashing)
- [SHA-256 and SHA3-256 Hashing in Java](https://www.baeldung.com/sha-256-hashing-java)
- More articles: [[<-- prev]](/core-java-modules/core-java-security)

View File

@ -16,4 +16,45 @@
<relativePath>../../parent-java</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>${commons-codec.version}</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>${bouncycastle.version}</version>
</dependency>
<!-- test scoped -->
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>${assertj-core.version}</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.xml.bind/jaxb-api -->
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
</dependencies>
<properties>
<!-- util -->
<bouncycastle.version>1.60</bouncycastle.version>
<commons-codec.version>1.11</commons-codec.version>
<!-- testing -->
<assertj-core.version>3.10.0</assertj-core.version>
</properties>
</project>

View File

@ -0,0 +1,23 @@
package com.baeldung.checksums;
import java.io.IOException;
import java.io.InputStream;
import java.util.zip.CRC32;
import java.util.zip.CheckedInputStream;
import java.util.zip.Checksum;
public class ChecksumUtils {
public static long getChecksumCRC32(byte[] bytes) {
Checksum crc32 = new CRC32();
crc32.update(bytes, 0, bytes.length);
return crc32.getValue();
}
public static long getChecksumCRC32(InputStream stream, int bufferSize) throws IOException {
CheckedInputStream checkedInputStream = new CheckedInputStream(stream, new CRC32());
byte[] buffer = new byte[bufferSize];
while (checkedInputStream.read(buffer, 0, buffer.length) >= 0) {}
return checkedInputStream.getChecksum().getValue();
}
}

View File

@ -0,0 +1,51 @@
package com.baeldung.checksums;
import org.junit.Before;
import org.junit.Test;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import static org.junit.jupiter.api.Assertions.*;
class ChecksumUtilsUnitTest {
byte[] arr;
@Before
void setUp() {
arr = new byte[]{0,10,21,20,35,40,120,56,72,22};
}
@Test
void givenByteArray_whenChecksumCreated_checkCorrect() {
long checksum = ChecksumUtils.getChecksumCRC32(arr);
assertEquals(3915397664L, checksum);
}
@Test
void givenTwoDifferentStrings_whenChecksumCreated_checkCollision() {
String plumless = "plumless";
String buckeroo = "buckeroo";
long plumlessChecksum = ChecksumUtils.getChecksumCRC32(plumless.getBytes());
long buckerooChecksum = ChecksumUtils.getChecksumCRC32(buckeroo.getBytes());
assertEquals(plumlessChecksum, buckerooChecksum);
}
@Test
void givenInputString_whenChecksumCreated_checkCorrect() throws IOException {
InputStream inputStream = new ByteArrayInputStream(arr);
long checksum = ChecksumUtils.getChecksumCRC32(inputStream, 10);
assertEquals(3915397664L, checksum);
}
}

View File

@ -3,17 +3,16 @@
This module contains articles about core Java Security
### Relevant Articles:
- [MD5 Hashing in Java](http://www.baeldung.com/java-md5)
- [Guide to the Cipher Class](http://www.baeldung.com/java-cipher-class)
- [Introduction to SSL in Java](http://www.baeldung.com/java-ssl)
- [Java KeyStore API](http://www.baeldung.com/java-keystore)
- [Encrypting and Decrypting Files in Java](http://www.baeldung.com/java-cipher-input-output-stream)
- [Hashing a Password in Java](https://www.baeldung.com/java-password-hashing)
- [SSL Handshake Failures](https://www.baeldung.com/java-ssl-handshake-failures)
- [SHA-256 and SHA3-256 Hashing in Java](https://www.baeldung.com/sha-256-hashing-java)
- [Enabling TLS v1.2 in Java 7](https://www.baeldung.com/java-7-tls-v12)
- [The Java SecureRandom Class](https://www.baeldung.com/java-secure-random)
- [An Introduction to Java SASL](https://www.baeldung.com/java-sasl)
- [A Guide to Java GSS API](https://www.baeldung.com/java-gss)
- [Intro to the Java SecurityManager](https://www.baeldung.com/java-security-manager)
- More articles: [[next -->]](/core-java-modules/core-java-security-2)

View File

@ -24,24 +24,9 @@
<version>${assertj-core.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>${commons-codec.version}</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>${bouncycastle.version}</version>
</dependency>
</dependencies>
<properties>
<!-- util -->
<bouncycastle.version>1.60</bouncycastle.version>
<commons-codec.version>1.11</commons-codec.version>
<!-- testing -->
<assertj-core.version>3.10.0</assertj-core.version>
</properties>

View File

@ -0,0 +1,42 @@
package com.baeldung.streams.bigdecimals;
import static org.junit.Assert.assertEquals;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import org.junit.Test;
public class AddNumbersUnitTest {
@Test
public void givenIntStream_whenSum_thenResultIsCorrect() {
IntStream intNumbers = IntStream.range(0, 3);
assertEquals(3, intNumbers.sum());
}
@Test
public void givenCollectionOfDouble_whenUsingMapToDoubleToSum_thenResultIsCorrect() {
List<Double> doubleNumbers = Arrays.asList(23.48, 52.26, 13.5);
double result = doubleNumbers.stream()
.mapToDouble(Double::doubleValue)
.sum();
assertEquals(89.24, result, .1);
}
public void givenStreamOfIntegers_whenUsingReduceToSum_thenResultIsCorrect() {
Stream<Integer> intNumbers = Stream.of(0, 1, 2);
int result = intNumbers.reduce(0, Integer::sum);
assertEquals(106, result);
}
public void givenStreamOfBigDecimals_whenUsingReduceToSum_thenResultIsCorrect() {
Stream<BigDecimal> bigDecimalNumber = Stream.of(BigDecimal.ZERO, BigDecimal.ONE, BigDecimal.TEN);
BigDecimal result = bigDecimalNumber.reduce(BigDecimal.ZERO, BigDecimal::add);
assertEquals(11, result);
}
}

View File

@ -0,0 +1,20 @@
package com.baeldung.guava.mapmaker;
public class Profile {
private long id;
private String type;
public Profile(long id, String type) {
this.id = id;
this.type = type;
}
public long getId() {
return id;
}
public String getName() {
return type;
}
}

View File

@ -0,0 +1,13 @@
package com.baeldung.guava.mapmaker;
public class Session {
private long id;
public Session(long id) {
this.id = id;
}
public long getId() {
return id;
}
}

View File

@ -0,0 +1,20 @@
package com.baeldung.guava.mapmaker;
public class User {
private long id;
private String name;
public User(long id, String name) {
this.id = id;
this.name = name;
}
public long getId() {
return id;
}
public String getName() {
return name;
}
}

View File

@ -0,0 +1,53 @@
package com.baeldung.guava.mapmaker;
import com.google.common.collect.MapMaker;
import org.junit.Assert;
import org.junit.Test;
import java.util.concurrent.ConcurrentMap;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.assertNotNull;
public class GuavaMapMakerUnitTest {
@Test
public void whenCreateCaches_thenCreated() {
ConcurrentMap<User, Session> sessionCache = new MapMaker().makeMap();
assertNotNull(sessionCache);
ConcurrentMap<User, Profile> profileCache = new MapMaker().makeMap();
assertNotNull(profileCache);
User userA = new User(1, "UserA");
sessionCache.put(userA, new Session(100));
Assert.assertThat(sessionCache.size(), equalTo(1));
profileCache.put(userA, new Profile(1000, "Personal"));
Assert.assertThat(profileCache.size(), equalTo(1));
}
@Test
public void whenCreateCacheWithInitialCapacity_thenCreated() {
ConcurrentMap<User, Profile> profileCache = new MapMaker().initialCapacity(100).makeMap();
assertNotNull(profileCache);
}
@Test
public void whenCreateCacheWithConcurrencyLevel_thenCreated() {
ConcurrentMap<User, Session> sessionCache = new MapMaker().concurrencyLevel(10).makeMap();
assertNotNull(sessionCache);
}
@Test
public void whenCreateCacheWithWeakKeys_thenCreated() {
ConcurrentMap<User, Session> sessionCache = new MapMaker().weakKeys().makeMap();
assertNotNull(sessionCache);
}
@Test
public void whenCreateCacheWithWeakValues_thenCreated() {
ConcurrentMap<User, Profile> profileCache = new MapMaker().weakValues().makeMap();
assertNotNull(profileCache);
}
}

View File

@ -13,5 +13,4 @@ This module contains articles about Map data structures in Java.
- [Sort a HashMap in Java](https://www.baeldung.com/java-hashmap-sort)
- [Finding the Highest Value in a Java Map](https://www.baeldung.com/java-find-map-max)
- [Initialize a HashMap in Java](https://www.baeldung.com/java-initialize-hashmap)
- [Java TreeMap vs HashMap](https://www.baeldung.com/java-treemap-vs-hashmap)
- More articles: [[<-- prev>]](/../java-collections-maps)
- More articles: [[<-- prev]](/java-collections-maps) [[next -->]](/java-collections-maps-3)

View File

@ -0,0 +1,8 @@
## Java Collections Cookbooks and Examples
This module contains articles about Map data structures in Java.
### Relevant Articles:
- [Java TreeMap vs HashMap](https://www.baeldung.com/java-treemap-vs-hashmap)
- [Comparing Two HashMaps in Java](https://www.baeldung.com/java-compare-hashmaps)
- More articles: [[<-- prev]](/java-collections-maps-2)

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<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>
<artifactId>java-collections-maps-3</artifactId>
<version>0.1.0-SNAPSHOT</version>
<name>java-collections-maps-3</name>
<packaging>jar</packaging>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-java</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../parent-java</relativePath>
</parent>
<dependencies>
</dependencies>
<properties>
</properties>
</project>

View File

@ -10,8 +10,7 @@ This module contains articles about Map data structures in Java.
- [How to Store Duplicate Keys in a Map in Java?](https://www.baeldung.com/java-map-duplicate-keys)
- [Get the Key for a Value from a Java Map](https://www.baeldung.com/java-map-key-from-value)
- [How to Check If a Key Exists in a Map](https://www.baeldung.com/java-map-key-exists)
- [Comparing Two HashMaps in Java](https://www.baeldung.com/java-compare-hashmaps)
- [Immutable Map Implementations in Java](https://www.baeldung.com/java-immutable-maps)
- [Guide to Apache Commons MultiValuedMap](https://www.baeldung.com/apache-commons-multi-valued-map)
- [The Java HashMap Under the Hood](https://www.baeldung.com/java-hashmap-advanced)
- More articles: [[next -->]](/../java-collections-maps-2)
- More articles: [[next -->]](/java-collections-maps-2)

View File

@ -0,0 +1,52 @@
package com.baeldung.abstractnumber;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
public class AbstractNumberUnitTest {
private final static double DOUBLE_VALUE = 9999.999;
private final static float FLOAT_VALUE = 101.99F;
private final static long LONG_VALUE = 1000L;
private final static int INTEGER_VALUE = 100;
private final static short SHORT_VALUE = 127;
private final static byte BYTE_VALUE = 120;
@Test
public void givenDoubleValue_whenShortValueUsed_thenShortValueReturned() {
Double doubleValue = Double.valueOf(DOUBLE_VALUE);
assertEquals(9999, doubleValue.shortValue());
}
@Test
public void givenFloatValue_whenByteValueUsed_thenByteValueReturned() {
Float floatValue = Float.valueOf(FLOAT_VALUE);
assertEquals(101, floatValue.byteValue());
}
@Test
public void givenLongValue_whenInitValueUsed_thenInitValueReturned() {
Long longValue = Long.valueOf(LONG_VALUE);
assertEquals(1000, longValue.intValue());
}
@Test
public void givenIntegerValue_whenLongValueUsed_thenLongValueReturned() {
Integer integerValue = Integer.valueOf(INTEGER_VALUE);
assertEquals(100, integerValue.longValue());
}
@Test
public void givenShortValue_whenFloatValueUsed_thenFloatValueReturned() {
Short shortValue = Short.valueOf(SHORT_VALUE);
assertEquals(127.0F, shortValue.floatValue(), 0);
}
@Test
public void givenByteValue_whenDoubleValueUsed_thenDoubleValueReturned() {
Byte byteValue = Byte.valueOf(BYTE_VALUE);
assertEquals(120.0, byteValue.doubleValue(), 0);
}
}

View File

@ -0,0 +1,84 @@
<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>
<artifactId>coroutines-with-quasar</artifactId>
<name>coroutines-with-quasar</name>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>libraries-concurrency</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>co.paralleluniverse</groupId>
<artifactId>quasar-core</artifactId>
<version>0.8.0</version>
</dependency>
<dependency>
<groupId>co.paralleluniverse</groupId>
<artifactId>quasar-actors</artifactId>
<version>0.8.0</version>
</dependency>
<dependency>
<groupId>co.paralleluniverse</groupId>
<artifactId>quasar-reactive-streams</artifactId>
<version>0.8.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.1.2</version>
<executions>
<execution>
<id>getClasspathFilenames</id>
<goals>
<goal>properties</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.6.0</version>
<configuration>
<mainClass>com.baeldung.quasar.App</mainClass>
<workingDirectory>target/classes</workingDirectory>
<executable>java</executable>
<arguments>
<!-- Turn off before production -->
<argument>-Dco.paralleluniverse.fibers.verifyInstrumentation=true</argument>
<!-- Quasar Agent -->
<argument>-javaagent:${co.paralleluniverse:quasar-core:jar}</argument>
<!-- Classpath -->
<argument>-classpath</argument>
<classpath />
<!-- Main class -->
<argument>com.baeldung.quasar.App</argument>
</arguments>
</configuration>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>12</source>
<target>12</target>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,11 @@
package com.baeldung.quasar;
import co.paralleluniverse.fibers.Fiber;
public class App {
public static void main(String[] args) {
new Fiber<Void>(() -> {
System.out.println("Inside fiber coroutine...");
}).start();
}
}

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<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>
<artifactId>libraries-concurrency</artifactId>
<name>libraries-concurrency</name>
<packaging>pom</packaging>
<parent>
<artifactId>parent-modules</artifactId>
<groupId>com.baeldung</groupId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<modules>
<!-- <module>coroutines-with-quasar</module> --><!-- we haven't upgraded to Java 12 -->
</modules>
</project>

6
netty/README.md Normal file
View File

@ -0,0 +1,6 @@
## Netty
This module contains articles about Netty.
### Relevant Articles:

34
netty/pom.xml Normal file
View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<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>
<artifactId>netty</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>netty</name>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-modules</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>${netty.version}</version>
</dependency>
<dependency>
<groupId>org.conscrypt</groupId>
<artifactId>conscrypt-openjdk-uber</artifactId>
<version>2.4.0</version>
</dependency>
</dependencies>
<properties>
<netty.version>4.1.48.Final</netty.version>
</properties>
</project>

View File

@ -0,0 +1,135 @@
package com.baeldung.netty.http2;
import static io.netty.handler.logging.LogLevel.INFO;
import java.security.cert.CertificateException;
import javax.net.ssl.SSLException;
import com.baeldung.netty.http2.client.Http2ClientResponseHandler;
import com.baeldung.netty.http2.client.Http2SettingsHandler;
import com.baeldung.netty.http2.server.Http2ServerResponseHandler;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPipeline;
import io.netty.handler.codec.http.DefaultFullHttpRequest;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpHeaderValues;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpScheme;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.http2.DefaultHttp2Connection;
import io.netty.handler.codec.http2.DelegatingDecompressorFrameListener;
import io.netty.handler.codec.http2.Http2Connection;
import io.netty.handler.codec.http2.Http2FrameCodecBuilder;
import io.netty.handler.codec.http2.Http2FrameLogger;
import io.netty.handler.codec.http2.Http2SecurityUtil;
import io.netty.handler.codec.http2.HttpConversionUtil;
import io.netty.handler.codec.http2.HttpToHttp2ConnectionHandler;
import io.netty.handler.codec.http2.HttpToHttp2ConnectionHandlerBuilder;
import io.netty.handler.codec.http2.InboundHttp2ToHttpAdapterBuilder;
import io.netty.handler.ssl.ApplicationProtocolConfig;
import io.netty.handler.ssl.ApplicationProtocolConfig.Protocol;
import io.netty.handler.ssl.ApplicationProtocolConfig.SelectedListenerFailureBehavior;
import io.netty.handler.ssl.ApplicationProtocolConfig.SelectorFailureBehavior;
import io.netty.handler.ssl.ApplicationProtocolNames;
import io.netty.handler.ssl.ApplicationProtocolNegotiationHandler;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.SslProvider;
import io.netty.handler.ssl.SupportedCipherSuiteFilter;
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
import io.netty.handler.ssl.util.SelfSignedCertificate;
public class Http2Util {
public static SslContext createSSLContext(boolean isServer) throws SSLException, CertificateException {
SslContext sslCtx;
SelfSignedCertificate ssc = new SelfSignedCertificate();
if (isServer) {
sslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey())
.sslProvider(SslProvider.JDK)
.ciphers(Http2SecurityUtil.CIPHERS, SupportedCipherSuiteFilter.INSTANCE)
.applicationProtocolConfig(new ApplicationProtocolConfig(Protocol.ALPN,
SelectorFailureBehavior.NO_ADVERTISE,
SelectedListenerFailureBehavior.ACCEPT, ApplicationProtocolNames.HTTP_2, ApplicationProtocolNames.HTTP_1_1))
.build();
} else {
sslCtx = SslContextBuilder.forClient()
.sslProvider(SslProvider.JDK)
.ciphers(Http2SecurityUtil.CIPHERS, SupportedCipherSuiteFilter.INSTANCE)
.trustManager(InsecureTrustManagerFactory.INSTANCE)
.applicationProtocolConfig(new ApplicationProtocolConfig(Protocol.ALPN,
SelectorFailureBehavior.NO_ADVERTISE,
SelectedListenerFailureBehavior.ACCEPT, ApplicationProtocolNames.HTTP_2))
.build();
}
return sslCtx;
}
public static ApplicationProtocolNegotiationHandler getServerAPNHandler() {
ApplicationProtocolNegotiationHandler serverAPNHandler = new ApplicationProtocolNegotiationHandler(ApplicationProtocolNames.HTTP_2) {
@Override
protected void configurePipeline(ChannelHandlerContext ctx, String protocol) throws Exception {
if (ApplicationProtocolNames.HTTP_2.equals(protocol)) {
ctx.pipeline()
.addLast(Http2FrameCodecBuilder.forServer()
.build(), new Http2ServerResponseHandler());
return;
}
throw new IllegalStateException("Protocol: " + protocol + " not supported");
}
};
return serverAPNHandler;
}
public static ApplicationProtocolNegotiationHandler getClientAPNHandler(int maxContentLength, Http2SettingsHandler settingsHandler, Http2ClientResponseHandler responseHandler) {
final Http2FrameLogger logger = new Http2FrameLogger(INFO, Http2Util.class);
final Http2Connection connection = new DefaultHttp2Connection(false);
HttpToHttp2ConnectionHandler connectionHandler = new HttpToHttp2ConnectionHandlerBuilder()
.frameListener(new DelegatingDecompressorFrameListener(connection, new InboundHttp2ToHttpAdapterBuilder(connection).maxContentLength(maxContentLength)
.propagateSettings(true)
.build()))
.frameLogger(logger)
.connection(connection)
.build();
ApplicationProtocolNegotiationHandler clientAPNHandler = new ApplicationProtocolNegotiationHandler(ApplicationProtocolNames.HTTP_2) {
@Override
protected void configurePipeline(ChannelHandlerContext ctx, String protocol) {
if (ApplicationProtocolNames.HTTP_2.equals(protocol)) {
ChannelPipeline p = ctx.pipeline();
p.addLast(connectionHandler);
p.addLast(settingsHandler, responseHandler);
return;
}
ctx.close();
throw new IllegalStateException("Protocol: " + protocol + " not supported");
}
};
return clientAPNHandler;
}
public static FullHttpRequest createGetRequest(String host, int port) {
FullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.valueOf("HTTP/2.0"), HttpMethod.GET, "/", Unpooled.EMPTY_BUFFER);
request.headers()
.add(HttpHeaderNames.HOST, new String(host + ":" + port));
request.headers()
.add(HttpConversionUtil.ExtensionHeaderNames.SCHEME.text(), HttpScheme.HTTPS);
request.headers()
.add(HttpHeaderNames.ACCEPT_ENCODING, HttpHeaderValues.GZIP);
request.headers()
.add(HttpHeaderNames.ACCEPT_ENCODING, HttpHeaderValues.DEFLATE);
return request;
}
}

View File

@ -0,0 +1,46 @@
package com.baeldung.netty.http2.client;
import com.baeldung.netty.http2.Http2Util;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.ssl.SslContext;
public class Http2ClientInitializer extends ChannelInitializer<SocketChannel> {
private final SslContext sslCtx;
private final int maxContentLength;
private Http2SettingsHandler settingsHandler;
private Http2ClientResponseHandler responseHandler;
private String host;
private int port;
public Http2ClientInitializer(SslContext sslCtx, int maxContentLength, String host, int port) {
this.sslCtx = sslCtx;
this.maxContentLength = maxContentLength;
this.host = host;
this.port = port;
}
@Override
public void initChannel(SocketChannel ch) throws Exception {
settingsHandler = new Http2SettingsHandler(ch.newPromise());
responseHandler = new Http2ClientResponseHandler();
if (sslCtx != null) {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(sslCtx.newHandler(ch.alloc(), host, port));
pipeline.addLast(Http2Util.getClientAPNHandler(maxContentLength, settingsHandler, responseHandler));
}
}
public Http2SettingsHandler getSettingsHandler() {
return settingsHandler;
}
public Http2ClientResponseHandler getResponseHandler() {
return responseHandler;
}
}

View File

@ -0,0 +1,128 @@
package com.baeldung.netty.http2.client;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http2.HttpConversionUtil;
import io.netty.util.CharsetUtil;
public class Http2ClientResponseHandler extends SimpleChannelInboundHandler<FullHttpResponse> {
private final Logger logger = LoggerFactory.getLogger(Http2ClientResponseHandler.class);
private final Map<Integer, MapValues> streamidMap;
public Http2ClientResponseHandler() {
streamidMap = new HashMap<Integer, MapValues>();
}
public MapValues put(int streamId, ChannelFuture writeFuture, ChannelPromise promise) {
return streamidMap.put(streamId, new MapValues(writeFuture, promise));
}
public String awaitResponses(long timeout, TimeUnit unit) {
Iterator<Entry<Integer, MapValues>> itr = streamidMap.entrySet()
.iterator();
String response = null;
while (itr.hasNext()) {
Entry<Integer, MapValues> entry = itr.next();
ChannelFuture writeFuture = entry.getValue()
.getWriteFuture();
if (!writeFuture.awaitUninterruptibly(timeout, unit)) {
throw new IllegalStateException("Timed out waiting to write for stream id " + entry.getKey());
}
if (!writeFuture.isSuccess()) {
throw new RuntimeException(writeFuture.cause());
}
ChannelPromise promise = entry.getValue()
.getPromise();
if (!promise.awaitUninterruptibly(timeout, unit)) {
throw new IllegalStateException("Timed out waiting for response on stream id " + entry.getKey());
}
if (!promise.isSuccess()) {
throw new RuntimeException(promise.cause());
}
logger.info("---Stream id: " + entry.getKey() + " received---");
response = entry.getValue().getResponse();
itr.remove();
}
return response;
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, FullHttpResponse msg) throws Exception {
Integer streamId = msg.headers()
.getInt(HttpConversionUtil.ExtensionHeaderNames.STREAM_ID.text());
if (streamId == null) {
logger.error("HttpResponseHandler unexpected message received: " + msg);
return;
}
MapValues value = streamidMap.get(streamId);
if (value == null) {
logger.error("Message received for unknown stream id " + streamId);
ctx.close();
} else {
ByteBuf content = msg.content();
if (content.isReadable()) {
int contentLength = content.readableBytes();
byte[] arr = new byte[contentLength];
content.readBytes(arr);
String response = new String(arr, 0, contentLength, CharsetUtil.UTF_8);
logger.info("Response from Server: "+ (response));
value.setResponse(response);
}
value.getPromise()
.setSuccess();
}
}
public static class MapValues {
ChannelFuture writeFuture;
ChannelPromise promise;
String response;
public String getResponse() {
return response;
}
public void setResponse(String response) {
this.response = response;
}
public MapValues(ChannelFuture writeFuture2, ChannelPromise promise2) {
this.writeFuture = writeFuture2;
this.promise = promise2;
}
public ChannelFuture getWriteFuture() {
return writeFuture;
}
public ChannelPromise getPromise() {
return promise;
}
}
}

View File

@ -0,0 +1,30 @@
package com.baeldung.netty.http2.client;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http2.Http2Settings;
import java.util.concurrent.TimeUnit;
public class Http2SettingsHandler extends SimpleChannelInboundHandler<Http2Settings> {
private final ChannelPromise promise;
public Http2SettingsHandler(ChannelPromise promise) {
this.promise = promise;
}
public void awaitSettings(long timeout, TimeUnit unit) throws Exception {
if (!promise.awaitUninterruptibly(timeout, unit)) {
throw new IllegalStateException("Timed out waiting for settings");
}
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, Http2Settings msg) throws Exception {
promise.setSuccess();
ctx.pipeline()
.remove(this);
}
}

View File

@ -0,0 +1,59 @@
package com.baeldung.netty.http2.server;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.baeldung.netty.http2.Http2Util;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.ssl.SslContext;
public final class Http2Server {
private static final int PORT = 8443;
private static final Logger logger = LoggerFactory.getLogger(Http2Server.class);
public static void main(String[] args) throws Exception {
SslContext sslCtx = Http2Util.createSSLContext(true);
EventLoopGroup group = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.option(ChannelOption.SO_BACKLOG, 1024);
b.group(group)
.channel(NioServerSocketChannel.class)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
if (sslCtx != null) {
ch.pipeline()
.addLast(sslCtx.newHandler(ch.alloc()), Http2Util.getServerAPNHandler());
}
}
});
Channel ch = b.bind(PORT)
.sync()
.channel();
logger.info("HTTP/2 Server is listening on https://127.0.0.1:" + PORT + '/');
ch.closeFuture()
.sync();
} finally {
group.shutdownGracefully();
}
}
}

View File

@ -0,0 +1,52 @@
package com.baeldung.netty.http2.server;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http2.DefaultHttp2DataFrame;
import io.netty.handler.codec.http2.DefaultHttp2Headers;
import io.netty.handler.codec.http2.DefaultHttp2HeadersFrame;
import io.netty.handler.codec.http2.Http2Headers;
import io.netty.handler.codec.http2.Http2HeadersFrame;
import io.netty.util.CharsetUtil;
@Sharable
public class Http2ServerResponseHandler extends ChannelDuplexHandler {
static final ByteBuf RESPONSE_BYTES = Unpooled.unreleasableBuffer(Unpooled.copiedBuffer("Hello World", CharsetUtil.UTF_8));
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
super.exceptionCaught(ctx, cause);
cause.printStackTrace();
ctx.close();
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
if (msg instanceof Http2HeadersFrame) {
Http2HeadersFrame msgHeader = (Http2HeadersFrame) msg;
if (msgHeader.isEndStream()) {
ByteBuf content = ctx.alloc()
.buffer();
content.writeBytes(RESPONSE_BYTES.duplicate());
Http2Headers headers = new DefaultHttp2Headers().status(HttpResponseStatus.OK.codeAsText());
ctx.write(new DefaultHttp2HeadersFrame(headers).stream(msgHeader.stream()));
ctx.write(new DefaultHttp2DataFrame(content, true).stream(msgHeader.stream()));
}
} else {
super.channelRead(ctx, msg);
}
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.flush();
}
}

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>

View File

@ -0,0 +1,91 @@
package com.baeldung.netty;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.util.concurrent.TimeUnit;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.baeldung.netty.http2.Http2Util;
import com.baeldung.netty.http2.client.Http2ClientInitializer;
import com.baeldung.netty.http2.client.Http2ClientResponseHandler;
import com.baeldung.netty.http2.client.Http2SettingsHandler;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.ssl.SslContext;
//Ensure the server class - Http2Server.java is already started before running this test
public class Http2ClientLiveTest {
private static final Logger logger = LoggerFactory.getLogger(Http2ClientLiveTest.class);
private static final String HOST = "127.0.0.1";
private static final int PORT = 8443;
private SslContext sslCtx;
private Channel channel;
@Before
public void setup() throws Exception {
sslCtx = Http2Util.createSSLContext(false);
}
@Test
public void whenRequestSent_thenHelloWorldReceived() throws Exception {
EventLoopGroup workerGroup = new NioEventLoopGroup();
Http2ClientInitializer initializer = new Http2ClientInitializer(sslCtx, Integer.MAX_VALUE, HOST, PORT);
try {
Bootstrap b = new Bootstrap();
b.group(workerGroup);
b.channel(NioSocketChannel.class);
b.option(ChannelOption.SO_KEEPALIVE, true);
b.remoteAddress(HOST, PORT);
b.handler(initializer);
channel = b.connect()
.syncUninterruptibly()
.channel();
logger.info("Connected to [" + HOST + ':' + PORT + ']');
Http2SettingsHandler http2SettingsHandler = initializer.getSettingsHandler();
http2SettingsHandler.awaitSettings(60, TimeUnit.SECONDS);
logger.info("Sending request(s)...");
FullHttpRequest request = Http2Util.createGetRequest(HOST, PORT);
Http2ClientResponseHandler responseHandler = initializer.getResponseHandler();
int streamId = 3;
responseHandler.put(streamId, channel.write(request), channel.newPromise());
channel.flush();
String response = responseHandler.awaitResponses(60, TimeUnit.SECONDS);
assertEquals("Hello World", response);
logger.info("Finished HTTP/2 request(s)");
} finally {
workerGroup.shutdownGracefully();
}
}
@After
public void cleanup() {
channel.close()
.syncUninterruptibly();
}
}

View File

@ -81,7 +81,7 @@
<rest-assured.version>3.3.0</rest-assured.version>
<!-- plugins -->
<thin.version>1.0.22.RELEASE</thin.version>
<spring-boot.version>2.2.2.RELEASE</spring-boot.version>
<spring-boot.version>2.2.6.RELEASE</spring-boot.version>
</properties>
</project>

View File

@ -31,8 +31,8 @@
</dependencies>
<properties>
<spring.version>5.2.2.RELEASE</spring.version>
<spring-security.version>5.2.1.RELEASE</spring-security.version>
<spring.version>5.2.5.RELEASE</spring.version>
<spring-security.version>5.2.3.RELEASE</spring-security.version>
</properties>
</project>

View File

@ -455,6 +455,7 @@
<module>java-collections-conversions-2</module>
<module>java-collections-maps</module>
<module>java-collections-maps-2</module>
<module>java-collections-maps-3</module>
<!-- <module>java-ee-8-security-api</module> --> <!-- long running -->
<module>javafx</module>
@ -535,6 +536,7 @@
<module>mybatis</module>
<module>netflix-modules</module>
<!-- <module>netty</module> --> <!-- we haven't upgraded to Java 13 -->
<module>ninja</module>
<module>open-liberty</module>
@ -966,6 +968,7 @@
<module>java-collections-conversions-2</module>
<module>java-collections-maps</module>
<module>java-collections-maps-2</module>
<module>java-collections-maps-3</module>
<!-- <module>java-ee-8-security-api</module> --> <!-- long running -->
<module>javafx</module>
@ -1045,6 +1048,7 @@
<module>mybatis</module>
<module>netflix-modules</module>
<!-- <module>netty</module> --> <!-- we haven't upgraded to Java 13 -->
<module>ninja</module>
<module>open-liberty</module>
@ -1261,6 +1265,7 @@
<module>wildfly</module>
<module>xml</module>
<module>xstream</module>
<module>libraries-concurrency</module>
</modules>
</profile>

View File

@ -0,0 +1,21 @@
package org.baeldung.conditionalflow;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ConditionalFlowApplication implements CommandLineRunner {
private static Logger logger = LoggerFactory.getLogger(ConditionalFlowApplication.class);
public static void main(String[] args) {
SpringApplication.run(ConditionalFlowApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
logger.info("Running conditional flow application...");
}
}

View File

@ -0,0 +1,29 @@
package org.baeldung.conditionalflow;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.job.flow.FlowExecutionStatus;
import org.springframework.batch.core.job.flow.JobExecutionDecider;
public class NumberInfoDecider implements JobExecutionDecider {
public static final String NOTIFY = "NOTIFY";
public static final String QUIET = "QUIET";
/**
* Method that determines notification status of job
* @return true if notifications should be sent.
*/
private boolean shouldNotify() {
return true;
}
@Override
public FlowExecutionStatus decide(JobExecution jobExecution, StepExecution stepExecution) {
if (shouldNotify()) {
return new FlowExecutionStatus(NOTIFY);
} else {
return new FlowExecutionStatus(QUIET);
}
}
}

View File

@ -0,0 +1,91 @@
package org.baeldung.conditionalflow.config;
import org.baeldung.conditionalflow.NumberInfoDecider;
import org.baeldung.conditionalflow.model.NumberInfo;
import org.baeldung.conditionalflow.step.*;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
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.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import static org.baeldung.conditionalflow.NumberInfoDecider.NOTIFY;
@Configuration
@EnableBatchProcessing
public class NumberInfoConfig {
@Bean
@Qualifier("NotificationStep")
public Step notificationStep(StepBuilderFactory sbf) {
return sbf.get("Notify step")
.tasklet(new NotifierTasklet())
.build();
}
public Step numberGeneratorStep(StepBuilderFactory sbf, int[] values, String prepend) {
return sbf.get("Number generator")
.<NumberInfo, Integer> chunk(1)
.reader(new NumberInfoGenerator(values))
.processor(new NumberInfoClassifier())
.writer(new PrependingStdoutWriter<>(prepend))
.build();
}
public Step numberGeneratorStepDecider(StepBuilderFactory sbf, int[] values, String prepend) {
return sbf.get("Number generator decider")
.<NumberInfo, Integer> chunk(1)
.reader(new NumberInfoGenerator(values))
.processor(new NumberInfoClassifierWithDecider())
.writer(new PrependingStdoutWriter<>(prepend))
.build();
}
@Bean
@Qualifier("first_job")
public Job numberGeneratorNonNotifierJob(JobBuilderFactory jobBuilderFactory, StepBuilderFactory stepBuilderFactory, @Qualifier("NotificationStep") Step notificationStep) {
int[] nonNotifierData = { -1, -2, -3 };
Step step = numberGeneratorStep(stepBuilderFactory, nonNotifierData, "First Dataset Processor");
return jobBuilderFactory.get("Number generator - first dataset")
.start(step)
.on(NOTIFY)
.to(notificationStep)
.from(step)
.on("*")
.stop()
.end()
.build();
}
@Bean
@Qualifier("second_job")
public Job numberGeneratorNotifierJob(JobBuilderFactory jobBuilderFactory, StepBuilderFactory stepBuilderFactory, @Qualifier("NotificationStep") Step notificationStep) {
int[] billableData = { 11, -2, -3 };
Step dataProviderStep = numberGeneratorStep(stepBuilderFactory, billableData, "Second Dataset Processor");
return jobBuilderFactory.get("Number generator - second dataset")
.start(dataProviderStep)
.on(NOTIFY)
.to(notificationStep)
.end()
.build();
}
@Bean
@Qualifier("third_job")
@Primary
public Job numberGeneratorNotifierJobWithDecider(JobBuilderFactory jobBuilderFactory, StepBuilderFactory stepBuilderFactory, @Qualifier("NotificationStep") Step notificationStep) {
int[] billableData = { 11, -2, -3 };
Step dataProviderStep = numberGeneratorStepDecider(stepBuilderFactory, billableData, "Third Dataset Processor");
return jobBuilderFactory.get("Number generator - third dataset")
.start(dataProviderStep)
.next(new NumberInfoDecider())
.on(NOTIFY)
.to(notificationStep)
.end()
.build();
}
}

View File

@ -0,0 +1,47 @@
package org.baeldung.conditionalflow.model;
import java.util.Objects;
public class NumberInfo {
private int number;
public NumberInfo(int number) {
this.number = number;
}
public static NumberInfo from(int number) {
return new NumberInfo(number);
}
public boolean isPositive() {
return number > 0;
}
public boolean isEven() {
return number % 2 == 0;
}
public int getNumber() {
return number;
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
NumberInfo that = (NumberInfo) o;
return number == that.number;
}
@Override
public int hashCode() {
return Objects.hash(number);
}
@Override
public String toString() {
return "NumberInfo{" + "number=" + number + '}';
}
}

View File

@ -0,0 +1,15 @@
package org.baeldung.conditionalflow.step;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
public class NotifierTasklet implements Tasklet {
@Override
public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
System.err.println("[" + chunkContext.getStepContext()
.getJobName() + "] contains interesting data!!");
return RepeatStatus.FINISHED;
}
}

View File

@ -0,0 +1,35 @@
package org.baeldung.conditionalflow.step;
import org.baeldung.conditionalflow.model.NumberInfo;
import org.springframework.batch.core.ExitStatus;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.annotation.BeforeStep;
import org.springframework.batch.core.listener.ItemListenerSupport;
import org.springframework.batch.item.ItemProcessor;
import static org.baeldung.conditionalflow.NumberInfoDecider.NOTIFY;
import static org.baeldung.conditionalflow.NumberInfoDecider.QUIET;
public class NumberInfoClassifier extends ItemListenerSupport<NumberInfo, Integer>
implements ItemProcessor<NumberInfo, Integer> {
private StepExecution stepExecution;
@BeforeStep
public void beforeStep(StepExecution stepExecution) {
this.stepExecution = stepExecution;
this.stepExecution.setExitStatus(new ExitStatus(QUIET));
}
@Override
public void afterProcess(NumberInfo item, Integer result) {
super.afterProcess(item, result);
if (item.isPositive()) {
stepExecution.setExitStatus(new ExitStatus(NOTIFY));
}
}
@Override
public Integer process(NumberInfo numberInfo) throws Exception {
return Integer.valueOf(numberInfo.getNumber());
}
}

View File

@ -0,0 +1,13 @@
package org.baeldung.conditionalflow.step;
import org.baeldung.conditionalflow.model.NumberInfo;
import org.springframework.batch.core.listener.ItemListenerSupport;
import org.springframework.batch.item.ItemProcessor;
public class NumberInfoClassifierWithDecider extends ItemListenerSupport<NumberInfo, Integer> implements ItemProcessor<NumberInfo, Integer> {
@Override
public Integer process(NumberInfo numberInfo) throws Exception {
return Integer.valueOf(numberInfo.getNumber());
}
}

View File

@ -0,0 +1,23 @@
package org.baeldung.conditionalflow.step;
import org.baeldung.conditionalflow.model.NumberInfo;
import org.springframework.batch.item.ItemReader;
public class NumberInfoGenerator implements ItemReader<NumberInfo> {
private int[] values;
private int counter;
public NumberInfoGenerator(int[] values) {
this.values = values;
counter = 0;
}
@Override
public NumberInfo read() {
if (counter == values.length) {
return null;
} else {
return new NumberInfo(values[counter++]);
}
}
}

View File

@ -0,0 +1,20 @@
package org.baeldung.conditionalflow.step;
import java.util.List;
import org.springframework.batch.item.ItemWriter;
public class PrependingStdoutWriter<T> implements ItemWriter<T> {
private String prependText;
public PrependingStdoutWriter(String prependText) {
this.prependText = prependText;
}
@Override
public void write(List<? extends T> list) {
for (T listItem : list) {
System.out.println(prependText + " " + listItem.toString());
}
}
}

View File

@ -0,0 +1,56 @@
package org.baeldung.conditionalflow;
import org.baeldung.conditionalflow.config.NumberInfoConfig;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.batch.core.ExitStatus;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.test.JobLauncherTestUtils;
import org.springframework.batch.test.context.SpringBatchTest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
import org.springframework.test.context.support.DirtiesContextTestExecutionListener;
import java.util.Collection;
import java.util.Iterator;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@RunWith(SpringRunner.class)
@SpringBatchTest
@EnableAutoConfiguration
@ContextConfiguration(classes = { NumberInfoConfig.class })
@TestExecutionListeners({ DependencyInjectionTestExecutionListener.class, DirtiesContextTestExecutionListener.class })
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
public class DeciderJobIntegrationTest {
@Autowired
private JobLauncherTestUtils jobLauncherTestUtils;
@Test
public void givenNumberGeneratorDecider_whenDeciderRuns_thenStatusIsNotify() throws Exception {
JobExecution jobExecution = jobLauncherTestUtils.launchJob();
Collection<StepExecution> actualStepExecutions = jobExecution.getStepExecutions();
ExitStatus actualJobExitStatus = jobExecution.getExitStatus();
assertEquals("COMPLETED", actualJobExitStatus.getExitCode()
.toString());
assertEquals(2, actualStepExecutions.size());
boolean notifyStepDidRun = false;
Iterator<StepExecution> iterator = actualStepExecutions.iterator();
while (iterator.hasNext() && !notifyStepDidRun) {
if (iterator.next()
.getStepName()
.equals("Notify step")) {
notifyStepDidRun = true;
}
}
assertTrue(notifyStepDidRun);
}
}

View File

@ -0,0 +1,71 @@
package org.baeldung.conditionalflow.model;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
class NumberInfoUnitTest {
@Test
void givenPositive_whenFrom_isPositive() {
assertTrue(NumberInfo.from(1)
.isPositive());
assertTrue(NumberInfo.from(11)
.isPositive());
assertFalse(NumberInfo.from(0)
.isPositive());
}
@Test
void givenNegative_whenFrom_isNegative() {
assertFalse(NumberInfo.from(-1)
.isPositive());
assertFalse(NumberInfo.from(-10)
.isPositive());
}
@Test
void givenEven_whenFrom_isEven() {
assertTrue(NumberInfo.from(0)
.isEven());
assertTrue(NumberInfo.from(-2)
.isEven());
assertTrue(NumberInfo.from(2)
.isEven());
assertTrue(NumberInfo.from(-22)
.isEven());
assertTrue(NumberInfo.from(22)
.isEven());
}
@Test
void givenOdd_whenFrom_isOdd() {
assertFalse(NumberInfo.from(1)
.isEven());
assertFalse(NumberInfo.from(-1)
.isEven());
assertFalse(NumberInfo.from(13)
.isEven());
assertFalse(NumberInfo.from(-13)
.isEven());
assertFalse(NumberInfo.from(31)
.isEven());
assertFalse(NumberInfo.from(-51)
.isEven());
}
@Test
void giveGeneratedInt_whenFrom_isNumberFromGenerator() {
for (int i = -100; i < 100; i++) {
assertEquals(i, NumberInfo.from(i)
.getNumber());
}
}
}

View File

@ -0,0 +1,16 @@
package org.baeldung.conditionalflow.step;
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.baeldung.conditionalflow.model.NumberInfo;
import org.junit.jupiter.api.Test;
class NumberInfoClassifierUnitTest {
@Test
void givenNumberInfo_whenProcess_thenConvertsToInteger() throws Exception {
NumberInfoClassifier nic = new NumberInfoClassifier();
assertEquals(Integer.valueOf(4), nic.process(NumberInfo.from(4)));
assertEquals(Integer.valueOf(-4), nic.process(NumberInfo.from(-4)));
}
}

View File

@ -0,0 +1,21 @@
package org.baeldung.conditionalflow.step;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import org.baeldung.conditionalflow.model.NumberInfo;
import org.junit.jupiter.api.Test;
public class NumberInfoGeneratorUnitTest {
@Test
public void givenArray_whenGenerator_correctOrderAndValue() {
int[] numbers = new int[] { 1, -2, 4, -10 };
NumberInfoGenerator numberGenerator = new NumberInfoGenerator(numbers);
assertEquals(new NumberInfo(numbers[0]), numberGenerator.read());
assertEquals(new NumberInfo(numbers[1]), numberGenerator.read());
assertEquals(new NumberInfo(numbers[2]), numberGenerator.read());
assertEquals(new NumberInfo(numbers[3]), numberGenerator.read());
assertNull(numberGenerator.read());
}
}

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

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

View File

@ -208,7 +208,7 @@
<properties>
<!-- The main class to start by executing java -jar -->
<start-class>org.baeldung.boot.Application</start-class>
<start-class>com.baeldung.boot.Application</start-class>
<jquery.version>3.1.1</jquery.version>
<bootstrap.version>3.3.7-1</bootstrap.version>
<jpa.version>2.2</jpa.version>

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.boot;
package com.baeldung.boot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

View File

@ -1,4 +1,4 @@
package org.baeldung.boot.client;
package com.baeldung.boot.client;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.stereotype.Service;

View File

@ -1,4 +1,4 @@
package org.baeldung.websocket.client;
package com.baeldung.websocket.client;
public class Message {

View File

@ -1,4 +1,4 @@
package org.baeldung.websocket.client;
package com.baeldung.websocket.client;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

View File

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

View File

@ -1,10 +1,12 @@
package org.baeldung.boot.client;
package com.baeldung.boot.client;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;
import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;
import org.baeldung.boot.Application;
import com.baeldung.boot.Application;
import com.baeldung.boot.client.Details;
import com.baeldung.boot.client.DetailsServiceClient;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

View File

@ -1,6 +1,5 @@
package com.baeldung.websocket.client;
import org.baeldung.websocket.client.MyStompSessionHandler;
import org.junit.Test;
import org.mockito.Mockito;
import org.springframework.messaging.simp.stomp.StompHeaders;

View File

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

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

@ -190,7 +190,7 @@
<properties>
<!-- The main class to start by executing java -jar -->
<start-class>org.baeldung.boot.Application</start-class>
<start-class>com.baeldung.boot.Application</start-class>
<jquery.version>3.1.1</jquery.version>
<bootstrap.version>3.3.7-1</bootstrap.version>
<jpa.version>2.2</jpa.version>

View File

@ -21,7 +21,7 @@ apply plugin: 'io.spring.dependency-management'
//add tasks thinJar and thinResolve for thin JAR deployments
apply plugin: 'org.springframework.boot.experimental.thin-launcher'
group = 'org.baeldung'
group = 'com.baeldung'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8
@ -35,16 +35,16 @@ dependencies {
}
springBoot {
mainClassName = 'org.baeldung.DemoApplication'
mainClassName = 'com.baeldung.DemoApplication'
}
bootJar {
// This is overridden by the mainClassName in springBoot{} and added here for reference purposes.
mainClassName = 'org.baeldung.DemoApplication'
mainClassName = 'com.baeldung.DemoApplication'
// This block serves the same purpose as the above thus commented out. Added here for reference purposes
// manifest {
// attributes 'Start-Class': 'org.baeldung.DemoApplication'
// attributes 'Start-Class': 'com.baeldung.DemoApplication'
// }
}

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.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

@ -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

@ -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

@ -7,7 +7,7 @@ import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
@Configuration
@ComponentScan("org.baeldung.properties.core")
@ComponentScan("com.baeldung.properties.core")
@PropertySource("classpath:foo.properties")
public class ExternalPropertiesWithJavaConfig {

View File

@ -6,7 +6,7 @@ import org.springframework.context.annotation.ImportResource;
@Configuration
@ImportResource("classpath:configForProperties.xml")
@ComponentScan("org.baeldung.core")
@ComponentScan("com.baeldung.core")
public class ExternalPropertiesWithXmlConfig {
public ExternalPropertiesWithXmlConfig() {

View File

@ -6,7 +6,7 @@ import org.springframework.context.annotation.ImportResource;
@Configuration
@ImportResource("classpath:configForPropertiesOne.xml")
@ComponentScan("org.baeldung.core")
@ComponentScan("com.baeldung.core")
public class ExternalPropertiesWithXmlConfigOne {
public ExternalPropertiesWithXmlConfigOne() {

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

@ -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.boot;
package com.baeldung.boot;
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