Merge branch 'master' of https://github.com/eugenp/tutorials into task/BAEL-9709
This commit is contained in:
commit
bbc4cdd3f7
@ -7,7 +7,7 @@ public class BubbleSort {
|
|||||||
void bubbleSort(Integer[] arr) {
|
void bubbleSort(Integer[] arr) {
|
||||||
int n = arr.length;
|
int n = arr.length;
|
||||||
IntStream.range(0, n - 1)
|
IntStream.range(0, n - 1)
|
||||||
.flatMap(i -> IntStream.range(i + 1, n - i))
|
.flatMap(i -> IntStream.range(1, n - i))
|
||||||
.forEach(j -> {
|
.forEach(j -> {
|
||||||
if (arr[j - 1] > arr[j]) {
|
if (arr[j - 1] > arr[j]) {
|
||||||
int temp = arr[j];
|
int temp = arr[j];
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package com.baeldung.algorithms.bubblesort;
|
package com.baeldung.algorithms.bubblesort;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
public class BubbleSortUnitTest {
|
public class BubbleSortUnitTest {
|
||||||
|
|
||||||
|
@ -1,13 +1,20 @@
|
|||||||
package com.baeldung.java8;
|
package com.baeldung.java8;
|
||||||
|
|
||||||
|
import java.util.ArrayDeque;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Queue;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
public class Java8ForEachUnitTest {
|
public class Java8ForEachUnitTest {
|
||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(Java8ForEachUnitTest.class);
|
private static final Logger LOG = LoggerFactory.getLogger(Java8ForEachUnitTest.class);
|
||||||
@ -29,8 +36,18 @@ public class Java8ForEachUnitTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Java 8 - forEach
|
// Java 8 - forEach
|
||||||
LOG.debug("--- forEach method ---");
|
names.forEach(name -> {
|
||||||
names.forEach(name -> LOG.debug(name));
|
System.out.println(name);
|
||||||
|
});
|
||||||
|
|
||||||
|
LOG.debug("--- Print Consumer ---");
|
||||||
|
Consumer<String> printConsumer = new Consumer<String>() {
|
||||||
|
public void accept(String name) {
|
||||||
|
System.out.println(name);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
names.forEach(printConsumer);
|
||||||
|
|
||||||
// Anonymous inner class that implements Consumer interface
|
// Anonymous inner class that implements Consumer interface
|
||||||
LOG.debug("--- Anonymous inner class ---");
|
LOG.debug("--- Anonymous inner class ---");
|
||||||
@ -40,17 +57,55 @@ public class Java8ForEachUnitTest {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Create a Consumer implementation to then use in a forEach method
|
// Java 8 - forEach - Lambda Syntax
|
||||||
Consumer<String> consumerNames = name -> {
|
LOG.debug("--- forEach method ---");
|
||||||
LOG.debug(name);
|
names.forEach(name -> LOG.debug(name));
|
||||||
};
|
|
||||||
LOG.debug("--- Implementation of Consumer interface ---");
|
|
||||||
names.forEach(consumerNames);
|
|
||||||
|
|
||||||
// Print elements using a Method Reference
|
// Java 8 - forEach - Print elements using a Method Reference
|
||||||
LOG.debug("--- Method Reference ---");
|
LOG.debug("--- Method Reference ---");
|
||||||
names.forEach(LOG::debug);
|
names.forEach(LOG::debug);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenList_thenIterateAndPrintResults() {
|
||||||
|
List<String> names = Arrays.asList("Larry", "Steve", "James");
|
||||||
|
|
||||||
|
names.forEach(System.out::println);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenSet_thenIterateAndPrintResults() {
|
||||||
|
Set<String> uniqueNames = new HashSet<>(Arrays.asList("Larry", "Steve", "James"));
|
||||||
|
|
||||||
|
uniqueNames.forEach(System.out::println);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenQueue_thenIterateAndPrintResults() {
|
||||||
|
Queue<String> namesQueue = new ArrayDeque<>(Arrays.asList("Larry", "Steve", "James"));
|
||||||
|
|
||||||
|
namesQueue.forEach(System.out::println);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenMap_thenIterateAndPrintResults() {
|
||||||
|
Map<Integer, String> namesMap = new HashMap<>();
|
||||||
|
namesMap.put(1, "Larry");
|
||||||
|
namesMap.put(2, "Steve");
|
||||||
|
namesMap.put(3, "James");
|
||||||
|
|
||||||
|
namesMap.entrySet()
|
||||||
|
.forEach(entry -> System.out.println(entry.getKey() + " " + entry.getValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenMap_whenUsingBiConsumer_thenIterateAndPrintResults2() {
|
||||||
|
Map<Integer, String> namesMap = new HashMap<>();
|
||||||
|
namesMap.put(1, "Larry");
|
||||||
|
namesMap.put(2, "Steve");
|
||||||
|
namesMap.put(3, "James");
|
||||||
|
|
||||||
|
namesMap.forEach((key, value) -> System.out.println(key + " " + value));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -154,6 +154,12 @@
|
|||||||
<artifactId>async-http-client</artifactId>
|
<artifactId>async-http-client</artifactId>
|
||||||
<version>${async-http-client.version}</version>
|
<version>${async-http-client.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.opencsv</groupId>
|
||||||
|
<artifactId>opencsv</artifactId>
|
||||||
|
<version>${opencsv.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
@ -247,7 +253,7 @@
|
|||||||
<protonpack.version>1.13</protonpack.version>
|
<protonpack.version>1.13</protonpack.version>
|
||||||
<streamex.version>0.6.5</streamex.version>
|
<streamex.version>0.6.5</streamex.version>
|
||||||
<vavr.version>0.9.0</vavr.version>
|
<vavr.version>0.9.0</vavr.version>
|
||||||
|
<opencsv.version>4.1</opencsv.version>
|
||||||
<!-- testing -->
|
<!-- testing -->
|
||||||
<assertj.version>3.6.1</assertj.version>
|
<assertj.version>3.6.1</assertj.version>
|
||||||
<avaitility.version>1.7.0</avaitility.version>
|
<avaitility.version>1.7.0</avaitility.version>
|
||||||
|
@ -9,13 +9,13 @@ import java.util.zip.ZipInputStream;
|
|||||||
|
|
||||||
public class UnzipFile {
|
public class UnzipFile {
|
||||||
public static void main(final String[] args) throws IOException {
|
public static void main(final String[] args) throws IOException {
|
||||||
final String fileZip = "src/main/resources/compressed.zip";
|
final String fileZip = "src/main/resources/unzipTest/compressed.zip";
|
||||||
|
final File destDir = new File("src/main/resources/unzipTest");
|
||||||
final byte[] buffer = new byte[1024];
|
final byte[] buffer = new byte[1024];
|
||||||
final ZipInputStream zis = new ZipInputStream(new FileInputStream(fileZip));
|
final ZipInputStream zis = new ZipInputStream(new FileInputStream(fileZip));
|
||||||
ZipEntry zipEntry = zis.getNextEntry();
|
ZipEntry zipEntry = zis.getNextEntry();
|
||||||
while (zipEntry != null) {
|
while (zipEntry != null) {
|
||||||
final String fileName = zipEntry.getName();
|
final File newFile = newFile(destDir, zipEntry);
|
||||||
final File newFile = new File("src/main/resources/unzipTest/" + fileName);
|
|
||||||
final FileOutputStream fos = new FileOutputStream(newFile);
|
final FileOutputStream fos = new FileOutputStream(newFile);
|
||||||
int len;
|
int len;
|
||||||
while ((len = zis.read(buffer)) > 0) {
|
while ((len = zis.read(buffer)) > 0) {
|
||||||
@ -27,4 +27,20 @@ public class UnzipFile {
|
|||||||
zis.closeEntry();
|
zis.closeEntry();
|
||||||
zis.close();
|
zis.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see https://snyk.io/research/zip-slip-vulnerability
|
||||||
|
*/
|
||||||
|
public static File newFile(File destinationDir, ZipEntry zipEntry) throws IOException {
|
||||||
|
File destFile = new File(destinationDir, zipEntry.getName());
|
||||||
|
|
||||||
|
String destDirPath = destinationDir.getCanonicalPath();
|
||||||
|
String destFilePath = destFile.getCanonicalPath();
|
||||||
|
|
||||||
|
if (!destFilePath.startsWith(destDirPath + File.separator)) {
|
||||||
|
throw new IOException("Entry is outside of the target dir: " + zipEntry.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
return destFile;
|
||||||
|
}
|
||||||
}
|
}
|
BIN
core-java-io/src/main/resources/unzipTest/compressed.zip
Normal file
BIN
core-java-io/src/main/resources/unzipTest/compressed.zip
Normal file
Binary file not shown.
@ -0,0 +1,106 @@
|
|||||||
|
package com.baeldung.csv;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Scanner;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import com.opencsv.CSVReader;
|
||||||
|
|
||||||
|
public class ReadCSVInArrayUnitTest {
|
||||||
|
public static final String COMMA_DELIMITER = ",";
|
||||||
|
public static final String CSV_FILE = "src/test/resources/book.csv";
|
||||||
|
public static final List<List<String>> EXPECTED_ARRAY = Collections.unmodifiableList(new ArrayList<List<String>>() {
|
||||||
|
{
|
||||||
|
add(new ArrayList<String>() {
|
||||||
|
{
|
||||||
|
add("Mary Kom");
|
||||||
|
add("Unbreakable");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
add(new ArrayList<String>() {
|
||||||
|
{
|
||||||
|
add("Kapil Isapuari");
|
||||||
|
add("Farishta");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenCSVFile_whenBufferedReader_thenContentsAsExpected() throws IOException {
|
||||||
|
List<List<String>> records = new ArrayList<List<String>>();
|
||||||
|
try (BufferedReader br = new BufferedReader(new FileReader(CSV_FILE))) {
|
||||||
|
String line = "";
|
||||||
|
while ((line = br.readLine()) != null) {
|
||||||
|
String[] values = line.split(COMMA_DELIMITER);
|
||||||
|
records.add(Arrays.asList(values));
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
for (int i = 0; i < EXPECTED_ARRAY.size(); i++) {
|
||||||
|
Assert.assertArrayEquals(EXPECTED_ARRAY.get(i)
|
||||||
|
.toArray(),
|
||||||
|
records.get(i)
|
||||||
|
.toArray());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenCSVFile_whenScanner_thenContentsAsExpected() throws IOException {
|
||||||
|
List<List<String>> records = new ArrayList<List<String>>();
|
||||||
|
try (Scanner scanner = new Scanner(new File(CSV_FILE));) {
|
||||||
|
while (scanner.hasNextLine()) {
|
||||||
|
records.add(getRecordFromLine(scanner.nextLine()));
|
||||||
|
}
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
for (int i = 0; i < EXPECTED_ARRAY.size(); i++) {
|
||||||
|
Assert.assertArrayEquals(EXPECTED_ARRAY.get(i)
|
||||||
|
.toArray(),
|
||||||
|
records.get(i)
|
||||||
|
.toArray());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> getRecordFromLine(String line) {
|
||||||
|
List<String> values = new ArrayList<String>();
|
||||||
|
try (Scanner rowScanner = new Scanner(line)) {
|
||||||
|
rowScanner.useDelimiter(COMMA_DELIMITER);
|
||||||
|
while (rowScanner.hasNext()) {
|
||||||
|
values.add(rowScanner.next());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenCSVFile_whenOpencsv_thenContentsAsExpected() throws IOException {
|
||||||
|
List<List<String>> records = new ArrayList<List<String>>();
|
||||||
|
try (CSVReader csvReader = new CSVReader(new FileReader(CSV_FILE));) {
|
||||||
|
String[] values = null;
|
||||||
|
while ((values = csvReader.readNext()) != null) {
|
||||||
|
records.add(Arrays.asList(values));
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
for (int i = 0; i < EXPECTED_ARRAY.size(); i++) {
|
||||||
|
Assert.assertArrayEquals(EXPECTED_ARRAY.get(i)
|
||||||
|
.toArray(),
|
||||||
|
records.get(i)
|
||||||
|
.toArray());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
2
core-java-io/src/test/resources/book.csv
Normal file
2
core-java-io/src/test/resources/book.csv
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
Mary Kom,Unbreakable
|
||||||
|
Kapil Isapuari,Farishta
|
|
@ -0,0 +1,41 @@
|
|||||||
|
package com.baeldung.string;
|
||||||
|
|
||||||
|
import java.math.RoundingMode;
|
||||||
|
import java.text.DecimalFormat;
|
||||||
|
import java.text.NumberFormat;
|
||||||
|
|
||||||
|
public class DoubleToString {
|
||||||
|
|
||||||
|
public static String truncateByCast(double d) {
|
||||||
|
return String.valueOf((int) d);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String roundWithStringFormat(double d) {
|
||||||
|
return String.format("%.0f", d);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String truncateWithNumberFormat(double d) {
|
||||||
|
NumberFormat nf = NumberFormat.getInstance();
|
||||||
|
nf.setMaximumFractionDigits(0);
|
||||||
|
nf.setRoundingMode(RoundingMode.FLOOR);
|
||||||
|
return nf.format(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String roundWithNumberFormat(double d) {
|
||||||
|
NumberFormat nf = NumberFormat.getInstance();
|
||||||
|
nf.setMaximumFractionDigits(0);
|
||||||
|
return nf.format(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String truncateWithDecimalFormat(double d) {
|
||||||
|
DecimalFormat df = new DecimalFormat("#,###");
|
||||||
|
df.setRoundingMode(RoundingMode.FLOOR);
|
||||||
|
return df.format(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String roundWithDecimalFormat(double d) {
|
||||||
|
DecimalFormat df = new DecimalFormat("#,###");
|
||||||
|
return df.format(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package com.baeldung;
|
package com.baeldung.simpledateformat;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
@ -32,6 +32,7 @@ public class SimpleDateFormatUnitTest {
|
|||||||
@Test
|
@Test
|
||||||
public void givenStringDate_whenParsed_thenCheckDateCorrect() throws Exception{
|
public void givenStringDate_whenParsed_thenCheckDateCorrect() throws Exception{
|
||||||
SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy");
|
SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy");
|
||||||
|
formatter.setTimeZone(TimeZone.getTimeZone("Europe/London"));
|
||||||
Date myDate = new Date(233276400000L);
|
Date myDate = new Date(233276400000L);
|
||||||
Date parsedDate = formatter.parse("24-05-1977");
|
Date parsedDate = formatter.parse("24-05-1977");
|
||||||
assertEquals(myDate.getTime(), parsedDate.getTime());
|
assertEquals(myDate.getTime(), parsedDate.getTime());
|
||||||
|
@ -0,0 +1,45 @@
|
|||||||
|
package com.baeldung.string;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class DoubleToStringUnitTest {
|
||||||
|
|
||||||
|
private static final double DOUBLE_VALUE = 3.56;
|
||||||
|
private static final String TRUNCATED_DOUBLE = "3";
|
||||||
|
private static final String ROUNDED_UP_DOUBLE = "4";
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void truncateByCastTest() {
|
||||||
|
assertThat(DoubleToString.truncateByCast(DOUBLE_VALUE)).isEqualTo(TRUNCATED_DOUBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void roundingWithStringFormatTest() {
|
||||||
|
assertThat(DoubleToString.roundWithStringFormat(DOUBLE_VALUE)).isEqualTo(ROUNDED_UP_DOUBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void truncateWithNumberFormatTest() {
|
||||||
|
assertThat(DoubleToString.truncateWithNumberFormat(DOUBLE_VALUE)).isEqualTo(TRUNCATED_DOUBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void roundWithNumberFormatTest() {
|
||||||
|
assertThat(DoubleToString.roundWithNumberFormat(DOUBLE_VALUE)).isEqualTo(ROUNDED_UP_DOUBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void truncateWithDecimalFormatTest() {
|
||||||
|
assertThat(DoubleToString.truncateWithDecimalFormat(DOUBLE_VALUE)).isEqualTo(TRUNCATED_DOUBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void roundWithDecimalFormatTest() {
|
||||||
|
assertThat(DoubleToString.roundWithDecimalFormat(DOUBLE_VALUE)).isEqualTo(ROUNDED_UP_DOUBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
package com.baeldung.thread
|
||||||
|
|
||||||
|
class SimpleRunnable: Runnable {
|
||||||
|
|
||||||
|
override fun run() {
|
||||||
|
println("${Thread.currentThread()} has run.")
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
package com.baeldung.thread
|
||||||
|
|
||||||
|
class SimpleThread: Thread() {
|
||||||
|
|
||||||
|
override fun run() {
|
||||||
|
println("${Thread.currentThread()} has run.")
|
||||||
|
}
|
||||||
|
}
|
@ -24,14 +24,15 @@ internal class SliceTest {
|
|||||||
assertIterableEquals(expected, actual)
|
assertIterableEquals(expected, actual)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
// From the 1.3 version of Kotlin APIs, slice doesn't return array of nulls but throw IndexOutOfBoundsException
|
||||||
fun whenSlicingBeyondTheRangeOfTheArray_thenContainManyNulls() {
|
// @Test
|
||||||
val original = arrayOf(12, 3, 34, 4)
|
// fun whenSlicingBeyondTheRangeOfTheArray_thenContainManyNulls() {
|
||||||
val actual = original.slice(3..8)
|
// val original = arrayOf(12, 3, 34, 4)
|
||||||
val expected = listOf(4, null, null, null, null, null)
|
// val actual = original.slice(3..8)
|
||||||
|
// val expected = listOf(4, null, null, null, null, null)
|
||||||
assertIterableEquals(expected, actual)
|
//
|
||||||
}
|
// assertIterableEquals(expected, actual)
|
||||||
|
// }
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun whenSlicingBeyondRangeOfArrayWithStep_thenOutOfBoundsException() {
|
fun whenSlicingBeyondRangeOfArrayWithStep_thenOutOfBoundsException() {
|
||||||
|
@ -1,16 +1,12 @@
|
|||||||
package com.baeldung.fuel
|
package com.baeldung.fuel
|
||||||
|
|
||||||
import awaitObjectResult
|
|
||||||
import awaitStringResponse
|
|
||||||
import com.github.kittinunf.fuel.Fuel
|
import com.github.kittinunf.fuel.Fuel
|
||||||
import com.github.kittinunf.fuel.core.FuelManager
|
import com.github.kittinunf.fuel.core.FuelManager
|
||||||
import com.github.kittinunf.fuel.core.Request
|
|
||||||
import com.github.kittinunf.fuel.core.interceptors.cUrlLoggingRequestInterceptor
|
import com.github.kittinunf.fuel.core.interceptors.cUrlLoggingRequestInterceptor
|
||||||
import com.github.kittinunf.fuel.gson.responseObject
|
import com.github.kittinunf.fuel.gson.responseObject
|
||||||
import com.github.kittinunf.fuel.httpGet
|
import com.github.kittinunf.fuel.httpGet
|
||||||
import com.github.kittinunf.fuel.rx.rx_object
|
import com.github.kittinunf.fuel.rx.rx_object
|
||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
import kotlinx.coroutines.experimental.runBlocking
|
|
||||||
import org.junit.jupiter.api.Assertions
|
import org.junit.jupiter.api.Assertions
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import java.io.File
|
import java.io.File
|
||||||
@ -226,32 +222,26 @@ internal class FuelHttpUnitTest {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
fun whenMakeGETRequestUsingCoroutines_thenResponseStatusCode200() {
|
|
||||||
|
|
||||||
runBlocking {
|
// The new 1.3 coroutine APIs, aren't implemented yet in Fuel Library
|
||||||
val (request, response, result) = Fuel.get("http://httpbin.org/get").awaitStringResponse()
|
// @Test
|
||||||
|
// fun whenMakeGETRequestUsingCoroutines_thenResponseStatusCode200() = runBlocking {
|
||||||
|
// val (request, response, result) = Fuel.get("http://httpbin.org/get").awaitStringResponse()
|
||||||
|
//
|
||||||
|
// result.fold({ data ->
|
||||||
|
// Assertions.assertEquals(200, response.statusCode)
|
||||||
|
//
|
||||||
|
// }, { error -> })
|
||||||
|
// }
|
||||||
|
|
||||||
result.fold({ data ->
|
// The new 1.3 coroutine APIs, aren't implemented yet in Fuel Library
|
||||||
Assertions.assertEquals(200, response.statusCode)
|
// @Test
|
||||||
|
// fun whenMakeGETRequestUsingCoroutines_thenDeserializeResponse() = runBlocking {
|
||||||
}, { error -> })
|
// Fuel.get("https://jsonplaceholder.typicode.com/posts?id=1").awaitObjectResult(Post.Deserializer())
|
||||||
}
|
// .fold({ data ->
|
||||||
|
// Assertions.assertEquals(1, data.get(0).userId)
|
||||||
}
|
// }, { error -> })
|
||||||
|
// }
|
||||||
@Test
|
|
||||||
fun whenMakeGETRequestUsingCoroutines_thenDeserializeResponse() {
|
|
||||||
|
|
||||||
|
|
||||||
runBlocking {
|
|
||||||
Fuel.get("https://jsonplaceholder.typicode.com/posts?id=1").awaitObjectResult(Post.Deserializer())
|
|
||||||
.fold({ data ->
|
|
||||||
Assertions.assertEquals(1, data.get(0).userId)
|
|
||||||
}, { error -> })
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun whenMakeGETPostRequestUsingRoutingAPI_thenDeserializeResponse() {
|
fun whenMakeGETPostRequestUsingRoutingAPI_thenDeserializeResponse() {
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
package com.baeldung.kotlin
|
package com.baeldung.kotlin
|
||||||
|
|
||||||
import kotlinx.coroutines.experimental.*
|
import kotlinx.coroutines.*
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.util.concurrent.atomic.AtomicInteger
|
import java.util.concurrent.atomic.AtomicInteger
|
||||||
import kotlin.coroutines.experimental.buildSequence
|
|
||||||
import kotlin.system.measureTimeMillis
|
import kotlin.system.measureTimeMillis
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
import kotlin.test.assertTrue
|
import kotlin.test.assertTrue
|
||||||
@ -14,7 +13,7 @@ class CoroutinesTest {
|
|||||||
@Test
|
@Test
|
||||||
fun givenBuildSequence_whenTakeNElements_thenShouldReturnItInALazyWay() {
|
fun givenBuildSequence_whenTakeNElements_thenShouldReturnItInALazyWay() {
|
||||||
//given
|
//given
|
||||||
val fibonacciSeq = buildSequence {
|
val fibonacciSeq = sequence {
|
||||||
var a = 0
|
var a = 0
|
||||||
var b = 1
|
var b = 1
|
||||||
|
|
||||||
@ -39,7 +38,7 @@ class CoroutinesTest {
|
|||||||
@Test
|
@Test
|
||||||
fun givenLazySeq_whenTakeNElements_thenShouldReturnAllElements() {
|
fun givenLazySeq_whenTakeNElements_thenShouldReturnAllElements() {
|
||||||
//given
|
//given
|
||||||
val lazySeq = buildSequence {
|
val lazySeq = sequence {
|
||||||
print("START ")
|
print("START ")
|
||||||
for (i in 1..5) {
|
for (i in 1..5) {
|
||||||
yield(i)
|
yield(i)
|
||||||
@ -60,8 +59,8 @@ class CoroutinesTest {
|
|||||||
val res = mutableListOf<String>()
|
val res = mutableListOf<String>()
|
||||||
|
|
||||||
//when
|
//when
|
||||||
runBlocking<Unit> {
|
runBlocking {
|
||||||
val promise = launch(CommonPool) { expensiveComputation(res) }
|
val promise = launch(Dispatchers.Default) { expensiveComputation(res) }
|
||||||
res.add("Hello,")
|
res.add("Hello,")
|
||||||
promise.join()
|
promise.join()
|
||||||
}
|
}
|
||||||
@ -85,7 +84,7 @@ class CoroutinesTest {
|
|||||||
|
|
||||||
//when
|
//when
|
||||||
val jobs = List(numberOfCoroutines) {
|
val jobs = List(numberOfCoroutines) {
|
||||||
launch(CommonPool) {
|
launch(Dispatchers.Default) {
|
||||||
delay(1L)
|
delay(1L)
|
||||||
counter.incrementAndGet()
|
counter.incrementAndGet()
|
||||||
}
|
}
|
||||||
@ -101,7 +100,7 @@ class CoroutinesTest {
|
|||||||
fun givenCancellableJob_whenRequestForCancel_thenShouldQuit() {
|
fun givenCancellableJob_whenRequestForCancel_thenShouldQuit() {
|
||||||
runBlocking<Unit> {
|
runBlocking<Unit> {
|
||||||
//given
|
//given
|
||||||
val job = launch(CommonPool) {
|
val job = launch(Dispatchers.Default) {
|
||||||
while (isActive) {
|
while (isActive) {
|
||||||
//println("is working")
|
//println("is working")
|
||||||
}
|
}
|
||||||
@ -135,8 +134,8 @@ class CoroutinesTest {
|
|||||||
val delay = 1000L
|
val delay = 1000L
|
||||||
val time = measureTimeMillis {
|
val time = measureTimeMillis {
|
||||||
//given
|
//given
|
||||||
val one = async(CommonPool) { someExpensiveComputation(delay) }
|
val one = async(Dispatchers.Default) { someExpensiveComputation(delay) }
|
||||||
val two = async(CommonPool) { someExpensiveComputation(delay) }
|
val two = async(Dispatchers.Default) { someExpensiveComputation(delay) }
|
||||||
|
|
||||||
//when
|
//when
|
||||||
runBlocking {
|
runBlocking {
|
||||||
@ -156,8 +155,8 @@ class CoroutinesTest {
|
|||||||
val delay = 1000L
|
val delay = 1000L
|
||||||
val time = measureTimeMillis {
|
val time = measureTimeMillis {
|
||||||
//given
|
//given
|
||||||
val one = async(CommonPool, CoroutineStart.LAZY) { someExpensiveComputation(delay) }
|
val one = async(Dispatchers.Default, CoroutineStart.LAZY) { someExpensiveComputation(delay) }
|
||||||
val two = async(CommonPool, CoroutineStart.LAZY) { someExpensiveComputation(delay) }
|
val two = async(Dispatchers.Default, CoroutineStart.LAZY) { someExpensiveComputation(delay) }
|
||||||
|
|
||||||
//when
|
//when
|
||||||
runBlocking {
|
runBlocking {
|
||||||
|
@ -0,0 +1,52 @@
|
|||||||
|
package com.baeldung.thread
|
||||||
|
|
||||||
|
import kotlinx.coroutines.*
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
|
||||||
|
class CoroutineUnitTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun whenCreateCoroutineWithLaunchWithoutContext_thenRun() = runBlocking {
|
||||||
|
|
||||||
|
val job = launch {
|
||||||
|
println("${Thread.currentThread()} has run.")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun whenCreateCoroutineWithLaunchWithDefaultContext_thenRun() = runBlocking {
|
||||||
|
|
||||||
|
val job = launch(Dispatchers.Default) {
|
||||||
|
println("${Thread.currentThread()} has run.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun whenCreateCoroutineWithLaunchWithUnconfinedContext_thenRun() = runBlocking {
|
||||||
|
|
||||||
|
val job = launch(Dispatchers.Unconfined) {
|
||||||
|
println("${Thread.currentThread()} has run.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun whenCreateCoroutineWithLaunchWithDedicatedThread_thenRun() = runBlocking {
|
||||||
|
|
||||||
|
val job = launch(newSingleThreadContext("dedicatedThread")) {
|
||||||
|
println("${Thread.currentThread()} has run.")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun whenCreateAsyncCoroutine_thenRun() = runBlocking {
|
||||||
|
|
||||||
|
val deferred = async(Dispatchers.IO) {
|
||||||
|
return@async "${Thread.currentThread()} has run."
|
||||||
|
}
|
||||||
|
|
||||||
|
val result = deferred.await()
|
||||||
|
println(result)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
package com.baeldung.thread
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
import kotlin.concurrent.thread
|
||||||
|
|
||||||
|
class ThreadUnitTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun whenCreateThread_thenRun() {
|
||||||
|
|
||||||
|
val thread = SimpleThread()
|
||||||
|
thread.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun whenCreateThreadWithRunnable_thenRun() {
|
||||||
|
|
||||||
|
val threadWithRunnable = Thread(SimpleRunnable())
|
||||||
|
threadWithRunnable.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun whenCreateThreadWithSAMConversions_thenRun() {
|
||||||
|
|
||||||
|
val thread = Thread {
|
||||||
|
println("${Thread.currentThread()} has run.")
|
||||||
|
}
|
||||||
|
thread.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun whenCreateThreadWithMethodExtension_thenRun() {
|
||||||
|
|
||||||
|
thread(start = true) {
|
||||||
|
println("${Thread.currentThread()} has run.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -11,7 +11,7 @@ import java.time.LocalDate;
|
|||||||
|
|
||||||
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
|
||||||
|
|
||||||
public class HibernateCustomTypesUnitTest {
|
public class HibernateCustomTypesManualTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void givenEmployee_whenSavedWithCustomTypes_thenEntityIsSaved() throws IOException {
|
public void givenEmployee_whenSavedWithCustomTypes_thenEntityIsSaved() throws IOException {
|
@ -1,19 +1,22 @@
|
|||||||
package com.baeldung.zoneddatetime;
|
package com.baeldung.zoneddatetime;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.time.format.DateTimeParseException;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
public class ZonedDateTimeUnitTest {
|
public class ZonedDateTimeUnitTest {
|
||||||
|
|
||||||
private static final Logger log = Logger.getLogger(ZonedDateTimeUnitTest.class.getName());
|
private static final Logger log = Logger.getLogger(ZonedDateTimeUnitTest.class.getName());
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testZonedDateTimeToString() {
|
public void givenZonedDateTime_whenConvertToString_thenOk() {
|
||||||
|
|
||||||
ZonedDateTime zonedDateTimeNow = ZonedDateTime.now(ZoneId.of("UTC"));
|
ZonedDateTime zonedDateTimeNow = ZonedDateTime.now(ZoneId.of("UTC"));
|
||||||
ZonedDateTime zonedDateTimeOf = ZonedDateTime.of(2018, 01, 01, 0, 0, 0, 0, ZoneId.of("UTC"));
|
ZonedDateTime zonedDateTimeOf = ZonedDateTime.of(2018, 01, 01, 0, 0, 0, 0, ZoneId.of("UTC"));
|
||||||
@ -21,10 +24,10 @@ public class ZonedDateTimeUnitTest {
|
|||||||
LocalDateTime localDateTime = LocalDateTime.now();
|
LocalDateTime localDateTime = LocalDateTime.now();
|
||||||
ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime, ZoneId.of("UTC"));
|
ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime, ZoneId.of("UTC"));
|
||||||
|
|
||||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM/dd/yyyy - hh:mm:ss Z");
|
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM/dd/yyyy - HH:mm:ss Z");
|
||||||
String formattedString = zonedDateTime.format(formatter);
|
String formattedString = zonedDateTime.format(formatter);
|
||||||
|
|
||||||
DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("MM/dd/yyyy - hh:mm:ss z");
|
DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("MM/dd/yyyy - HH:mm:ss z");
|
||||||
String formattedString2 = zonedDateTime.format(formatter2);
|
String formattedString2 = zonedDateTime.format(formatter2);
|
||||||
|
|
||||||
log.info(formattedString);
|
log.info(formattedString);
|
||||||
@ -33,9 +36,21 @@ public class ZonedDateTimeUnitTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testZonedDateTimeFromString() {
|
public void givenString_whenParseZonedDateTime_thenOk() {
|
||||||
|
ZonedDateTime zonedDateTime = ZonedDateTime.parse("2011-12-03T10:15:30+01:00");
|
||||||
|
|
||||||
ZonedDateTime zonedDateTime = ZonedDateTime.parse("2011-12-03T10:15:30+01:00", DateTimeFormatter.ISO_ZONED_DATE_TIME);
|
log.info(zonedDateTime.format(DateTimeFormatter.ISO_ZONED_DATE_TIME));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenString_whenParseZonedDateTimeWithoutZone_thenException() {
|
||||||
|
assertThrows(DateTimeParseException.class, () -> ZonedDateTime.parse("2011-12-03T10:15:30", DateTimeFormatter.ISO_DATE_TIME));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenString_whenParseLocalDateTimeAtZone_thenOk() {
|
||||||
|
ZoneId timeZone = ZoneId.systemDefault();
|
||||||
|
ZonedDateTime zonedDateTime = LocalDateTime.parse("2011-12-03T10:15:30", DateTimeFormatter.ISO_DATE_TIME).atZone(timeZone);
|
||||||
|
|
||||||
log.info(zonedDateTime.format(DateTimeFormatter.ISO_ZONED_DATE_TIME));
|
log.info(zonedDateTime.format(DateTimeFormatter.ISO_ZONED_DATE_TIME));
|
||||||
}
|
}
|
||||||
|
@ -259,6 +259,11 @@
|
|||||||
<artifactId>slf4j-api</artifactId>
|
<artifactId>slf4j-api</artifactId>
|
||||||
<version>${slf4j.version}</version>
|
<version>${slf4j.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.storm</groupId>
|
||||||
|
<artifactId>storm-core</artifactId>
|
||||||
|
<version>${storm.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>ch.qos.logback</groupId>
|
<groupId>ch.qos.logback</groupId>
|
||||||
@ -432,6 +437,7 @@
|
|||||||
</repositories>
|
</repositories>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
|
<storm.version>1.2.2</storm.version>
|
||||||
<kryo.version>4.0.1</kryo.version>
|
<kryo.version>4.0.1</kryo.version>
|
||||||
<h2.version>1.4.196</h2.version>
|
<h2.version>1.4.196</h2.version>
|
||||||
<reladomo.version>16.5.1</reladomo.version>
|
<reladomo.version>16.5.1</reladomo.version>
|
||||||
|
@ -0,0 +1,34 @@
|
|||||||
|
package com.baeldung.storm;
|
||||||
|
|
||||||
|
import com.baeldung.storm.bolt.AggregatingBolt;
|
||||||
|
import com.baeldung.storm.bolt.FileWritingBolt;
|
||||||
|
import com.baeldung.storm.bolt.FilteringBolt;
|
||||||
|
import com.baeldung.storm.bolt.PrintingBolt;
|
||||||
|
import com.baeldung.storm.spout.RandomNumberSpout;
|
||||||
|
import org.apache.storm.Config;
|
||||||
|
import org.apache.storm.LocalCluster;
|
||||||
|
import org.apache.storm.topology.TopologyBuilder;
|
||||||
|
import org.apache.storm.topology.base.BaseWindowedBolt;
|
||||||
|
|
||||||
|
public class TopologyRunner {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
runTopology();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void runTopology() {
|
||||||
|
String filePath = "./src/main/resources/operations.txt";
|
||||||
|
TopologyBuilder builder = new TopologyBuilder();
|
||||||
|
builder.setSpout("randomNumberSpout", new RandomNumberSpout());
|
||||||
|
builder.setBolt("filteringBolt", new FilteringBolt()).shuffleGrouping("randomNumberSpout");
|
||||||
|
builder.setBolt("aggregatingBolt", new AggregatingBolt()
|
||||||
|
.withTimestampField("timestamp")
|
||||||
|
.withLag(BaseWindowedBolt.Duration.seconds(1))
|
||||||
|
.withWindow(BaseWindowedBolt.Duration.seconds(5))).shuffleGrouping("filteringBolt");
|
||||||
|
builder.setBolt("fileBolt", new FileWritingBolt(filePath)).shuffleGrouping("aggregatingBolt");
|
||||||
|
|
||||||
|
Config config = new Config();
|
||||||
|
config.setDebug(false);
|
||||||
|
LocalCluster cluster = new LocalCluster();
|
||||||
|
cluster.submitTopology("Test", config, builder.createTopology());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
package com.baeldung.storm.bolt;
|
||||||
|
|
||||||
|
import org.apache.storm.task.OutputCollector;
|
||||||
|
import org.apache.storm.task.TopologyContext;
|
||||||
|
import org.apache.storm.topology.OutputFieldsDeclarer;
|
||||||
|
import org.apache.storm.topology.base.BaseWindowedBolt;
|
||||||
|
import org.apache.storm.tuple.Fields;
|
||||||
|
import org.apache.storm.tuple.Tuple;
|
||||||
|
import org.apache.storm.tuple.Values;
|
||||||
|
import org.apache.storm.windowing.TupleWindow;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class AggregatingBolt extends BaseWindowedBolt {
|
||||||
|
private OutputCollector outputCollector;
|
||||||
|
@Override
|
||||||
|
public void prepare(Map stormConf, TopologyContext context, OutputCollector collector) {
|
||||||
|
this.outputCollector = collector;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void declareOutputFields(OutputFieldsDeclarer declarer) {
|
||||||
|
declarer.declare(new Fields("sumOfOperations", "beginningTimestamp", "endTimestamp"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(TupleWindow tupleWindow) {
|
||||||
|
List<Tuple> tuples = tupleWindow.get();
|
||||||
|
tuples.sort(Comparator.comparing(a -> a.getLongByField("timestamp")));
|
||||||
|
//This is safe since the window is calculated basing on Tuple's timestamp, thus it can't really be empty
|
||||||
|
Long beginningTimestamp = tuples.get(0).getLongByField("timestamp");
|
||||||
|
Long endTimestamp = tuples.get(tuples.size() - 1).getLongByField("timestamp");
|
||||||
|
int sumOfOperations = tuples.stream().mapToInt(tuple -> tuple.getIntegerByField("operation")).sum();
|
||||||
|
Values values = new Values(sumOfOperations, beginningTimestamp, endTimestamp);
|
||||||
|
outputCollector.emit(values);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,72 @@
|
|||||||
|
package com.baeldung.storm.bolt;
|
||||||
|
|
||||||
|
import com.baeldung.storm.model.AggregatedWindow;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||||
|
import com.fasterxml.jackson.annotation.PropertyAccessor;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import org.apache.storm.task.OutputCollector;
|
||||||
|
import org.apache.storm.task.TopologyContext;
|
||||||
|
import org.apache.storm.topology.OutputFieldsDeclarer;
|
||||||
|
import org.apache.storm.topology.base.BaseRichBolt;
|
||||||
|
import org.apache.storm.tuple.Tuple;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.BufferedWriter;
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class FileWritingBolt extends BaseRichBolt {
|
||||||
|
public static Logger logger = LoggerFactory.getLogger(FileWritingBolt.class);
|
||||||
|
private BufferedWriter writer;
|
||||||
|
private String filePath;
|
||||||
|
private ObjectMapper objectMapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void prepare(Map map, TopologyContext topologyContext, OutputCollector outputCollector) {
|
||||||
|
objectMapper = new ObjectMapper();
|
||||||
|
objectMapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
|
||||||
|
try {
|
||||||
|
writer = new BufferedWriter(new FileWriter(filePath));
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error("Failed to open a file for writing.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(Tuple tuple) {
|
||||||
|
int sumOfOperations = tuple.getIntegerByField("sumOfOperations");
|
||||||
|
long beginningTimestamp = tuple.getLongByField("beginningTimestamp");
|
||||||
|
long endTimestamp = tuple.getLongByField("endTimestamp");
|
||||||
|
|
||||||
|
if(sumOfOperations > 200) {
|
||||||
|
AggregatedWindow aggregatedWindow = new AggregatedWindow(sumOfOperations, beginningTimestamp, endTimestamp);
|
||||||
|
try {
|
||||||
|
writer.write(objectMapper.writeValueAsString(aggregatedWindow));
|
||||||
|
writer.write("\n");
|
||||||
|
writer.flush();
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error("Failed to write data to file.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public FileWritingBolt(String filePath) {
|
||||||
|
this.filePath = filePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cleanup() {
|
||||||
|
try {
|
||||||
|
writer.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error("Failed to close the writer!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void declareOutputFields(OutputFieldsDeclarer outputFieldsDeclarer) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
package com.baeldung.storm.bolt;
|
||||||
|
|
||||||
|
import org.apache.storm.topology.BasicOutputCollector;
|
||||||
|
import org.apache.storm.topology.OutputFieldsDeclarer;
|
||||||
|
import org.apache.storm.topology.base.BaseBasicBolt;
|
||||||
|
import org.apache.storm.tuple.Fields;
|
||||||
|
import org.apache.storm.tuple.Tuple;
|
||||||
|
|
||||||
|
public class FilteringBolt extends BaseBasicBolt {
|
||||||
|
@Override
|
||||||
|
public void execute(Tuple tuple, BasicOutputCollector basicOutputCollector) {
|
||||||
|
int operation = tuple.getIntegerByField("operation");
|
||||||
|
if(operation > 0 ) {
|
||||||
|
basicOutputCollector.emit(tuple.getValues());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void declareOutputFields(OutputFieldsDeclarer outputFieldsDeclarer) {
|
||||||
|
outputFieldsDeclarer.declare(new Fields("operation", "timestamp"));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package com.baeldung.storm.bolt;
|
||||||
|
|
||||||
|
import org.apache.storm.topology.BasicOutputCollector;
|
||||||
|
import org.apache.storm.topology.OutputFieldsDeclarer;
|
||||||
|
import org.apache.storm.topology.base.BaseBasicBolt;
|
||||||
|
import org.apache.storm.tuple.Tuple;
|
||||||
|
|
||||||
|
public class PrintingBolt extends BaseBasicBolt {
|
||||||
|
@Override
|
||||||
|
public void execute(Tuple tuple, BasicOutputCollector basicOutputCollector) {
|
||||||
|
System.out.println(tuple);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void declareOutputFields(OutputFieldsDeclarer outputFieldsDeclarer) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package com.baeldung.storm.model;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||||
|
|
||||||
|
@JsonSerialize
|
||||||
|
public class AggregatedWindow {
|
||||||
|
int sumOfOperations;
|
||||||
|
long beginningTimestamp;
|
||||||
|
long endTimestamp;
|
||||||
|
|
||||||
|
public AggregatedWindow(int sumOfOperations, long beginningTimestamp, long endTimestamp) {
|
||||||
|
this.sumOfOperations = sumOfOperations;
|
||||||
|
this.beginningTimestamp = beginningTimestamp;
|
||||||
|
this.endTimestamp = endTimestamp;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
package com.baeldung.storm.model;
|
||||||
|
|
||||||
|
public class User {
|
||||||
|
private String username;
|
||||||
|
private String password;
|
||||||
|
private String email;
|
||||||
|
private int age;
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsername(String username) {
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPassword(String password) {
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEmail() {
|
||||||
|
return email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEmail(String email) {
|
||||||
|
this.email = email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getAge() {
|
||||||
|
return age;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAge(int age) {
|
||||||
|
this.age = age;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
package com.baeldung.storm.serialization;
|
||||||
|
|
||||||
|
|
||||||
|
import com.baeldung.storm.model.User;
|
||||||
|
import com.esotericsoftware.kryo.Kryo;
|
||||||
|
import com.esotericsoftware.kryo.Serializer;
|
||||||
|
import com.esotericsoftware.kryo.io.Input;
|
||||||
|
import com.esotericsoftware.kryo.io.Output;
|
||||||
|
|
||||||
|
public class UserSerializer extends Serializer<User>{
|
||||||
|
@Override
|
||||||
|
public void write(Kryo kryo, Output output, User user) {
|
||||||
|
output.writeString(user.getEmail());
|
||||||
|
output.writeString(user.getUsername());
|
||||||
|
output.write(user.getAge());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public User read(Kryo kryo, Input input, Class<User> aClass) {
|
||||||
|
User user = new User();
|
||||||
|
String email = input.readString();
|
||||||
|
String name = input.readString();
|
||||||
|
int age = input.read();
|
||||||
|
user.setAge(age);
|
||||||
|
user.setEmail(email);
|
||||||
|
user.setUsername(name);
|
||||||
|
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
package com.baeldung.storm.spout;
|
||||||
|
|
||||||
|
import org.apache.storm.spout.SpoutOutputCollector;
|
||||||
|
import org.apache.storm.task.TopologyContext;
|
||||||
|
import org.apache.storm.topology.OutputFieldsDeclarer;
|
||||||
|
import org.apache.storm.topology.base.BaseRichSpout;
|
||||||
|
import org.apache.storm.tuple.Fields;
|
||||||
|
import org.apache.storm.tuple.Values;
|
||||||
|
import org.apache.storm.utils.Utils;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
public class RandomIntSpout extends BaseRichSpout {
|
||||||
|
|
||||||
|
private Random random;
|
||||||
|
private SpoutOutputCollector outputCollector;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void open(Map map, TopologyContext topologyContext, SpoutOutputCollector spoutOutputCollector) {
|
||||||
|
random = new Random();
|
||||||
|
outputCollector = spoutOutputCollector;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void nextTuple() {
|
||||||
|
Utils.sleep(1000);
|
||||||
|
outputCollector.emit(new Values(random.nextInt(), System.currentTimeMillis()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void declareOutputFields(OutputFieldsDeclarer outputFieldsDeclarer) {
|
||||||
|
outputFieldsDeclarer.declare(new Fields("randomInt", "timestamp"));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
package com.baeldung.storm.spout;
|
||||||
|
|
||||||
|
import org.apache.storm.spout.SpoutOutputCollector;
|
||||||
|
import org.apache.storm.task.OutputCollector;
|
||||||
|
import org.apache.storm.task.TopologyContext;
|
||||||
|
import org.apache.storm.topology.OutputFieldsDeclarer;
|
||||||
|
import org.apache.storm.topology.base.BaseRichSpout;
|
||||||
|
import org.apache.storm.tuple.Fields;
|
||||||
|
import org.apache.storm.tuple.Values;
|
||||||
|
import org.apache.storm.utils.Utils;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
public class RandomNumberSpout extends BaseRichSpout {
|
||||||
|
private Random random;
|
||||||
|
private SpoutOutputCollector collector;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void open(Map map, TopologyContext topologyContext, SpoutOutputCollector spoutOutputCollector) {
|
||||||
|
random = new Random();
|
||||||
|
collector = spoutOutputCollector;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void nextTuple() {
|
||||||
|
Utils.sleep(1000);
|
||||||
|
//This will select random int from the range (0, 100)
|
||||||
|
int operation = random.nextInt(101);
|
||||||
|
long timestamp = System.currentTimeMillis();
|
||||||
|
|
||||||
|
Values values = new Values(operation, timestamp);
|
||||||
|
collector.emit(values);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void declareOutputFields(OutputFieldsDeclarer outputFieldsDeclarer) {
|
||||||
|
outputFieldsDeclarer.declare(new Fields("operation", "timestamp"));
|
||||||
|
}
|
||||||
|
}
|
@ -22,8 +22,19 @@
|
|||||||
<id>kotlin-ktor</id>
|
<id>kotlin-ktor</id>
|
||||||
<url>https://dl.bintray.com/kotlin/ktor/</url>
|
<url>https://dl.bintray.com/kotlin/ktor/</url>
|
||||||
</repository>
|
</repository>
|
||||||
|
<repository>
|
||||||
|
<id>kotlin-eap</id>
|
||||||
|
<url>http://dl.bintray.com/kotlin/kotlin-eap</url>
|
||||||
|
</repository>
|
||||||
</repositories>
|
</repositories>
|
||||||
|
|
||||||
|
<pluginRepositories>
|
||||||
|
<pluginRepository>
|
||||||
|
<id>kotlin-eap</id>
|
||||||
|
<url>http://dl.bintray.com/kotlin/kotlin-eap</url>
|
||||||
|
</pluginRepository>
|
||||||
|
</pluginRepositories>
|
||||||
|
|
||||||
<dependencyManagement>
|
<dependencyManagement>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
@ -42,6 +53,11 @@
|
|||||||
<artifactId>kotlin-stdlib-jdk8</artifactId>
|
<artifactId>kotlin-stdlib-jdk8</artifactId>
|
||||||
<version>${kotlin.version}</version>
|
<version>${kotlin.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jetbrains.kotlin</groupId>
|
||||||
|
<artifactId>kotlin-stdlib</artifactId>
|
||||||
|
<version>${kotlin.version}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jetbrains.kotlin</groupId>
|
<groupId>org.jetbrains.kotlin</groupId>
|
||||||
<artifactId>kotlin-reflect</artifactId>
|
<artifactId>kotlin-reflect</artifactId>
|
||||||
@ -157,6 +173,7 @@
|
|||||||
</executions>
|
</executions>
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-failsafe-plugin</artifactId>
|
<artifactId>maven-failsafe-plugin</artifactId>
|
||||||
<version>${maven-failsafe-plugin.version}</version>
|
<version>${maven-failsafe-plugin.version}</version>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
@ -185,8 +202,8 @@
|
|||||||
</build>
|
</build>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<kotlin.version>1.2.61</kotlin.version>
|
<kotlin.version>1.3.0-rc-146</kotlin.version>
|
||||||
<kotlinx.version>0.25.0</kotlinx.version>
|
<kotlinx.version>0.26.1-eap13</kotlinx.version>
|
||||||
<ktor.io.version>0.9.3</ktor.io.version>
|
<ktor.io.version>0.9.3</ktor.io.version>
|
||||||
<assertj.version>3.11.0</assertj.version>
|
<assertj.version>3.11.0</assertj.version>
|
||||||
<junit.platform.version>1.2.0</junit.platform.version>
|
<junit.platform.version>1.2.0</junit.platform.version>
|
||||||
|
@ -16,22 +16,35 @@
|
|||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||||
<exclusions>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>com.zaxxer</groupId>
|
|
||||||
<artifactId>HikariCP</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-test</artifactId>
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mockito</groupId>
|
||||||
|
<artifactId>mockito-core</artifactId>
|
||||||
|
<version>${mockito.version}</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
<groupId>com.h2database</groupId>
|
||||||
|
<artifactId>h2</artifactId>
|
||||||
|
<version>${h2database.version}</version>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
<groupId>org.apache.tomcat</groupId>
|
<groupId>org.apache.tomcat</groupId>
|
||||||
<artifactId>tomcat-jdbc</artifactId>
|
<artifactId>tomcat-jdbc</artifactId>
|
||||||
<version>${tomcat-jdbc.version}</version>
|
<version>${tomcat-jdbc.version}</version>
|
||||||
@ -41,20 +54,14 @@
|
|||||||
<artifactId>mysql-connector-java</artifactId>
|
<artifactId>mysql-connector-java</artifactId>
|
||||||
<version>${mysql-connector-java.version}</version>
|
<version>${mysql-connector-java.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>com.h2database</groupId>
|
|
||||||
<artifactId>h2</artifactId>
|
|
||||||
<version>${h2database.version}</version>
|
|
||||||
<scope>runtime</scope>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<java.version>1.8</java.version>
|
<java.version>1.8</java.version>
|
||||||
<mysql-connector-java.version>8.0.12</mysql-connector-java.version>
|
<mysql-connector-java.version>8.0.12</mysql-connector-java.version>
|
||||||
<tomcat-jdbc.version>9.0.10</tomcat-jdbc.version>
|
<tomcat-jdbc.version>9.0.10</tomcat-jdbc.version>
|
||||||
<h2database.version>1.4.197</h2database.version>
|
<h2database.version>1.4.197</h2database.version>
|
||||||
|
<mockito.version>2.23.0</mockito.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
@ -0,0 +1,22 @@
|
|||||||
|
package com.baeldung.springbootcrudapp.application;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||||
|
import org.springframework.boot.autoconfigure.domain.EntityScan;
|
||||||
|
import org.springframework.context.annotation.ComponentScan;
|
||||||
|
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
||||||
|
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
@EnableAutoConfiguration
|
||||||
|
@ComponentScan(basePackages={"com.baeldung.springbootcrudapp.application"})
|
||||||
|
@EnableJpaRepositories(basePackages="com.baeldung.springbootcrudapp.application.repositories")
|
||||||
|
@EnableTransactionManagement
|
||||||
|
@EntityScan(basePackages="com.baeldung.springbootcrudapp.application.entities")
|
||||||
|
public class Application {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(Application.class, args);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
package com.baeldung.springbootcrudapp.application.controllers;
|
||||||
|
|
||||||
|
import com.baeldung.springbootcrudapp.application.repositories.UserRepository;
|
||||||
|
import com.baeldung.springbootcrudapp.application.entities.User;
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.ui.Model;
|
||||||
|
import org.springframework.validation.BindingResult;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
|
||||||
|
@Controller
|
||||||
|
public class UserController {
|
||||||
|
|
||||||
|
private final UserRepository userRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public UserController(UserRepository userRepository) {
|
||||||
|
this.userRepository = userRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/signup")
|
||||||
|
public String showSignUpForm(User user) {
|
||||||
|
return "add-user";
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/adduser")
|
||||||
|
public String addUser(@Valid User user, BindingResult result, Model model) {
|
||||||
|
if (result.hasErrors()) {
|
||||||
|
return "add-user";
|
||||||
|
}
|
||||||
|
|
||||||
|
userRepository.save(user);
|
||||||
|
model.addAttribute("users", userRepository.findAll());
|
||||||
|
return "index";
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/edit/{id}")
|
||||||
|
public String showUpdateForm(@PathVariable("id") long id, Model model) {
|
||||||
|
User user = userRepository.findById(id).orElseThrow(() -> new IllegalArgumentException("Invalid user Id:" + id));
|
||||||
|
model.addAttribute("user", user);
|
||||||
|
return "update-user";
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/update/{id}")
|
||||||
|
public String updateUser(@PathVariable("id") long id, @Valid User user, BindingResult result, Model model) {
|
||||||
|
if (result.hasErrors()) {
|
||||||
|
user.setId(id);
|
||||||
|
return "update-user";
|
||||||
|
}
|
||||||
|
|
||||||
|
userRepository.save(user);
|
||||||
|
model.addAttribute("users", userRepository.findAll());
|
||||||
|
return "index";
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/delete/{id}")
|
||||||
|
public String deleteUser(@PathVariable("id") long id, Model model) {
|
||||||
|
User user = userRepository.findById(id).orElseThrow(() -> new IllegalArgumentException("Invalid user Id:" + id));
|
||||||
|
userRepository.delete(user);
|
||||||
|
model.addAttribute("users", userRepository.findAll());
|
||||||
|
return "index";
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,56 @@
|
|||||||
|
package com.baeldung.springbootcrudapp.application.entities;
|
||||||
|
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.GenerationType;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.validation.constraints.NotBlank;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
public class User {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||||
|
private long id;
|
||||||
|
@NotBlank(message = "Name is mandatory")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@NotBlank(message = "Email is mandatory")
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
public User() {}
|
||||||
|
|
||||||
|
public User(String name, String email) {
|
||||||
|
this.name = name;
|
||||||
|
this.email = email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEmail(String email) {
|
||||||
|
this.email = email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEmail() {
|
||||||
|
return email;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "User{" + "id=" + id + ", name=" + name + ", email=" + email + '}';
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
package com.baeldung.springbootcrudapp.application.repositories;
|
||||||
|
|
||||||
|
import com.baeldung.springbootcrudapp.application.entities.User;
|
||||||
|
import java.util.List;
|
||||||
|
import org.springframework.data.repository.CrudRepository;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface UserRepository extends CrudRepository<User, Long> {
|
||||||
|
|
||||||
|
List<User> findByName(String name);
|
||||||
|
|
||||||
|
}
|
2
persistence-modules/spring-boot-persistence/src/main/resources/css/shards.min.css
vendored
Normal file
2
persistence-modules/spring-boot-persistence/src/main/resources/css/shards.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -0,0 +1,40 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html xmlns:th="http://www.thymeleaf.org">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
||||||
|
<title>Add User</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
|
||||||
|
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.4.1/css/all.css" integrity="sha384-5sAR7xN1Nv6T6+dT2mhtzEpVJvfS3NScPQTrOxhwjIuvcA67KV2R5Jz6kr4abQsz" crossorigin="anonymous">
|
||||||
|
<link rel="stylesheet" href="../css/shards.min.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container my-5">
|
||||||
|
<h2 class="mb-5">New User</h2>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<form action="#" th:action="@{/adduser}" th:object="${user}" method="post">
|
||||||
|
<div class="row">
|
||||||
|
<div class="form-group col-md-6">
|
||||||
|
<label for="name" class="col-form-label">Name</label>
|
||||||
|
<input type="text" th:field="*{name}" class="form-control" id="name" placeholder="Name">
|
||||||
|
<span th:if="${#fields.hasErrors('name')}" th:errors="*{name}" class="text-danger"></span>
|
||||||
|
</div>
|
||||||
|
<div class="form-group col-md-6">
|
||||||
|
<label for="email" class="col-form-label">Email</label>
|
||||||
|
<input type="text" th:field="*{email}" class="form-control" id="email" placeholder="Email">
|
||||||
|
<span th:if="${#fields.hasErrors('email')}" th:errors="*{email}" class="text-danger"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6 mt-5">
|
||||||
|
<input type="submit" class="btn btn-primary" value="Add User">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1,43 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html xmlns:th="http://www.thymeleaf.org">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
||||||
|
<title>Users</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
|
||||||
|
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.4.1/css/all.css" integrity="sha384-5sAR7xN1Nv6T6+dT2mhtzEpVJvfS3NScPQTrOxhwjIuvcA67KV2R5Jz6kr4abQsz" crossorigin="anonymous">
|
||||||
|
<link rel="stylesheet" href="../css/shards.min.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div th:switch="${users}" class="container my-5">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<h2 th:case="null">No users yet!</h2>
|
||||||
|
<div th:case="*">
|
||||||
|
<h2 class="my-5">Users</h2>
|
||||||
|
<table class="table table-striped table-responsive-md">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Email</th>
|
||||||
|
<th>Edit</th>
|
||||||
|
<th>Delete</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr th:each="user : ${users}">
|
||||||
|
<td th:text="${user.name}"></td>
|
||||||
|
<td th:text="${user.email}"></td>
|
||||||
|
<td><a th:href="@{/edit/{id}(id=${user.id})}" class="btn btn-primary"><i class="fas fa-user-edit ml-2"></i></a></td>
|
||||||
|
<td><a th:href="@{/delete/{id}(id=${user.id})}" class="btn btn-primary"><i class="fas fa-user-times ml-2"></i></a></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<p class="my-5"><a href="/signup" class="btn btn-primary"><i class="fas fa-user-plus ml-2"></i></a></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1,40 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html xmlns:th="http://www.thymeleaf.org">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
||||||
|
<title>Update User</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
|
||||||
|
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.4.1/css/all.css" integrity="sha384-5sAR7xN1Nv6T6+dT2mhtzEpVJvfS3NScPQTrOxhwjIuvcA67KV2R5Jz6kr4abQsz" crossorigin="anonymous">
|
||||||
|
<link rel="stylesheet" href="../css/shards.min.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container my-5">
|
||||||
|
<h2 class="mb-5">Update User</h2>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<form action="#" th:action="@{/update/{id}(id=${user.id})}" th:object="${user}" method="post">
|
||||||
|
<div class="row">
|
||||||
|
<div class="form-group col-md-6">
|
||||||
|
<label for="name" class="col-form-label">Name</label>
|
||||||
|
<input type="text" th:field="*{name}" class="form-control" id="name" placeholder="Name">
|
||||||
|
<span th:if="${#fields.hasErrors('name')}" th:errors="*{name}" class="text-danger"></span>
|
||||||
|
</div>
|
||||||
|
<div class="form-group col-md-6">
|
||||||
|
<label for="email" class="col-form-label">Email</label>
|
||||||
|
<input type="text" th:field="*{email}" class="form-control" id="email" placeholder="Email">
|
||||||
|
<span th:if="${#fields.hasErrors('email')}" th:errors="*{email}" class="text-danger"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6 mt-5">
|
||||||
|
<input type="submit" class="btn btn-primary" value="Update User">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1,81 @@
|
|||||||
|
package com.baeldung.springbootcrudapp.application.tests;
|
||||||
|
|
||||||
|
import com.baeldung.springbootcrudapp.application.controllers.UserController;
|
||||||
|
import com.baeldung.springbootcrudapp.application.entities.User;
|
||||||
|
import com.baeldung.springbootcrudapp.application.repositories.UserRepository;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Test;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
import org.springframework.ui.Model;
|
||||||
|
import org.springframework.validation.BindingResult;
|
||||||
|
|
||||||
|
public class UserControllerUnitTest {
|
||||||
|
|
||||||
|
private static UserController userController;
|
||||||
|
private static UserRepository mockedUserRepository;
|
||||||
|
private static BindingResult mockedBindingResult;
|
||||||
|
private static Model mockedModel;
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void setUpUserControllerInstance() {
|
||||||
|
mockedUserRepository = mock(UserRepository.class);
|
||||||
|
mockedBindingResult = mock(BindingResult.class);
|
||||||
|
mockedModel = mock(Model.class);
|
||||||
|
userController = new UserController(mockedUserRepository);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenCalledshowSignUpForm_thenCorrect() {
|
||||||
|
User user = new User("John", "john@domain.com");
|
||||||
|
|
||||||
|
assertThat(userController.showSignUpForm(user)).isEqualTo("add-user");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenCalledaddUserAndValidUser_thenCorrect() {
|
||||||
|
User user = new User("John", "john@domain.com");
|
||||||
|
|
||||||
|
when(mockedBindingResult.hasErrors()).thenReturn(false);
|
||||||
|
|
||||||
|
assertThat(userController.addUser(user, mockedBindingResult, mockedModel)).isEqualTo("index");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenCalledaddUserAndInValidUser_thenCorrect() {
|
||||||
|
User user = new User("John", "john@domain.com");
|
||||||
|
|
||||||
|
when(mockedBindingResult.hasErrors()).thenReturn(true);
|
||||||
|
|
||||||
|
assertThat(userController.addUser(user, mockedBindingResult, mockedModel)).isEqualTo("add-user");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void whenCalledshowUpdateForm_thenIllegalArgumentException() {
|
||||||
|
assertThat(userController.showUpdateForm(0, mockedModel)).isEqualTo("update-user");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenCalledupdateUserAndValidUser_thenCorrect() {
|
||||||
|
User user = new User("John", "john@domain.com");
|
||||||
|
|
||||||
|
when(mockedBindingResult.hasErrors()).thenReturn(false);
|
||||||
|
|
||||||
|
assertThat(userController.updateUser(1l, user, mockedBindingResult, mockedModel)).isEqualTo("index");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenCalledupdateUserAndInValidUser_thenCorrect() {
|
||||||
|
User user = new User("John", "john@domain.com");
|
||||||
|
|
||||||
|
when(mockedBindingResult.hasErrors()).thenReturn(true);
|
||||||
|
|
||||||
|
assertThat(userController.updateUser(1l, user, mockedBindingResult, mockedModel)).isEqualTo("update-user");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void whenCalleddeleteUser_thenIllegalArgumentException() {
|
||||||
|
assertThat(userController.deleteUser(1l, mockedModel)).isEqualTo("index");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
package com.baeldung.springbootcrudapp.application.tests;
|
||||||
|
|
||||||
|
import com.baeldung.springbootcrudapp.application.entities.User;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class UserUnitTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenCalledGetName_thenCorrect() {
|
||||||
|
User user = new User("Julie", "julie@domain.com");
|
||||||
|
|
||||||
|
assertThat(user.getName()).isEqualTo("Julie");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenCalledGetEmail_thenCorrect() {
|
||||||
|
User user = new User("Julie", "julie@domain.com");
|
||||||
|
|
||||||
|
assertThat(user.getEmail()).isEqualTo("julie@domain.com");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenCalledSetName_thenCorrect() {
|
||||||
|
User user = new User("Julie", "julie@domain.com");
|
||||||
|
|
||||||
|
user.setName("John");
|
||||||
|
|
||||||
|
assertThat(user.getName()).isEqualTo("John");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenCalledSetEmail_thenCorrect() {
|
||||||
|
User user = new User("Julie", "julie@domain.com");
|
||||||
|
|
||||||
|
user.setEmail("john@domain.com");
|
||||||
|
|
||||||
|
assertThat(user.getEmail()).isEqualTo("john@domain.com");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenCalledtoString_thenCorrect() {
|
||||||
|
User user = new User("Julie", "julie@domain.com");
|
||||||
|
assertThat(user.toString()).isEqualTo("User{id=0, name=Julie, email=julie@domain.com}");
|
||||||
|
}
|
||||||
|
}
|
@ -16,5 +16,6 @@ public class CollectionInjectionDemo {
|
|||||||
collectionsBean.printNameSet();
|
collectionsBean.printNameSet();
|
||||||
collectionsBean.printNameMap();
|
collectionsBean.printNameMap();
|
||||||
collectionsBean.printBeanList();
|
collectionsBean.printBeanList();
|
||||||
|
collectionsBean.printNameListWithDefaults();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
package com.baeldung.collection;
|
package com.baeldung.collection;
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by Gebruiker on 5/18/2018.
|
* Created by Gebruiker on 5/18/2018.
|
||||||
*/
|
*/
|
||||||
@ -24,6 +25,9 @@ public class CollectionsBean {
|
|||||||
@Qualifier("CollectionsBean")
|
@Qualifier("CollectionsBean")
|
||||||
private List<BaeldungBean> beanList = new ArrayList<>();
|
private List<BaeldungBean> beanList = new ArrayList<>();
|
||||||
|
|
||||||
|
@Value("${names.list:}#{T(java.util.Collections).emptyList()}")
|
||||||
|
private List<String> nameListWithDefaultValue;
|
||||||
|
|
||||||
public CollectionsBean() {
|
public CollectionsBean() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,4 +55,8 @@ public class CollectionsBean {
|
|||||||
public void printBeanList() {
|
public void printBeanList() {
|
||||||
System.out.println(beanList);
|
System.out.println(beanList);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void printNameListWithDefaults() {
|
||||||
|
System.out.println(nameListWithDefaultValue);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,45 @@
|
|||||||
|
package org.baeldung.security;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import javax.servlet.Filter;
|
||||||
|
import javax.servlet.FilterChain;
|
||||||
|
import javax.servlet.FilterConfig;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.ServletRequest;
|
||||||
|
import javax.servlet.ServletResponse;
|
||||||
|
import javax.servlet.http.Cookie;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
public class SessionFilter implements Filter{
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(FilterConfig filterConfig) throws ServletException {
|
||||||
|
System.out.println("init filter");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
|
||||||
|
HttpServletRequest req = (HttpServletRequest) request;
|
||||||
|
HttpServletResponse res = (HttpServletResponse) response;
|
||||||
|
Cookie[] allCookies = req.getCookies();
|
||||||
|
if (allCookies != null) {
|
||||||
|
Cookie session = Arrays.stream(allCookies).filter(x -> x.getName().equals("JSESSIONID")).findFirst().orElse(null);
|
||||||
|
|
||||||
|
if (session != null) {
|
||||||
|
session.setHttpOnly(true);
|
||||||
|
session.setSecure(true);
|
||||||
|
res.addCookie(session);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
chain.doFilter(req, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroy() {
|
||||||
|
System.out.println("destroy filter");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -8,6 +8,10 @@
|
|||||||
|
|
||||||
<session-config>
|
<session-config>
|
||||||
<session-timeout>1</session-timeout>
|
<session-timeout>1</session-timeout>
|
||||||
|
<!-- <cookie-config>
|
||||||
|
<http-only>true</http-only>
|
||||||
|
<secure>true</secure>
|
||||||
|
</cookie-config> -->
|
||||||
</session-config>
|
</session-config>
|
||||||
<listener>
|
<listener>
|
||||||
<listener-class>org.baeldung.web.SessionListenerWithMetrics</listener-class>
|
<listener-class>org.baeldung.web.SessionListenerWithMetrics</listener-class>
|
||||||
@ -53,6 +57,15 @@
|
|||||||
<url-pattern>/*</url-pattern>
|
<url-pattern>/*</url-pattern>
|
||||||
</filter-mapping>
|
</filter-mapping>
|
||||||
|
|
||||||
|
<!-- <filter>
|
||||||
|
<filter-name>SessionFilter</filter-name>
|
||||||
|
<filter-class>org.baeldung.security.SessionFilter</filter-class>
|
||||||
|
</filter>
|
||||||
|
<filter-mapping>
|
||||||
|
<filter-name>SessionFilter</filter-name>
|
||||||
|
<url-pattern>/*</url-pattern>
|
||||||
|
</filter-mapping> -->
|
||||||
|
|
||||||
<!-- <welcome-file-list> -->
|
<!-- <welcome-file-list> -->
|
||||||
<!-- <welcome-file>index.html</welcome-file> -->
|
<!-- <welcome-file>index.html</welcome-file> -->
|
||||||
<!-- </welcome-file-list> -->
|
<!-- </welcome-file-list> -->
|
||||||
|
Loading…
x
Reference in New Issue
Block a user