commit
f7522a1bb9
|
@ -13,6 +13,5 @@ This module contains articles about algorithms. Some classes of algorithms, e.g.
|
|||
- [Checking if a Java Graph has a Cycle](https://www.baeldung.com/java-graph-has-a-cycle)
|
||||
- [A Guide to the Folding Technique in Java](https://www.baeldung.com/folding-hashing-technique)
|
||||
- [Creating a Triangle with for Loops in Java](https://www.baeldung.com/java-print-triangle)
|
||||
- [Efficient Word Frequency Calculator in Java](https://www.baeldung.com/java-word-frequency)
|
||||
- [The K-Means Clustering Algorithm in Java](https://www.baeldung.com/java-k-means-clustering-algorithm)
|
||||
- More articles: [[<-- prev]](/algorithms-miscellaneous-2) [[next -->]](/algorithms-miscellaneous-4)
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
### Relevant Articles:
|
||||
|
||||
- [Intro to OData with Olingo](https://www.baeldung.com/olingo)
|
|
@ -1,146 +0,0 @@
|
|||
CAS Overlay Template [![Build Status](https://travis-ci.org/apereo/cas-overlay-template.svg?branch=master)](https://travis-ci.org/apereo/cas-overlay-template)
|
||||
=======================
|
||||
|
||||
Generic CAS WAR overlay to exercise the latest versions of CAS. This overlay could be freely used as a starting template for local CAS war overlays.
|
||||
|
||||
# Versions
|
||||
|
||||
- CAS `6.1.x`
|
||||
- JDK `11`
|
||||
|
||||
# Overview
|
||||
|
||||
To build the project, use:
|
||||
|
||||
```bash
|
||||
# Use --refresh-dependencies to force-update SNAPSHOT versions
|
||||
./gradlew[.bat] clean build
|
||||
```
|
||||
|
||||
To see what commands are available to the build script, run:
|
||||
|
||||
```bash
|
||||
./gradlew[.bat] tasks
|
||||
```
|
||||
|
||||
To launch into the CAS command-line shell:
|
||||
|
||||
```bash
|
||||
./gradlew[.bat] downloadShell runShell
|
||||
```
|
||||
|
||||
To fetch and overlay a CAS resource or view, use:
|
||||
|
||||
```bash
|
||||
./gradlew[.bat] getResource -PresourceName=[resource-name]
|
||||
```
|
||||
|
||||
To list all available CAS views and templates:
|
||||
|
||||
```bash
|
||||
./gradlew[.bat] listTemplateViews
|
||||
```
|
||||
|
||||
To unzip and explode the CAS web application file and the internal resources jar:
|
||||
|
||||
```bash
|
||||
./gradlew[.bat] explodeWar
|
||||
```
|
||||
|
||||
# Configuration
|
||||
|
||||
- The `etc` directory contains the configuration files and directories that need to be copied to `/etc/cas/config`.
|
||||
|
||||
```bash
|
||||
./gradlew[.bat] copyCasConfiguration
|
||||
```
|
||||
|
||||
- The specifics of the build are controlled using the `gradle.properties` file.
|
||||
|
||||
## Adding Modules
|
||||
|
||||
CAS modules may be specified under the `dependencies` block of the [Gradle build script](build.gradle):
|
||||
|
||||
```gradle
|
||||
dependencies {
|
||||
compile "org.apereo.cas:cas-server-some-module:${project.casVersion}"
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
To collect the list of all project modules and dependencies:
|
||||
|
||||
```bash
|
||||
./gradlew[.bat] allDependencies
|
||||
```
|
||||
|
||||
### Clear Gradle Cache
|
||||
|
||||
If you need to, on Linux/Unix systems, you can delete all the existing artifacts (artifacts and metadata) Gradle has downloaded using:
|
||||
|
||||
```bash
|
||||
# Only do this when absolutely necessary
|
||||
rm -rf $HOME/.gradle/caches/
|
||||
```
|
||||
|
||||
Same strategy applies to Windows too, provided you switch `$HOME` to its equivalent in the above command.
|
||||
|
||||
# Deployment
|
||||
|
||||
- Create a keystore file `thekeystore` under `/etc/cas`. Use the password `changeit` for both the keystore and the key/certificate entries. This can either be done using the JDK's `keytool` utility or via the following command:
|
||||
|
||||
```bash
|
||||
./gradlew[.bat] createKeystore
|
||||
```
|
||||
|
||||
- Ensure the keystore is loaded up with keys and certificates of the server.
|
||||
|
||||
On a successful deployment via the following methods, CAS will be available at:
|
||||
|
||||
* `https://cas.server.name:8443/cas`
|
||||
|
||||
## Executable WAR
|
||||
|
||||
Run the CAS web application as an executable WAR:
|
||||
|
||||
```bash
|
||||
./gradlew[.bat] run
|
||||
```
|
||||
|
||||
Debug the CAS web application as an executable WAR:
|
||||
|
||||
```bash
|
||||
./gradlew[.bat] debug
|
||||
```
|
||||
|
||||
Run the CAS web application as a *standalone* executable WAR:
|
||||
|
||||
```bash
|
||||
./gradlew[.bat] clean executable
|
||||
```
|
||||
|
||||
## External
|
||||
|
||||
Deploy the binary web application file `cas.war` after a successful build to a servlet container of choice.
|
||||
|
||||
## Docker
|
||||
|
||||
The following strategies outline how to build and deploy CAS Docker images.
|
||||
|
||||
### Jib
|
||||
|
||||
The overlay embraces the [Jib Gradle Plugin](https://github.com/GoogleContainerTools/jib) to provide easy-to-use out-of-the-box tooling for building CAS docker images. Jib is an open-source Java containerizer from Google that lets Java developers build containers using the tools they know. It is a container image builder that handles all the steps of packaging your application into a container image. It does not require you to write a Dockerfile or have Docker installed, and it is directly integrated into the overlay.
|
||||
|
||||
```bash
|
||||
./gradlew build jibDockerBuild
|
||||
```
|
||||
|
||||
### Dockerfile
|
||||
|
||||
You can also use the native Docker tooling and the provided `Dockerfile` to build and run CAS.
|
||||
|
||||
```bash
|
||||
chmod +x *.sh
|
||||
./docker-build.sh
|
||||
./docker-run.sh
|
||||
```
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -4,7 +4,6 @@ This module contains articles about Java 8 core features
|
|||
|
||||
### Relevant Articles:
|
||||
|
||||
- [How to Delay Code Execution in Java](https://www.baeldung.com/java-delay-code-execution)
|
||||
- [Run a Java Application from the Command Line](https://www.baeldung.com/java-run-jar-with-arguments)
|
||||
- [Java 8 Stream skip() vs limit()](https://www.baeldung.com/java-stream-skip-vs-limit)
|
||||
- [Guide to Java BiFunction Interface](https://www.baeldung.com/java-bifunction-interface)
|
||||
|
|
|
@ -12,4 +12,3 @@
|
|||
- [Sorting in Java](https://www.baeldung.com/java-sorting)
|
||||
- [Getting the Size of an Iterable in Java](https://www.baeldung.com/java-iterable-size)
|
||||
- [Java Null-Safe Streams from Collections](https://www.baeldung.com/java-null-safe-streams-from-collections)
|
||||
- [Operating on and Removing an Item from Stream](https://www.baeldung.com/java-use-remove-item-stream)
|
||||
|
|
|
@ -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]](/core-java-modules/core-java-collections-maps) [[next -->]](/core-java-modules/core-java-collections-maps-3)
|
|
@ -3,16 +3,16 @@
|
|||
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-2</artifactId>
|
||||
<artifactId>core-java-collections-maps-2</artifactId>
|
||||
<version>0.1.0-SNAPSHOT</version>
|
||||
<name>java-collections-maps-2</name>
|
||||
<name>core-java-collections-maps-2</name>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>parent-java</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<relativePath>../parent-java</relativePath>
|
||||
<relativePath>../../parent-java</relativePath>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
|
@ -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]](/core-java-modules/core-java-collections-maps-2)
|
|
@ -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>core-java-collections-maps-3</artifactId>
|
||||
<version>0.1.0-SNAPSHOT</version>
|
||||
<name>core-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>
|
|
@ -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 -->]](/core-java-modules/core-java-collections-maps-2)
|
|
@ -2,16 +2,16 @@
|
|||
<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</artifactId>
|
||||
<artifactId>core-java-collections-maps</artifactId>
|
||||
<version>0.1.0-SNAPSHOT</version>
|
||||
<name>java-collections-maps</name>
|
||||
<name>core-java-collections-maps</name>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<parent>
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>parent-java</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<relativePath>../parent-java</relativePath>
|
||||
<relativePath>../../parent-java</relativePath>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
|
@ -3,7 +3,6 @@
|
|||
This module contains articles about Java collections
|
||||
|
||||
### Relevant Articles:
|
||||
- [Collect a Java Stream to an Immutable Collection](https://www.baeldung.com/java-stream-immutable-collection)
|
||||
- [Introduction to the Java ArrayDeque](https://www.baeldung.com/java-array-deque)
|
||||
- [An Introduction to Java.util.Hashtable Class](https://www.baeldung.com/java-hash-table)
|
||||
- [Thread Safe LIFO Data Structure Implementations](https://www.baeldung.com/java-lifo-thread-safe)
|
||||
|
@ -13,4 +12,4 @@ This module contains articles about Java collections
|
|||
- [Defining a Char Stack in Java](https://www.baeldung.com/java-char-stack)
|
||||
- [Guide to the Java Queue Interface](https://www.baeldung.com/java-queue)
|
||||
- [An Introduction to Synchronized Java Collections](https://www.baeldung.com/java-synchronized-collections)
|
||||
- [[More -->]](/core-java-modules/core-java-collections-2)
|
||||
- [[More -->]](/core-java-modules/core-java-collections-2)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
### Relevant Articles:
|
||||
|
||||
- [Introduction to Lock Striping](https://www.baeldung.com/java-lock-stripping)
|
|
@ -12,4 +12,5 @@ This module contains articles about core Java input and output (IO)
|
|||
- [Java – Append Data to a File](https://www.baeldung.com/java-append-to-file)
|
||||
- [How to Copy a File with Java](https://www.baeldung.com/java-copy-file)
|
||||
- [Create a Directory in Java](https://www.baeldung.com/java-create-directory)
|
||||
- [Java IO vs NIO](https://www.baeldung.com/java-io-vs-nio)
|
||||
- [[<-- Prev]](/core-java-modules/core-java-io)
|
||||
|
|
|
@ -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() {
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -42,6 +42,9 @@
|
|||
<module>core-java-collections-list</module>
|
||||
<module>core-java-collections-list-2</module>
|
||||
<module>core-java-collections-list-3</module>
|
||||
<module>core-java-collections-maps</module>
|
||||
<module>core-java-collections-maps-2</module>
|
||||
<module>core-java-collections-maps-3</module>
|
||||
<!-- <module>core-java-collections-set</module> --> <!-- We haven't upgraded to java 11. Fixing in BAEL-10841 -->
|
||||
|
||||
<module>core-java-concurrency-2</module>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
This module contains articles about Kotlin core features.
|
||||
|
||||
### Relevant articles:
|
||||
- [Introduction to the Kotlin Language](https://www.baeldung.com/kotlin-intro)
|
||||
- [Introduction to the Kotlin Language](https://www.baeldung.com/kotlin/tutorial)
|
||||
- [Kotlin Java Interoperability](https://www.baeldung.com/kotlin-java-interoperability)
|
||||
- [Get a Random Number in Kotlin](https://www.baeldung.com/kotlin-random-number)
|
||||
- [Create a Java and Kotlin Project with Maven](https://www.baeldung.com/kotlin-maven-java-project)
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
### Relevant Articles:
|
||||
|
||||
- [Pattern Matching in Scala](https://www.baeldung.com/scala/pattern-matching)
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -12,4 +12,5 @@ This module contains articles about numbers in Java.
|
|||
- [Calculating the nth Root in Java](https://www.baeldung.com/java-nth-root)
|
||||
- [Convert Double to String, Removing Decimal Places](https://www.baeldung.com/java-double-to-string)
|
||||
- [Changing the Order in a Sum Operation Can Produce Different Results?](https://www.baeldung.com/java-floating-point-sum-order)
|
||||
- [Using Math.sin with Degrees](https://www.baeldung.com/java-math-sin-degrees)
|
||||
- More articles: [[next -->]](/../java-numbers-2)
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
<repositories>
|
||||
<repository>
|
||||
<id>OpenNMS Repository</id>
|
||||
<url>http://repo.opennms.org/maven2/</url>
|
||||
<url>https://repo.opennms.org/maven2/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
|
@ -27,11 +27,6 @@
|
|||
<artifactId>jnlp-servlet</artifactId>
|
||||
<version>${jnlp-servlet.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.samples.jnlp</groupId>
|
||||
<artifactId>jnlp-jardiff</artifactId>
|
||||
<version>${jnlp-jardiff.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
@ -84,7 +79,6 @@
|
|||
|
||||
<properties>
|
||||
<maven-jar-plugin.version>3.0.2</maven-jar-plugin.version>
|
||||
<jnlp-jardiff.version>1.6.0</jnlp-jardiff.version>
|
||||
<jnlp-servlet.version>1.6.0</jnlp-servlet.version>
|
||||
</properties>
|
||||
|
||||
|
|
|
@ -15,4 +15,4 @@ Remember, for advanced libraries like [Jackson](/jackson) and [JUnit](/testing-m
|
|||
- [Introduction to the jcabi-aspects AOP Annotations Library](https://www.baeldung.com/java-jcabi-aspects)
|
||||
- [Introduction to Takes](https://www.baeldung.com/java-takes)
|
||||
- [Using NullAway to Avoid NullPointerExceptions](https://www.baeldung.com/java-nullaway)
|
||||
|
||||
- [Introduction to Alibaba Arthas](https://www.baeldung.com/java-alibaba-arthas-intro)
|
||||
|
|
|
@ -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>
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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>
|
|
@ -0,0 +1,3 @@
|
|||
### Relevant Articles:
|
||||
|
||||
- [How to Use Command Line Arguments in a Bash Script](https://www.baeldung.com/linux/use-command-line-arguments-in-bash-script)
|
|
@ -0,0 +1,3 @@
|
|||
### Relevant Articles
|
||||
|
||||
- [Bash Functions in Linux](https://www.baeldung.com/linux/bash-functions)
|
|
@ -0,0 +1,3 @@
|
|||
### Relevant Articles:
|
||||
|
||||
- [Guide to the Linux read Command](https://www.baeldung.com/linux/read-command)
|
|
@ -1,3 +1,4 @@
|
|||
### Relevant Articles:
|
||||
|
||||
- [Linux Commands – Remove All Text After X](https://www.baeldung.com/linux/tr-manipulate-strings)
|
||||
- [Linux Commands for Appending Multiple Lines to a File](https://www.baeldung.com/linux/appending-multiple-lines-to-file2)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
### Relevant Articles:
|
||||
- TBD
|
||||
- [Improved Java Logging with Mapped Diagnostic Context (MDC)](https://www.baeldung.com/mdc-in-log4j-2-logback)
|
||||
- [Java Logging with Nested Diagnostic Context (NDC)](https:www.baeldung.com/java-logging-ndc-log4j)
|
||||
- [Java Logging with Nested Diagnostic Context (NDC)](https://www.baeldung.com/java-logging-ndc-log4j)
|
||||
- [Drools Using Rules from Excel Files](https://www.baeldung.com/drools-excel)
|
||||
|
||||
### References
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
### Relevant Articles:
|
||||
|
||||
- [Guide to the Linux wc Command](https://www.baeldung.com/linux/wc-command)
|
|
@ -0,0 +1,6 @@
|
|||
## Netty
|
||||
|
||||
This module contains articles about Netty.
|
||||
|
||||
### Relevant Articles:
|
||||
|
|
@ -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>
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue