commit
470ccf8c9a
@ -10,4 +10,4 @@ This module contains articles about algorithms. Some classes of algorithms, e.g.
|
||||
- [Introduction to Minimax Algorithm](https://www.baeldung.com/java-minimax-algorithm)
|
||||
- [How to Calculate Levenshtein Distance in Java?](https://www.baeldung.com/java-levenshtein-distance)
|
||||
- [How to Find the Kth Largest Element in Java](https://www.baeldung.com/java-kth-largest-element)
|
||||
- More articles: [[next -->]](/../algorithms-miscellaneous-2)
|
||||
- More articles: [[next -->]](/algorithms-miscellaneous-2)
|
||||
|
@ -14,4 +14,4 @@ This module contains articles about algorithms. Some classes of algorithms, e.g.
|
||||
- [Displaying Money Amounts in Words](https://www.baeldung.com/java-money-into-words)
|
||||
- [A Collaborative Filtering Recommendation System in Java](https://www.baeldung.com/java-collaborative-filtering-recommendations)
|
||||
- [Implementing A* Pathfinding in Java](https://www.baeldung.com/java-a-star-pathfinding)
|
||||
- More articles: [[<-- prev]](/../algorithms-miscellaneous-1) [[next -->]](/../algorithms-miscellaneous-3)
|
||||
- More articles: [[<-- prev]](/algorithms-miscellaneous-1) [[next -->]](/algorithms-miscellaneous-3)
|
||||
|
@ -15,5 +15,5 @@ This module contains articles about algorithms. Some classes of algorithms, e.g.
|
||||
- [Maximum Subarray Problem](https://www.baeldung.com/java-maximum-subarray)
|
||||
- [How to Merge Two Sorted Arrays](https://www.baeldung.com/java-merge-sorted-arrays)
|
||||
- [Median of Stream of Integers using Heap](https://www.baeldung.com/java-stream-integers-median-using-heap)
|
||||
- More articles: [[<-- prev]](/../algorithms-miscellaneous-4) [[next -->]](/../algorithms-miscellaneous-6)
|
||||
- More articles: [[<-- prev]](/algorithms-miscellaneous-4) [[next -->]](/algorithms-miscellaneous-6)
|
||||
|
||||
|
@ -10,4 +10,4 @@
|
||||
- [Implementing a 2048 Solver in Java](https://www.baeldung.com/2048-java-solver)
|
||||
- [Finding Top K Elements in an Array](https://www.baeldung.com/java-array-top-elements)
|
||||
- [Reversing a Linked List in Java](https://www.baeldung.com/java-reverse-linked-list)
|
||||
- More articles: [[<-- prev]](/../algorithms-miscellaneous-5)
|
||||
- More articles: [[<-- prev]](/algorithms-miscellaneous-5)
|
||||
|
@ -8,3 +8,4 @@ This module contains articles about Apache Spark
|
||||
- [Building a Data Pipeline with Kafka, Spark Streaming and Cassandra](https://www.baeldung.com/kafka-spark-data-pipeline)
|
||||
- [Machine Learning with Spark MLlib](https://www.baeldung.com/spark-mlib-machine-learning)
|
||||
- [Introduction to Spark Graph Processing with GraphFrames](https://www.baeldung.com/spark-graph-graphframes)
|
||||
- [Apache Spark: Differences between Dataframes, Datasets and RDDs](https://www.baeldung.com/java-spark-dataframe-dataset-rdd)
|
||||
|
@ -19,12 +19,12 @@ public class StudentDbService implements StudentService {
|
||||
}
|
||||
|
||||
public Student update(Student student) {
|
||||
logger.log(Level.INFO, "Updating sutdent in DB...");
|
||||
logger.log(Level.INFO, "Updating student in DB...");
|
||||
return student;
|
||||
}
|
||||
|
||||
public String delete(String registrationId) {
|
||||
logger.log(Level.INFO, "Deleteing sutdent in DB...");
|
||||
logger.log(Level.INFO, "Deleting student in DB...");
|
||||
return registrationId;
|
||||
}
|
||||
}
|
@ -33,11 +33,15 @@ public class HashSetBenchmark {
|
||||
private List<Employee> employeeList1 = new ArrayList<>();
|
||||
private Set<Employee> employeeSet2 = new HashSet<>();
|
||||
private List<Employee> employeeList2 = new ArrayList<>();
|
||||
private Set<Employee> employeeSet3 = new HashSet<>();
|
||||
private Set<Employee> employeeSet4 = new HashSet<>();
|
||||
|
||||
private long set1Size = 60000;
|
||||
private long list1Size = 50000;
|
||||
private long set2Size = 50000;
|
||||
private long list2Size = 60000;
|
||||
private long set3Size = 50000;
|
||||
private long set4Size = 60000;
|
||||
|
||||
@Setup(Level.Trial)
|
||||
public void setUp() {
|
||||
@ -58,6 +62,14 @@ public class HashSetBenchmark {
|
||||
employeeList2.add(new Employee(i, RandomStringUtils.random(7, true, false)));
|
||||
}
|
||||
|
||||
for (long i = 0; i < set3Size; i++) {
|
||||
employeeSet3.add(new Employee(i, RandomStringUtils.random(7, true, false)));
|
||||
}
|
||||
|
||||
for (long i = 0; i < set4Size; i++) {
|
||||
employeeSet4.add(new Employee(i, RandomStringUtils.random(7, true, false)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -72,6 +84,11 @@ public class HashSetBenchmark {
|
||||
return state.employeeSet2.removeAll(state.employeeList2);
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public boolean given_SizeOfHashsetSmallerThanSizeOfAnotherHashSet_When_RemoveAllFromHashSet_Then_GoodPerformance(MyState state) {
|
||||
return state.employeeSet3.removeAll(state.employeeSet4);
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
Options options = new OptionsBuilder().include(HashSetBenchmark.class.getSimpleName())
|
||||
.threads(1)
|
||||
|
@ -73,7 +73,7 @@ public class LivelockExample {
|
||||
|
||||
public void tryLock(Lock lock, long millis) {
|
||||
try {
|
||||
lock.tryLock(10, TimeUnit.MILLISECONDS);
|
||||
lock.tryLock(millis, TimeUnit.MILLISECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
@ -0,0 +1,6 @@
|
||||
package com.baeldung.exceptions.classcastexception;
|
||||
|
||||
public interface Animal {
|
||||
|
||||
String getName();
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package com.baeldung.exceptions.classcastexception;
|
||||
|
||||
public class Box<T> {
|
||||
|
||||
private T content;
|
||||
|
||||
public T getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
public void setContent(T content) {
|
||||
this.content = content;
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package com.baeldung.exceptions.classcastexception;
|
||||
|
||||
public class Frog extends Reptile {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return super.getName() + ": Frog";
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package com.baeldung.exceptions.classcastexception;
|
||||
|
||||
public class Mammal implements Animal {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Mammal";
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package com.baeldung.exceptions.classcastexception;
|
||||
|
||||
public class Reptile implements Animal {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Reptile";
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
package com.baeldung.exceptions.classcastexception;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class CheckedCastsUnitTest {
|
||||
|
||||
@Test(expected = ClassCastException.class)
|
||||
public void givenBaseTypeVariableReferencingChildInstance_whenCastToIncompatibleSubtype_thenClassCastException() {
|
||||
Animal animal = new Frog();
|
||||
|
||||
//A checked downcast to Mammal is incompatible from Frog because Frog is not a subtype of Mammal.
|
||||
Mammal mammal = (Mammal) animal;
|
||||
}
|
||||
|
||||
@Test(expected = ClassCastException.class)
|
||||
public void givenBaseTypeVariableReferencingChildInstance_whenCastToIncompatibleInterface_thenClassCastException() {
|
||||
Animal animal = new Frog();
|
||||
|
||||
//A checked cast to Serializable is incompatible from Frog because Frog is not a subtype of Serializable.
|
||||
Serializable serial = (Serializable) animal;
|
||||
}
|
||||
|
||||
@Test(expected = ClassCastException.class)
|
||||
public void givenObjectVariableReferencingPrimitiveArray_whenCastToBoxedTypeArray_thenClassCastException() {
|
||||
Object primitives = new int[1];
|
||||
|
||||
//A checked cast to Integer[] is incompatible from primitive arrays. Auto-boxing does not work for arrays.
|
||||
Integer[] integers = (Integer[]) primitives;
|
||||
}
|
||||
|
||||
@Test(expected = ClassCastException.class)
|
||||
public void givenObjectVariableReferencingPrimitiveArray_whenCastToPromotedTypeArray_thenClassCastException() {
|
||||
Object primitives = new int[1];
|
||||
|
||||
//A checked cast to long[] is incompatible from int[]. Type promotion does not work for arrays.
|
||||
long[] longs = (long[]) primitives;
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package com.baeldung.exceptions.classcastexception;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class GenericConversionUnitTest {
|
||||
|
||||
@Test(expected = ClassCastException.class)
|
||||
public void givenIncompatibleType_whenConvertInstanceOfObject_thenClassCastException() {
|
||||
// Should have been null, but due to type erasure, inside convertInstanceOfObject,
|
||||
// it will attempt to cast to Object instead of String, so it casts to Object, which is always possible.
|
||||
String shouldBeNull = convertInstanceOfObject(123);
|
||||
}
|
||||
|
||||
public static <T> T convertInstanceOfObject(Object o) {
|
||||
try {
|
||||
return (T) o; // Casts to Object due to type erasure
|
||||
} catch (ClassCastException e) {
|
||||
return null; // Will never reach this
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package com.baeldung.exceptions.classcastexception;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class UncheckedConversionUnitTest {
|
||||
|
||||
@Test(expected = ClassCastException.class)
|
||||
public void givenPollutedGenericType_whenGetProperty_thenClassCastException() {
|
||||
Box<Long> originalBox = new Box<>();
|
||||
Box raw = originalBox;
|
||||
raw.setContent(2.5);
|
||||
Box<Long> bound = (Box<Long>) raw;
|
||||
|
||||
//An incompatible element was found in the raw box.
|
||||
Long content = bound.getContent();
|
||||
}
|
||||
}
|
@ -7,4 +7,5 @@ This module contains articles about core features in the Java language
|
||||
- [When are Static Variables Initialized in Java?](https://www.baeldung.com/java-static-variables-initialization)
|
||||
- [Checking if a Class Exists in Java](https://www.baeldung.com/java-check-class-exists)
|
||||
- [The Difference Between a.getClass() and A.class in Java](https://www.baeldung.com/java-getclass-vs-class)
|
||||
- [Constants in Java: Patterns and Anti-Patterns](https://www.baeldung.com/java-constants-good-practices)
|
||||
- [[<-- Prev]](/core-java-modules/core-java-lang-2)
|
||||
|
@ -0,0 +1,37 @@
|
||||
package com.baeldung.constantspatterns;
|
||||
|
||||
public class Calculator {
|
||||
public static final double PI = 3.14159265359;
|
||||
private static final double UPPER_LIMIT = 0x1.fffffffffffffP+1023;
|
||||
|
||||
public enum Operation {
|
||||
ADD, SUBTRACT, DIVIDE, MULTIPLY
|
||||
}
|
||||
|
||||
public double operateOnTwoNumbers(double numberOne, double numberTwo, Operation operation) {
|
||||
if (numberOne > UPPER_LIMIT) {
|
||||
throw new IllegalArgumentException("'numberOne' is too large");
|
||||
}
|
||||
if (numberTwo > UPPER_LIMIT) {
|
||||
throw new IllegalArgumentException("'numberTwo' is too large");
|
||||
}
|
||||
double answer = 0;
|
||||
|
||||
switch (operation) {
|
||||
case ADD:
|
||||
answer = numberOne + numberTwo;
|
||||
break;
|
||||
case SUBTRACT:
|
||||
answer = numberOne - numberTwo;
|
||||
break;
|
||||
case DIVIDE:
|
||||
answer = numberOne / numberTwo;
|
||||
break;
|
||||
case MULTIPLY:
|
||||
answer = numberOne * numberTwo;
|
||||
break;
|
||||
}
|
||||
|
||||
return answer;
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package com.baeldung.constantspatterns;
|
||||
|
||||
public interface CalculatorConstants {
|
||||
double PI = 3.14159265359;
|
||||
double UPPER_LIMIT = 0x1.fffffffffffffP+1023;
|
||||
|
||||
enum Operation {
|
||||
ADD, SUBTRACT, MULTIPLY, DIVIDE
|
||||
};
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package com.baeldung.constantspatterns;
|
||||
|
||||
public class GeometryCalculator implements CalculatorConstants {
|
||||
public static final double UPPER_LIMIT = 100000000000000000000.0;
|
||||
|
||||
public double operateOnTwoNumbers(double numberOne, double numberTwo, Operation operation) {
|
||||
if (numberOne > UPPER_LIMIT) {
|
||||
throw new IllegalArgumentException("'numberOne' is too large");
|
||||
}
|
||||
if (numberTwo > UPPER_LIMIT) {
|
||||
throw new IllegalArgumentException("'numberTwo' is too large");
|
||||
}
|
||||
double answer = 0;
|
||||
|
||||
switch (operation) {
|
||||
case ADD:
|
||||
answer = numberOne + numberTwo;
|
||||
break;
|
||||
case SUBTRACT:
|
||||
answer = numberOne - numberTwo;
|
||||
break;
|
||||
case DIVIDE:
|
||||
answer = numberOne / numberTwo;
|
||||
break;
|
||||
case MULTIPLY:
|
||||
answer = numberOne * numberTwo;
|
||||
break;
|
||||
}
|
||||
|
||||
return answer;
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package com.baeldung.constantspatterns.calculations;
|
||||
|
||||
public final class MathConstants {
|
||||
public static final double PI = 3.14159265359;
|
||||
static final double GOLDEN_RATIO = 1.6180;
|
||||
static final double GRAVITATIONAL_ACCELERATION = 9.8;
|
||||
static final double EULERS_NUMBER = 2.7182818284590452353602874713527;
|
||||
|
||||
public enum Operation {
|
||||
ADD, SUBTRACT, DIVIDE, MULTIPLY
|
||||
}
|
||||
|
||||
private MathConstants() {
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package com.baeldung.constantspatterns;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class ConstantPatternUnitTest {
|
||||
@Test
|
||||
public void givenTwoNumbersAndAdd_whenCallingCalculatorOperatOneTwoNumbers_thenCorrectAnswerReturned() {
|
||||
Calculator calculator = new Calculator();
|
||||
double expected = 4;
|
||||
double answer = calculator.operateOnTwoNumbers(2, 2, Calculator.Operation.ADD);
|
||||
assertEquals(expected, answer);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenTwoNumbersAndAdd_whenCallingGeometryCalculatorOperatOneTwoNumbers_thenCorrectAnswerReturned() {
|
||||
GeometryCalculator calculator = new GeometryCalculator();
|
||||
double expected = 4;
|
||||
double answer = calculator.operateOnTwoNumbers(2, 2, GeometryCalculator.Operation.ADD);
|
||||
assertEquals(expected, answer);
|
||||
}
|
||||
}
|
@ -14,4 +14,5 @@ This module contains articles about networking in Java
|
||||
- [Handling java.net.ConnectException](https://www.baeldung.com/java-net-connectexception)
|
||||
- [Getting MAC addresses in Java](https://www.baeldung.com/java-mac-address)
|
||||
- [Sending Emails with Attachments in Java](https://www.baeldung.com/java-send-emails-attachments)
|
||||
- [Finding a Free Port in Java](https://www.baeldung.com/java-free-port)
|
||||
- [[<-- Prev]](/core-java-modules/core-java-networking)
|
||||
|
@ -3,7 +3,7 @@ package com.baeldung.hashing;
|
||||
class SHACommonUtils {
|
||||
|
||||
public static String bytesToHex(byte[] hash) {
|
||||
StringBuffer hexString = new StringBuffer();
|
||||
StringBuilder hexString = new StringBuilder(2 * hash.length);
|
||||
for (byte h : hash) {
|
||||
String hex = Integer.toHexString(0xff & h);
|
||||
if (hex.length() == 1)
|
||||
|
@ -104,16 +104,12 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>${maven-surefire-plugin.version}</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<properties>
|
||||
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
|
||||
|
||||
<joda-money.version>1.0.1</joda-money.version>
|
||||
|
||||
<junit-jupiter.version>5.6.2</junit-jupiter.version>
|
||||
</properties>
|
||||
</project>
|
||||
|
78
netflix-modules/mantis/pom.xml
Normal file
78
netflix-modules/mantis/pom.xml
Normal file
@ -0,0 +1,78 @@
|
||||
<?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>mantis</artifactId>
|
||||
<name>Mantis</name>
|
||||
<packaging>jar</packaging>
|
||||
<description>Sample project for Netflix Mantis</description>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>parent-boot-2</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<relativePath>../../parent-boot-2</relativePath>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
<version>2.1.3.RELEASE</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.mantisrx</groupId>
|
||||
<artifactId>mantis-runtime</artifactId>
|
||||
<version>1.2.63</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-log4j12</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>2.10.2</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>net.andreinc.mockneat</groupId>
|
||||
<artifactId>mockneat</artifactId>
|
||||
<version>0.3.8</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.12</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-webflux</artifactId>
|
||||
<version>5.0.9.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.projectreactor.netty</groupId>
|
||||
<artifactId>reactor-netty</artifactId>
|
||||
<version>0.9.12.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>SpringLibReleaseRepo</id>
|
||||
<url>https://repo.spring.io/libs-release/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
</project>
|
@ -0,0 +1,23 @@
|
||||
package com.baeldung.netflix.mantis;
|
||||
|
||||
import com.baeldung.netflix.mantis.job.LogAggregationJob;
|
||||
import io.mantisrx.runtime.executor.LocalJobExecutorNetworked;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.boot.CommandLineRunner;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@Slf4j
|
||||
@SpringBootApplication
|
||||
public class MantisApplication implements CommandLineRunner {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(MantisApplication.class, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(String... args) {
|
||||
LocalJobExecutorNetworked.execute(new LogAggregationJob().getJobInstance());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package com.baeldung.netflix.mantis.job;
|
||||
|
||||
import com.baeldung.netflix.mantis.model.LogAggregate;
|
||||
import com.baeldung.netflix.mantis.source.RandomLogSource;
|
||||
import com.baeldung.netflix.mantis.stage.CountLogStage;
|
||||
import com.baeldung.netflix.mantis.stage.GroupLogStage;
|
||||
import com.baeldung.netflix.mantis.stage.TransformLogStage;
|
||||
import io.mantisrx.runtime.Job;
|
||||
import io.mantisrx.runtime.MantisJob;
|
||||
import io.mantisrx.runtime.MantisJobProvider;
|
||||
import io.mantisrx.runtime.Metadata;
|
||||
import io.mantisrx.runtime.sink.Sink;
|
||||
import io.mantisrx.runtime.sink.Sinks;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class LogAggregationJob extends MantisJobProvider<LogAggregate> {
|
||||
|
||||
private Sink<LogAggregate> sink = Sinks.eagerSubscribe(Sinks.sse(LogAggregate::toJsonString));
|
||||
|
||||
@Override
|
||||
public Job<LogAggregate> getJobInstance() {
|
||||
|
||||
return MantisJob
|
||||
.source(new RandomLogSource())
|
||||
.stage(new TransformLogStage(), TransformLogStage.stageConfig())
|
||||
.stage(new GroupLogStage(), GroupLogStage.config())
|
||||
.stage(new CountLogStage(), CountLogStage.config())
|
||||
.sink(sink)
|
||||
.metadata(new Metadata.Builder().build())
|
||||
.create();
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package com.baeldung.netflix.mantis.job;
|
||||
|
||||
import com.baeldung.netflix.mantis.model.LogEvent;
|
||||
import com.baeldung.netflix.mantis.sink.LogSink;
|
||||
import com.baeldung.netflix.mantis.source.RandomLogSource;
|
||||
import com.baeldung.netflix.mantis.stage.TransformLogStage;
|
||||
import io.mantisrx.runtime.Job;
|
||||
import io.mantisrx.runtime.MantisJob;
|
||||
import io.mantisrx.runtime.MantisJobProvider;
|
||||
import io.mantisrx.runtime.Metadata;
|
||||
import io.mantisrx.runtime.ScalarToScalar;
|
||||
import io.mantisrx.runtime.sink.Sink;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class LogCollectingJob extends MantisJobProvider<LogEvent> {
|
||||
|
||||
private Sink<LogEvent> sink = new LogSink();
|
||||
|
||||
@Override
|
||||
public Job<LogEvent> getJobInstance() {
|
||||
|
||||
return MantisJob
|
||||
.source(new RandomLogSource())
|
||||
.stage(new TransformLogStage(), new ScalarToScalar.Config<>())
|
||||
.sink(sink)
|
||||
.metadata(new Metadata.Builder().build())
|
||||
.create();
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package com.baeldung.netflix.mantis.model;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import io.mantisrx.runtime.codec.JsonType;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class LogAggregate implements JsonType {
|
||||
|
||||
private static final ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
private Integer count;
|
||||
private String level;
|
||||
|
||||
public String toJsonString() {
|
||||
try {
|
||||
return mapper.writeValueAsString(this);
|
||||
} catch (JsonProcessingException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package com.baeldung.netflix.mantis.model;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import io.mantisrx.runtime.codec.JsonType;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
public class LogEvent implements JsonType {
|
||||
|
||||
private static final ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
private Long index;
|
||||
private String level;
|
||||
private String message;
|
||||
|
||||
public LogEvent(String[] parts) {
|
||||
this.index = Long.valueOf(parts[0]);
|
||||
this.level = parts[1];
|
||||
this.message = parts[2];
|
||||
}
|
||||
|
||||
public String toJsonString() {
|
||||
try {
|
||||
return mapper.writeValueAsString(this);
|
||||
} catch (JsonProcessingException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package com.baeldung.netflix.mantis.sink;
|
||||
|
||||
import com.baeldung.netflix.mantis.model.LogEvent;
|
||||
import io.mantisrx.runtime.Context;
|
||||
import io.mantisrx.runtime.PortRequest;
|
||||
import io.mantisrx.runtime.sink.SelfDocumentingSink;
|
||||
import io.mantisrx.runtime.sink.ServerSentEventsSink;
|
||||
import io.mantisrx.runtime.sink.Sink;
|
||||
import io.mantisrx.runtime.sink.predicate.Predicate;
|
||||
import rx.Observable;
|
||||
|
||||
public class LogSink implements Sink<LogEvent> {
|
||||
|
||||
@Override
|
||||
public void call(Context context, PortRequest portRequest, Observable<LogEvent> logEventObservable) {
|
||||
|
||||
SelfDocumentingSink<LogEvent> sink = new ServerSentEventsSink.Builder<LogEvent>()
|
||||
.withEncoder(LogEvent::toJsonString)
|
||||
.withPredicate(filterByLogMessage())
|
||||
.build();
|
||||
|
||||
logEventObservable.subscribe();
|
||||
|
||||
sink.call(context, portRequest, logEventObservable);
|
||||
}
|
||||
|
||||
private Predicate<LogEvent> filterByLogMessage() {
|
||||
return new Predicate<>("filter by message",
|
||||
parameters -> {
|
||||
if (parameters != null && parameters.containsKey("filter")) {
|
||||
return logEvent -> logEvent.getMessage().contains(parameters.get("filter").get(0));
|
||||
}
|
||||
return logEvent -> true;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package com.baeldung.netflix.mantis.source;
|
||||
|
||||
import io.mantisrx.runtime.Context;
|
||||
import io.mantisrx.runtime.source.Index;
|
||||
import io.mantisrx.runtime.source.Source;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.andreinc.mockneat.MockNeat;
|
||||
import rx.Observable;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Slf4j
|
||||
public class RandomLogSource implements Source<String> {
|
||||
|
||||
private MockNeat mockDataGenerator;
|
||||
|
||||
@Override
|
||||
public void init(Context context, Index index) {
|
||||
mockDataGenerator = MockNeat.threadLocal();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Observable<Observable<String>> call(Context context, Index index) {
|
||||
return Observable.just(
|
||||
Observable
|
||||
.interval(250, TimeUnit.MILLISECONDS)
|
||||
.map(this::createRandomLogEvent));
|
||||
}
|
||||
|
||||
private String createRandomLogEvent(Long tick) {
|
||||
String level = mockDataGenerator.probabilites(String.class)
|
||||
.add(0.5, "INFO")
|
||||
.add(0.3, "WARN")
|
||||
.add(0.2, "ERROR")
|
||||
.get();
|
||||
|
||||
String message = mockDataGenerator.probabilites(String.class)
|
||||
.add(0.5, "login attempt")
|
||||
.add(0.5, "user created")
|
||||
.get();
|
||||
|
||||
return tick + "#" + level + "#" + message;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
package com.baeldung.netflix.mantis.stage;
|
||||
|
||||
import com.baeldung.netflix.mantis.model.LogAggregate;
|
||||
import com.baeldung.netflix.mantis.model.LogEvent;
|
||||
import io.mantisrx.common.MantisGroup;
|
||||
import io.mantisrx.runtime.Context;
|
||||
import io.mantisrx.runtime.GroupToScalar;
|
||||
import io.mantisrx.runtime.codec.JacksonCodecs;
|
||||
import io.mantisrx.runtime.computation.GroupToScalarComputation;
|
||||
import io.mantisrx.runtime.parameter.ParameterDefinition;
|
||||
import io.mantisrx.runtime.parameter.type.IntParameter;
|
||||
import io.mantisrx.runtime.parameter.validator.Validators;
|
||||
import rx.Observable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class CountLogStage implements GroupToScalarComputation<String, LogEvent, LogAggregate> {
|
||||
|
||||
private int duration;
|
||||
|
||||
@Override
|
||||
public void init(Context context) {
|
||||
duration = (int)context.getParameters().get("LogAggregationDuration", 1000);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Observable<LogAggregate> call(Context context, Observable<MantisGroup<String, LogEvent>> mantisGroup) {
|
||||
return mantisGroup
|
||||
.window(duration, TimeUnit.MILLISECONDS)
|
||||
.flatMap(o -> o.groupBy(MantisGroup::getKeyValue)
|
||||
.flatMap(group -> group.reduce(0, (count, value) -> count = count + 1)
|
||||
.map((count) -> new LogAggregate(count, group.getKey()))
|
||||
));
|
||||
}
|
||||
|
||||
public static GroupToScalar.Config<String, LogEvent, LogAggregate> config(){
|
||||
return new GroupToScalar.Config<String, LogEvent, LogAggregate>()
|
||||
.description("sum events for a log level")
|
||||
.codec(JacksonCodecs.pojo(LogAggregate.class))
|
||||
.withParameters(getParameters());
|
||||
}
|
||||
|
||||
public static List<ParameterDefinition<?>> getParameters() {
|
||||
List<ParameterDefinition<?>> params = new ArrayList<>();
|
||||
|
||||
params.add(new IntParameter()
|
||||
.name("LogAggregationDuration")
|
||||
.description("window size for aggregation in milliseconds")
|
||||
.validator(Validators.range(100, 10000))
|
||||
.defaultValue(5000)
|
||||
.build()) ;
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package com.baeldung.netflix.mantis.stage;
|
||||
|
||||
import com.baeldung.netflix.mantis.model.LogEvent;
|
||||
import io.mantisrx.common.MantisGroup;
|
||||
import io.mantisrx.runtime.Context;
|
||||
import io.mantisrx.runtime.ScalarToGroup;
|
||||
import io.mantisrx.runtime.codec.JacksonCodecs;
|
||||
import io.mantisrx.runtime.computation.ToGroupComputation;
|
||||
import rx.Observable;
|
||||
|
||||
public class GroupLogStage implements ToGroupComputation<LogEvent, String, LogEvent> {
|
||||
|
||||
@Override
|
||||
public Observable<MantisGroup<String, LogEvent>> call(Context context, Observable<LogEvent> logEvent) {
|
||||
return logEvent.map(log -> new MantisGroup<>(log.getLevel(), log));
|
||||
}
|
||||
|
||||
public static ScalarToGroup.Config<LogEvent, String, LogEvent> config(){
|
||||
return new ScalarToGroup.Config<LogEvent, String, LogEvent>()
|
||||
.description("Group event data by level")
|
||||
.codec(JacksonCodecs.pojo(LogEvent.class))
|
||||
.concurrentInput();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package com.baeldung.netflix.mantis.stage;
|
||||
|
||||
import com.baeldung.netflix.mantis.model.LogEvent;
|
||||
import io.mantisrx.runtime.Context;
|
||||
import io.mantisrx.runtime.ScalarToScalar;
|
||||
import io.mantisrx.runtime.codec.JacksonCodecs;
|
||||
import io.mantisrx.runtime.computation.ScalarComputation;
|
||||
import rx.Observable;
|
||||
|
||||
public class TransformLogStage implements ScalarComputation<String, LogEvent> {
|
||||
|
||||
@Override
|
||||
public Observable<LogEvent> call(Context context, Observable<String> logEntry) {
|
||||
return logEntry
|
||||
.map(log -> log.split("#"))
|
||||
.filter(parts -> parts.length == 3)
|
||||
.map(LogEvent::new);
|
||||
}
|
||||
|
||||
public static ScalarToScalar.Config<String, LogEvent> stageConfig() {
|
||||
return new ScalarToScalar.Config<String, LogEvent>()
|
||||
.codec(JacksonCodecs.pojo(LogEvent.class));
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
package com.baeldung.netflix.mantis.job;
|
||||
|
||||
import com.baeldung.netflix.mantis.model.LogAggregate;
|
||||
import io.mantisrx.runtime.PortRequest;
|
||||
import io.mantisrx.runtime.sink.Sinks;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static java.util.Optional.of;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class LogAggregationJobIntegrationTest extends MantisJobTestBase<LogAggregate> {
|
||||
|
||||
private final static int PORT = 7382;
|
||||
private final static String SINK_URL = "http://localhost:" + PORT;
|
||||
|
||||
@BeforeAll
|
||||
static void beforeAll() {
|
||||
start(new LogAggregationJob((context, portRequest, logAggregateObservable) -> {
|
||||
logAggregateObservable.subscribe();
|
||||
Sinks.sse(LogAggregate::toJsonString).call(context, new PortRequest(PORT), logAggregateObservable);
|
||||
}));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSinkUrl() {
|
||||
return SINK_URL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<LogAggregate> getEventType() {
|
||||
return LogAggregate.class;
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenReadingFromSink_thenShouldRetrieveCorrectNumberOfLogAggregates() {
|
||||
assertEquals(of(5L), sinkStream.take(5).count().blockOptional());
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenReadingFromSink_thenShouldRetrieveLogAggregate() {
|
||||
assertNotNull(sinkStream.take(1).blockFirst());
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenReadingFromSink_thenShouldRetrieveValidLogAggregate() {
|
||||
LogAggregate logAggregate = sinkStream.take(1).blockFirst();
|
||||
|
||||
assertTrue(asList("ERROR", "WARN", "INFO").contains(logAggregate.getLevel()));
|
||||
assertTrue(logAggregate.getCount() > 0);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
package com.baeldung.netflix.mantis.job;
|
||||
|
||||
import com.baeldung.netflix.mantis.model.LogEvent;
|
||||
import com.baeldung.netflix.mantis.sink.LogSink;
|
||||
import io.mantisrx.runtime.Context;
|
||||
import io.mantisrx.runtime.PortRequest;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import rx.Observable;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static java.util.Optional.of;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class LogCollectingJobIntegrationTest extends MantisJobTestBase<LogEvent> {
|
||||
|
||||
private final static int PORT = 7381;
|
||||
private final static String SINK_URL = "http://localhost:" + PORT;
|
||||
|
||||
@BeforeAll
|
||||
static void beforeAll() {
|
||||
|
||||
start(new LogCollectingJob(new LogSink() {
|
||||
|
||||
@Override
|
||||
public void call(Context context, PortRequest portRequest, Observable<LogEvent> observable) {
|
||||
super.call(context, new PortRequest(PORT), observable);
|
||||
}
|
||||
|
||||
}));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSinkUrl() {
|
||||
return SINK_URL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<LogEvent> getEventType() {
|
||||
return LogEvent.class;
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenReadingFromSink_thenShouldRetrieveCorrectNumberOfLogEvents() {
|
||||
assertEquals(of(5L), sinkStream.take(5).count().blockOptional());
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenReadingFromSink_thenShouldRetrieveLogEvent() {
|
||||
assertNotNull(sinkStream.take(1).blockFirst());
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenReadingFromSink_thenShouldRetrieveValidLogEvent() {
|
||||
LogEvent logEvent = sinkStream.take(1).blockFirst();
|
||||
|
||||
assertTrue(asList("ERROR", "WARN", "INFO").contains(logEvent.getLevel()));
|
||||
assertTrue(asList("login attempt", "user created").contains(logEvent.getMessage()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenReadingFromSink_thenShouldRetrieveFilteredLogEvents() {
|
||||
getSinkStream(SINK_URL + "?filter=login")
|
||||
.take(7)
|
||||
.toStream().forEach(
|
||||
logEvent -> assertEquals("login attempt", logEvent.getMessage())
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package com.baeldung.netflix.mantis.job;
|
||||
|
||||
import io.mantisrx.runtime.Job;
|
||||
import io.mantisrx.runtime.MantisJobProvider;
|
||||
import io.mantisrx.runtime.executor.LocalJobExecutorNetworked;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.util.retry.Retry;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
public abstract class MantisJobTestBase<T> {
|
||||
|
||||
private static Job jobInstance;
|
||||
Flux<T> sinkStream;
|
||||
|
||||
public abstract String getSinkUrl();
|
||||
public abstract Class<T> getEventType();
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
sinkStream = getSinkStream(getSinkUrl());
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void afterAll() {
|
||||
stopJob();
|
||||
}
|
||||
|
||||
protected Flux<T> getSinkStream(String sinkUrl) {
|
||||
return WebClient.builder().build().get()
|
||||
.uri(sinkUrl)
|
||||
.retrieve()
|
||||
.bodyToFlux(getEventType())
|
||||
.retryWhen(Retry.fixedDelay(10, Duration.ofMillis(2000)));
|
||||
}
|
||||
|
||||
static <T> void start(MantisJobProvider<T> job) {
|
||||
jobInstance = job.getJobInstance();
|
||||
new Thread(() -> LocalJobExecutorNetworked.execute(jobInstance)).start();
|
||||
}
|
||||
|
||||
static void stopJob() {
|
||||
jobInstance.getLifecycle().shutdown();
|
||||
}
|
||||
|
||||
}
|
@ -15,6 +15,7 @@
|
||||
|
||||
<modules>
|
||||
<module>genie</module>
|
||||
<module>mantis</module>
|
||||
</modules>
|
||||
|
||||
</project>
|
3
persistence-modules/core-java-persistence-2/README.md
Normal file
3
persistence-modules/core-java-persistence-2/README.md
Normal file
@ -0,0 +1,3 @@
|
||||
### Relevant Articles:
|
||||
|
||||
- [Getting Database URL From JDBC Connection Object](https://www.baeldung.com/jdbc-get-url-from-connection)
|
29
persistence-modules/core-java-persistence-2/pom.xml
Normal file
29
persistence-modules/core-java-persistence-2/pom.xml
Normal file
@ -0,0 +1,29 @@
|
||||
<?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>
|
||||
<groupId>com.baeldung.core-java-persistence-2</groupId>
|
||||
<artifactId>core-java-persistence-2</artifactId>
|
||||
<version>0.1.0-SNAPSHOT</version>
|
||||
<name>core-java-persistence-2</name>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>persistence-modules</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<version>${h2.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<h2.version>1.4.200</h2.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
@ -0,0 +1,13 @@
|
||||
package com.baeldung.getdburl;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
|
||||
public class DBConfiguration {
|
||||
|
||||
public static Connection getConnection() throws Exception {
|
||||
Class.forName("org.h2.Driver");
|
||||
String url = "jdbc:h2:mem:testdb";
|
||||
return DriverManager.getConnection(url, "user", "password");
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package com.baeldung.getdburl;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import java.sql.Connection;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class DBConfigurationUnitTest {
|
||||
|
||||
@Test
|
||||
void givenConnectionObject_whenExtractMetaData_thenGetDbURL() throws Exception {
|
||||
Connection connection = DBConfiguration.getConnection();
|
||||
String dbUrl = connection.getMetaData().getURL();
|
||||
assertEquals("jdbc:h2:mem:testdb", dbUrl);
|
||||
}
|
||||
|
||||
}
|
@ -76,10 +76,6 @@
|
||||
<properties>
|
||||
<flyway.configFiles>src/main/resources/application-${spring-boot.run.profiles}.properties</flyway.configFiles>
|
||||
|
||||
<!-- testing -->
|
||||
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
|
||||
<junit-jupiter.version>5.6.2</junit-jupiter.version>
|
||||
<junit.version>4.13</junit.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
|
@ -66,10 +66,6 @@
|
||||
<flyway-core.version>5.2.3</flyway-core.version>
|
||||
<flyway-maven-plugin.version>5.0.2</flyway-maven-plugin.version>
|
||||
|
||||
<!-- testing -->
|
||||
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
|
||||
<junit-jupiter.version>5.6.2</junit-jupiter.version>
|
||||
<junit.version>4.13</junit.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
|
@ -8,7 +8,7 @@ public class Application {
|
||||
|
||||
public static void main(String[] args) {
|
||||
EntityManager entityManager = getJpaEntityManager();
|
||||
User user = entityManager.find(User.class, 1);
|
||||
User user = entityManager.find(User.class, 1l);
|
||||
System.out.println(user);
|
||||
entityManager.getTransaction().begin();
|
||||
user.setName("John");
|
||||
|
@ -1,9 +1,9 @@
|
||||
package com.baeldung.hibernate.onetoone.sharedkeybased;
|
||||
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.MapsId;
|
||||
import javax.persistence.OneToOne;
|
||||
import javax.persistence.Table;
|
||||
@ -13,7 +13,7 @@ import javax.persistence.Table;
|
||||
public class Address {
|
||||
|
||||
@Id
|
||||
@Column(name = "id")
|
||||
@Column(name = "user_id")
|
||||
private Long id;
|
||||
|
||||
@Column(name = "street")
|
||||
@ -24,6 +24,7 @@ public class Address {
|
||||
|
||||
@OneToOne
|
||||
@MapsId
|
||||
@JoinColumn(name = "user_id")
|
||||
private User user;
|
||||
|
||||
public Long getId() {
|
||||
|
@ -8,6 +8,7 @@ import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.OneToOne;
|
||||
import javax.persistence.PrimaryKeyJoinColumn;
|
||||
import javax.persistence.Table;
|
||||
|
||||
@Entity
|
||||
@ -22,6 +23,7 @@ public class User {
|
||||
private String userName;
|
||||
|
||||
@OneToOne(mappedBy = "user", cascade = CascadeType.ALL)
|
||||
@PrimaryKeyJoinColumn
|
||||
private Address address;
|
||||
|
||||
public Long getId() {
|
||||
|
@ -17,6 +17,7 @@
|
||||
<module>apache-bookkeeper</module><!-- BAEL-2322 -->
|
||||
<module>apache-cayenne</module>
|
||||
<module>core-java-persistence</module>
|
||||
<module>core-java-persistence-2</module>
|
||||
<module>deltaspike</module>
|
||||
<module>elasticsearch</module>
|
||||
<module>flyway</module>
|
||||
|
@ -69,10 +69,6 @@
|
||||
<r2dbc-h2.version>0.8.1.RELEASE</r2dbc-h2.version>
|
||||
<h2.version>1.4.200</h2.version>
|
||||
|
||||
<!-- testing -->
|
||||
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
|
||||
<junit-jupiter.version>5.6.2</junit-jupiter.version>
|
||||
<junit.version>4.13</junit.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
|
@ -62,10 +62,6 @@
|
||||
<jedis.version>3.3.0</jedis.version>
|
||||
<epoll.version>4.1.50.Final</epoll.version>
|
||||
|
||||
<!-- testing -->
|
||||
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
|
||||
<junit-jupiter.version>5.6.2</junit-jupiter.version>
|
||||
<junit.version>4.13</junit.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
|
@ -40,10 +40,6 @@
|
||||
<properties>
|
||||
<mysql-connector-java.version>8.0.12</mysql-connector-java.version>
|
||||
|
||||
<!-- testing -->
|
||||
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
|
||||
<junit-jupiter.version>5.6.2</junit-jupiter.version>
|
||||
<junit.version>4.13</junit.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
|
@ -5,4 +5,5 @@
|
||||
- [Integrating Spring Boot with HSQLDB](https://www.baeldung.com/spring-boot-hsqldb)
|
||||
- [List of In-Memory Databases](https://www.baeldung.com/java-in-memory-databases)
|
||||
- [Oracle Connection Pooling With Spring](https://www.baeldung.com/spring-oracle-connection-pooling)
|
||||
- [Object States in Hibernate’s Session](https://www.baeldung.com/hibernate-session-object-states)
|
||||
- More articles: [[<-- prev]](../spring-boot-persistence)
|
||||
|
@ -47,10 +47,6 @@
|
||||
<start-class>com.baeldung.h2db.demo.server.SpringBootApp</start-class>
|
||||
<db-util.version>1.0.4</db-util.version>
|
||||
|
||||
<!-- testing -->
|
||||
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
|
||||
<junit-jupiter.version>5.6.2</junit-jupiter.version>
|
||||
<junit.version>4.13</junit.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
|
@ -37,9 +37,5 @@
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<!-- testing -->
|
||||
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
|
||||
<junit-jupiter.version>5.6.2</junit-jupiter.version>
|
||||
<junit.version>4.13</junit.version>
|
||||
</properties>
|
||||
</project>
|
@ -76,11 +76,6 @@
|
||||
<properties>
|
||||
<mockito.version>2.23.0</mockito.version>
|
||||
<validation-api.version>2.0.1.Final</validation-api.version>
|
||||
|
||||
<!-- testing -->
|
||||
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
|
||||
<junit-jupiter.version>5.6.2</junit-jupiter.version>
|
||||
<junit.version>4.13</junit.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
|
@ -54,10 +54,6 @@
|
||||
<spring-boot.version>2.2.6.RELEASE</spring-boot.version>
|
||||
<cassandra-unit-spring.version>3.11.2.0</cassandra-unit-spring.version>
|
||||
|
||||
<!-- testing -->
|
||||
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
|
||||
<junit-jupiter.version>5.6.2</junit-jupiter.version>
|
||||
<junit.version>4.13</junit.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
|
@ -105,10 +105,6 @@
|
||||
<cassandra-unit-shaded.version>2.1.9.2</cassandra-unit-shaded.version>
|
||||
<hector-core.version>2.0-0</hector-core.version>
|
||||
|
||||
<!-- testing -->
|
||||
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
|
||||
<junit-jupiter.version>5.6.2</junit-jupiter.version>
|
||||
<junit.version>4.13</junit.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
|
@ -17,10 +17,6 @@
|
||||
<java.version>1.8</java.version>
|
||||
<cosmodb.version>2.3.0</cosmodb.version>
|
||||
|
||||
<!-- testing -->
|
||||
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
|
||||
<junit-jupiter.version>5.6.2</junit-jupiter.version>
|
||||
<junit.version>4.13</junit.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
@ -182,11 +182,6 @@
|
||||
<dynamodblocal.version>1.11.86</dynamodblocal.version>
|
||||
<dynamodblocal.repository.url>https://s3-us-west-2.amazonaws.com/dynamodb-local/release</dynamodblocal.repository.url>
|
||||
<maven-dependency-plugin.version>3.1.1</maven-dependency-plugin.version>
|
||||
|
||||
<!-- testing -->
|
||||
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
|
||||
<junit-jupiter.version>5.6.2</junit-jupiter.version>
|
||||
<junit.version>4.13</junit.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
|
@ -69,10 +69,5 @@
|
||||
<fastjson.version>1.2.47</fastjson.version>
|
||||
<spatial4j.version>0.7</spatial4j.version>
|
||||
<jts.version>1.15.0</jts.version>
|
||||
|
||||
<!-- testing -->
|
||||
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
|
||||
<junit-jupiter.version>5.6.2</junit-jupiter.version>
|
||||
<junit.version>4.13</junit.version>
|
||||
</properties>
|
||||
</project>
|
@ -28,9 +28,5 @@
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<!-- testing -->
|
||||
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
|
||||
<junit-jupiter.version>5.6.2</junit-jupiter.version>
|
||||
<junit.version>4.13</junit.version>
|
||||
</properties>
|
||||
</project>
|
||||
|
@ -73,10 +73,6 @@
|
||||
<postgresql.version>42.2.5</postgresql.version>
|
||||
<guava.version>21.0</guava.version>
|
||||
|
||||
<!-- testing -->
|
||||
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
|
||||
<junit-jupiter.version>5.6.2</junit-jupiter.version>
|
||||
<junit.version>4.13</junit.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
@ -16,10 +16,6 @@
|
||||
|
||||
<dependencies>
|
||||
<!-- Prod Dependencies -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
@ -66,11 +62,6 @@
|
||||
<datasource-proxy.version>1.4.1</datasource-proxy.version>
|
||||
<guava.version>21.0</guava.version>
|
||||
<testcontainers.version>1.12.2</testcontainers.version>
|
||||
|
||||
<!-- testing -->
|
||||
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
|
||||
<junit-jupiter.version>5.6.2</junit-jupiter.version>
|
||||
<junit.version>4.13</junit.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
|
@ -99,10 +99,6 @@
|
||||
<guava.version>21.0</guava.version>
|
||||
<testcontainers.version>1.12.2</testcontainers.version>
|
||||
|
||||
<!-- testing -->
|
||||
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
|
||||
<junit-jupiter.version>5.6.2</junit-jupiter.version>
|
||||
<junit.version>4.13</junit.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
|
@ -73,10 +73,6 @@
|
||||
<postgresql.version>42.2.5</postgresql.version>
|
||||
<guava.version>21.0</guava.version>
|
||||
|
||||
<!-- testing -->
|
||||
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
|
||||
<junit-jupiter.version>5.6.2</junit-jupiter.version>
|
||||
<junit.version>4.13</junit.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
@ -84,10 +84,6 @@
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<!-- testing -->
|
||||
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
|
||||
<junit-jupiter.version>5.6.2</junit-jupiter.version>
|
||||
<junit.version>4.13</junit.version>
|
||||
<tomcat-dbcp.version>9.0.0.M26</tomcat-dbcp.version>
|
||||
<jta.version>1.1</jta.version>
|
||||
<guava.version>21.0</guava.version>
|
||||
|
@ -44,10 +44,6 @@
|
||||
<properties>
|
||||
<datasource-proxy.version>1.4.1</datasource-proxy.version>
|
||||
|
||||
<!-- testing -->
|
||||
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
|
||||
<junit-jupiter.version>5.6.2</junit-jupiter.version>
|
||||
<junit.version>4.13</junit.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
@ -44,9 +44,5 @@
|
||||
<properties>
|
||||
<guava.version>29.0-jre</guava.version>
|
||||
|
||||
<!-- testing -->
|
||||
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
|
||||
<junit-jupiter.version>5.6.2</junit-jupiter.version>
|
||||
<junit.version>4.13</junit.version>
|
||||
</properties>
|
||||
</project>
|
@ -50,9 +50,6 @@
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<!-- testing -->
|
||||
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
|
||||
<junit-jupiter.version>5.6.2</junit-jupiter.version>
|
||||
<junit.version>4.13</junit.version>
|
||||
|
||||
</properties>
|
||||
</project>
|
@ -29,9 +29,6 @@
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<!-- testing -->
|
||||
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
|
||||
<junit-jupiter.version>5.6.2</junit-jupiter.version>
|
||||
<junit.version>4.13</junit.version>
|
||||
|
||||
</properties>
|
||||
</project>
|
@ -108,10 +108,6 @@
|
||||
<projectreactor.version>3.2.0.RELEASE</projectreactor.version>
|
||||
<mongodb-driver.version>4.0.5</mongodb-driver.version>
|
||||
|
||||
<!-- testing -->
|
||||
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
|
||||
<junit-jupiter.version>5.6.2</junit-jupiter.version>
|
||||
<junit.version>4.13</junit.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
|
@ -98,11 +98,6 @@
|
||||
<cglib.version>3.2.4</cglib.version>
|
||||
<nosqlunit.version>0.10.0</nosqlunit.version>
|
||||
<embedded-redis.version>0.6</embedded-redis.version>
|
||||
|
||||
<!-- testing -->
|
||||
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
|
||||
<junit-jupiter.version>5.6.2</junit-jupiter.version>
|
||||
<junit.version>4.13</junit.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
|
@ -5,7 +5,6 @@ import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
|
||||
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.listener.ChannelTopic;
|
||||
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
|
||||
|
@ -1,16 +1,32 @@
|
||||
package com.baeldung;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.annotation.DirtiesContext.ClassMode;
|
||||
|
||||
import com.baeldung.spring.data.redis.config.RedisConfig;
|
||||
import com.baeldung.spring.data.redis.SpringRedisApplication;
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(classes = RedisConfig.class)
|
||||
import redis.embedded.RedisServerBuilder;
|
||||
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = SpringRedisApplication.class)
|
||||
@DirtiesContext(classMode = ClassMode.BEFORE_CLASS)
|
||||
public class SpringContextTest {
|
||||
|
||||
private static redis.embedded.RedisServer redisServer;
|
||||
|
||||
@BeforeClass
|
||||
public static void startRedisServer() {
|
||||
redisServer = new RedisServerBuilder().port(6379).setting("maxmemory 256M").build();
|
||||
redisServer.start();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void stopRedisServer() {
|
||||
redisServer.stop();
|
||||
}
|
||||
@Test
|
||||
public void whenSpringContextIsBootstrapped_thenNoExceptions() {
|
||||
}
|
||||
|
@ -46,10 +46,6 @@
|
||||
<properties>
|
||||
<spring-data-solr.version>2.0.5.RELEASE</spring-data-solr.version>
|
||||
|
||||
<!-- testing -->
|
||||
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
|
||||
<junit-jupiter.version>5.6.2</junit-jupiter.version>
|
||||
<junit.version>4.13</junit.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
@ -18,7 +18,6 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-jdbc</artifactId>
|
||||
<version>${spring-data-jdbc.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
@ -36,11 +35,5 @@
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<spring-data-jdbc.version>2.0.3.RELEASE</spring-data-jdbc.version>
|
||||
|
||||
<!-- testing -->
|
||||
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
|
||||
<junit-jupiter.version>5.6.2</junit-jupiter.version>
|
||||
<junit.version>4.13</junit.version>
|
||||
</properties>
|
||||
</project>
|
@ -7,6 +7,7 @@
|
||||
- [Transaction Propagation and Isolation in Spring @Transactional](https://www.baeldung.com/spring-transactional-propagation-isolation)
|
||||
- [JTA Transaction with Spring](https://www.baeldung.com/spring-vs-jta-transactional)
|
||||
- [Test a Mock JNDI Datasource with Spring](https://www.baeldung.com/spring-mock-jndi-datasource)
|
||||
- [Detecting If a Spring Transaction Is Active](https://www.baeldung.com/spring-transaction-active)
|
||||
|
||||
### Eclipse Config
|
||||
After importing the project into Eclipse, you may see the following error:
|
||||
|
@ -9,3 +9,4 @@ This module contains articles about Spring Boot annotations
|
||||
- [Spring Web Annotations](https://www.baeldung.com/spring-mvc-annotations)
|
||||
- [Spring Core Annotations](https://www.baeldung.com/spring-core-annotations)
|
||||
- [Spring Bean Annotations](https://www.baeldung.com/spring-bean-annotations)
|
||||
- [Difference Between @ComponentScan and @EnableAutoConfiguration in Spring Boot](https://www.baeldung.com/spring-componentscan-vs-enableautoconfiguration)
|
||||
|
@ -4,11 +4,12 @@
|
||||
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>
|
||||
|
||||
<!-- this module should use the Boot parent directly to avoid inherit the logback dependency from our other parents -->
|
||||
<parent>
|
||||
<groupId>com.baeldung.spring-boot-modules</groupId>
|
||||
<artifactId>spring-boot-modules</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<relativePath>../</relativePath>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.1.1.RELEASE</version>
|
||||
<relativePath/> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
|
||||
<artifactId>spring-boot-mvc-birt</artifactId>
|
||||
@ -19,10 +20,6 @@
|
||||
<description>Module For Spring Boot Integration with BIRT</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
@ -51,17 +48,14 @@
|
||||
<artifactId>org.eclipse.birt.runtime_4.8.0-20180626</artifactId>
|
||||
<version>${eclipse.birt.runtime.version}</version>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
|
||||
<dependency>
|
||||
<groupId>log4j</groupId>
|
||||
<artifactId>log4j</artifactId>
|
||||
<version>${log4j.version}</version>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>${lombok.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@ -81,6 +75,7 @@
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
<eclipse.birt.runtime.version>4.8.0</eclipse.birt.runtime.version>
|
||||
<log4j.version>1.2.17</log4j.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
|
@ -0,0 +1,9 @@
|
||||
# Set root logger level to DEBUG and its only appender to A1.
|
||||
log4j.rootLogger=DEBUG, A1
|
||||
|
||||
# A1 is set to be a ConsoleAppender.
|
||||
log4j.appender.A1=org.apache.log4j.ConsoleAppender
|
||||
|
||||
# A1 uses PatternLayout.
|
||||
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n
|
@ -0,0 +1,13 @@
|
||||
package com.baeldung.birt.engine;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
@SpringBootTest
|
||||
public class SpringContextTest {
|
||||
|
||||
@Test
|
||||
public void whenSpringContextIsBootstrapped_thenNoExceptions() {
|
||||
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@ package com.baeldung.cloud.openfeign.config;
|
||||
|
||||
import feign.Logger;
|
||||
import feign.RequestInterceptor;
|
||||
import feign.auth.BasicAuthRequestInterceptor;
|
||||
import feign.codec.ErrorDecoder;
|
||||
import feign.okhttp.OkHttpClient;
|
||||
import org.apache.http.entity.ContentType;
|
||||
@ -34,4 +35,9 @@ public class ClientConfiguration {
|
||||
requestTemplate.header("Accept", ContentType.APPLICATION_JSON.getMimeType());
|
||||
};
|
||||
}
|
||||
|
||||
// @Bean - uncomment to use this interceptor and remove @Bean from the requestInterceptor()
|
||||
public BasicAuthRequestInterceptor basicAuthRequestInterceptor() {
|
||||
return new BasicAuthRequestInterceptor("ajeje", "brazof");
|
||||
}
|
||||
}
|
||||
|
@ -226,7 +226,7 @@
|
||||
<httpcore.version>4.4.9</httpcore.version>
|
||||
<httpclient.version>4.5.5</httpclient.version>
|
||||
<javax.servlet-api.version>4.0.0</javax.servlet-api.version>
|
||||
<wiremock.version>2.25.1</wiremock.version>
|
||||
<wiremock.version>2.27.2</wiremock.version>
|
||||
<assertj-core.version>3.10.0</assertj-core.version>
|
||||
<spring-boot.version>1.5.10.RELEASE</spring-boot.version>
|
||||
</properties>
|
||||
|
@ -206,7 +206,7 @@
|
||||
<lifecycle-mapping.version>1.0.0</lifecycle-mapping.version>
|
||||
<sql-maven-plugin.version>1.5</sql-maven-plugin.version>
|
||||
<properties-maven-plugin.version>1.0.0</properties-maven-plugin.version>
|
||||
<start-class>org.jooq.example.spring.Application</start-class>
|
||||
<h2.version>1.4.198</h2.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
@ -119,7 +119,7 @@ public class EmailConfiguration {
|
||||
@Bean
|
||||
public ResourceBundleMessageSource emailMessageSource() {
|
||||
final ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
|
||||
messageSource.setBasename("/mailMessages");
|
||||
messageSource.setBasename("mailMessages");
|
||||
return messageSource;
|
||||
}
|
||||
|
||||
|
@ -11,11 +11,7 @@ public class MaxSizeConstraintValidator implements ConstraintValidator<MaxSizeCo
|
||||
|
||||
@Override
|
||||
public boolean isValid(List<Movie> values, ConstraintValidatorContext context) {
|
||||
boolean isValid = true;
|
||||
if (values.size() > 4) {
|
||||
isValid = false;
|
||||
}
|
||||
return isValid;
|
||||
return values.size() <= 4;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
package com.baeldung.resttemplate;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
|
@ -1,14 +0,0 @@
|
||||
package com.baeldung.resttemplate.logging;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableAutoConfiguration
|
||||
public class RestTemplateConfigurationApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(RestTemplateConfigurationApplication.class, args);
|
||||
}
|
||||
}
|
@ -14,16 +14,18 @@ import org.springframework.http.client.ClientHttpResponse;
|
||||
|
||||
public class LoggingInterceptor implements ClientHttpRequestInterceptor {
|
||||
|
||||
final static Logger log = LoggerFactory.getLogger(LoggingInterceptor.class);
|
||||
final static Logger LOGGER = LoggerFactory.getLogger(LoggingInterceptor.class);
|
||||
|
||||
@Override
|
||||
public ClientHttpResponse intercept(HttpRequest req, byte[] reqBody, ClientHttpRequestExecution ex) throws IOException {
|
||||
log.debug("Request body: {}", new String(reqBody, StandardCharsets.UTF_8));
|
||||
LOGGER.debug("Request body: {}", new String(reqBody, StandardCharsets.UTF_8));
|
||||
ClientHttpResponse response = ex.execute(req, reqBody);
|
||||
InputStreamReader isr = new InputStreamReader(response.getBody(), StandardCharsets.UTF_8);
|
||||
String body = new BufferedReader(isr).lines()
|
||||
.collect(Collectors.joining("\n"));
|
||||
log.debug("Response body: {}", body);
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
InputStreamReader isr = new InputStreamReader(response.getBody(), StandardCharsets.UTF_8);
|
||||
String body = new BufferedReader(isr).lines()
|
||||
.collect(Collectors.joining("\n"));
|
||||
LOGGER.debug("Response body: {}", body);
|
||||
}
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
@ -1,18 +1,21 @@
|
||||
package com.baeldung.resttemplate.logging;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||
import org.springframework.http.client.ClientHttpRequestInterceptor;
|
||||
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
|
||||
import org.springframework.http.client.SimpleClientHttpRequestFactory;
|
||||
import org.springframework.http.client.BufferingClientHttpRequestFactory;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
@ -22,6 +25,7 @@ import org.springframework.web.client.RestTemplate;
|
||||
public class RestTemplateLoggingLiveTest {
|
||||
|
||||
private static final String baseUrl = "http://localhost:8080/spring-rest";
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(RestTemplateLoggingLiveTest.class);
|
||||
|
||||
@Test
|
||||
public void givenHttpClientConfiguration_whenSendGetForRequestEntity_thenRequestResponseFullLog() {
|
||||
@ -30,13 +34,22 @@ public class RestTemplateLoggingLiveTest {
|
||||
restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory());
|
||||
|
||||
final ResponseEntity<String> response = restTemplate.postForEntity(baseUrl + "/persons", "my request body", String.class);
|
||||
assertThat(response.getStatusCode(), equalTo(HttpStatus.OK));
|
||||
assertEquals(HttpStatus.OK, response.getStatusCode());
|
||||
assertEquals("[\"Lucie\",\"Jackie\",\"Danesh\",\"Tao\"]", response.getBody());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenLoggingInterceptorConfiguration_whenSendGetForRequestEntity_thenRequestResponseCustomLog() {
|
||||
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
RestTemplate restTemplate = null;
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
ClientHttpRequestFactory factory = new BufferingClientHttpRequestFactory(
|
||||
new SimpleClientHttpRequestFactory());
|
||||
restTemplate = new RestTemplate(factory);
|
||||
} else {
|
||||
restTemplate = new RestTemplate();
|
||||
}
|
||||
|
||||
List<ClientHttpRequestInterceptor> interceptors = restTemplate.getInterceptors();
|
||||
if (CollectionUtils.isEmpty(interceptors)) {
|
||||
interceptors = new ArrayList<>();
|
||||
@ -45,6 +58,7 @@ public class RestTemplateLoggingLiveTest {
|
||||
restTemplate.setInterceptors(interceptors);
|
||||
|
||||
final ResponseEntity<String> response = restTemplate.postForEntity(baseUrl + "/persons", "my request body", String.class);
|
||||
assertThat(response.getStatusCode(), equalTo(HttpStatus.OK));
|
||||
assertEquals(HttpStatus.OK, response.getStatusCode());
|
||||
assertEquals("[\"Lucie\",\"Jackie\",\"Danesh\",\"Tao\"]", response.getBody());
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
logging.level.org.springframework.web.client.RestTemplate=DEBUG
|
||||
logging.level.com.baeldung.resttemplate.logging.LoggingInterceptor=DEBUG
|
||||
logging.level.com.baeldung.resttemplate.logging=DEBUG
|
||||
logging.level.org.apache.http=DEBUG
|
||||
logging.level.httpclient.wire=DEBUG
|
||||
logging.pattern.console=%20logger{20} - %msg%n
|
||||
|
@ -28,6 +28,7 @@
|
||||
<module>spring-security-web-login</module>
|
||||
<module>spring-security-web-persisted-remember-me</module>
|
||||
<module>spring-security-web-sockets</module>
|
||||
<module>spring-security-legacy-oidc</module>
|
||||
<module>spring-security-oidc</module>
|
||||
<module>spring-security-okta</module>
|
||||
<module>spring-security-web-react</module>
|
||||
|
@ -0,0 +1,23 @@
|
||||
## Spring Security OpenID
|
||||
|
||||
This module contains articles about OpenID with Spring Security
|
||||
|
||||
### Relevant articles
|
||||
|
||||
- [Spring Security and OpenID Connect (Legacy)](https://www.baeldung.com/spring-security-openid-connect-legacy)
|
||||
|
||||
### OpenID Connect with Spring Security
|
||||
|
||||
### Run the Project
|
||||
|
||||
```
|
||||
mvn spring-boot:run
|
||||
```
|
||||
|
||||
### Obtain Google App - Client ID, Secret
|
||||
|
||||
- We need to get client id and client secret by creating a new project at [Google Developer Console](https://console.developers.google.com/project/_/apiui/credential?pli=1)
|
||||
- We can follow these instructions to register our client application on their platform
|
||||
|
||||
- Once we have the client id and secret, we have to make sure we add them to the application.properties file.
|
||||
|
58
spring-security-modules/spring-security-legacy-oidc/pom.xml
Normal file
58
spring-security-modules/spring-security-legacy-oidc/pom.xml
Normal file
@ -0,0 +1,58 @@
|
||||
<?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>spring-security-legacy-oidc</artifactId>
|
||||
<name>spring-security-legacy-oidc</name>
|
||||
<packaging>war</packaging>
|
||||
<description>Spring OpenID Connect sample project</description>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>parent-boot-2</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<relativePath>../../parent-boot-2</relativePath>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-tomcat</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.security.oauth</groupId>
|
||||
<artifactId>spring-security-oauth2</artifactId>
|
||||
<version>${spring-security-oauth2.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-jwt</artifactId>
|
||||
<version>${spring-security-jwt.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.auth0</groupId>
|
||||
<artifactId>jwks-rsa</artifactId>
|
||||
<version>${jwks-rsa.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<spring-security-oauth2.version>2.2.1.RELEASE</spring-security-oauth2.version>
|
||||
<spring-security-jwt.version>1.0.9.RELEASE</spring-security-jwt.version>
|
||||
<jwks-rsa.version>0.3.0</jwks-rsa.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
@ -0,0 +1,51 @@
|
||||
package com.baeldung.openid.oidc;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.oauth2.client.OAuth2ClientContext;
|
||||
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
|
||||
import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails;
|
||||
import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeResourceDetails;
|
||||
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableOAuth2Client;
|
||||
|
||||
@Configuration
|
||||
@EnableOAuth2Client
|
||||
public class GoogleOpenIdConnectConfig {
|
||||
@Value("${google.clientId}")
|
||||
private String clientId;
|
||||
|
||||
@Value("${google.clientSecret}")
|
||||
private String clientSecret;
|
||||
|
||||
@Value("${google.accessTokenUri}")
|
||||
private String accessTokenUri;
|
||||
|
||||
@Value("${google.userAuthorizationUri}")
|
||||
private String userAuthorizationUri;
|
||||
|
||||
@Value("${google.redirectUri}")
|
||||
private String redirectUri;
|
||||
|
||||
@Bean
|
||||
public OAuth2ProtectedResourceDetails googleOpenId() {
|
||||
final AuthorizationCodeResourceDetails details = new AuthorizationCodeResourceDetails();
|
||||
details.setClientId(clientId);
|
||||
details.setClientSecret(clientSecret);
|
||||
details.setAccessTokenUri(accessTokenUri);
|
||||
details.setUserAuthorizationUri(userAuthorizationUri);
|
||||
details.setScope(Arrays.asList("openid", "email"));
|
||||
details.setPreEstablishedRedirectUri(redirectUri);
|
||||
details.setUseCurrentUri(false);
|
||||
return details;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public OAuth2RestTemplate googleOpenIdTemplate(final OAuth2ClientContext clientContext) {
|
||||
final OAuth2RestTemplate template = new OAuth2RestTemplate(googleOpenId(), clientContext);
|
||||
return template;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package com.baeldung.openid.oidc;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
@Controller
|
||||
public class HomeController {
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
@RequestMapping("/")
|
||||
@ResponseBody
|
||||
public final String home() {
|
||||
final String username = SecurityContextHolder.getContext().getAuthentication().getName();
|
||||
logger.info(username);
|
||||
return "Welcome, " + username;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,103 @@
|
||||
package com.baeldung.openid.oidc;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.jwt.Jwt;
|
||||
import org.springframework.security.jwt.JwtHelper;
|
||||
import org.springframework.security.jwt.crypto.sign.RsaVerifier;
|
||||
import org.springframework.security.oauth2.client.OAuth2RestOperations;
|
||||
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
|
||||
import org.springframework.security.oauth2.common.OAuth2AccessToken;
|
||||
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
|
||||
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
|
||||
|
||||
import com.auth0.jwk.Jwk;
|
||||
import com.auth0.jwk.JwkProvider;
|
||||
import com.auth0.jwk.UrlJwkProvider;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
public class OpenIdConnectFilter extends AbstractAuthenticationProcessingFilter {
|
||||
@Value("${google.clientId}")
|
||||
private String clientId;
|
||||
|
||||
@Value("${google.issuer}")
|
||||
private String issuer;
|
||||
|
||||
@Value("${google.jwkUrl}")
|
||||
private String jwkUrl;
|
||||
|
||||
public OAuth2RestOperations restTemplate;
|
||||
|
||||
public OpenIdConnectFilter(String defaultFilterProcessesUrl) {
|
||||
super(defaultFilterProcessesUrl);
|
||||
setAuthenticationManager(new NoopAuthenticationManager());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
|
||||
|
||||
OAuth2AccessToken accessToken;
|
||||
try {
|
||||
accessToken = restTemplate.getAccessToken();
|
||||
} catch (final OAuth2Exception e) {
|
||||
throw new BadCredentialsException("Could not obtain access token", e);
|
||||
}
|
||||
try {
|
||||
final String idToken = accessToken.getAdditionalInformation().get("id_token").toString();
|
||||
String kid = JwtHelper.headers(idToken)
|
||||
.get("kid");
|
||||
final Jwt tokenDecoded = JwtHelper.decodeAndVerify(idToken, verifier(kid));
|
||||
final Map<String, String> authInfo = new ObjectMapper().readValue(tokenDecoded.getClaims(), Map.class);
|
||||
verifyClaims(authInfo);
|
||||
final OpenIdConnectUserDetails user = new OpenIdConnectUserDetails(authInfo, accessToken);
|
||||
return new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities());
|
||||
} catch (final Exception e) {
|
||||
throw new BadCredentialsException("Could not obtain user details from token", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void verifyClaims(Map claims) {
|
||||
int exp = (int) claims.get("exp");
|
||||
Date expireDate = new Date(exp * 1000L);
|
||||
Date now = new Date();
|
||||
if (expireDate.before(now) || !claims.get("iss").equals(issuer) || !claims.get("aud").equals(clientId)) {
|
||||
throw new RuntimeException("Invalid claims");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private RsaVerifier verifier(String kid) throws Exception {
|
||||
JwkProvider provider = new UrlJwkProvider(new URL(jwkUrl));
|
||||
Jwk jwk = provider.get(kid);
|
||||
return new RsaVerifier((RSAPublicKey) jwk.getPublicKey());
|
||||
}
|
||||
|
||||
public void setRestTemplate(OAuth2RestTemplate restTemplate2) {
|
||||
restTemplate = restTemplate2;
|
||||
|
||||
}
|
||||
|
||||
private static class NoopAuthenticationManager implements AuthenticationManager {
|
||||
|
||||
@Override
|
||||
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
||||
throw new UnsupportedOperationException("No authentication should be done with this AuthenticationManager");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
package com.baeldung.openid.oidc;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.oauth2.common.OAuth2AccessToken;
|
||||
|
||||
public class OpenIdConnectUserDetails implements UserDetails {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String userId;
|
||||
private String username;
|
||||
private OAuth2AccessToken token;
|
||||
|
||||
public OpenIdConnectUserDetails(Map<String, String> userInfo, OAuth2AccessToken token) {
|
||||
this.userId = userInfo.get("sub");
|
||||
this.username = userInfo.get("email");
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends GrantedAuthority> getAuthorities() {
|
||||
return Arrays.asList(new SimpleGrantedAuthority("ROLE_USER"));
|
||||
}
|
||||
|
||||
public String getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public void setUserId(String userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
public OAuth2AccessToken getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
public void setToken(OAuth2AccessToken token) {
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPassword() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccountNonExpired() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccountNonLocked() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCredentialsNonExpired() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user