Merge branch 'master' of https://github.com/eugenp/tutorials
This commit is contained in:
commit
a24e221aa2
|
@ -9,7 +9,7 @@
|
||||||
<url>http://maven.apache.org</url>
|
<url>http://maven.apache.org</url>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<maven-compiler-plugin.version>3.6.0</maven-compiler-plugin.version>
|
<maven-compiler-plugin.version>3.7.0</maven-compiler-plugin.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
@ -26,8 +26,8 @@
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
<version>3.7.0</version>
|
<version>3.7.0</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<source>1.6</source>
|
<source>1.8</source>
|
||||||
<target>1.6</target>
|
<target>1.8</target>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<auto-service.version>1.0-rc2</auto-service.version>
|
<auto-service.version>1.0-rc2</auto-service.version>
|
||||||
<maven-compiler-plugin.version>3.6.0</maven-compiler-plugin.version>
|
<maven-compiler-plugin.version>3.7.0</maven-compiler-plugin.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
|
|
@ -65,7 +65,7 @@
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
<version>3.6.2</version>
|
<version>3.7.0</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<source>1.8</source>
|
<source>1.8</source>
|
||||||
<target>1.8</target>
|
<target>1.8</target>
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<maven-compiler-plugin.version>3.6.0</maven-compiler-plugin.version>
|
<maven-compiler-plugin.version>3.7.0</maven-compiler-plugin.version>
|
||||||
<maven-surefire-plugin.version>2.19.1</maven-surefire-plugin.version>
|
<maven-surefire-plugin.version>2.19.1</maven-surefire-plugin.version>
|
||||||
<camel.version>2.19.1</camel.version>
|
<camel.version>2.19.1</camel.version>
|
||||||
<spring-boot-starter.version>1.5.4.RELEASE</spring-boot-starter.version>
|
<spring-boot-starter.version>1.5.4.RELEASE</spring-boot-starter.version>
|
||||||
|
|
|
@ -52,7 +52,11 @@
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
<version>3.3</version>
|
<version>3.7.0</version>
|
||||||
|
<configuration>
|
||||||
|
<source>1.8</source>
|
||||||
|
<target>1.8</target>
|
||||||
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
<finalName>cas</finalName>
|
<finalName>cas</finalName>
|
||||||
|
|
|
@ -33,3 +33,4 @@
|
||||||
- [Display All Time Zones With GMT And UTC in Java](http://www.baeldung.com/java-time-zones)
|
- [Display All Time Zones With GMT And UTC in Java](http://www.baeldung.com/java-time-zones)
|
||||||
- [Copy a File with Java](http://www.baeldung.com/java-copy-file)
|
- [Copy a File with Java](http://www.baeldung.com/java-copy-file)
|
||||||
- [Generating Prime Numbers in Java](http://www.baeldung.com/java-generate-prime-numbers)
|
- [Generating Prime Numbers in Java](http://www.baeldung.com/java-generate-prime-numbers)
|
||||||
|
- [Static and Default Methods in Interfaces in Java](http://www.baeldung.com/java-static-default-methods)
|
||||||
|
|
|
@ -2,7 +2,6 @@ package com.baeldung.datetime;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.time.LocalTime;
|
import java.time.LocalTime;
|
||||||
import java.time.Period;
|
|
||||||
|
|
||||||
public class UseDuration {
|
public class UseDuration {
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
package com.baeldung.defaultstaticinterfacemethods.application;
|
||||||
|
|
||||||
|
import com.baeldung.defaultstaticinterfacemethods.model.Car;
|
||||||
|
import com.baeldung.defaultstaticinterfacemethods.model.Vehicle;
|
||||||
|
|
||||||
|
public class Application {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
|
||||||
|
Vehicle car = new Car("BMW");
|
||||||
|
System.out.println(car.getBrand());
|
||||||
|
System.out.println(car.speedUp());
|
||||||
|
System.out.println(car.slowDown());
|
||||||
|
System.out.println(car.turnAlarmOn());
|
||||||
|
System.out.println(car.turnAlarmOff());
|
||||||
|
System.out.println(Vehicle.getHorsePower(2500, 480));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
package com.baeldung.defaultstaticinterfacemethods.model;
|
||||||
|
|
||||||
|
public interface Alarm {
|
||||||
|
|
||||||
|
default String turnAlarmOn() {
|
||||||
|
return "Turning the alarm on.";
|
||||||
|
}
|
||||||
|
|
||||||
|
default String turnAlarmOff() {
|
||||||
|
return "Turning the alarm off.";
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
package com.baeldung.defaultstaticinterfacemethods.model;
|
||||||
|
|
||||||
|
public class Car implements Vehicle {
|
||||||
|
|
||||||
|
private final String brand;
|
||||||
|
|
||||||
|
public Car(String brand) {
|
||||||
|
this.brand = brand;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getBrand() {
|
||||||
|
return brand;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String speedUp() {
|
||||||
|
return "The car is speeding up.";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String slowDown() {
|
||||||
|
return "The car is slowing down.";
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
package com.baeldung.defaultstaticinterfacemethods.model;
|
||||||
|
|
||||||
|
public class Motorbike implements Vehicle {
|
||||||
|
|
||||||
|
private final String brand;
|
||||||
|
|
||||||
|
public Motorbike(String brand) {
|
||||||
|
this.brand = brand;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getBrand() {
|
||||||
|
return brand;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String speedUp() {
|
||||||
|
return "The motorbike is speeding up.";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String slowDown() {
|
||||||
|
return "The motorbike is slowing down.";
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
package com.baeldung.defaultstaticinterfacemethods.model;
|
||||||
|
|
||||||
|
public class MultiAlarmCar implements Vehicle, Alarm {
|
||||||
|
|
||||||
|
private final String brand;
|
||||||
|
|
||||||
|
public MultiAlarmCar(String brand) {
|
||||||
|
this.brand = brand;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getBrand() {
|
||||||
|
return brand;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String speedUp() {
|
||||||
|
return "The motorbike is speeding up.";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String slowDown() {
|
||||||
|
return "The mootorbike is slowing down.";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String turnAlarmOn() {
|
||||||
|
return Vehicle.super.turnAlarmOn() + " " + Alarm.super.turnAlarmOn();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String turnAlarmOff() {
|
||||||
|
return Vehicle.super.turnAlarmOff() + " " + Alarm.super.turnAlarmOff();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
package com.baeldung.defaultstaticinterfacemethods.model;
|
||||||
|
|
||||||
|
public interface Vehicle {
|
||||||
|
|
||||||
|
String getBrand();
|
||||||
|
|
||||||
|
String speedUp();
|
||||||
|
|
||||||
|
String slowDown();
|
||||||
|
|
||||||
|
default String turnAlarmOn() {
|
||||||
|
return "Turning the vehice alarm on.";
|
||||||
|
}
|
||||||
|
|
||||||
|
default String turnAlarmOff() {
|
||||||
|
return "Turning the vehicle alarm off.";
|
||||||
|
}
|
||||||
|
|
||||||
|
static int getHorsePower(int rpm, int torque) {
|
||||||
|
return (rpm * torque) / 5252;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,80 @@
|
||||||
|
package com.baeldung.iterators;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Source code https://github.com/eugenp/tutorials
|
||||||
|
*
|
||||||
|
* @author Santosh Thakur
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class Iterators {
|
||||||
|
|
||||||
|
public static int failFast1() {
|
||||||
|
ArrayList<Integer> numbers = new ArrayList<>();
|
||||||
|
|
||||||
|
numbers.add(10);
|
||||||
|
numbers.add(20);
|
||||||
|
numbers.add(30);
|
||||||
|
numbers.add(40);
|
||||||
|
|
||||||
|
Iterator<Integer> iterator = numbers.iterator();
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
Integer number = iterator.next();
|
||||||
|
numbers.add(50);
|
||||||
|
}
|
||||||
|
|
||||||
|
return numbers.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int failFast2() {
|
||||||
|
ArrayList<Integer> numbers = new ArrayList<>();
|
||||||
|
numbers.add(10);
|
||||||
|
numbers.add(20);
|
||||||
|
numbers.add(30);
|
||||||
|
numbers.add(40);
|
||||||
|
|
||||||
|
Iterator<Integer> iterator = numbers.iterator();
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
if (iterator.next() == 30) {
|
||||||
|
// will not throw Exception
|
||||||
|
iterator.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("using iterator's remove method = " + numbers);
|
||||||
|
|
||||||
|
iterator = numbers.iterator();
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
if (iterator.next() == 40) {
|
||||||
|
// will throw Exception on
|
||||||
|
// next call of next() method
|
||||||
|
numbers.remove(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return numbers.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int failSafe1() {
|
||||||
|
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
map.put("First", 10);
|
||||||
|
map.put("Second", 20);
|
||||||
|
map.put("Third", 30);
|
||||||
|
map.put("Fourth", 40);
|
||||||
|
|
||||||
|
Iterator<String> iterator = map.keySet()
|
||||||
|
.iterator();
|
||||||
|
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
String key = iterator.next();
|
||||||
|
map.put("Fifth", 50);
|
||||||
|
}
|
||||||
|
|
||||||
|
return map.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,8 +1,6 @@
|
||||||
package com.baeldung.streamApi;
|
package com.baeldung.streamApi;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.stream.IntStream;
|
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -2,6 +2,7 @@ package com.baeldung.counter;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
import org.openjdk.jmh.annotations.Benchmark;
|
import org.openjdk.jmh.annotations.Benchmark;
|
||||||
import org.openjdk.jmh.annotations.BenchmarkMode;
|
import org.openjdk.jmh.annotations.BenchmarkMode;
|
||||||
|
@ -18,6 +19,16 @@ public class CounterStatistics {
|
||||||
private static final Map<String, MutableInteger> counterWithMutableIntMap = new HashMap<>();
|
private static final Map<String, MutableInteger> counterWithMutableIntMap = new HashMap<>();
|
||||||
private static final Map<String, int[]> counterWithIntArrayMap = new HashMap<>();
|
private static final Map<String, int[]> counterWithIntArrayMap = new HashMap<>();
|
||||||
private static final Map<String, Long> counterWithLongWrapperMap = new HashMap<>();
|
private static final Map<String, Long> counterWithLongWrapperMap = new HashMap<>();
|
||||||
|
private static final Map<String, Long> counterWithLongWrapperStreamMap = new HashMap<>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
CounterUtil.COUNTRY_NAMES = new String[10000];
|
||||||
|
final String prefix = "NewString";
|
||||||
|
Random random = new Random();
|
||||||
|
for (int i=0; i<10000; i++) {
|
||||||
|
CounterUtil.COUNTRY_NAMES[i] = new String(prefix + random.nextInt(1000));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Benchmark
|
@Benchmark
|
||||||
public void wrapperAsCounter() {
|
public void wrapperAsCounter() {
|
||||||
|
@ -29,6 +40,11 @@ public class CounterStatistics {
|
||||||
CounterUtil.counterWithLambdaAndWrapper(counterWithLongWrapperMap);
|
CounterUtil.counterWithLambdaAndWrapper(counterWithLongWrapperMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public void parallelStreamWithWrapper() {
|
||||||
|
CounterUtil.counterWithParallelStreamAndWrapper(counterWithLongWrapperStreamMap);
|
||||||
|
}
|
||||||
|
|
||||||
@Benchmark
|
@Benchmark
|
||||||
public void mutableIntegerAsCounter() {
|
public void mutableIntegerAsCounter() {
|
||||||
CounterUtil.counterWithMutableInteger(counterWithMutableIntMap);
|
CounterUtil.counterWithMutableInteger(counterWithMutableIntMap);
|
||||||
|
|
|
@ -6,7 +6,7 @@ import java.util.stream.Stream;
|
||||||
|
|
||||||
public class CounterUtil {
|
public class CounterUtil {
|
||||||
|
|
||||||
private final static String[] COUNTRY_NAMES = { "China", "Australia", "India", "USA", "USSR", "UK", "China", "France", "Poland", "Austria", "India", "USA", "Egypt", "China" };
|
public static String[] COUNTRY_NAMES = { "China", "Australia", "India", "USA", "USSR", "UK", "China", "France", "Poland", "Austria", "India", "USA", "Egypt", "China" };
|
||||||
|
|
||||||
public static void counterWithWrapperObject(Map<String, Integer> counterMap) {
|
public static void counterWithWrapperObject(Map<String, Integer> counterMap) {
|
||||||
for (String country : COUNTRY_NAMES) {
|
for (String country : COUNTRY_NAMES) {
|
||||||
|
@ -15,9 +15,14 @@ public class CounterUtil {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void counterWithLambdaAndWrapper(Map<String, Long> counterMap) {
|
public static void counterWithLambdaAndWrapper(Map<String, Long> counterMap) {
|
||||||
counterMap.putAll(Stream.of(COUNTRY_NAMES)
|
Stream.of(COUNTRY_NAMES)
|
||||||
|
.collect(Collectors.groupingBy(k -> k, () -> counterMap, Collectors.counting()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void counterWithParallelStreamAndWrapper(Map<String, Long> counterMap) {
|
||||||
|
Stream.of(COUNTRY_NAMES)
|
||||||
.parallel()
|
.parallel()
|
||||||
.collect(Collectors.groupingBy(k -> k, Collectors.counting())));
|
.collect(Collectors.groupingBy(k -> k, () -> counterMap, Collectors.counting()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class MutableInteger {
|
public static class MutableInteger {
|
||||||
|
|
|
@ -4,7 +4,6 @@ import java.time.LocalDate;
|
||||||
import java.time.LocalTime;
|
import java.time.LocalTime;
|
||||||
import java.time.Month;
|
import java.time.Month;
|
||||||
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
|
@ -4,7 +4,6 @@ import java.time.DayOfWeek;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
package com.baeldung.defaultistaticinterfacemethods.test;
|
||||||
|
|
||||||
|
import com.baeldung.defaultstaticinterfacemethods.model.Car;
|
||||||
|
import com.baeldung.defaultstaticinterfacemethods.model.Motorbike;
|
||||||
|
import com.baeldung.defaultstaticinterfacemethods.model.Vehicle;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Test;
|
||||||
|
import static org.assertj.core.api.Assertions.*;
|
||||||
|
|
||||||
|
public class StaticDefaulInterfaceMethodUnitTest {
|
||||||
|
|
||||||
|
private static Car car;
|
||||||
|
private static Motorbike motorbike;
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void setUpCarInstance() {
|
||||||
|
car = new Car("BMW");
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void setUpMotorbikeInstance() {
|
||||||
|
motorbike = new Motorbike("Yamaha");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenCarInstace_whenBrandisBMW_thenOneAssertion() {
|
||||||
|
assertThat(car.getBrand()).isEqualTo("BMW");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenCarInstance_whenCallingSpeedUp_thenOneAssertion() {
|
||||||
|
assertThat(car.speedUp()).isEqualTo("The car is speeding up.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenCarInstance_whenCallingSlowDown_thenOneAssertion() {
|
||||||
|
assertThat(car.slowDown()).isEqualTo("The car is slowing down.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenCarInstance_whenCallingTurnAlarmOn_thenOneAssertion() {
|
||||||
|
assertThat(car.turnAlarmOn()).isEqualTo("Turning the vehice alarm on.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenCarInstance_whenCallingTurnAlarmOff_thenOneAssertion() {
|
||||||
|
assertThat(car.turnAlarmOff()).isEqualTo("Turning the vehicle alarm off.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenVehicleInterface_whenCallinggetHorsePower_thenOneAssertion() {
|
||||||
|
assertThat(Vehicle.getHorsePower(2500, 480)).isEqualTo(228);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenMooorbikeInstace_whenBrandisYamaha_thenOneAssertion() {
|
||||||
|
assertThat(motorbike.getBrand()).isEqualTo("Yamaha");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenMotorbikeInstance_whenCallingSpeedUp_thenOneAssertion() {
|
||||||
|
assertThat(motorbike.speedUp()).isEqualTo("The motorbike is speeding up.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenMotorbikeInstance_whenCallingSlowDown_thenOneAssertion() {
|
||||||
|
assertThat(motorbike.slowDown()).isEqualTo("The motorbike is slowing down.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenMotorbikeInstance_whenCallingTurnAlarmOn_thenOneAssertion() {
|
||||||
|
assertThat(motorbike.turnAlarmOn()).isEqualTo("Turning the vehice alarm on.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenMotorbikeInstance_whenCallingTurnAlarmOff_thenOneAssertion() {
|
||||||
|
assertThat(motorbike.turnAlarmOff()).isEqualTo("Turning the vehicle alarm off.");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
package com.baeldung.iterators;
|
||||||
|
|
||||||
|
import static com.baeldung.iterators.Iterators.failFast1;
|
||||||
|
import static com.baeldung.iterators.Iterators.failFast2;
|
||||||
|
import static com.baeldung.iterators.Iterators.failSafe1;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||||
|
|
||||||
|
import java.util.ConcurrentModificationException;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Source code https://github.com/eugenp/tutorials
|
||||||
|
*
|
||||||
|
* @author Santosh Thakur
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class IteratorsTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenFailFast_ThenThrowsException() {
|
||||||
|
assertThatThrownBy(() -> {
|
||||||
|
failFast1();
|
||||||
|
}).isInstanceOf(ConcurrentModificationException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenFailFast_ThenThrowsExceptionInSecondIteration() {
|
||||||
|
assertThatThrownBy(() -> {
|
||||||
|
failFast2();
|
||||||
|
}).isInstanceOf(ConcurrentModificationException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenFailSafe_ThenDoesNotThrowException() {
|
||||||
|
assertThat(failSafe1()).isGreaterThanOrEqualTo(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -6,7 +6,6 @@ import java.util.Comparator;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
public class Java8ComparatorUnitTest {
|
public class Java8ComparatorUnitTest {
|
||||||
|
@ -134,8 +133,7 @@ public class Java8ComparatorUnitTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void whenThenComparing_thenSortedByAgeName() {
|
public void whenThenComparing_thenSortedByAgeName() {
|
||||||
Comparator<Employee> employee_Age_Name_Comparator = Comparator.comparing(Employee::getAge)
|
Comparator<Employee> employee_Age_Name_Comparator = Comparator.comparing(Employee::getAge).thenComparing(Employee::getName);
|
||||||
.thenComparing(Employee::getName);
|
|
||||||
|
|
||||||
Arrays.sort(someMoreEmployees, employee_Age_Name_Comparator);
|
Arrays.sort(someMoreEmployees, employee_Age_Name_Comparator);
|
||||||
// System.out.println(Arrays.toString(someMoreEmployees));
|
// System.out.println(Arrays.toString(someMoreEmployees));
|
||||||
|
@ -144,8 +142,7 @@ public class Java8ComparatorUnitTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void whenThenComparing_thenSortedByNameAge() {
|
public void whenThenComparing_thenSortedByNameAge() {
|
||||||
Comparator<Employee> employee_Name_Age_Comparator = Comparator.comparing(Employee::getName)
|
Comparator<Employee> employee_Name_Age_Comparator = Comparator.comparing(Employee::getName).thenComparingInt(Employee::getAge);
|
||||||
.thenComparingInt(Employee::getAge);
|
|
||||||
|
|
||||||
Arrays.sort(someMoreEmployees, employee_Name_Age_Comparator);
|
Arrays.sort(someMoreEmployees, employee_Name_Age_Comparator);
|
||||||
// System.out.println(Arrays.toString(someMoreEmployees));
|
// System.out.println(Arrays.toString(someMoreEmployees));
|
||||||
|
|
|
@ -2,7 +2,6 @@ package com.baeldung.stream;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package com.baeldung.temporaladjusters;
|
package com.baeldung.temporaladjusters;
|
||||||
|
|
||||||
import com.baeldung.temporaladjuster.CustomTemporalAdjuster;
|
import com.baeldung.temporaladjuster.CustomTemporalAdjuster;
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
|
|
|
@ -19,3 +19,4 @@
|
||||||
- [Java 9 java.util.Objects Additions](http://www.baeldung.com/java-9-objects-new)
|
- [Java 9 java.util.Objects Additions](http://www.baeldung.com/java-9-objects-new)
|
||||||
- [Compact Strings in Java 9](http://www.baeldung.com/java-9-compact-string)
|
- [Compact Strings in Java 9](http://www.baeldung.com/java-9-compact-string)
|
||||||
- [Convert Date to LocalDate or LocalDateTime and Back](http://www.baeldung.com/java-date-to-localdate-and-localdatetime)
|
- [Convert Date to LocalDate or LocalDateTime and Back](http://www.baeldung.com/java-date-to-localdate-and-localdatetime)
|
||||||
|
- [Java 9 Variable Handles Demistyfied](http://www.baeldung.com/java-variable-handles)
|
||||||
|
|
|
@ -90,7 +90,7 @@
|
||||||
<org.slf4j.version>1.7.21</org.slf4j.version>
|
<org.slf4j.version>1.7.21</org.slf4j.version>
|
||||||
<ch.qos.logback.version>1.2.1</ch.qos.logback.version>
|
<ch.qos.logback.version>1.2.1</ch.qos.logback.version>
|
||||||
<!-- maven plugins -->
|
<!-- maven plugins -->
|
||||||
<maven-compiler-plugin.version>3.6.0</maven-compiler-plugin.version>
|
<maven-compiler-plugin.version>3.7.0</maven-compiler-plugin.version>
|
||||||
<maven-surefire-plugin.version>2.19.1</maven-surefire-plugin.version>
|
<maven-surefire-plugin.version>2.19.1</maven-surefire-plugin.version>
|
||||||
|
|
||||||
<!-- testing -->
|
<!-- testing -->
|
||||||
|
|
|
@ -0,0 +1,106 @@
|
||||||
|
package com.baeldung.java9.varhandles;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.lang.invoke.MethodHandles;
|
||||||
|
import java.lang.invoke.VarHandle;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
public class VariableHandlesTest {
|
||||||
|
|
||||||
|
public int publicTestVariable = 1;
|
||||||
|
private int privateTestVariable = 1;
|
||||||
|
public int variableToSet = 1;
|
||||||
|
public int variableToCompareAndSet = 1;
|
||||||
|
public int variableToGetAndAdd = 0;
|
||||||
|
public byte variableToBitwiseOr = 0;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenVariableHandleForPublicVariableIsCreated_ThenItIsInitializedProperly() throws NoSuchFieldException, IllegalAccessException {
|
||||||
|
VarHandle publicIntHandle = MethodHandles
|
||||||
|
.lookup()
|
||||||
|
.in(VariableHandlesTest.class)
|
||||||
|
.findVarHandle(VariableHandlesTest.class, "publicTestVariable", int.class);
|
||||||
|
|
||||||
|
assertThat(publicIntHandle.coordinateTypes().size() == 1);
|
||||||
|
assertThat(publicIntHandle.coordinateTypes().get(0) == VariableHandles.class);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenVariableHandleForPrivateVariableIsCreated_ThenItIsInitializedProperly() throws NoSuchFieldException, IllegalAccessException {
|
||||||
|
VarHandle privateIntHandle = MethodHandles
|
||||||
|
.privateLookupIn(VariableHandlesTest.class, MethodHandles.lookup())
|
||||||
|
.findVarHandle(VariableHandlesTest.class, "privateTestVariable", int.class);
|
||||||
|
|
||||||
|
assertThat(privateIntHandle.coordinateTypes().size() == 1);
|
||||||
|
assertThat(privateIntHandle.coordinateTypes().get(0) == VariableHandlesTest.class);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenVariableHandleForArrayVariableIsCreated_ThenItIsInitializedProperly() throws NoSuchFieldException, IllegalAccessException {
|
||||||
|
VarHandle arrayVarHandle = MethodHandles
|
||||||
|
.arrayElementVarHandle(int[].class);
|
||||||
|
|
||||||
|
assertThat(arrayVarHandle.coordinateTypes().size() == 2);
|
||||||
|
assertThat(arrayVarHandle.coordinateTypes().get(0) == int[].class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenVarHandle_whenGetIsInvoked_ThenValueOfVariableIsReturned() throws NoSuchFieldException, IllegalAccessException {
|
||||||
|
VarHandle publicIntHandle = MethodHandles
|
||||||
|
.lookup()
|
||||||
|
.in(VariableHandlesTest.class)
|
||||||
|
.findVarHandle(VariableHandlesTest.class, "publicTestVariable", int.class);
|
||||||
|
|
||||||
|
assertThat((int) publicIntHandle.get(this) == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenVarHandle_whenSetIsInvoked_ThenValueOfVariableIsChanged() throws NoSuchFieldException, IllegalAccessException {
|
||||||
|
VarHandle publicIntHandle = MethodHandles
|
||||||
|
.lookup()
|
||||||
|
.in(VariableHandlesTest.class)
|
||||||
|
.findVarHandle(VariableHandlesTest.class, "variableToSet", int.class);
|
||||||
|
publicIntHandle.set(this, 15);
|
||||||
|
|
||||||
|
assertThat((int) publicIntHandle.get(this) == 15);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenVarHandle_whenCompareAndSetIsInvoked_ThenValueOfVariableIsChanged() throws NoSuchFieldException, IllegalAccessException {
|
||||||
|
VarHandle publicIntHandle = MethodHandles
|
||||||
|
.lookup()
|
||||||
|
.in(VariableHandlesTest.class)
|
||||||
|
.findVarHandle(VariableHandlesTest.class, "variableToCompareAndSet", int.class);
|
||||||
|
publicIntHandle.compareAndSet(this, 1, 100);
|
||||||
|
|
||||||
|
assertThat((int) publicIntHandle.get(this) == 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenVarHandle_whenGetAndAddIsInvoked_ThenValueOfVariableIsChanged() throws NoSuchFieldException, IllegalAccessException {
|
||||||
|
VarHandle publicIntHandle = MethodHandles
|
||||||
|
.lookup()
|
||||||
|
.in(VariableHandlesTest.class)
|
||||||
|
.findVarHandle(VariableHandlesTest.class, "variableToGetAndAdd", int.class);
|
||||||
|
int before = (int) publicIntHandle.getAndAdd(this, 200);
|
||||||
|
|
||||||
|
assertThat(before == 0);
|
||||||
|
assertThat((int) publicIntHandle.get(this) == 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenVarHandle_whenGetAndBitwiseOrIsInvoked_ThenValueOfVariableIsChanged() throws NoSuchFieldException, IllegalAccessException {
|
||||||
|
VarHandle publicIntHandle = MethodHandles
|
||||||
|
.lookup()
|
||||||
|
.in(VariableHandlesTest.class)
|
||||||
|
.findVarHandle(VariableHandlesTest.class, "variableToBitwiseOr", byte.class);
|
||||||
|
byte before = (byte) publicIntHandle.getAndBitwiseOr(this, (byte) 127);
|
||||||
|
|
||||||
|
assertThat(before == 0);
|
||||||
|
assertThat(variableToBitwiseOr == 127);
|
||||||
|
}
|
||||||
|
}
|
|
@ -483,7 +483,7 @@
|
||||||
<avaitility.version>1.7.0</avaitility.version>
|
<avaitility.version>1.7.0</avaitility.version>
|
||||||
|
|
||||||
<!-- maven plugins -->
|
<!-- maven plugins -->
|
||||||
<maven-compiler-plugin.version>3.6.0</maven-compiler-plugin.version>
|
<maven-compiler-plugin.version>3.7.0</maven-compiler-plugin.version>
|
||||||
<maven-surefire-plugin.version>2.19.1</maven-surefire-plugin.version>
|
<maven-surefire-plugin.version>2.19.1</maven-surefire-plugin.version>
|
||||||
</properties>
|
</properties>
|
||||||
</project>
|
</project>
|
|
@ -126,3 +126,9 @@
|
||||||
- [Java – Append Data to a File](http://www.baeldung.com/java-append-to-file)
|
- [Java – Append Data to a File](http://www.baeldung.com/java-append-to-file)
|
||||||
- [Introduction to the Java ArrayDeque](http://www.baeldung.com/java-array-deque)
|
- [Introduction to the Java ArrayDeque](http://www.baeldung.com/java-array-deque)
|
||||||
- [Guide to java.util.Formatter](http://www.baeldung.com/java-string-formatter)
|
- [Guide to java.util.Formatter](http://www.baeldung.com/java-string-formatter)
|
||||||
|
- [Batch Processing in JDBC](http://www.baeldung.com/jdbc-batch-processing)
|
||||||
|
- [Check if a Java Array Contains a Value](http://www.baeldung.com/java-array-contains-value)
|
||||||
|
- [How to Invert an Array in Java](http://www.baeldung.com/java-invert-array)
|
||||||
|
- [Guide to the Cipher Class](http://www.baeldung.com/java-cipher-class)
|
||||||
|
- [A Guide to Java Initialization](http://www.baeldung.com/java-initialization)
|
||||||
|
|
||||||
|
|
|
@ -180,12 +180,7 @@
|
||||||
<artifactId>esapi</artifactId>
|
<artifactId>esapi</artifactId>
|
||||||
<version>2.1.0.1</version>
|
<version>2.1.0.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>com.h2database</groupId>
|
|
||||||
<artifactId>h2</artifactId>
|
|
||||||
<version>1.4.196</version>
|
|
||||||
<scope>runtime</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.sun.messaging.mq</groupId>
|
<groupId>com.sun.messaging.mq</groupId>
|
||||||
<artifactId>fscontext</artifactId>
|
<artifactId>fscontext</artifactId>
|
||||||
|
@ -221,13 +216,17 @@
|
||||||
<artifactId>spring-web</artifactId>
|
<artifactId>spring-web</artifactId>
|
||||||
<version>4.3.4.RELEASE</version>
|
<version>4.3.4.RELEASE</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter</artifactId>
|
<artifactId>spring-boot-starter</artifactId>
|
||||||
<version>1.5.8.RELEASE</version>
|
<version>1.5.8.RELEASE</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.hsqldb</groupId>
|
||||||
|
<artifactId>hsqldb</artifactId>
|
||||||
|
<version>2.4.0</version>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
@ -261,7 +260,7 @@
|
||||||
<exclude>**/*LongRunningUnitTest.java</exclude>
|
<exclude>**/*LongRunningUnitTest.java</exclude>
|
||||||
<exclude>**/*ManualTest.java</exclude>
|
<exclude>**/*ManualTest.java</exclude>
|
||||||
</excludes>
|
</excludes>
|
||||||
|
<testFailureIgnore>true</testFailureIgnore>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
|
||||||
|
@ -385,7 +384,7 @@
|
||||||
<argument>-Xmx300m</argument>
|
<argument>-Xmx300m</argument>
|
||||||
<argument>-XX:+UseParallelGC</argument>
|
<argument>-XX:+UseParallelGC</argument>
|
||||||
<argument>-classpath</argument>
|
<argument>-classpath</argument>
|
||||||
<classpath />
|
<classpath/>
|
||||||
<argument>com.baeldung.outofmemoryerror.OutOfMemoryGCLimitExceed</argument>
|
<argument>com.baeldung.outofmemoryerror.OutOfMemoryGCLimitExceed</argument>
|
||||||
</arguments>
|
</arguments>
|
||||||
</configuration>
|
</configuration>
|
||||||
|
@ -433,7 +432,7 @@
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
<id>run-benchmarks</id>
|
<id>run-benchmarks</id>
|
||||||
<!-- <phase>integration-test</phase> -->
|
<!-- <phase>integration-test</phase>-->
|
||||||
<phase>none</phase>
|
<phase>none</phase>
|
||||||
<goals>
|
<goals>
|
||||||
<goal>exec</goal>
|
<goal>exec</goal>
|
||||||
|
@ -443,7 +442,7 @@
|
||||||
<executable>java</executable>
|
<executable>java</executable>
|
||||||
<arguments>
|
<arguments>
|
||||||
<argument>-classpath</argument>
|
<argument>-classpath</argument>
|
||||||
<classpath />
|
<classpath/>
|
||||||
<argument>org.openjdk.jmh.Main</argument>
|
<argument>org.openjdk.jmh.Main</argument>
|
||||||
<argument>.*</argument>
|
<argument>.*</argument>
|
||||||
</arguments>
|
</arguments>
|
||||||
|
@ -490,7 +489,7 @@
|
||||||
<avaitility.version>1.7.0</avaitility.version>
|
<avaitility.version>1.7.0</avaitility.version>
|
||||||
|
|
||||||
<!-- maven plugins -->
|
<!-- maven plugins -->
|
||||||
<maven-compiler-plugin.version>3.6.0</maven-compiler-plugin.version>
|
<maven-compiler-plugin.version>3.7.0</maven-compiler-plugin.version>
|
||||||
<maven-surefire-plugin.version>2.19.1</maven-surefire-plugin.version>
|
<maven-surefire-plugin.version>2.19.1</maven-surefire-plugin.version>
|
||||||
</properties>
|
</properties>
|
||||||
</project>
|
</project>
|
|
@ -25,7 +25,9 @@ public class ArrayInverter {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object[] invertUsingStreams(final Object[] array) {
|
public Object[] invertUsingStreams(final Object[] array) {
|
||||||
return IntStream.range(1, array.length + 1).mapToObj(i -> array[array.length - i]).toArray();
|
return IntStream.rangeClosed(1, array.length)
|
||||||
|
.mapToObj(i -> array[array.length - i])
|
||||||
|
.toArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void invertUsingCommonsLang(Object[] array) {
|
public void invertUsingCommonsLang(Object[] array) {
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
package com.baeldung.cipher;
|
||||||
|
|
||||||
|
import javax.crypto.*;
|
||||||
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
import java.security.InvalidKeyException;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.cert.Certificate;
|
||||||
|
|
||||||
|
public class Encryptor {
|
||||||
|
|
||||||
|
public byte[] encryptMessage(byte[] message, byte[] keyBytes) throws InvalidKeyException, NoSuchPaddingException, NoSuchAlgorithmException, BadPaddingException, IllegalBlockSizeException {
|
||||||
|
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
|
||||||
|
SecretKey secretKey = new SecretKeySpec(keyBytes, "AES");
|
||||||
|
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
|
||||||
|
byte[] encryptedMessage = cipher.doFinal(message);
|
||||||
|
return encryptedMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] encryptMessage(byte[] message, Certificate publicKeyCertificate) throws InvalidKeyException, NoSuchPaddingException, NoSuchAlgorithmException, BadPaddingException, IllegalBlockSizeException {
|
||||||
|
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
|
||||||
|
cipher.init(Cipher.ENCRYPT_MODE, publicKeyCertificate);
|
||||||
|
byte[] encryptedMessage = cipher.doFinal(message);
|
||||||
|
return encryptedMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] decryptMessage(byte[] encryptedMessage, byte[] keyBytes) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
|
||||||
|
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
|
||||||
|
SecretKey secretKey = new SecretKeySpec(keyBytes, "AES");
|
||||||
|
cipher.init(Cipher.DECRYPT_MODE, secretKey);
|
||||||
|
byte[] clearMessage = cipher.doFinal(encryptedMessage);
|
||||||
|
return clearMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
package com.baeldung.initializationguide;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
public class User implements Serializable, Cloneable {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
static String forum;
|
||||||
|
private String name;
|
||||||
|
private int id;
|
||||||
|
|
||||||
|
{
|
||||||
|
id = 0;
|
||||||
|
System.out.println("Instance Initializer");
|
||||||
|
}
|
||||||
|
|
||||||
|
static {
|
||||||
|
forum = "Java";
|
||||||
|
System.out.println("Static Initializer");
|
||||||
|
}
|
||||||
|
|
||||||
|
public User(String name, int id) {
|
||||||
|
super();
|
||||||
|
this.name = name;
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public User() {
|
||||||
|
System.out.println("Constructor");
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(int id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Object clone() throws CloneNotSupportedException {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,96 @@
|
||||||
|
package com.baeldung.jdbc;
|
||||||
|
|
||||||
|
import java.sql.*;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class BatchProcessing {
|
||||||
|
|
||||||
|
private final String[] EMPLOYEES = new String[]{"Zuck","Mike","Larry","Musk","Steve"};
|
||||||
|
private final String[] DESIGNATIONS = new String[]{"CFO","CSO","CTO","CEO","CMO"};
|
||||||
|
private final String[] ADDRESSES = new String[]{"China","York","Diego","Carolina","India"};
|
||||||
|
|
||||||
|
private Connection connection;
|
||||||
|
|
||||||
|
public void getConnection(){
|
||||||
|
try {
|
||||||
|
Class.forName("org.hsqldb.jdbcDriver");
|
||||||
|
connection = DriverManager.getConnection("jdbc:hsqldb:file:C:\\EMPLOYEEDB", "SA", "");
|
||||||
|
connection.setAutoCommit(false);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace(System.out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void createTables(){
|
||||||
|
try {
|
||||||
|
connection.createStatement().executeUpdate("create table EMPLOYEE (ID VARCHAR(36), NAME VARCHAR(45), DESIGNATION VARCHAR(15))");
|
||||||
|
connection.createStatement().executeUpdate("create table EMP_ADDRESS (ID VARCHAR(36), EMP_ID VARCHAR(36), ADDRESS VARCHAR(45))");
|
||||||
|
System.out.println("Tables Created!!!");
|
||||||
|
} catch (SQLException e) {
|
||||||
|
e.printStackTrace(System.out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void useStatement(){
|
||||||
|
try {
|
||||||
|
String insertEmployeeSQL = "INSERT INTO EMPLOYEE(ID, NAME, DESIGNATION) VALUES ('%s','%s','%s');";
|
||||||
|
String insertEmployeeAddrSQL = "INSERT INTO EMP_ADDRESS(ID, EMP_ID, ADDRESS) VALUES ('%s','%s','%s');";
|
||||||
|
Statement statement = connection.createStatement();
|
||||||
|
for(int i = 0; i < EMPLOYEES.length; i++){
|
||||||
|
String employeeId = UUID.randomUUID().toString();
|
||||||
|
statement.addBatch(String.format(insertEmployeeSQL, employeeId, EMPLOYEES[i],DESIGNATIONS[i]));
|
||||||
|
statement.addBatch(String.format(insertEmployeeAddrSQL, UUID.randomUUID().toString(),employeeId,ADDRESSES[i]));
|
||||||
|
}
|
||||||
|
statement.executeBatch();
|
||||||
|
connection.commit();
|
||||||
|
} catch (Exception e) {
|
||||||
|
try {
|
||||||
|
connection.rollback();
|
||||||
|
} catch (SQLException ex) {
|
||||||
|
System.out.println("Error during rollback");
|
||||||
|
System.out.println(ex.getMessage());
|
||||||
|
}
|
||||||
|
e.printStackTrace(System.out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void usePreparedStatement(){
|
||||||
|
try {
|
||||||
|
String insertEmployeeSQL = "INSERT INTO EMPLOYEE(ID, NAME, DESIGNATION) VALUES (?,?,?);";
|
||||||
|
String insertEmployeeAddrSQL = "INSERT INTO EMP_ADDRESS(ID, EMP_ID, ADDRESS) VALUES (?,?,?);";
|
||||||
|
PreparedStatement employeeStmt = connection.prepareStatement(insertEmployeeSQL);
|
||||||
|
PreparedStatement empAddressStmt = connection.prepareStatement(insertEmployeeAddrSQL);
|
||||||
|
for(int i = 0; i < EMPLOYEES.length; i++){
|
||||||
|
String employeeId = UUID.randomUUID().toString();
|
||||||
|
employeeStmt.setString(1,employeeId);
|
||||||
|
employeeStmt.setString(2,EMPLOYEES[i]);
|
||||||
|
employeeStmt.setString(3,DESIGNATIONS[i]);
|
||||||
|
employeeStmt.addBatch();
|
||||||
|
|
||||||
|
empAddressStmt.setString(1,UUID.randomUUID().toString());
|
||||||
|
empAddressStmt.setString(2,employeeId);
|
||||||
|
empAddressStmt.setString(3,ADDRESSES[i]);
|
||||||
|
empAddressStmt.addBatch();
|
||||||
|
}
|
||||||
|
employeeStmt.executeBatch();
|
||||||
|
empAddressStmt.executeBatch();
|
||||||
|
connection.commit();
|
||||||
|
} catch (Exception e) {
|
||||||
|
try {
|
||||||
|
connection.rollback();
|
||||||
|
} catch (SQLException ex) {
|
||||||
|
System.out.println("Error during rollback");
|
||||||
|
System.out.println(ex.getMessage());
|
||||||
|
}
|
||||||
|
e.printStackTrace(System.out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
BatchProcessing batchProcessing = new BatchProcessing();
|
||||||
|
batchProcessing.getConnection();
|
||||||
|
batchProcessing.createTables();
|
||||||
|
batchProcessing.useStatement();
|
||||||
|
batchProcessing.usePreparedStatement();
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,15 +8,7 @@ public class BinaryTree {
|
||||||
Node root;
|
Node root;
|
||||||
|
|
||||||
public void add(int value) {
|
public void add(int value) {
|
||||||
|
root = addRecursive(root, value);
|
||||||
Node newNode = new Node(value);
|
|
||||||
|
|
||||||
if (root == null) {
|
|
||||||
root = newNode;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
addRecursive(root, value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Node addRecursive(Node current, int value) {
|
private Node addRecursive(Node current, int value) {
|
||||||
|
@ -27,34 +19,41 @@ public class BinaryTree {
|
||||||
|
|
||||||
if (value < current.value) {
|
if (value < current.value) {
|
||||||
current.left = addRecursive(current.left, value);
|
current.left = addRecursive(current.left, value);
|
||||||
} else {
|
} else if (value > current.value) {
|
||||||
current.right = addRecursive(current.right, value);
|
current.right = addRecursive(current.right, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return current;
|
return current;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isEmpty() {
|
public boolean isEmpty() {
|
||||||
return root == null;
|
return root == null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getSize() {
|
||||||
|
return getSizeRecursive(root);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getSizeRecursive(Node current) {
|
||||||
|
return current == null ? 0 : getSizeRecursive(current.left) + 1 + getSizeRecursive(current.right);
|
||||||
|
}
|
||||||
|
|
||||||
public boolean containsNode(int value) {
|
public boolean containsNode(int value) {
|
||||||
return containsNodeRecursive(root, value);
|
return containsNodeRecursive(root, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean containsNodeRecursive(Node current, int value) {
|
private boolean containsNodeRecursive(Node current, int value) {
|
||||||
|
|
||||||
if (current == null) {
|
if (current == null) {
|
||||||
return false;
|
return false;
|
||||||
} else if (value == current.value) {
|
|
||||||
return true;
|
|
||||||
} else if (value < current.value) {
|
|
||||||
return containsNodeRecursive(current.left, value);
|
|
||||||
} else {
|
|
||||||
return containsNodeRecursive(current.right, value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (value == current.value) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value < current.value
|
||||||
|
? containsNodeRecursive(current.left, value)
|
||||||
|
: containsNodeRecursive(current.right, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void delete(int value) {
|
public void delete(int value) {
|
||||||
|
@ -86,23 +85,18 @@ public class BinaryTree {
|
||||||
current.value = smallestValue;
|
current.value = smallestValue;
|
||||||
current.right = deleteRecursive(current.right, smallestValue);
|
current.right = deleteRecursive(current.right, smallestValue);
|
||||||
return current;
|
return current;
|
||||||
|
}
|
||||||
} else if (value < current.value) {
|
if (value < current.value) {
|
||||||
current.left = deleteRecursive(current.left, value);
|
current.left = deleteRecursive(current.left, value);
|
||||||
return current;
|
return current;
|
||||||
} else {
|
}
|
||||||
|
|
||||||
current.right = deleteRecursive(current.right, value);
|
current.right = deleteRecursive(current.right, value);
|
||||||
return current;
|
return current;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private int findSmallestValue(Node root) {
|
private int findSmallestValue(Node root) {
|
||||||
|
return root.left == null ? root.value : findSmallestValue(root.left);
|
||||||
if (root.left == null) {
|
|
||||||
return root.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return findSmallestValue(root.left);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void traverseInOrder(Node node) {
|
public void traverseInOrder(Node node) {
|
||||||
|
@ -125,12 +119,15 @@ public class BinaryTree {
|
||||||
if (node != null) {
|
if (node != null) {
|
||||||
traversePostOrder(node.left);
|
traversePostOrder(node.left);
|
||||||
traversePostOrder(node.right);
|
traversePostOrder(node.right);
|
||||||
|
|
||||||
System.out.print(" " + node.value);
|
System.out.print(" " + node.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void traverseLevelOrder() {
|
public void traverseLevelOrder() {
|
||||||
|
if (root == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Queue<Node> nodes = new LinkedList<>();
|
Queue<Node> nodes = new LinkedList<>();
|
||||||
nodes.add(root);
|
nodes.add(root);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
package com.baeldung.cipher;
|
||||||
|
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.security.cert.CertificateFactory;
|
||||||
|
import java.security.cert.X509Certificate;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
public class EncryptorUnitTest {
|
||||||
|
private String encKeyString;
|
||||||
|
private String message;
|
||||||
|
private String certificateString;
|
||||||
|
private Encryptor encryptor;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void init(){
|
||||||
|
encKeyString = "1234567890123456";
|
||||||
|
message = "This is a secret message";
|
||||||
|
encryptor = new Encryptor();
|
||||||
|
certificateString = "-----BEGIN CERTIFICATE-----\n" +
|
||||||
|
"MIICVjCCAb8CAg37MA0GCSqGSIb3DQEBBQUAMIGbMQswCQYDVQQGEwJKUDEOMAwG\n" +
|
||||||
|
"A1UECBMFVG9reW8xEDAOBgNVBAcTB0NodW8ta3UxETAPBgNVBAoTCEZyYW5rNERE\n" +
|
||||||
|
"MRgwFgYDVQQLEw9XZWJDZXJ0IFN1cHBvcnQxGDAWBgNVBAMTD0ZyYW5rNEREIFdl\n" +
|
||||||
|
"YiBDQTEjMCEGCSqGSIb3DQEJARYUc3VwcG9ydEBmcmFuazRkZC5jb20wHhcNMTIw\n" +
|
||||||
|
"ODIyMDUyNzIzWhcNMTcwODIxMDUyNzIzWjBKMQswCQYDVQQGEwJKUDEOMAwGA1UE\n" +
|
||||||
|
"CAwFVG9reW8xETAPBgNVBAoMCEZyYW5rNEREMRgwFgYDVQQDDA93d3cuZXhhbXBs\n" +
|
||||||
|
"ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMYBBrx5PlP0WNI/ZdzD\n" +
|
||||||
|
"+6Pktmurn+F2kQYbtc7XQh8/LTBvCo+P6iZoLEmUA9e7EXLRxgU1CVqeAi7QcAn9\n" +
|
||||||
|
"MwBlc8ksFJHB0rtf9pmf8Oza9E0Bynlq/4/Kb1x+d+AyhL7oK9tQwB24uHOueHi1\n" +
|
||||||
|
"C/iVv8CSWKiYe6hzN1txYe8rAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAASPdjigJ\n" +
|
||||||
|
"kXCqKWpnZ/Oc75EUcMi6HztaW8abUMlYXPIgkV2F7YanHOB7K4f7OOLjiz8DTPFf\n" +
|
||||||
|
"jC9UeuErhaA/zzWi8ewMTFZW/WshOrm3fNvcMrMLKtH534JKvcdMg6qIdjTFINIr\n" +
|
||||||
|
"evnAhf0cwULaebn+lMs8Pdl7y37+sfluVok=\n" +
|
||||||
|
"-----END CERTIFICATE-----";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenEncryptionKey_whenMessageIsPassedToEncryptor_thenMessageIsEncrypted() throws Exception {
|
||||||
|
byte[] encryptedMessage = encryptor.encryptMessage(message.getBytes(),encKeyString.getBytes());
|
||||||
|
|
||||||
|
assertThat(encryptedMessage).isNotNull();
|
||||||
|
assertThat(encryptedMessage.length % 32).isEqualTo(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenCertificateWithPublicKey_whenMessageIsPassedToEncryptor_thenMessageIsEncrypted() throws Exception {
|
||||||
|
CertificateFactory factory = CertificateFactory.getInstance("X.509");
|
||||||
|
InputStream is = new ByteArrayInputStream(certificateString.getBytes());
|
||||||
|
X509Certificate certificate = (X509Certificate) factory.generateCertificate(is);
|
||||||
|
|
||||||
|
byte[] encryptedMessage = encryptor.encryptMessage(message.getBytes(),certificate);
|
||||||
|
|
||||||
|
assertThat(encryptedMessage).isNotNull();
|
||||||
|
assertThat(encryptedMessage.length % 128).isEqualTo(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenEncryptionKey_whenMessageIsEncrypted_thenDecryptMessage() throws Exception{
|
||||||
|
byte[] encryptedMessageBytes = encryptor.encryptMessage(message.getBytes(),encKeyString.getBytes());
|
||||||
|
|
||||||
|
byte[] clearMessageBytes = encryptor.decryptMessage(encryptedMessageBytes, encKeyString.getBytes());
|
||||||
|
|
||||||
|
assertThat(message).isEqualTo(new String(clearMessageBytes));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
package com.baeldung.collection;
|
||||||
|
|
||||||
|
import java.util.ConcurrentModificationException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
|
||||||
|
import org.hamcrest.Matchers;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class WhenComparingTreeMapVsHashMap {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenInsertObjectsTreeMap_thenNaturalOrder() {
|
||||||
|
Map<Integer, String> treemap = new TreeMap<>();
|
||||||
|
treemap.put(3, "TreeMap");
|
||||||
|
treemap.put(2, "vs");
|
||||||
|
treemap.put(1, "HashMap");
|
||||||
|
Assert.assertThat(treemap.keySet(), Matchers.contains(1, 2, 3));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = NullPointerException.class)
|
||||||
|
public void whenInsertNullInTreeMap_thenException() {
|
||||||
|
Map<Integer, String> treemap = new TreeMap<>();
|
||||||
|
treemap.put(null, "NullPointerException");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenInsertObjectsHashMap_thenRandomOrder() {
|
||||||
|
Map<Integer, String> hashmap = new HashMap<>();
|
||||||
|
hashmap.put(3, "TreeMap");
|
||||||
|
hashmap.put(2, "vs");
|
||||||
|
hashmap.put(1, "HashMap");
|
||||||
|
Assert.assertThat(hashmap.keySet(), Matchers.containsInAnyOrder(1, 2, 3));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenInsertNullInHashMap_thenInsertsNull() {
|
||||||
|
Map<Integer, String> hashmap = new HashMap<>();
|
||||||
|
hashmap.put(null, null);
|
||||||
|
Assert.assertNull(hashmap.get(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenHashMapAndTreeMap_whenputDuplicates_thenOnlyUnique() {
|
||||||
|
Map<Integer, String> treeMap = new HashMap<>();
|
||||||
|
treeMap.put(1, "Baeldung");
|
||||||
|
treeMap.put(1, "Baeldung");
|
||||||
|
|
||||||
|
Assert.assertTrue(treeMap.size() == 1);
|
||||||
|
|
||||||
|
Map<Integer, String> treeMap2 = new TreeMap<>();
|
||||||
|
treeMap2.put(1, "Baeldung");
|
||||||
|
treeMap2.put(1, "Baeldung");
|
||||||
|
|
||||||
|
Assert.assertTrue(treeMap2.size() == 1);
|
||||||
|
}
|
||||||
|
}
|
|
@ -26,7 +26,6 @@ public class WhenUsingTreeSet {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
// TODO Auto-generated method stub
|
|
||||||
return id.toString();
|
return id.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -189,8 +188,14 @@ public class WhenUsingTreeSet {
|
||||||
treeSet.add(5);
|
treeSet.add(5);
|
||||||
treeSet.add(6);
|
treeSet.add(6);
|
||||||
|
|
||||||
|
Set<Integer> expectedSet = new TreeSet<>();
|
||||||
|
expectedSet.add(2);
|
||||||
|
expectedSet.add(3);
|
||||||
|
expectedSet.add(4);
|
||||||
|
expectedSet.add(5);
|
||||||
|
|
||||||
Set<Integer> subSet = treeSet.subSet(2, 6);
|
Set<Integer> subSet = treeSet.subSet(2, 6);
|
||||||
System.out.println(subSet);
|
Assert.assertEquals(expectedSet, subSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
package com.baeldung.initializationguide;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.*;
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
|
||||||
|
public class UserTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenUserInstance_whenIntializedWithNew_thenInstanceIsNotNull() {
|
||||||
|
User user = new User("Alice", 1);
|
||||||
|
assertThat(user).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenUserInstance_whenInitializedWithReflection_thenInstanceIsNotNull() throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
|
||||||
|
User user = User.class.getConstructor(String.class, int.class)
|
||||||
|
.newInstance("Alice", 2);
|
||||||
|
assertThat(user).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenUserInstance_whenCopiedWithClone_thenExactMatchIsCreated() throws CloneNotSupportedException {
|
||||||
|
User user = new User("Alice", 3);
|
||||||
|
User clonedUser = (User) user.clone();
|
||||||
|
assertThat(clonedUser).isEqualTo(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenUserInstance_whenValuesAreNotInitialized_thenUserNameAndIdReturnDefault() {
|
||||||
|
User user = new User();
|
||||||
|
assertThat(user.getName()).isNull();
|
||||||
|
assertThat(user.getId() == 0);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,71 @@
|
||||||
|
package com.baeldung.jdbc;
|
||||||
|
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.InjectMocks;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.Statement;
|
||||||
|
|
||||||
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
|
public class BatchProcessingTest {
|
||||||
|
|
||||||
|
|
||||||
|
@InjectMocks
|
||||||
|
private BatchProcessing target = new BatchProcessing();
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private Connection connection;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private Statement statement;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private PreparedStatement employeeStatement;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private PreparedStatement employeeAddressStatement;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void before(){
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void when_useStatement_thenInsertData_success() throws Exception {
|
||||||
|
Mockito.when(connection.createStatement()).thenReturn(statement);
|
||||||
|
target.useStatement();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void when_useStatement_ifThrowException_thenCatchException() throws Exception {
|
||||||
|
Mockito.when(connection.createStatement()).thenThrow(new RuntimeException());
|
||||||
|
target.useStatement();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void when_usePreparedStatement_thenInsertData_success() throws Exception {
|
||||||
|
String insertEmployeeSQL = "INSERT INTO EMPLOYEE(ID, NAME, DESIGNATION) VALUES (?,?,?);";
|
||||||
|
String insertEmployeeAddrSQL = "INSERT INTO EMP_ADDRESS(ID, EMP_ID, ADDRESS) VALUES (?,?,?);";
|
||||||
|
Mockito.when(connection.prepareStatement(insertEmployeeSQL)).thenReturn(employeeStatement);
|
||||||
|
Mockito.when(connection.prepareStatement(insertEmployeeAddrSQL)).thenReturn(employeeAddressStatement);
|
||||||
|
target.usePreparedStatement();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void when_usePreparedStatement_ifThrowException_thenCatchException() throws Exception {
|
||||||
|
String insertEmployeeSQL = "INSERT INTO EMPLOYEE(ID, NAME, DESIGNATION) VALUES (?,?,?);";
|
||||||
|
String insertEmployeeAddrSQL = "INSERT INTO EMP_ADDRESS(ID, EMP_ID, ADDRESS) VALUES (?,?,?);";
|
||||||
|
Mockito.when(connection.prepareStatement(insertEmployeeSQL)).thenReturn(employeeStatement);
|
||||||
|
Mockito.when(connection.prepareStatement(insertEmployeeAddrSQL)).thenThrow(new RuntimeException());
|
||||||
|
target.usePreparedStatement();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
package com.baeldung.tree;
|
package com.baeldung.tree;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
@ -26,6 +27,26 @@ public class BinaryTreeTest {
|
||||||
assertFalse(bt.containsNode(1));
|
assertFalse(bt.containsNode(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenABinaryTree_WhenAddingExistingElement_ThenElementIsNotAdded() {
|
||||||
|
|
||||||
|
BinaryTree bt = createBinaryTree();
|
||||||
|
|
||||||
|
int initialSize = bt.getSize();
|
||||||
|
|
||||||
|
assertTrue(bt.containsNode(3));
|
||||||
|
bt.add(3);
|
||||||
|
assertEquals(initialSize, bt.getSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenABinaryTree_WhenLookingForNonExistingElement_ThenReturnsFalse() {
|
||||||
|
|
||||||
|
BinaryTree bt = createBinaryTree();
|
||||||
|
|
||||||
|
assertFalse(bt.containsNode(99));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void givenABinaryTree_WhenDeletingElements_ThenTreeDoesNotContainThoseElements() {
|
public void givenABinaryTree_WhenDeletingElements_ThenTreeDoesNotContainThoseElements() {
|
||||||
|
|
||||||
|
@ -36,6 +57,19 @@ public class BinaryTreeTest {
|
||||||
assertFalse(bt.containsNode(9));
|
assertFalse(bt.containsNode(9));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenABinaryTree_WhenDeletingNonExistingElement_ThenTreeDoesNotDelete() {
|
||||||
|
|
||||||
|
BinaryTree bt = createBinaryTree();
|
||||||
|
|
||||||
|
int initialSize = bt.getSize();
|
||||||
|
|
||||||
|
assertFalse(bt.containsNode(99));
|
||||||
|
bt.delete(99);
|
||||||
|
assertFalse(bt.containsNode(99));
|
||||||
|
assertEquals(initialSize, bt.getSize());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void givenABinaryTree_WhenTraversingInOrder_ThenPrintValues() {
|
public void givenABinaryTree_WhenTraversingInOrder_ThenPrintValues() {
|
||||||
|
|
||||||
|
|
|
@ -105,7 +105,11 @@
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
<version>3.5.1</version>
|
<version>3.7.0</version>
|
||||||
|
<configuration>
|
||||||
|
<source>1.8</source>
|
||||||
|
<target>1.8</target>
|
||||||
|
</configuration>
|
||||||
<executions>
|
<executions>
|
||||||
<!-- Replacing default-compile as it is treated specially
|
<!-- Replacing default-compile as it is treated specially
|
||||||
by maven -->
|
by maven -->
|
||||||
|
|
|
@ -52,6 +52,7 @@
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.7.0</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<source>1.8</source>
|
<source>1.8</source>
|
||||||
<target>1.8</target>
|
<target>1.8</target>
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
## Relevant articles:
|
|
|
@ -82,7 +82,7 @@
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
<version>3.1</version>
|
<version>3.7.0</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<source>1.8</source>
|
<source>1.8</source>
|
||||||
<target>1.8</target>
|
<target>1.8</target>
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
<?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>flyway</artifactId>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<name>flyway</name>
|
||||||
|
<description>Flyway Callbacks Demo</description>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<artifactId>parent-boot-5</artifactId>
|
||||||
|
<groupId>com.baeldung</groupId>
|
||||||
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
<relativePath>../parent-boot-5</relativePath>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||||
|
<java.version>1.8</java.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.flywaydb</groupId>
|
||||||
|
<artifactId>flyway-core</artifactId>
|
||||||
|
<version>5.0.2</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-jdbc</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>mysql</groupId>
|
||||||
|
<artifactId>mysql-connector-java</artifactId>
|
||||||
|
<version>6.0.3</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.h2database</groupId>
|
||||||
|
<artifactId>h2</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.flywaydb</groupId>
|
||||||
|
<artifactId>flyway-maven-plugin</artifactId>
|
||||||
|
<version>5.0.2</version>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
|
||||||
|
</project>
|
|
@ -0,0 +1,33 @@
|
||||||
|
package com.baeldung.flywaycallbacks;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.flywaydb.core.api.MigrationInfo;
|
||||||
|
import org.flywaydb.core.api.callback.BaseFlywayCallback;
|
||||||
|
|
||||||
|
public class ExampleFlywayCallback extends BaseFlywayCallback {
|
||||||
|
|
||||||
|
private Log log = LogFactory.getLog(getClass());
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterEachMigrate(Connection connection, MigrationInfo info) {
|
||||||
|
log.info("> afterEachMigrate");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterMigrate(Connection connection) {
|
||||||
|
log.info("> afterMigrate");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beforeEachMigrate(Connection connection, MigrationInfo info) {
|
||||||
|
log.info("> beforeEachMigrate");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beforeMigrate(Connection connection) {
|
||||||
|
log.info("> beforeMigrate");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
package com.baeldung.flywaycallbacks;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
public class FlywayApplication {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(FlywayApplication.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
SELECT 1
|
|
@ -0,0 +1 @@
|
||||||
|
SELECT 1
|
|
@ -0,0 +1,5 @@
|
||||||
|
create table table_one (
|
||||||
|
id numeric,
|
||||||
|
name varchar(50),
|
||||||
|
constraint pk_table_one primary key (id)
|
||||||
|
);
|
|
@ -0,0 +1,5 @@
|
||||||
|
create table table_two (
|
||||||
|
id numeric,
|
||||||
|
name varchar(50),
|
||||||
|
constraint pk_table_two primary key (id)
|
||||||
|
);
|
|
@ -0,0 +1,19 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<configuration>
|
||||||
|
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
|
<encoder>
|
||||||
|
<pattern>%date [%thread] %-5level %logger{36} - %message%n
|
||||||
|
</pattern>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<logger name="org.springframework" level="WARN" />
|
||||||
|
<logger name="org.springframework.transaction" level="WARN" />
|
||||||
|
|
||||||
|
<!-- in order to debug some marshalling issues, this needs to be TRACE -->
|
||||||
|
<logger name="org.springframework.web.servlet.mvc" level="WARN" />
|
||||||
|
|
||||||
|
<root level="INFO">
|
||||||
|
<appender-ref ref="STDOUT" />
|
||||||
|
</root>
|
||||||
|
</configuration>
|
|
@ -0,0 +1,68 @@
|
||||||
|
package com.baeldung.flywaycallbacks;
|
||||||
|
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.flywaydb.core.Flyway;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.test.annotation.DirtiesContext;
|
||||||
|
import org.springframework.test.annotation.DirtiesContext.ClassMode;
|
||||||
|
import org.springframework.test.context.ContextConfiguration;
|
||||||
|
import org.springframework.test.context.junit4.SpringRunner;
|
||||||
|
|
||||||
|
@RunWith(SpringRunner.class)
|
||||||
|
@DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
|
||||||
|
@ContextConfiguration(classes = FlywayCallbackTestConfig.class)
|
||||||
|
public class FlywayApplicationTest {
|
||||||
|
|
||||||
|
private Log log = LogFactory.getLog(getClass());
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private DataSource dataSource;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void migrateWithNoCallbacks() {
|
||||||
|
logTestBoundary("migrateWithNoCallbacks");
|
||||||
|
Flyway flyway = new Flyway();
|
||||||
|
flyway.setDataSource(dataSource);
|
||||||
|
flyway.setLocations("db/migration");
|
||||||
|
flyway.migrate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void migrateWithJavaCallbacks() {
|
||||||
|
logTestBoundary("migrateWithJavaCallbacks");
|
||||||
|
Flyway flyway = new Flyway();
|
||||||
|
flyway.setDataSource(dataSource);
|
||||||
|
flyway.setLocations("db/migration");
|
||||||
|
flyway.setCallbacks(new ExampleFlywayCallback());
|
||||||
|
flyway.migrate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void migrateWithSqlCallbacks() {
|
||||||
|
logTestBoundary("migrateWithSqlCallbacks");
|
||||||
|
Flyway flyway = new Flyway();
|
||||||
|
flyway.setDataSource(dataSource);
|
||||||
|
flyway.setLocations("db/migration", "db/callbacks");
|
||||||
|
flyway.migrate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void migrateWithSqlAndJavaCallbacks() {
|
||||||
|
logTestBoundary("migrateWithSqlAndJavaCallbacks");
|
||||||
|
Flyway flyway = new Flyway();
|
||||||
|
flyway.setDataSource(dataSource);
|
||||||
|
flyway.setLocations("db/migration", "db/callbacks");
|
||||||
|
flyway.setCallbacks(new ExampleFlywayCallback());
|
||||||
|
flyway.migrate();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void logTestBoundary(String testName) {
|
||||||
|
System.out.println("\n");
|
||||||
|
log.info("> " + testName);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
package com.baeldung.flywaycallbacks;
|
||||||
|
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
|
||||||
|
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class FlywayCallbackTestConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public DataSource createDatasource() {
|
||||||
|
EmbeddedDatabaseBuilder dbBuilder = new EmbeddedDatabaseBuilder();
|
||||||
|
return dbBuilder.setType(EmbeddedDatabaseType.H2)
|
||||||
|
.setName("DATABASE")
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -59,6 +59,7 @@
|
||||||
<inherited>true</inherited>
|
<inherited>true</inherited>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.7.0</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<source>1.8</source>
|
<source>1.8</source>
|
||||||
<target>1.8</target>
|
<target>1.8</target>
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
<version>3.6.2</version>
|
<version>3.7.0</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<source>1.9</source>
|
<source>1.9</source>
|
||||||
<target>1.9</target>
|
<target>1.9</target>
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
<version>3.5</version>
|
<version>3.7.0</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<source>1.8</source>
|
<source>1.8</source>
|
||||||
<target>1.8</target>
|
<target>1.8</target>
|
||||||
|
|
|
@ -41,7 +41,7 @@
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
<version>3.5</version>
|
<version>3.7.0</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<source>1.8</source>
|
<source>1.8</source>
|
||||||
<target>1.8</target>
|
<target>1.8</target>
|
||||||
|
|
|
@ -39,7 +39,7 @@
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
<version>3.5</version>
|
<version>3.7.0</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<source>1.8</source>
|
<source>1.8</source>
|
||||||
<target>1.8</target>
|
<target>1.8</target>
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
<version>3.5</version>
|
<version>3.7.0</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<source>1.8</source>
|
<source>1.8</source>
|
||||||
<target>1.8</target>
|
<target>1.8</target>
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
<version>3.5</version>
|
<version>3.7.0</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<source>1.8</source>
|
<source>1.8</source>
|
||||||
<target>1.8</target>
|
<target>1.8</target>
|
||||||
|
|
|
@ -38,7 +38,7 @@
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
<version>3.6.1</version>
|
<version>3.7.0</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<source>1.8</source>
|
<source>1.8</source>
|
||||||
<target>1.8</target>
|
<target>1.8</target>
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
<version>3.5.1</version>
|
<version>3.7.0</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<source>1.8</source>
|
<source>1.8</source>
|
||||||
<target>1.8</target>
|
<target>1.8</target>
|
||||||
|
|
|
@ -52,7 +52,7 @@
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
<version>3.5.1</version>
|
<version>3.7.0</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<source>1.8</source>
|
<source>1.8</source>
|
||||||
<target>1.8</target>
|
<target>1.8</target>
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
<version>3.5</version>
|
<version>3.7.0</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<source>1.8</source>
|
<source>1.8</source>
|
||||||
<target>1.8</target>
|
<target>1.8</target>
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
<version>3.5.1</version>
|
<version>3.7.0</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<source>1.8</source>
|
<source>1.8</source>
|
||||||
<target>1.8</target>
|
<target>1.8</target>
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
<properties>
|
<properties>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<!-- Maven plugins -->
|
<!-- Maven plugins -->
|
||||||
<maven-compiler-plugin.version>3.6.0</maven-compiler-plugin.version>
|
<maven-compiler-plugin.version>3.7.0</maven-compiler-plugin.version>
|
||||||
<hibernate.version>5.2.12.Final</hibernate.version>
|
<hibernate.version>5.2.12.Final</hibernate.version>
|
||||||
<mysql.version>6.0.6</mysql.version>
|
<mysql.version>6.0.6</mysql.version>
|
||||||
<mariaDB4j.version>2.2.3</mariaDB4j.version>
|
<mariaDB4j.version>2.2.3</mariaDB4j.version>
|
||||||
|
@ -41,7 +41,7 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.h2database</groupId>
|
<groupId>com.h2database</groupId>
|
||||||
<artifactId>h2</artifactId>
|
<artifactId>h2</artifactId>
|
||||||
<version>1.4.194</version>
|
<version>1.4.196</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.hibernate</groupId>
|
<groupId>org.hibernate</groupId>
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
package com.baeldung.hibernate;
|
|
||||||
|
|
||||||
import org.hibernate.Session;
|
|
||||||
import org.hibernate.SessionFactory;
|
|
||||||
import org.hibernate.Transaction;
|
|
||||||
|
|
||||||
import com.baeldung.hibernate.pojo.Supplier;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hello world!
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class App {
|
|
||||||
public static void main(String[] args) {
|
|
||||||
try {
|
|
||||||
// NOTE: this is just for boostrap testing for multitenancy.
|
|
||||||
System.out.println("Checking the system.");
|
|
||||||
SessionFactory sessionFactory = HibernateMultiTenantUtil.getSessionFactory();
|
|
||||||
Session currentSession = sessionFactory.withOptions().tenantIdentifier("h2db1").openSession();
|
|
||||||
Transaction transaction = currentSession.getTransaction();
|
|
||||||
transaction.begin();
|
|
||||||
currentSession.createCriteria(Supplier.class).list().stream().forEach(System.out::println);
|
|
||||||
transaction.commit();
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,41 +0,0 @@
|
||||||
package com.baeldung.hibernate;
|
|
||||||
|
|
||||||
import java.sql.Connection;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import org.hibernate.engine.jdbc.connections.spi.AbstractMultiTenantConnectionProvider;
|
|
||||||
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
|
|
||||||
|
|
||||||
public class ConfigurableMultiTenantConnectionProvider extends AbstractMultiTenantConnectionProvider {
|
|
||||||
|
|
||||||
private final Map<String, ConnectionProvider> connectionProviderMap =
|
|
||||||
new HashMap<>();
|
|
||||||
|
|
||||||
|
|
||||||
public ConfigurableMultiTenantConnectionProvider(
|
|
||||||
Map<String, ConnectionProvider> connectionProviderMap) {
|
|
||||||
this.connectionProviderMap.putAll( connectionProviderMap );
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
protected ConnectionProvider getAnyConnectionProvider() {
|
|
||||||
System.out.println("Any");
|
|
||||||
return connectionProviderMap.values().iterator().next();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected ConnectionProvider selectConnectionProvider(String tenantIdentifier) {
|
|
||||||
System.out.println("Specific");
|
|
||||||
return connectionProviderMap.get( tenantIdentifier );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Connection getConnection(String tenantIdentifier) throws SQLException {
|
|
||||||
Connection connection = super.getConnection(tenantIdentifier);
|
|
||||||
// uncomment to see option 2 for SCHEMA strategy.
|
|
||||||
//connection.createStatement().execute("SET SCHEMA '" + tenantIdentifier + "'");
|
|
||||||
return connection;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,115 +0,0 @@
|
||||||
package com.baeldung.hibernate;
|
|
||||||
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Properties;
|
|
||||||
|
|
||||||
import org.hibernate.SessionFactory;
|
|
||||||
import org.hibernate.boot.Metadata;
|
|
||||||
import org.hibernate.boot.MetadataSources;
|
|
||||||
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
|
||||||
import org.hibernate.cfg.AvailableSettings;
|
|
||||||
import org.hibernate.cfg.Configuration;
|
|
||||||
import org.hibernate.cfg.Environment;
|
|
||||||
import org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl;
|
|
||||||
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
|
|
||||||
import org.hibernate.service.ServiceRegistry;
|
|
||||||
|
|
||||||
import com.baeldung.hibernate.pojo.Supplier;
|
|
||||||
|
|
||||||
public class HibernateMultiTenantUtil {
|
|
||||||
private static SessionFactory sessionFactory;
|
|
||||||
private static Map<String, ConnectionProvider> connectionProviderMap = new HashMap<>();
|
|
||||||
private static final String[] tenantDBNames = { "mydb1", "mydb2" };
|
|
||||||
|
|
||||||
public static SessionFactory getSessionFactory() throws UnsupportedTenancyException, IOException {
|
|
||||||
if (sessionFactory == null) {
|
|
||||||
// Configuration configuration = new Configuration().configure();
|
|
||||||
ServiceRegistry serviceRegistry = configureServiceRegistry();
|
|
||||||
sessionFactory = makeSessionFactory(serviceRegistry);
|
|
||||||
|
|
||||||
}
|
|
||||||
return sessionFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static SessionFactory makeSessionFactory(ServiceRegistry serviceRegistry) {
|
|
||||||
MetadataSources metadataSources = new MetadataSources(serviceRegistry);
|
|
||||||
for (Class annotatedClasses : getAnnotatedClasses()) {
|
|
||||||
metadataSources.addAnnotatedClass(annotatedClasses);
|
|
||||||
}
|
|
||||||
|
|
||||||
Metadata metadata = metadataSources.buildMetadata();
|
|
||||||
return metadata.getSessionFactoryBuilder()
|
|
||||||
.build();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Class<?>[] getAnnotatedClasses() {
|
|
||||||
return new Class<?>[] { Supplier.class };
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ServiceRegistry configureServiceRegistry() throws UnsupportedTenancyException, IOException {
|
|
||||||
|
|
||||||
// Properties properties = configuration.getProperties();
|
|
||||||
Properties properties = getProperties();
|
|
||||||
|
|
||||||
connectionProviderMap = setUpConnectionProviders(properties, tenantDBNames);
|
|
||||||
properties.put(AvailableSettings.MULTI_TENANT_CONNECTION_PROVIDER, new ConfigurableMultiTenantConnectionProvider(connectionProviderMap));
|
|
||||||
|
|
||||||
return new StandardServiceRegistryBuilder().applySettings(properties)
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Properties getProperties() throws IOException {
|
|
||||||
Properties properties = new Properties();
|
|
||||||
URL propertiesURL = Thread.currentThread()
|
|
||||||
.getContextClassLoader()
|
|
||||||
.getResource("hibernate-multitenancy.properties");
|
|
||||||
FileInputStream inputStream = new FileInputStream(propertiesURL.getFile());
|
|
||||||
properties.load(inputStream);
|
|
||||||
System.out.println("LOADED PROPERTIES FROM hibernate.properties");
|
|
||||||
|
|
||||||
return properties;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Map<String, ConnectionProvider> setUpConnectionProviders(Properties properties, String[] tenantNames) throws UnsupportedTenancyException {
|
|
||||||
Map<String, ConnectionProvider> providerMap = new HashMap<>();
|
|
||||||
for (String tenant : tenantNames) {
|
|
||||||
DriverManagerConnectionProviderImpl connectionProvider = new DriverManagerConnectionProviderImpl();
|
|
||||||
|
|
||||||
String tenantStrategy = properties.getProperty("hibernate.multiTenancy");
|
|
||||||
System.out.println("Strategy:" + tenantStrategy);
|
|
||||||
properties.put(Environment.URL, tenantUrl(properties.getProperty(Environment.URL), tenant, tenantStrategy));
|
|
||||||
System.out.println("URL:" + properties.getProperty(Environment.URL));
|
|
||||||
connectionProvider.configure(properties);
|
|
||||||
System.out.println("Tenant:" + tenant);
|
|
||||||
providerMap.put(tenant, connectionProvider);
|
|
||||||
|
|
||||||
}
|
|
||||||
System.out.println("Added connections for:");
|
|
||||||
providerMap.keySet()
|
|
||||||
.stream()
|
|
||||||
.forEach(System.out::println);
|
|
||||||
return providerMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Object tenantUrl(String originalUrl, String tenant, String tenantStrategy) throws UnsupportedTenancyException {
|
|
||||||
if (tenantStrategy.toUpperCase()
|
|
||||||
.equals("DATABASE")) {
|
|
||||||
return originalUrl.replace(DEFAULT_DB_NAME, tenant);
|
|
||||||
} else if (tenantStrategy.toUpperCase()
|
|
||||||
.equals("SCHEMA")) {
|
|
||||||
return originalUrl + String.format(SCHEMA_TOKEN, tenant);
|
|
||||||
} else {
|
|
||||||
throw new UnsupportedTenancyException("Not yet supported");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final String SCHEMA_TOKEN = ";INIT=CREATE SCHEMA IF NOT EXISTS %1$s\\;SET SCHEMA %1$s";
|
|
||||||
public static final String DEFAULT_DB_NAME = "mydb1";
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
package com.baeldung.hibernate.dao;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public interface GenericDao<T> {
|
|
||||||
|
|
||||||
void save (T entity);
|
|
||||||
void delete (T Entity);
|
|
||||||
T findByName(String name);
|
|
||||||
List<T> findAll();
|
|
||||||
void populate();
|
|
||||||
}
|
|
|
@ -1,80 +0,0 @@
|
||||||
package com.baeldung.hibernate.dao;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.hibernate.Criteria;
|
|
||||||
import org.hibernate.Session;
|
|
||||||
import org.hibernate.SessionFactory;
|
|
||||||
import org.hibernate.Transaction;
|
|
||||||
import org.hibernate.criterion.Expression;
|
|
||||||
|
|
||||||
import com.baeldung.hibernate.pojo.Supplier;
|
|
||||||
|
|
||||||
public class SupplierDao implements GenericDao<Supplier>{
|
|
||||||
private SessionFactory sessionFactory;
|
|
||||||
private String tenant;
|
|
||||||
|
|
||||||
public SupplierDao(SessionFactory sessionFactory, String tenant) {
|
|
||||||
this.sessionFactory = sessionFactory;
|
|
||||||
this.tenant = tenant;
|
|
||||||
populate();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void save(Supplier entity) {
|
|
||||||
Session session = sessionFactory.withOptions().tenantIdentifier(tenant).openSession();
|
|
||||||
session.save(entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void delete(Supplier supplier) {
|
|
||||||
Session session = sessionFactory.withOptions().tenantIdentifier(tenant).openSession();
|
|
||||||
session.delete(supplier);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Supplier findByName(String name) {
|
|
||||||
Session session = sessionFactory.withOptions().tenantIdentifier(tenant).openSession();
|
|
||||||
List<Supplier> fetchedSuppliers = session.createCriteria(Supplier.class).add(Expression.eq("name", name)).list();
|
|
||||||
if (fetchedSuppliers.size()>0) {
|
|
||||||
return fetchedSuppliers.get(0);
|
|
||||||
}else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<Supplier> findAll() {
|
|
||||||
Session session = sessionFactory.withOptions().tenantIdentifier(tenant).openSession();
|
|
||||||
return session.createCriteria(Supplier.class).list();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void populate() {
|
|
||||||
System.out.println("Init DB1");
|
|
||||||
Session session = sessionFactory.withOptions().tenantIdentifier(tenant).openSession();
|
|
||||||
Transaction transaction = session.getTransaction();
|
|
||||||
|
|
||||||
transaction.begin();
|
|
||||||
session.createSQLQuery("DROP ALL OBJECTS").executeUpdate();
|
|
||||||
session
|
|
||||||
.createSQLQuery(
|
|
||||||
"create table Supplier (id integer generated by default as identity, country varchar(255), name varchar(255), primary key (id))")
|
|
||||||
.executeUpdate();
|
|
||||||
Supplier genertedSupplier = generateEntityForTenant(tenant);
|
|
||||||
System.out.println("Inserting Supplier"+genertedSupplier);
|
|
||||||
save (genertedSupplier);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private Supplier generateEntityForTenant(String forTenant) {
|
|
||||||
if (forTenant.equals("mydb1")) {
|
|
||||||
return new Supplier ("John","USA");
|
|
||||||
}
|
|
||||||
return new Supplier ("Miller","UK");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
package com.baeldung.hibernate.interceptors;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import org.hibernate.EmptyInterceptor;
|
||||||
|
import org.hibernate.type.Type;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.baeldung.hibernate.interceptors.entity.User;
|
||||||
|
|
||||||
|
public class CustomInterceptor extends EmptyInterceptor {
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(CustomInterceptor.class);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) {
|
||||||
|
if (entity instanceof User) {
|
||||||
|
logger.info(((User) entity).toString());
|
||||||
|
}
|
||||||
|
return super.onSave(entity, id, state, propertyNames, types);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object [] previousState, String[] propertyNames, Type[] types) {
|
||||||
|
if (entity instanceof User) {
|
||||||
|
((User) entity).setLastModified(new Date());
|
||||||
|
logger.info(((User) entity).toString());
|
||||||
|
}
|
||||||
|
return super.onFlushDirty(entity, id, currentState, previousState, propertyNames, types);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,122 @@
|
||||||
|
package com.baeldung.hibernate.interceptors;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import org.hibernate.CallbackException;
|
||||||
|
import org.hibernate.EntityMode;
|
||||||
|
import org.hibernate.Interceptor;
|
||||||
|
import org.hibernate.Transaction;
|
||||||
|
import org.hibernate.type.Type;
|
||||||
|
|
||||||
|
public class CustomInterceptorImpl implements Interceptor {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onLoad(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) throws CallbackException {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) throws CallbackException {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) throws CallbackException {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDelete(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) throws CallbackException {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCollectionRecreate(Object collection, Serializable key) throws CallbackException {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCollectionRemove(Object collection, Serializable key) throws CallbackException {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCollectionUpdate(Object collection, Serializable key) throws CallbackException {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void preFlush(Iterator entities) throws CallbackException {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void postFlush(Iterator entities) throws CallbackException {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Boolean isTransient(Object entity) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int[] findDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object instantiate(String entityName, EntityMode entityMode, Serializable id) throws CallbackException {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getEntityName(Object object) throws CallbackException {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getEntity(String entityName, Serializable id) throws CallbackException {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterTransactionBegin(Transaction tx) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beforeTransactionCompletion(Transaction tx) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterTransactionCompletion(Transaction tx) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String onPrepareStatement(String sql) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,79 @@
|
||||||
|
package com.baeldung.hibernate.interceptors;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.hibernate.Interceptor;
|
||||||
|
import org.hibernate.Session;
|
||||||
|
import org.hibernate.SessionFactory;
|
||||||
|
import org.hibernate.boot.Metadata;
|
||||||
|
import org.hibernate.boot.MetadataSources;
|
||||||
|
import org.hibernate.boot.SessionFactoryBuilder;
|
||||||
|
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||||
|
import org.hibernate.service.ServiceRegistry;
|
||||||
|
|
||||||
|
import com.baeldung.hibernate.interceptors.entity.User;
|
||||||
|
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
public class HibernateUtil {
|
||||||
|
private static SessionFactory sessionFactory;
|
||||||
|
private static String PROPERTY_FILE_NAME;
|
||||||
|
|
||||||
|
public static SessionFactory getSessionFactory() throws IOException {
|
||||||
|
return getSessionFactory(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SessionFactory getSessionFactory(String propertyFileName) throws IOException {
|
||||||
|
PROPERTY_FILE_NAME = propertyFileName;
|
||||||
|
if (sessionFactory == null) {
|
||||||
|
ServiceRegistry serviceRegistry = configureServiceRegistry();
|
||||||
|
sessionFactory = getSessionFactoryBuilder(serviceRegistry).build();
|
||||||
|
}
|
||||||
|
return sessionFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SessionFactory getSessionFactoryWithInterceptor(String propertyFileName, Interceptor interceptor) throws IOException {
|
||||||
|
PROPERTY_FILE_NAME = propertyFileName;
|
||||||
|
if (sessionFactory == null) {
|
||||||
|
ServiceRegistry serviceRegistry = configureServiceRegistry();
|
||||||
|
sessionFactory = getSessionFactoryBuilder(serviceRegistry).applyInterceptor(interceptor)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
return sessionFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Session getSessionWithInterceptor(Interceptor interceptor) throws IOException {
|
||||||
|
return getSessionFactory().withOptions()
|
||||||
|
.interceptor(interceptor)
|
||||||
|
.openSession();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SessionFactoryBuilder getSessionFactoryBuilder(ServiceRegistry serviceRegistry) {
|
||||||
|
MetadataSources metadataSources = new MetadataSources(serviceRegistry);
|
||||||
|
metadataSources.addPackage("com.baeldung.hibernate.interceptors");
|
||||||
|
metadataSources.addAnnotatedClass(User.class);
|
||||||
|
|
||||||
|
Metadata metadata = metadataSources.buildMetadata();
|
||||||
|
return metadata.getSessionFactoryBuilder();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ServiceRegistry configureServiceRegistry() throws IOException {
|
||||||
|
Properties properties = getProperties();
|
||||||
|
return new StandardServiceRegistryBuilder().applySettings(properties)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Properties getProperties() throws IOException {
|
||||||
|
Properties properties = new Properties();
|
||||||
|
URL propertiesURL = Thread.currentThread()
|
||||||
|
.getContextClassLoader()
|
||||||
|
.getResource(StringUtils.defaultString(PROPERTY_FILE_NAME, "hibernate-interceptors.properties"));
|
||||||
|
try (FileInputStream inputStream = new FileInputStream(propertiesURL.getFile())) {
|
||||||
|
properties.load(inputStream);
|
||||||
|
}
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
package com.baeldung.hibernate.interceptors.entity;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import javax.persistence.Basic;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.GenerationType;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.Temporal;
|
||||||
|
import javax.persistence.TemporalType;
|
||||||
|
|
||||||
|
@Entity(name = "hbi_user")
|
||||||
|
public class User {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.SEQUENCE)
|
||||||
|
private long id;
|
||||||
|
private String name;
|
||||||
|
private String about;
|
||||||
|
@Basic
|
||||||
|
@Temporal(TemporalType.DATE)
|
||||||
|
private Date lastModified;
|
||||||
|
|
||||||
|
public User() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public User(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getLastModified() {
|
||||||
|
return lastModified;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLastModified(Date lastModified) {
|
||||||
|
this.lastModified = lastModified;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAbout() {
|
||||||
|
return about;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAbout(String about) {
|
||||||
|
this.about = about;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format("ID: %d\nName: %s\nLast Modified: %s\nAbout: %s\n", getId(), getName(), getLastModified(), getAbout());
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,67 +0,0 @@
|
||||||
package com.baeldung.hibernate.pojo;
|
|
||||||
// Generated Feb 9, 2017 11:31:36 AM by Hibernate Tools 5.1.0.Final
|
|
||||||
|
|
||||||
import javax.persistence.Entity;
|
|
||||||
import javax.persistence.GeneratedValue;
|
|
||||||
import javax.persistence.GenerationType;
|
|
||||||
import javax.persistence.Id;
|
|
||||||
import javax.persistence.Table;
|
|
||||||
|
|
||||||
import org.junit.runners.Suite.SuiteClasses;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Suppliers generated by hbm2java
|
|
||||||
*/
|
|
||||||
@Entity(name = "Supplier")
|
|
||||||
@Table(name ="Supplier")
|
|
||||||
public class Supplier implements java.io.Serializable {
|
|
||||||
|
|
||||||
@Id
|
|
||||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
|
||||||
private Integer id;
|
|
||||||
private String name;
|
|
||||||
private String country;
|
|
||||||
|
|
||||||
public Supplier() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public Supplier(String name, String country) {
|
|
||||||
this.name = name;
|
|
||||||
this.country = country;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getId() {
|
|
||||||
return this.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setId(Integer id) {
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return this.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setName(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getCountry() {
|
|
||||||
return this.country;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCountry(String country) {
|
|
||||||
this.country = country;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return new StringBuffer().append("[").append(id).append(",").append(name).append(",").append(country).append("]").toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object obj) {
|
|
||||||
return name.equals(((Supplier) obj).getName());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,30 +0,0 @@
|
||||||
package com.baeldung.hibernate;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import org.hibernate.SessionFactory;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import com.baeldung.hibernate.dao.SupplierDao;
|
|
||||||
import com.baeldung.hibernate.pojo.Supplier;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertNull;;
|
|
||||||
|
|
||||||
public class MultiTenantDaoHibernateIntegrationTest {
|
|
||||||
@Test
|
|
||||||
public void givenDBMode_whenFetchingSuppliersByName_thenChecking() throws UnsupportedTenancyException, IOException {
|
|
||||||
SessionFactory sessionFactory = HibernateMultiTenantUtil.getSessionFactory();
|
|
||||||
|
|
||||||
SupplierDao myDb1Dao = new SupplierDao(sessionFactory, "mydb1");
|
|
||||||
Supplier db1SupplierName = myDb1Dao.findByName("John");
|
|
||||||
|
|
||||||
// finding the same supplier name in another tenant
|
|
||||||
// and we should not be able to find in there and both dbs are different.
|
|
||||||
SupplierDao myDb2Dao = new SupplierDao(sessionFactory, "mydb2");
|
|
||||||
Supplier db2SupplierName = myDb2Dao.findByName(db1SupplierName.getName());
|
|
||||||
|
|
||||||
assertNull(db2SupplierName);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
package com.baeldung.hibernate.interceptors;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
import org.hibernate.Session;
|
||||||
|
import org.hibernate.SessionFactory;
|
||||||
|
import org.hibernate.Transaction;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import com.baeldung.hibernate.interceptors.entity.User;
|
||||||
|
|
||||||
|
public class HibernateInterceptorTest {
|
||||||
|
private static SessionFactory sessionFactory;
|
||||||
|
private static Serializable userId;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void init() throws IOException {
|
||||||
|
sessionFactory = HibernateUtil.getSessionFactoryWithInterceptor(null, new CustomInterceptor());
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void finish() {
|
||||||
|
if(userId != null) {
|
||||||
|
Session session = sessionFactory.getCurrentSession();
|
||||||
|
Transaction transaction = session.beginTransaction();
|
||||||
|
User user = session.load(User.class, userId);
|
||||||
|
if(user != null) {
|
||||||
|
session.delete(user);
|
||||||
|
}
|
||||||
|
transaction.commit();
|
||||||
|
session.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenHibernateInterceptorAndSessionScoped_whenUserCreated_shouldSucceed() {
|
||||||
|
Session session = sessionFactory.withOptions().interceptor(new CustomInterceptor()).openSession();
|
||||||
|
User user = new User("Benjamin Franklin");
|
||||||
|
Transaction transaction = session.beginTransaction();
|
||||||
|
userId = session.save(user);
|
||||||
|
transaction.commit();
|
||||||
|
session.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenHibernateInterceptorAndSessionFactoryScoped_whenUserModified_shouldSucceed() {
|
||||||
|
Session session = sessionFactory.openSession();
|
||||||
|
Transaction transaction = session.beginTransaction();
|
||||||
|
User user = session.load(User.class, userId);
|
||||||
|
if(user != null) {
|
||||||
|
user.setAbout("I am a scientist.");
|
||||||
|
session.update(user);
|
||||||
|
}
|
||||||
|
transaction.commit();
|
||||||
|
session.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
package com.baeldung.hibernate.multitenancy;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
|
||||||
|
@Entity(name = "Car")
|
||||||
|
@Table(name = "Car")
|
||||||
|
public class Car implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1015320564683423342L;
|
||||||
|
|
||||||
|
private String brand;
|
||||||
|
|
||||||
|
@Id
|
||||||
|
public String getBrand() {
|
||||||
|
return brand;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBrand(String brand) {
|
||||||
|
this.brand = brand;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,104 @@
|
||||||
|
package com.baeldung.hibernate.multitenancy;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import org.hibernate.Session;
|
||||||
|
import org.hibernate.SessionFactory;
|
||||||
|
import org.hibernate.Transaction;
|
||||||
|
import org.hibernate.boot.MetadataSources;
|
||||||
|
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||||
|
import org.hibernate.cfg.AvailableSettings;
|
||||||
|
import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
|
||||||
|
import org.hibernate.service.ServiceRegistry;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
|
import com.baeldung.hibernate.multitenancy.database.TenantIdNames;
|
||||||
|
|
||||||
|
public abstract class MultitenancyIntegrationTest {
|
||||||
|
|
||||||
|
public abstract String getPropertyFile();
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private CurrentTenantIdentifierResolver currentTenantIdentifierResolver;
|
||||||
|
|
||||||
|
private SessionFactory sessionFactory;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup() throws IOException {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
|
||||||
|
Mockito.when(currentTenantIdentifierResolver.validateExistingCurrentSessions())
|
||||||
|
.thenReturn(false);
|
||||||
|
|
||||||
|
Properties properties = getHibernateProperties();
|
||||||
|
properties.put(AvailableSettings.MULTI_TENANT_IDENTIFIER_RESOLVER, currentTenantIdentifierResolver);
|
||||||
|
|
||||||
|
sessionFactory = buildSessionFactory(properties);
|
||||||
|
|
||||||
|
initTenant(TenantIdNames.MYDB1);
|
||||||
|
initTenant(TenantIdNames.MYDB2);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void initTenant(String tenantId) {
|
||||||
|
whenCurrentTenantIs(tenantId);
|
||||||
|
createCarTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void whenCurrentTenantIs(String tenantId) {
|
||||||
|
Mockito.when(currentTenantIdentifierResolver.resolveCurrentTenantIdentifier())
|
||||||
|
.thenReturn(tenantId);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void whenAddCar(String brand) {
|
||||||
|
Session session = sessionFactory.openSession();
|
||||||
|
Transaction tx = session.beginTransaction();
|
||||||
|
Car car = new Car();
|
||||||
|
car.setBrand(brand);
|
||||||
|
session.save(car);
|
||||||
|
tx.commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void thenCarFound(String brand) {
|
||||||
|
Session session = sessionFactory.openSession();
|
||||||
|
assertNotNull(session.get(Car.class, brand));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void thenCarNotFound(String brand) {
|
||||||
|
Session session = sessionFactory.openSession();
|
||||||
|
assertNull(session.get(Car.class, brand));
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
private void createCarTable() {
|
||||||
|
Session session = sessionFactory.openSession();
|
||||||
|
Transaction tx = session.beginTransaction();
|
||||||
|
session.createSQLQuery("drop table Car if exists")
|
||||||
|
.executeUpdate();
|
||||||
|
session.createSQLQuery("create table Car (brand varchar(255) primary key)")
|
||||||
|
.executeUpdate();
|
||||||
|
tx.commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Properties getHibernateProperties() throws IOException {
|
||||||
|
Properties properties = new Properties();
|
||||||
|
properties.load(getClass().getResourceAsStream(getPropertyFile()));
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SessionFactory buildSessionFactory(Properties properties) {
|
||||||
|
ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings(properties)
|
||||||
|
.build();
|
||||||
|
MetadataSources metadataSources = new MetadataSources(serviceRegistry);
|
||||||
|
metadataSources.addAnnotatedClass(Car.class);
|
||||||
|
return metadataSources.buildMetadata()
|
||||||
|
.buildSessionFactory();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
package com.baeldung.hibernate.multitenancy.database;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import com.baeldung.hibernate.multitenancy.MultitenancyIntegrationTest;
|
||||||
|
|
||||||
|
public class DatabaseApproachMultitenancyIntegrationTest extends MultitenancyIntegrationTest {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPropertyFile() {
|
||||||
|
return "/hibernate-database-multitenancy.properties";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenDatabaseApproach_whenAddingEntries_thenOnlyAddedToConcreteDatabase() throws IOException {
|
||||||
|
whenCurrentTenantIs(TenantIdNames.MYDB1);
|
||||||
|
whenAddCar("myCar");
|
||||||
|
thenCarFound("myCar");
|
||||||
|
whenCurrentTenantIs(TenantIdNames.MYDB2);
|
||||||
|
thenCarNotFound("myCar");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
package com.baeldung.hibernate.multitenancy.database;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl;
|
||||||
|
import org.hibernate.engine.jdbc.connections.spi.AbstractMultiTenantConnectionProvider;
|
||||||
|
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
|
||||||
|
|
||||||
|
@SuppressWarnings("serial")
|
||||||
|
public class MapMultiTenantConnectionProvider extends AbstractMultiTenantConnectionProvider {
|
||||||
|
|
||||||
|
private final Map<String, ConnectionProvider> connectionProviderMap = new HashMap<>();
|
||||||
|
|
||||||
|
public MapMultiTenantConnectionProvider() throws IOException {
|
||||||
|
initConnectionProviderForTenant(TenantIdNames.MYDB1);
|
||||||
|
initConnectionProviderForTenant(TenantIdNames.MYDB2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ConnectionProvider getAnyConnectionProvider() {
|
||||||
|
return connectionProviderMap.values()
|
||||||
|
.iterator()
|
||||||
|
.next();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ConnectionProvider selectConnectionProvider(String tenantIdentifier) {
|
||||||
|
return connectionProviderMap.get(tenantIdentifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initConnectionProviderForTenant(String tenantId) throws IOException {
|
||||||
|
Properties properties = new Properties();
|
||||||
|
properties.load(getClass().getResourceAsStream(String.format("/hibernate-database-%s.properties", tenantId)));
|
||||||
|
DriverManagerConnectionProviderImpl connectionProvider = new DriverManagerConnectionProviderImpl();
|
||||||
|
connectionProvider.configure(properties);
|
||||||
|
this.connectionProviderMap.put(tenantId, connectionProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
package com.baeldung.hibernate.multitenancy.database;
|
||||||
|
|
||||||
|
public class TenantIdNames {
|
||||||
|
public static final String MYDB1 = "mydb1";
|
||||||
|
public static final String MYDB2 = "mydb2";
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
package com.baeldung.hibernate.multitenancy.schema;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import com.baeldung.hibernate.multitenancy.MultitenancyIntegrationTest;
|
||||||
|
import com.baeldung.hibernate.multitenancy.database.TenantIdNames;
|
||||||
|
|
||||||
|
public class SchemaApproachMultitenancyIntegrationTest extends MultitenancyIntegrationTest {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPropertyFile() {
|
||||||
|
return "/hibernate-schema-multitenancy.properties";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenSchemaApproach_whenAddingEntries_thenOnlyAddedToConcreteSchema() throws IOException {
|
||||||
|
whenCurrentTenantIs(TenantIdNames.MYDB1);
|
||||||
|
whenAddCar("Ferrari");
|
||||||
|
thenCarFound("Ferrari");
|
||||||
|
whenCurrentTenantIs(TenantIdNames.MYDB2);
|
||||||
|
thenCarNotFound("Ferrari");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
package com.baeldung.hibernate.multitenancy.schema;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl;
|
||||||
|
import org.hibernate.engine.jdbc.connections.spi.AbstractMultiTenantConnectionProvider;
|
||||||
|
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
|
||||||
|
import org.junit.Assert;
|
||||||
|
|
||||||
|
@SuppressWarnings("serial")
|
||||||
|
public class SchemaMultiTenantConnectionProvider extends AbstractMultiTenantConnectionProvider {
|
||||||
|
|
||||||
|
private final ConnectionProvider connectionProvider = initConnectionProvider();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ConnectionProvider getAnyConnectionProvider() {
|
||||||
|
return connectionProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ConnectionProvider selectConnectionProvider(String tenantIdentifier) {
|
||||||
|
return connectionProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Connection getConnection(String tenantIdentifier) throws SQLException {
|
||||||
|
Connection connection = super.getConnection(tenantIdentifier);
|
||||||
|
connection.createStatement()
|
||||||
|
.execute(String.format("SET SCHEMA %s;", tenantIdentifier));
|
||||||
|
return connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ConnectionProvider initConnectionProvider() {
|
||||||
|
Properties properties = new Properties();
|
||||||
|
try {
|
||||||
|
properties.load(getClass().getResourceAsStream("/hibernate-schema-multitenancy.properties"));
|
||||||
|
} catch (IOException e) {
|
||||||
|
Assert.fail("Error loading resource. Cause: " + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
DriverManagerConnectionProviderImpl connectionProvider = new DriverManagerConnectionProviderImpl();
|
||||||
|
connectionProvider.configure(properties);
|
||||||
|
return connectionProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
package com.baeldung.hibernate.multitenancy.schema;
|
||||||
|
|
||||||
|
public class TenantIdNames {
|
||||||
|
public static final String MYDB1 = "mydb1";
|
||||||
|
public static final String MYDB2 = "mydb2";
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
hibernate.multiTenancy=DATABASE
|
||||||
|
hibernate.multi_tenant_connection_provider=com.baeldung.hibernate.multitenancy.database.MapMultiTenantConnectionProvider
|
|
@ -0,0 +1,4 @@
|
||||||
|
hibernate.connection.driver_class=org.h2.Driver
|
||||||
|
hibernate.connection.url=jdbc:h2:mem:mydb1;DB_CLOSE_DELAY=-1
|
||||||
|
hibernate.connection.username=sa
|
||||||
|
hibernate.dialect=org.hibernate.dialect.H2Dialect
|
|
@ -0,0 +1,4 @@
|
||||||
|
hibernate.connection.driver_class=org.h2.Driver
|
||||||
|
hibernate.connection.url=jdbc:h2:mem:mydb2;DB_CLOSE_DELAY=-1
|
||||||
|
hibernate.connection.username=sa
|
||||||
|
hibernate.dialect=org.hibernate.dialect.H2Dialect
|
|
@ -6,4 +6,5 @@ jdbc.password=
|
||||||
|
|
||||||
hibernate.dialect=org.hibernate.dialect.H2Dialect
|
hibernate.dialect=org.hibernate.dialect.H2Dialect
|
||||||
hibernate.show_sql=true
|
hibernate.show_sql=true
|
||||||
hibernate.multiTenancy=DATABASE
|
hibernate.hbm2ddl.auto=create-drop
|
||||||
|
hibernate.current_session_context_class=org.hibernate.context.internal.ThreadLocalSessionContext
|
|
@ -0,0 +1,7 @@
|
||||||
|
hibernate.connection.driver_class=org.h2.Driver
|
||||||
|
hibernate.connection.url=jdbc:h2:mem:mydb1;DB_CLOSE_DELAY=-1;INIT=CREATE SCHEMA IF NOT EXISTS MYDB1\\;CREATE SCHEMA IF NOT EXISTS MYDB2\\;
|
||||||
|
hibernate.connection.username=sa
|
||||||
|
hibernate.connection.autocommit=true
|
||||||
|
hibernate.dialect=org.hibernate.dialect.H2Dialect
|
||||||
|
hibernate.multiTenancy=SCHEMA
|
||||||
|
hibernate.multi_tenant_connection_provider=com.baeldung.hibernate.multitenancy.schema.SchemaMultiTenantConnectionProvider
|
|
@ -0,0 +1,17 @@
|
||||||
|
## Influx SDK Tutorial Project
|
||||||
|
|
||||||
|
### Relevant Article:
|
||||||
|
- [Introduction to using InfluxDB with Java](http://www.baeldung.com/using-influxdb-with-java/)
|
||||||
|
|
||||||
|
### Overview
|
||||||
|
This Maven project contains the Java code for the article linked above.
|
||||||
|
|
||||||
|
### Package Organization
|
||||||
|
Java classes for the intro tutorial are in the
|
||||||
|
org.baeldung.influxdb package.
|
||||||
|
|
||||||
|
|
||||||
|
### Running the tests
|
||||||
|
The test class expects an InfluxDB server to be available on localhost, at the default port of 8086 and with the default "admin" credentials.
|
||||||
|
|
||||||
|
```
|
|
@ -0,0 +1,44 @@
|
||||||
|
<?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>influxdb</artifactId>
|
||||||
|
<version>0.1-SNAPSHOT</version>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
<name>influxdb</name>
|
||||||
|
<description>InfluxDB SDK Tutorial</description>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>com.baeldung</groupId>
|
||||||
|
<artifactId>parent-modules</artifactId>
|
||||||
|
<version>1.0.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.influxdb</groupId>
|
||||||
|
<artifactId>influxdb-java</artifactId>
|
||||||
|
<version>${influxdb.sdk.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
<!-- Check for the most recent available version: https://projectlombok.org/changelog.html -->
|
||||||
|
<version>${lombok.version}</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<java.version>1.8</java.version>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<influxdb.sdk.version>2.8</influxdb.sdk.version>
|
||||||
|
<lombok.version>1.16.18</lombok.version>
|
||||||
|
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
</project>
|
|
@ -0,0 +1,28 @@
|
||||||
|
package com.baeldung.influxdb;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import org.influxdb.annotation.Column;
|
||||||
|
import org.influxdb.annotation.Measurement;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Measurement(name = "memory")
|
||||||
|
public class MemoryPoint {
|
||||||
|
|
||||||
|
@Column(name = "time")
|
||||||
|
private Instant time;
|
||||||
|
|
||||||
|
@Column(name = "name")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Column(name = "free")
|
||||||
|
private Long free;
|
||||||
|
|
||||||
|
@Column(name = "used")
|
||||||
|
private Long used;
|
||||||
|
|
||||||
|
@Column(name = "buffer")
|
||||||
|
private Long buffer;
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,179 @@
|
||||||
|
package com.baeldung.influxdb;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.influxdb.InfluxDB;
|
||||||
|
import org.influxdb.InfluxDBFactory;
|
||||||
|
import org.influxdb.InfluxDBIOException;
|
||||||
|
import org.influxdb.dto.*;
|
||||||
|
import org.influxdb.impl.InfluxDBResultMapper;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import static junit.framework.TestCase.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class InfluxDBConnectionLiveTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenCorrectInfoDatabaseConnects() {
|
||||||
|
|
||||||
|
InfluxDB connection = connectDatabase();
|
||||||
|
assertTrue(pingServer(connection));
|
||||||
|
}
|
||||||
|
|
||||||
|
private InfluxDB connectDatabase() {
|
||||||
|
|
||||||
|
// Connect to database assumed on localhost with default credentials.
|
||||||
|
return InfluxDBFactory.connect("http://127.0.0.1:8086", "admin", "admin");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean pingServer(InfluxDB influxDB) {
|
||||||
|
try {
|
||||||
|
// Ping and check for version string
|
||||||
|
Pong response = influxDB.ping();
|
||||||
|
if (response.getVersion().equalsIgnoreCase("unknown")) {
|
||||||
|
log.error("Error pinging server.");
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
log.info("Database version: {}", response.getVersion());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch (InfluxDBIOException idbo) {
|
||||||
|
log.error("Exception while pinging database: ", idbo);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenDatabaseCreatedDatabaseChecksOk() {
|
||||||
|
|
||||||
|
InfluxDB connection = connectDatabase();
|
||||||
|
|
||||||
|
// Create "baeldung and check for it
|
||||||
|
connection.createDatabase("baeldung");
|
||||||
|
assertTrue(connection.databaseExists("baeldung"));
|
||||||
|
|
||||||
|
// Verify that nonsense databases are not there
|
||||||
|
assertFalse(connection.databaseExists("foobar"));
|
||||||
|
|
||||||
|
// Drop "baeldung" and check again
|
||||||
|
connection.deleteDatabase("baeldung");
|
||||||
|
assertFalse(connection.databaseExists("baeldung"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenPointsWrittenPointsExists() throws Exception {
|
||||||
|
|
||||||
|
InfluxDB connection = connectDatabase();
|
||||||
|
|
||||||
|
String dbName = "baeldung";
|
||||||
|
connection.createDatabase(dbName);
|
||||||
|
|
||||||
|
// Need a retention policy before we can proceed
|
||||||
|
connection.createRetentionPolicy("defaultPolicy", "baeldung", "30d", 1, true);
|
||||||
|
|
||||||
|
// Since we are doing a batch thread, we need to set this as a default
|
||||||
|
connection.setRetentionPolicy("defaultPolicy");
|
||||||
|
|
||||||
|
// Enable batch mode
|
||||||
|
connection.enableBatch(10, 10, TimeUnit.MILLISECONDS);
|
||||||
|
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
Point point = Point.measurement("memory")
|
||||||
|
.time(System.currentTimeMillis(), TimeUnit.MILLISECONDS)
|
||||||
|
.addField("name", "server1")
|
||||||
|
.addField("free", 4743656L)
|
||||||
|
.addField("used", 1015096L)
|
||||||
|
.addField("buffer", 1010467L)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
connection.write(dbName, "defaultPolicy", point);
|
||||||
|
Thread.sleep(2);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unfortunately, the sleep inside the loop doesn't always add enough time to insure
|
||||||
|
// that Influx's batch thread flushes all of the writes and this sometimes fails without
|
||||||
|
// another brief pause.
|
||||||
|
Thread.sleep(10);
|
||||||
|
|
||||||
|
List<MemoryPoint> memoryPointList = getPoints(connection, "Select * from memory", "baeldung");
|
||||||
|
|
||||||
|
assertEquals(10, memoryPointList.size());
|
||||||
|
|
||||||
|
// Turn off batch and clean up
|
||||||
|
connection.disableBatch();
|
||||||
|
connection.deleteDatabase("baeldung");
|
||||||
|
connection.close();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<MemoryPoint> getPoints(InfluxDB connection, String query, String databaseName) {
|
||||||
|
|
||||||
|
// Run the query
|
||||||
|
Query queryObject = new Query(query, databaseName);
|
||||||
|
QueryResult queryResult = connection.query(queryObject);
|
||||||
|
|
||||||
|
// Map it
|
||||||
|
InfluxDBResultMapper resultMapper = new InfluxDBResultMapper();
|
||||||
|
return resultMapper.toPOJO(queryResult, MemoryPoint.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenBatchWrittenBatchExists() {
|
||||||
|
|
||||||
|
InfluxDB connection = connectDatabase();
|
||||||
|
|
||||||
|
String dbName = "baeldung";
|
||||||
|
connection.createDatabase(dbName);
|
||||||
|
|
||||||
|
// Need a retention policy before we can proceed
|
||||||
|
// Since we are doing batches, we need not set it
|
||||||
|
connection.createRetentionPolicy("defaultPolicy", "baeldung", "30d", 1, true);
|
||||||
|
|
||||||
|
|
||||||
|
BatchPoints batchPoints = BatchPoints
|
||||||
|
.database(dbName)
|
||||||
|
.retentionPolicy("defaultPolicy")
|
||||||
|
.build();
|
||||||
|
Point point1 = Point.measurement("memory")
|
||||||
|
.time(System.currentTimeMillis(), TimeUnit.MILLISECONDS)
|
||||||
|
.addField("free", 4743656L)
|
||||||
|
.addField("used", 1015096L)
|
||||||
|
.addField("buffer", 1010467L)
|
||||||
|
.build();
|
||||||
|
Point point2 = Point.measurement("memory")
|
||||||
|
.time(System.currentTimeMillis() - 100, TimeUnit.MILLISECONDS)
|
||||||
|
.addField("free", 4743696L)
|
||||||
|
.addField("used", 1016096L)
|
||||||
|
.addField("buffer", 1008467L)
|
||||||
|
.build();
|
||||||
|
batchPoints.point(point1);
|
||||||
|
batchPoints.point(point2);
|
||||||
|
connection.write(batchPoints);
|
||||||
|
|
||||||
|
List<MemoryPoint> memoryPointList = getPoints(connection, "Select * from memory", "baeldung");
|
||||||
|
|
||||||
|
assertEquals(2, memoryPointList.size());
|
||||||
|
assertTrue(4743696L == memoryPointList.get(0).getFree());
|
||||||
|
|
||||||
|
|
||||||
|
memoryPointList = getPoints(connection, "Select * from memory order by time desc", "baeldung");
|
||||||
|
|
||||||
|
assertEquals(2, memoryPointList.size());
|
||||||
|
assertTrue(4743656L == memoryPointList.get(0).getFree());
|
||||||
|
|
||||||
|
// Clean up database
|
||||||
|
connection.deleteDatabase("baeldung");
|
||||||
|
connection.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<configuration>
|
||||||
|
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
|
<encoder>
|
||||||
|
<pattern>web - %date [%thread] %-5level %logger{36} - %message%n
|
||||||
|
</pattern>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<root level="INFO">
|
||||||
|
<appender-ref ref="STDOUT" />
|
||||||
|
</root>
|
||||||
|
</configuration>
|
|
@ -41,6 +41,7 @@
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<version>3.7.0</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<target>1.8</target>
|
<target>1.8</target>
|
||||||
<target>1.8</target>
|
<target>1.8</target>
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue