Merge branch 'eugenp:master' into master
This commit is contained in:
commit
fda1afcf35
@ -10,3 +10,4 @@ This module contains complete guides about arrays in Java
|
||||
- [Creating a Generic Array in Java](https://www.baeldung.com/java-generic-array)
|
||||
- [Maximum Size of Java Arrays](https://www.baeldung.com/java-arrays-max-size)
|
||||
- [Merge Two Arrays and Remove Duplicates in Java](https://www.baeldung.com/java-merge-two-arrays-delete-duplicates)
|
||||
- [Print a Java 2D Array](https://www.baeldung.com/java-2d-array-print)
|
||||
|
@ -0,0 +1,24 @@
|
||||
package com.baeldung.equilibriumindex;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
class EquilibriumIndexFinder {
|
||||
|
||||
List<Integer> findEquilibriumIndexes(int[] array) {
|
||||
int[] partialSums = new int[array.length + 1];
|
||||
partialSums[0] = 0;
|
||||
for (int i = 0; i < array.length; i++) {
|
||||
partialSums[i+1] = partialSums[i] + array[i];
|
||||
}
|
||||
|
||||
List<Integer> equilibriumIndexes = new ArrayList<Integer>();
|
||||
for (int i = 0; i < array.length; i++) {
|
||||
if (partialSums[i] == (partialSums[array.length] - (partialSums[i+1]))) {
|
||||
equilibriumIndexes.add(i);
|
||||
}
|
||||
}
|
||||
return equilibriumIndexes;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package com.baeldung.equilibriumindex;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class EquilibriumIndexFinderUnitTest {
|
||||
|
||||
@Test
|
||||
void givenArrayHasEquilibriumIndexes_whenFindEquilibriumIndexes_thenListAllEquilibriumIndexes() {
|
||||
int[] array = {1, -3, 0, 4, -5, 4, 0, 1, -2, -1};
|
||||
assertThat(new EquilibriumIndexFinder().findEquilibriumIndexes(array)).containsExactly(1, 4, 9);
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenArrayWithoutEquilibriumIndexes_whenFindEquilibriumIndexes_thenEmptyList() {
|
||||
int[] array = {1, 2, 3};
|
||||
assertThat(new EquilibriumIndexFinder().findEquilibriumIndexes(array)).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenArrayWithOneElement_whenFindEquilibriumIndexes_thenListFirstIndex() {
|
||||
int[] array = {5};
|
||||
assertThat(new EquilibriumIndexFinder().findEquilibriumIndexes(array)).containsExactly(0);
|
||||
}
|
||||
|
||||
}
|
@ -6,3 +6,4 @@ This module contains articles about Java Character Class
|
||||
- [Character#isAlphabetic vs. Character#isLetter](https://www.baeldung.com/java-character-isletter-isalphabetic)
|
||||
- [Difference Between Java’s “char” and “String”](https://www.baeldung.com/java-char-vs-string)
|
||||
- [Increment Character in Java](https://www.baeldung.com/java-char-sequence)
|
||||
- [Creating Unicode Character From Its Code Point Hex String](https://www.baeldung.com/java-unicode-character-from-code-point-hex-string)
|
||||
|
@ -0,0 +1,33 @@
|
||||
package com.baeldung.countdownlatchvssemaphore;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
public class CountDownLatchDemo {
|
||||
|
||||
public static void main(String[] args) throws InterruptedException {
|
||||
// Create a CountDownLatch with an initial count equal to the number of tasks to be completed
|
||||
int numberOfTasks = 3;
|
||||
CountDownLatch latch = new CountDownLatch(numberOfTasks);
|
||||
|
||||
// Simulate completion of tasks by worker threads
|
||||
for (int i = 1; i <= numberOfTasks; i++) {
|
||||
new Thread(() -> {
|
||||
System.out.println("Task completed by Thread " + Thread.currentThread()
|
||||
.getId());
|
||||
|
||||
// Decrement the latch count to signal completion of a task
|
||||
latch.countDown();
|
||||
}).start();
|
||||
}
|
||||
|
||||
// Main thread waits until all tasks are completed
|
||||
latch.await();
|
||||
System.out.println("All tasks completed. Main thread proceeds.");
|
||||
|
||||
// Attempting to reset will have no effect
|
||||
latch.countDown();
|
||||
// Latch is already at zero, await() returns immediately
|
||||
latch.await(); // This line won't block
|
||||
System.out.println("Latch is already at zero and cannot be reset.");
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package com.baeldung.countdownlatchvssemaphore;
|
||||
|
||||
import java.util.concurrent.Semaphore;
|
||||
|
||||
public class SemaphoreDemo {
|
||||
|
||||
public static void main(String[] args) {
|
||||
// Create a Semaphore with a fixed number of permits
|
||||
int NUM_PERMITS = 3;
|
||||
Semaphore semaphore = new Semaphore(NUM_PERMITS);
|
||||
|
||||
// Simulate resource access by worker threads
|
||||
for (int i = 1; i <= 5; i++) {
|
||||
new Thread(() -> {
|
||||
try {
|
||||
// Acquire a permit to access the resource
|
||||
semaphore.acquire();
|
||||
System.out.println("Thread " + Thread.currentThread().getId() + " accessing resource.");
|
||||
|
||||
// Simulate resource usage
|
||||
Thread.sleep(2000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
// Release the permit after resource access is complete
|
||||
semaphore.release();
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
// Simulate resetting the Semaphore by releasing additional permits after a delay
|
||||
try {
|
||||
Thread.sleep(5000);
|
||||
|
||||
// Resetting the semaphore permits to the initial count
|
||||
semaphore.release(NUM_PERMITS);
|
||||
System.out.println("Semaphore permits reset to initial count.");
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
@ -3,4 +3,4 @@ This module contains articles about date operations in Java.
|
||||
|
||||
### Relevant Articles:
|
||||
- [Calculate Number of Weekdays Between Two Dates in Java](https://www.baeldung.com/java-count-weekdays-between-two-dates)
|
||||
|
||||
- [Convert Long to Date in Java](https://www.baeldung.com/java-long-date-conversion)
|
||||
|
@ -3,4 +3,4 @@
|
||||
This module contains articles about converting between Java date and time objects.
|
||||
|
||||
### Relevant Articles:
|
||||
|
||||
- [Convert Gregorian to Hijri Date in Java](https://www.baeldung.com/java-date-gregorian-hijri-conversion)
|
||||
|
@ -14,3 +14,4 @@ This module contains articles about core features in the Java language
|
||||
- [Static Final Variables in Java](https://www.baeldung.com/java-static-final-variables)
|
||||
- [What Is the Error: “Non-static method cannot be referenced from a static context”?](https://www.baeldung.com/java-non-static-method-cannot-be-referenced-from-a-static-context)
|
||||
- [Recursively Sum the Integers in an Array](https://www.baeldung.com/java-recursive-sum-integer-array)
|
||||
- [Set an Environment Variable at Runtime in Java](https://www.baeldung.com/java-set-environment-variable-runtime)
|
||||
|
@ -0,0 +1,55 @@
|
||||
package com.baeldung.customurlconnection;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
|
||||
public class CustomURLConnection extends URLConnection {
|
||||
private final String simulatedData = "This is the simulated data from the resource.";
|
||||
private URL url;
|
||||
private boolean connected = false;
|
||||
private String headerValue = "SimulatedHeaderValue";
|
||||
|
||||
protected CustomURLConnection(URL url) {
|
||||
super(url);
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connect() throws IOException {
|
||||
connected = true;
|
||||
System.out.println("Connection established to: " + url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getInputStream() throws IOException {
|
||||
if (!connected) {
|
||||
connect();
|
||||
}
|
||||
return new ByteArrayInputStream(simulatedData.getBytes());
|
||||
}
|
||||
|
||||
@Override
|
||||
public OutputStream getOutputStream() throws IOException {
|
||||
ByteArrayOutputStream simulatedOutput = new ByteArrayOutputStream();
|
||||
return simulatedOutput;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getContentLength() {
|
||||
return simulatedData.length();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHeaderField(String name) {
|
||||
if ("SimulatedHeader".equalsIgnoreCase(name)) { // Example header name
|
||||
return headerValue;
|
||||
} else {
|
||||
return null; // Header not found
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package com.baeldung.customurlconnection;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.net.URLStreamHandler;
|
||||
|
||||
public class CustomURLStreamHandler extends URLStreamHandler {
|
||||
|
||||
@Override
|
||||
protected URLConnection openConnection(URL u) throws IOException {
|
||||
// Create and return an instance of CustomURLConnection
|
||||
return new CustomURLConnection(u);
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package com.baeldung.customurlconnection;
|
||||
|
||||
import java.net.URLStreamHandler;
|
||||
import java.net.URLStreamHandlerFactory;
|
||||
|
||||
public class CustomURLStreamHandlerFactory implements URLStreamHandlerFactory {
|
||||
|
||||
@Override
|
||||
public URLStreamHandler createURLStreamHandler(String protocol) {
|
||||
// Check if the requested protocol is our custom protocol
|
||||
if ("myprotocol".equals(protocol)) {
|
||||
return new CustomURLStreamHandler();
|
||||
}
|
||||
return null; // Let the default handler deal with other protocols
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package com.baeldung.customurlconnection;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.util.Scanner;
|
||||
|
||||
public class Main {
|
||||
|
||||
public static void main(String[] args) {
|
||||
URL.setURLStreamHandlerFactory(new CustomURLStreamHandlerFactory());
|
||||
|
||||
try {
|
||||
URL url = new URL("myprotocol://example.com/resource");
|
||||
|
||||
CustomURLConnection customConnection = (CustomURLConnection) url.openConnection();
|
||||
customConnection.connect();
|
||||
|
||||
InputStream inputStream = customConnection.getInputStream();
|
||||
|
||||
String content = new Scanner(inputStream).useDelimiter("\\A").next();
|
||||
System.out.println(content);
|
||||
|
||||
int contentLength = customConnection.getContentLength();
|
||||
System.out.println("Content Length: " + contentLength);
|
||||
|
||||
String headerValue = customConnection.getHeaderField("SimulatedHeader");
|
||||
System.out.println("Header Value: " + headerValue);
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
package com.baeldung.urlencoder;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class SpaceURLEncoderUnitTest {
|
||||
|
||||
@Test
|
||||
void givenSpaceInString_whenUsingDefaultEncoding_thenReturnPlusSign() {
|
||||
String originalString = "Welcome to the Baeldung Website!";
|
||||
String encodedString = URLEncoder.encode(originalString);
|
||||
assertEquals("Welcome+to+the+Baeldung+Website%21", encodedString);
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenSpaceInString_whenUsingUTF8Encoding_thenReturnPlusSign() throws UnsupportedEncodingException {
|
||||
String originalString = "Welcome to the Baeldung Website!";
|
||||
String encodedString = URLEncoder.encode(originalString, StandardCharsets.UTF_8.toString());
|
||||
assertEquals("Welcome+to+the+Baeldung+Website%21", encodedString);
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenSpaceInString_whenUsingDefaultEncodingAndReplace_thenReturnPct20() throws UnsupportedEncodingException {
|
||||
String originalString = "Welcome to the Baeldung Website!";
|
||||
String encodedString = URLEncoder.encode(originalString)
|
||||
.replace("+", "%20");
|
||||
assertEquals("Welcome%20to%20the%20Baeldung%20Website%21", encodedString);
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenSpaceInString_whenUsingDefaultEncodingAndReplaceAll_thenReturnPct20() throws UnsupportedEncodingException {
|
||||
String originalString = "Welcome to the Baeldung Website!";
|
||||
String encodedString = URLEncoder.encode(originalString)
|
||||
.replaceAll("\\+", "%20");
|
||||
assertEquals("Welcome%20to%20the%20Baeldung%20Website%21", encodedString);
|
||||
}
|
||||
}
|
@ -22,7 +22,7 @@ public class URLNormalizationUnitTest {
|
||||
String normalizedUri = originalUrl.split("\\?")[0];
|
||||
assertEquals(expectedNormalizedUrl, normalizedUri);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Invalid URL: " + originalUrl);
|
||||
fail(originalUrl);
|
||||
}
|
||||
}
|
||||
|
||||
@ -35,7 +35,7 @@ public class URLNormalizationUnitTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenOriginalUrl_whenUsingRegularExpression_thenNormalizedUrl() throws URISyntaxException, UnsupportedEncodingException {
|
||||
public void givenOriginalUrl_whenUsingRegularExpression_thenNormalizedUrl() {
|
||||
String regex = "^(https?://[^/]+/[^?#]+)";
|
||||
Pattern pattern = Pattern.compile(regex);
|
||||
Matcher matcher = pattern.matcher(originalUrl);
|
||||
@ -44,7 +44,7 @@ public class URLNormalizationUnitTest {
|
||||
String normalizedUrl = matcher.group(1);
|
||||
assertEquals(expectedNormalizedUrl, normalizedUrl);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Invalid URL: " + originalUrl);
|
||||
fail(originalUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,20 @@
|
||||
package com.baeldung.reflection.innerclass;
|
||||
|
||||
public class Person {
|
||||
String name;
|
||||
Address address;
|
||||
|
||||
public Person() {
|
||||
}
|
||||
|
||||
public class Address {
|
||||
String zip;
|
||||
|
||||
public Address(String zip) {
|
||||
this.zip = zip;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
}
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
package com.baeldung.reflection.innerclass;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Arrays;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class CreateInnerClassWithReflectionUnitTest {
|
||||
|
||||
static Logger logger = LoggerFactory.getLogger(CreateInnerClassWithReflectionUnitTest.class);
|
||||
|
||||
@Test
|
||||
void givenInnerClass_whenUseReflection_thenShowConstructors() {
|
||||
final String personBuilderClassName = "com.baeldung.reflection.innerclass.Person$Builder";
|
||||
final String personAddressClassName = "com.baeldung.reflection.innerclass.Person$Address";
|
||||
assertDoesNotThrow(() -> logConstructors(Class.forName(personAddressClassName)));
|
||||
assertDoesNotThrow(() -> logConstructors(Class.forName(personBuilderClassName)));
|
||||
}
|
||||
|
||||
private static void logConstructors(Class<?> clazz) {
|
||||
Arrays.stream(clazz.getDeclaredConstructors())
|
||||
.map(c -> formatConstructorSignature(c))
|
||||
.forEach(logger::info);
|
||||
}
|
||||
|
||||
private static String formatConstructorSignature(Constructor<?> constructor) {
|
||||
String params = Arrays.stream(constructor.getParameters())
|
||||
.map(parameter -> parameter.getType().getSimpleName() + " " + parameter.getName())
|
||||
.collect(Collectors.joining(", "));
|
||||
return constructor.getName() + "(" + params + ")";
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenStaticInnerClass_whenUseReflection_thenInstantiate()
|
||||
throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException,
|
||||
InstantiationException, IllegalAccessException {
|
||||
final String personBuilderClassName = "com.baeldung.reflection.innerclass.Person$Builder";
|
||||
Class<Person.Builder> personBuilderClass = (Class<Person.Builder>) Class.forName(personBuilderClassName);
|
||||
Person.Builder personBuilderObj = personBuilderClass.getDeclaredConstructor().newInstance();
|
||||
assertTrue(personBuilderObj instanceof Person.Builder);
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenNonStaticInnerClass_whenUseReflection_thenInstantiate()
|
||||
throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException,
|
||||
InstantiationException, IllegalAccessException {
|
||||
final String personClassName = "com.baeldung.reflection.innerclass.Person";
|
||||
final String personAddressClassName = "com.baeldung.reflection.innerclass.Person$Address";
|
||||
|
||||
Class<Person> personClass = (Class<Person>) Class.forName(personClassName);
|
||||
Person personObj = personClass.getConstructor().newInstance();
|
||||
|
||||
Class<Person.Address> personAddressClass = (Class<Person.Address>) Class.forName(personAddressClassName);
|
||||
|
||||
assertThrows(NoSuchMethodException.class, () -> personAddressClass.getDeclaredConstructor(String.class));
|
||||
|
||||
Constructor<Person.Address> constructorOfPersonAddress = personAddressClass.getDeclaredConstructor(Person.class, String.class);
|
||||
Person.Address personAddressObj = constructorOfPersonAddress.newInstance(personObj, "751003");
|
||||
assertTrue(personAddressObj instanceof Person.Address);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package com.baeldung.stream.range;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class StreamRangeUnitTest {
|
||||
|
||||
@Test
|
||||
public void whenRangeStreamUsingLimitSkip_thenPrintsRange() {
|
||||
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
|
||||
List<Integer> expectedRange = Arrays.asList(3, 4, 5, 6, 7);
|
||||
|
||||
List<Integer> range = numbers.stream()
|
||||
.skip(2)
|
||||
.limit(5)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
assertEquals(expectedRange, range);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenRangeStreamUsingCollectingAndThen_thenPrintsRange() {
|
||||
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
|
||||
List<Integer> expectedRange = Arrays.asList(3, 4, 5, 6, 7);
|
||||
|
||||
List<Integer> range = numbers.stream()
|
||||
.filter(n -> n >= 3 && n <= 7)
|
||||
.collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
|
||||
|
||||
assertEquals(expectedRange, range);
|
||||
}
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
package com.baeldung.string.runlength;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class RunLengthEncodingUnitTest {
|
||||
private static final String INPUT = "WWWWWWWWWWWWBAAACCDEEEEE";
|
||||
private static final String RLE = "12W1B3A2C1D5E";
|
||||
|
||||
String runLengthEncode(String input) {
|
||||
StringBuilder result = new StringBuilder();
|
||||
int count = 1;
|
||||
char[] chars = input.toCharArray();
|
||||
for (int i = 0; i < chars.length; i++) {
|
||||
char c = chars[i];
|
||||
if (i + 1 < chars.length && c == chars[i + 1]) {
|
||||
count++;
|
||||
} else {
|
||||
result.append(count).append(c);
|
||||
count = 1;
|
||||
}
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
|
||||
String runLengthDecode(String rle) {
|
||||
StringBuilder result = new StringBuilder();
|
||||
char[] chars = rle.toCharArray();
|
||||
|
||||
int count = 0;
|
||||
for (char c : chars) {
|
||||
if (Character.isDigit(c)) {
|
||||
count = 10 * count + Character.getNumericValue(c);
|
||||
} else {
|
||||
result.append(String.join("", Collections.nCopies(count, String.valueOf(c))));
|
||||
count = 0;
|
||||
}
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
String runLengthEncodeByRegEx(String input) {
|
||||
String[] arr = input.split("(?<=(\\D))(?!\\1)");
|
||||
StringBuilder result = new StringBuilder();
|
||||
for (String run : arr) {
|
||||
result.append(run.length()).append(run.charAt(0));
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
String runLengthDecodeByRegEx(String rle) {
|
||||
if (rle.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
String[] arr = rle.split("(?<=\\D)|(?=\\D+)");
|
||||
if (arr.length % 2 != 0) {
|
||||
throw new IllegalArgumentException("Not a RLE string");
|
||||
}
|
||||
StringBuilder result = new StringBuilder();
|
||||
|
||||
for (int i = 1; i <= arr.length; i += 2) {
|
||||
int count = Integer.parseInt(arr[i - 1]);
|
||||
String c = arr[i];
|
||||
|
||||
result.append(String.join("", Collections.nCopies(count, c)));
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenInvokingRunLengthEncode_thenGetExpectedResult() {
|
||||
assertEquals(RLE, runLengthEncode(INPUT));
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenInvokingRunLengthDecode_thenGetExpectedResult() {
|
||||
assertEquals(INPUT, runLengthDecode(RLE));
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenInvokingRunLengthEncodeByRegEx_thenGetExpectedResult() {
|
||||
assertEquals(RLE, runLengthEncodeByRegEx(INPUT));
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenInvokingRunLengthDecodeByRegEx_thenGetExpectedResult() {
|
||||
assertEquals(INPUT, runLengthDecodeByRegEx(RLE));
|
||||
}
|
||||
}
|
@ -14,3 +14,4 @@
|
||||
- [UTF-8 Validation in Java](https://www.baeldung.com/java-utf-8-validation)
|
||||
- [Simple Morse Code Translation in Java](https://www.baeldung.com/java-morse-code-english-translate)
|
||||
- [How to Determine if a String Contains Invalid Encoded Characters](https://www.baeldung.com/java-check-string-contains-invalid-encoded-characters)
|
||||
- [Regular Expression for Password Validation in Java](https://www.baeldung.com/java-regex-password-validation)
|
||||
|
@ -14,7 +14,7 @@ public class DecodeUUIDStringFromBase64UnitTest {
|
||||
private final UUID originalUUID = UUID.fromString("cc5f93f7-8cf1-4a51-83c6-e740313a0c6c");
|
||||
|
||||
@Test
|
||||
public void shouldDecodeUUIDUsingByteArrayAndBase64Decoder() {
|
||||
public void givenEncodedString_whenDecodingUsingBase64Decoder_thenGiveExpectedUUID() {
|
||||
String expectedEncodedString = "UUrxjPeTX8xsDDoxQOfGgw";
|
||||
byte[] decodedBytes = Base64.getDecoder()
|
||||
.decode(expectedEncodedString);
|
||||
@ -23,7 +23,7 @@ public class DecodeUUIDStringFromBase64UnitTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldDecodeUUIDUsingByteBufferAndBase64UrlDecoder() {
|
||||
public void givenEncodedString_whenDecodingUsingByteBufferAndBase64UrlDecoder_thenGiveExpectedUUID() {
|
||||
String expectedEncodedString = "zF-T94zxSlGDxudAMToMbA";
|
||||
byte[] decodedBytes = Base64.getUrlDecoder()
|
||||
.decode(expectedEncodedString);
|
||||
@ -35,7 +35,7 @@ public class DecodeUUIDStringFromBase64UnitTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldDecodeUUIDUsingApacheUtils() {
|
||||
public void givenEncodedString_whenDecodingUsingApacheUtils_thenGiveExpectedUUID() {
|
||||
String expectedEncodedString = "UUrxjPeTX8xsDDoxQOfGgw";
|
||||
byte[] decodedBytes = decodeBase64(expectedEncodedString);
|
||||
UUID uuid = Conversion.byteArrayToUuid(decodedBytes, 0);
|
||||
|
@ -14,7 +14,7 @@ public class EncodeUUIDToBase64StringUnitTest {
|
||||
private final UUID originalUUID = UUID.fromString("cc5f93f7-8cf1-4a51-83c6-e740313a0c6c");
|
||||
|
||||
@Test
|
||||
public void shouldEncodeUUIDUsingByteArrayAndBase64Encoder() {
|
||||
public void givenUUID_whenEncodingUsingBase64Encoder_thenGiveExpectedEncodedString() {
|
||||
String expectedEncodedString = "UUrxjPeTX8xsDDoxQOfGgw";
|
||||
byte[] uuidBytes = convertToByteArray(originalUUID);
|
||||
String encodedUUID = Base64.getEncoder().withoutPadding()
|
||||
@ -23,7 +23,7 @@ public class EncodeUUIDToBase64StringUnitTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldEncodeUUIDUsingByteBufferAndBase64UrlEncoder() {
|
||||
public void givenUUID_whenEncodingUsingByteBufferAndBase64UrlEncoder_thenGiveExpectedEncodedString() {
|
||||
String expectedEncodedString = "zF-T94zxSlGDxudAMToMbA";
|
||||
ByteBuffer byteBuffer = ByteBuffer.wrap(new byte[16]);
|
||||
byteBuffer.putLong(originalUUID.getMostSignificantBits());
|
||||
@ -34,7 +34,7 @@ public class EncodeUUIDToBase64StringUnitTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldEncodeUUIDUsingApacheUtils() {
|
||||
public void givenUUID_whenEncodingUsingApacheUtils_thenGiveExpectedEncodedString() {
|
||||
String expectedEncodedString = "UUrxjPeTX8xsDDoxQOfGgw";
|
||||
byte[] bytes = Conversion.uuidToByteArray(originalUUID, new byte[16], 0, 16);
|
||||
String encodedUUID = encodeBase64URLSafeString(bytes);
|
||||
|
BIN
javax-sound/src/main/resources/AudioFileWithMpegFormat.mpeg
Normal file
BIN
javax-sound/src/main/resources/AudioFileWithMpegFormat.mpeg
Normal file
Binary file not shown.
BIN
javax-sound/src/main/resources/AudioFileWithWavFormat.wav
Normal file
BIN
javax-sound/src/main/resources/AudioFileWithWavFormat.wav
Normal file
Binary file not shown.
2
logging-modules/logging-techniques/README.md
Normal file
2
logging-modules/logging-techniques/README.md
Normal file
@ -0,0 +1,2 @@
|
||||
### Relevant Articles:
|
||||
- [Structured Logging in Java](https://www.baeldung.com/java-structured-logging)
|
@ -8,6 +8,36 @@
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<name>maven-exec-plugin</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven.shared</groupId>
|
||||
<artifactId>maven-invoker</artifactId>
|
||||
<version>${apache.maven.invoker.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven</groupId>
|
||||
<artifactId>maven-embedder</artifactId>
|
||||
<version>${apache.maven.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<version>${junit.jupiter.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<version>${junit.jupiter.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<version>${junit.jupiter.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
@ -38,6 +68,9 @@
|
||||
<properties>
|
||||
<maven-compiler-plugin.version>3.12.1</maven-compiler-plugin.version>
|
||||
<exec-maven-plugin.version>3.1.0</exec-maven-plugin.version>
|
||||
<junit.jupiter.version>5.10.0</junit.jupiter.version>
|
||||
<apache.maven.version>3.9.6</apache.maven.version>
|
||||
<apache.maven.invoker.version>3.2.0</apache.maven.invoker.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
@ -0,0 +1,17 @@
|
||||
package com.baeldung.learningplatform;
|
||||
|
||||
public enum JavaVersion {
|
||||
|
||||
JAVA_8("1.8"), JAVA_9("9"), JAVA_17("17");
|
||||
|
||||
private final String version;
|
||||
|
||||
|
||||
JavaVersion(String version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return this.version;
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package com.baeldung.learningplatform;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
public interface Maven {
|
||||
String POM_XML = "pom.xml";
|
||||
String COMPILE_GOAL = "compile";
|
||||
String USE_CUSTOM_POM = "-f";
|
||||
int OK = 0;
|
||||
String MVN = "mvn";
|
||||
|
||||
void compile(Path projectFolder);
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package com.baeldung.learningplatform;
|
||||
|
||||
public class MavenCompilationException extends RuntimeException {
|
||||
|
||||
public MavenCompilationException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public MavenCompilationException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package com.baeldung.learningplatform;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import org.apache.maven.cli.MavenCli;
|
||||
|
||||
public class MavenEmbedder implements Maven {
|
||||
|
||||
public static final String MVN_HOME = "maven.multiModuleProjectDirectory";
|
||||
|
||||
@Override
|
||||
public void compile(Path projectFolder) {
|
||||
MavenCli cli = new MavenCli();
|
||||
System.setProperty(MVN_HOME, projectFolder.toString());
|
||||
cli.doMain(new String[]{COMPILE_GOAL}, projectFolder.toString(), null, null);
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package com.baeldung.learningplatform;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public abstract class MavenExecutorAdapter implements Maven {
|
||||
|
||||
@Override
|
||||
public void compile(Path projectFolder) {
|
||||
int exitCode;
|
||||
try {
|
||||
exitCode = execute(projectFolder, COMPILE_GOAL);
|
||||
} catch (InterruptedException e) {
|
||||
throw new MavenCompilationException("Interrupted during compilation", e);
|
||||
} catch (IOException e) {
|
||||
throw new MavenCompilationException("Incorrect execution", e);
|
||||
}
|
||||
if (exitCode != OK) {
|
||||
throw new MavenCompilationException("Failure during compilation: " + exitCode);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract int execute(Path projectFolder, String compileGoal)
|
||||
throws InterruptedException, IOException;
|
||||
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package com.baeldung.learningplatform;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
import org.apache.maven.shared.invoker.DefaultInvocationRequest;
|
||||
import org.apache.maven.shared.invoker.DefaultInvoker;
|
||||
import org.apache.maven.shared.invoker.InvocationRequest;
|
||||
import org.apache.maven.shared.invoker.InvocationResult;
|
||||
import org.apache.maven.shared.invoker.Invoker;
|
||||
import org.apache.maven.shared.invoker.MavenInvocationException;
|
||||
|
||||
public class MavenInvoker implements Maven {
|
||||
|
||||
@Override
|
||||
public void compile(Path projectFolder) {
|
||||
InvocationRequest request = new DefaultInvocationRequest();
|
||||
request.setPomFile(projectFolder.resolve(POM_XML).toFile());
|
||||
request.setGoals(Collections.singletonList(Maven.COMPILE_GOAL));
|
||||
Invoker invoker = new DefaultInvoker();
|
||||
try {
|
||||
InvocationResult result = invoker.execute(request);
|
||||
if (result.getExitCode() != 0) {
|
||||
throw new MavenCompilationException("Build failed", result.getExecutionException());
|
||||
}
|
||||
} catch (MavenInvocationException e) {
|
||||
throw new MavenCompilationException("Exception during Maven invocation", e);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package com.baeldung.learningplatform;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class MavenProcessBuilder extends MavenExecutorAdapter {
|
||||
private static final ProcessBuilder PROCESS_BUILDER = new ProcessBuilder();
|
||||
|
||||
protected int execute(Path projectFolder, String compileGoal) throws IOException, InterruptedException {
|
||||
Process process = PROCESS_BUILDER
|
||||
.command(MVN, USE_CUSTOM_POM, projectFolder.resolve(POM_XML).toString(), compileGoal)
|
||||
.start();
|
||||
return process.waitFor();
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package com.baeldung.learningplatform;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class MavenRuntimeExec extends MavenExecutorAdapter {
|
||||
@Override
|
||||
protected int execute(Path projectFolder, String compileGoal) throws InterruptedException, IOException {
|
||||
String[] arguments = {MVN, USE_CUSTOM_POM, projectFolder.resolve(POM_XML).toString(), COMPILE_GOAL};
|
||||
Process process = Runtime.getRuntime().exec(arguments);
|
||||
return process.waitFor();
|
||||
}
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
package com.baeldung.learningplatform;
|
||||
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.apache.maven.model.Build;
|
||||
import org.apache.maven.model.Dependency;
|
||||
import org.apache.maven.model.Model;
|
||||
import org.apache.maven.model.Plugin;
|
||||
import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
|
||||
import org.codehaus.plexus.util.xml.Xpp3Dom;
|
||||
|
||||
public class ProjectBuilder {
|
||||
|
||||
private static final String PACKAGE = "package ";
|
||||
private static final String POM_XML = "pom.xml";
|
||||
private static final String SRC_TEST = "src/test/";
|
||||
private static final String SRC_MAIN_JAVA = "src/main/java/";
|
||||
private static final String PACKAGE_DELIMITER = ".";
|
||||
private static final String MAIN_JAVA = "Main.java";
|
||||
private final List<Dependency> dependencies = new ArrayList<>();
|
||||
private JavaVersion javaVersion = JavaVersion.JAVA_8;
|
||||
|
||||
public ProjectBuilder addDependency(String groupId, String artifactId, String version) {
|
||||
Dependency dependency = new Dependency();
|
||||
dependency.setGroupId(groupId);
|
||||
dependency.setArtifactId(artifactId);
|
||||
dependency.setVersion(version);
|
||||
dependencies.add(dependency);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ProjectBuilder setJavaVersion(JavaVersion version) {
|
||||
this.javaVersion = version;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void build(String userName, Path projectPath, String packageName) throws IOException {
|
||||
Model model = new Model();
|
||||
configureModel(userName, model);
|
||||
dependencies.forEach(model::addDependency);
|
||||
Build build = configureJavaVersion();
|
||||
model.setBuild(build);
|
||||
MavenXpp3Writer writer = new MavenXpp3Writer();
|
||||
writer.write(new FileWriter(projectPath.resolve(POM_XML).toFile()), model);
|
||||
generateFolders(projectPath, SRC_TEST);
|
||||
|
||||
Path generatedPackage = generateFolders(projectPath,
|
||||
SRC_MAIN_JAVA +
|
||||
packageName.replace(PACKAGE_DELIMITER, FileSystems.getDefault().getSeparator()));
|
||||
String generatedClass = generateMainClass(PACKAGE + packageName);
|
||||
Files.writeString(generatedPackage.resolve(MAIN_JAVA), generatedClass);
|
||||
}
|
||||
|
||||
private static void configureModel(String userName, Model model) {
|
||||
model.setModelVersion("4.0.0");
|
||||
model.setArtifactId("com." + userName.toLowerCase());
|
||||
model.setGroupId("learning-project");
|
||||
model.setVersion("0.0.1-SNAPSHOT");
|
||||
}
|
||||
|
||||
private static String generateMainClass(String packageName) {
|
||||
return packageName + ";\n" +
|
||||
"\n" +
|
||||
"public class Main {\n" +
|
||||
" public static void main(String[] args){\n" +
|
||||
" System.out.println(\"Hello World!\");\n" +
|
||||
" }\n" +
|
||||
"}\n";
|
||||
}
|
||||
|
||||
private static Path generateFolders(Path sourceFolder, String packageName) throws IOException {
|
||||
return Files.createDirectories(sourceFolder.resolve(packageName));
|
||||
}
|
||||
|
||||
private Build configureJavaVersion() {
|
||||
Plugin plugin = new Plugin();
|
||||
plugin.setGroupId("org.apache.maven.plugins");
|
||||
plugin.setArtifactId("maven-compiler-plugin");
|
||||
plugin.setVersion("3.8.1");
|
||||
|
||||
Xpp3Dom configuration = new Xpp3Dom("configuration");
|
||||
Xpp3Dom source = new Xpp3Dom("source");
|
||||
source.setValue(javaVersion.getVersion());
|
||||
Xpp3Dom target = new Xpp3Dom("target");
|
||||
target.setValue(javaVersion.getVersion());
|
||||
configuration.addChild(source);
|
||||
configuration.addChild(target);
|
||||
|
||||
plugin.setConfiguration(configuration);
|
||||
|
||||
Build build = new Build();
|
||||
build.addPlugin(plugin);
|
||||
return build;
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package com.baeldung.learningplatform;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.FileVisitResult;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.SimpleFileVisitor;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
|
||||
public class FileUtil {
|
||||
|
||||
private FileUtil() {
|
||||
}
|
||||
|
||||
public static void removeDirectoryRecursively(Path folder) throws IOException {
|
||||
if (Files.exists(folder)) {
|
||||
Files.walkFileTree(folder, new SimpleFileVisitor<>() {
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
||||
Files.delete(file);
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
|
||||
Files.delete(dir);
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package com.baeldung.learningplatform;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.stream.Stream;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
class MavenRuntimeExecUnitTest {
|
||||
|
||||
private static final String PACKAGE_NAME = "com.baeldung.generatedcode";
|
||||
private static final String USER_NAME = "john_doe";
|
||||
@TempDir
|
||||
private Path tempDir;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() throws IOException {
|
||||
ProjectBuilder projectBuilder = new ProjectBuilder();
|
||||
projectBuilder.build(USER_NAME, tempDir, PACKAGE_NAME);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource
|
||||
void givenMavenInterface_whenCompileMavenProject_thenCreateTargetDirectory(Maven maven) {
|
||||
maven.compile(tempDir);
|
||||
assertTrue(Files.exists(tempDir));
|
||||
}
|
||||
|
||||
static Stream<Maven> givenMavenInterface_whenCompileMavenProject_thenCreateTargetDirectory() {
|
||||
return Stream.of(
|
||||
new MavenRuntimeExec(),
|
||||
new MavenProcessBuilder(),
|
||||
new MavenEmbedder(),
|
||||
new MavenInvoker());
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package com.baeldung.learningplatform;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
public interface ProjectsPaths {
|
||||
|
||||
public static final Path PROJECT_DIR = Paths.get("src/test/resources/learning-project/");
|
||||
public static final Path PROJECT_POM_XML = PROJECT_DIR.resolve("pom.xml");
|
||||
public static final Path PROJECT_TARGET = PROJECT_DIR.resolve("target");
|
||||
}
|
@ -12,7 +12,7 @@ class ConnectionPerChannelPublisherLiveTest {
|
||||
// host, workerCount, iterations, payloadSize
|
||||
Stream.of(1,5,10,20,50,100,150)
|
||||
.forEach(workers -> {
|
||||
ConnectionPerChannelPublisher.main(new String[]{"192.168.99.100", Integer.toString(workers), "1000", "4096"});
|
||||
ConnectionPerChannelPublisher.main(new String[]{"localhost", Integer.toString(workers), "1000", "4096"});
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -10,9 +10,9 @@ class SingleConnectionPublisherLiveTest {
|
||||
@Test
|
||||
void whenSingleChannel_thenRunBenchmark() throws Exception {
|
||||
// host, workerCount, iterations, payloadSize
|
||||
Stream.of(1,5,10,20,50,100,150)
|
||||
Stream.of(1,5,10,20,50)
|
||||
.forEach(workers -> {
|
||||
SingleConnectionPublisher.main(new String[]{"192.168.99.100", Integer.toString(workers), "1000", "4096"});
|
||||
SingleConnectionPublisher.main(new String[]{"localhost", Integer.toString(workers), "1000", "4096"});
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -56,11 +56,17 @@ public class DynamicQueueCreationLiveTest {
|
||||
|
||||
@Test
|
||||
void givenQueueName_whenQueueDoesNotExist_thenCheckingIfQueueExists() throws IOException, TimeoutException {
|
||||
|
||||
try (Channel channel = connection.createChannel()) {
|
||||
Channel temp = null;
|
||||
try {
|
||||
Channel channel = connection.createChannel();
|
||||
assertThrows(IOException.class, () -> {
|
||||
channel.queueDeclarePassive(QUEUE_NAME_NEW);
|
||||
});
|
||||
temp = channel;
|
||||
} finally {
|
||||
if(temp != null && temp.isOpen()) {
|
||||
temp.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,7 @@
|
||||
<groupId>io.micronaut.platform</groupId>
|
||||
<artifactId>micronaut-parent</artifactId>
|
||||
<version>4.1.2</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
<properties>
|
||||
<packaging>jar</packaging>
|
||||
|
@ -1 +1,2 @@
|
||||
### Relevant Articles:
|
||||
- [Monkey Patching in Java](https://www.baeldung.com/java-monkey-patching)
|
||||
|
@ -6,6 +6,18 @@
|
||||
<artifactId>core-java-persistence-3</artifactId>
|
||||
<version>0.1.0-SNAPSHOT</version>
|
||||
<name>core-java-persistence-3</name>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>17</source>
|
||||
<target>17</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<parent>
|
||||
|
@ -0,0 +1,33 @@
|
||||
package jdbcpagination;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
public class PaginationLogic {
|
||||
|
||||
public static ResultSet readPageWithLimitAndOffset(Connection connection, int offset, int pageSize) throws SQLException {
|
||||
String sql = """
|
||||
SELECT * FROM employees
|
||||
LIMIT ? OFFSET ?
|
||||
""";
|
||||
PreparedStatement preparedStatement = connection.prepareStatement(sql);
|
||||
preparedStatement.setInt(1, pageSize);
|
||||
preparedStatement.setInt(2, offset);
|
||||
|
||||
return preparedStatement.executeQuery();
|
||||
}
|
||||
|
||||
public static ResultSet readPageWithSortedKeys(Connection connection, int lastFetchedId, int pageSize) throws SQLException {
|
||||
String sql = """
|
||||
SELECT * FROM employees
|
||||
WHERE id > ? LIMIT ?
|
||||
""";
|
||||
PreparedStatement preparedStatement = connection.prepareStatement(sql);
|
||||
preparedStatement.setInt(1, lastFetchedId);
|
||||
preparedStatement.setInt(2, pageSize);
|
||||
|
||||
return preparedStatement.executeQuery();
|
||||
}
|
||||
}
|
@ -0,0 +1,134 @@
|
||||
package jdbcpagination;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class PaginationLogicUnitTest {
|
||||
private static Connection connection = null;
|
||||
private static final String JDBC_URL = "jdbc:h2:mem:testDB";
|
||||
private static final String USERNAME = "dbUser";
|
||||
private static final String PASSWORD = "dbPassword";
|
||||
|
||||
@BeforeAll
|
||||
public static void setup() throws Exception {
|
||||
connection = connect(JDBC_URL, USERNAME, PASSWORD);
|
||||
populateDB();
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void tearDown() throws SQLException {
|
||||
destroyDB();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenDBPopulated_WhenReadPaginatedWithLimitAndOffset_ThenReturnsPaginatedResult() throws SQLException {
|
||||
int offset = 0; // offset is set to 0 and keep updating with pageSize
|
||||
int pageSize = 100_000;
|
||||
int totalPages = 0;
|
||||
while (true) {
|
||||
ResultSet resultSet = PaginationLogic.readPageWithLimitAndOffset(connection, offset, pageSize);
|
||||
if (!resultSet.next())
|
||||
break;
|
||||
List<String> resultPage = new ArrayList<>();
|
||||
|
||||
do {
|
||||
resultPage.add(resultSet.getString("first_name"));
|
||||
} while (resultSet.next());
|
||||
assertEquals("firstname" + (resultPage.size() * (totalPages + 1)), resultPage.get(resultPage.size() - 1));
|
||||
offset += pageSize;
|
||||
totalPages++;
|
||||
}
|
||||
assertEquals(10, totalPages);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenDBPopulated_WhenReadPaginatedWithSortedKeys_ThenReturnsPaginatedResult() throws SQLException {
|
||||
// find min and max ID
|
||||
PreparedStatement preparedStatement = connection.prepareStatement("SELECT min(id) as min_id, max(id) as max_id FROM employees");
|
||||
ResultSet resultSet = preparedStatement.executeQuery();
|
||||
resultSet.next();
|
||||
|
||||
int minId = resultSet.getInt("min_id");
|
||||
int maxId = resultSet.getInt("max_id");
|
||||
int lastFetchedId = 0; // assign lastFetchedId to minId
|
||||
|
||||
int pageSize = 100_000;
|
||||
int totalPages = 0;
|
||||
|
||||
while ((lastFetchedId + pageSize) <= maxId) {
|
||||
resultSet = PaginationLogic.readPageWithSortedKeys(connection, lastFetchedId, pageSize);
|
||||
if (!resultSet.next())
|
||||
break;
|
||||
List<String> resultPage = new ArrayList<>();
|
||||
do {
|
||||
resultPage.add(resultSet.getString("first_name"));
|
||||
lastFetchedId = resultSet.getInt("id");
|
||||
} while (resultSet.next());
|
||||
assertEquals("firstname" + (resultPage.size() * (totalPages + 1)), resultPage.get(resultPage.size() - 1));
|
||||
totalPages++;
|
||||
}
|
||||
assertEquals(10, totalPages);
|
||||
}
|
||||
|
||||
private static void destroyDB() throws SQLException {
|
||||
String destroy = """
|
||||
DROP table IF EXISTS EMPLOYEES;
|
||||
""";
|
||||
connection.prepareStatement(destroy)
|
||||
.execute();
|
||||
}
|
||||
|
||||
private static void populateDB() throws SQLException {
|
||||
String createTable = """
|
||||
CREATE TABLE EMPLOYEES (
|
||||
id SERIAL PRIMARY KEY,
|
||||
first_name VARCHAR(50),
|
||||
last_name VARCHAR(50),
|
||||
salary DECIMAL(10, 2)
|
||||
);
|
||||
""";
|
||||
PreparedStatement preparedStatement = connection.prepareStatement(createTable);
|
||||
preparedStatement.execute();
|
||||
|
||||
String load = """
|
||||
INSERT INTO EMPLOYEES (first_name, last_name, salary)
|
||||
VALUES(?,?,?)
|
||||
""";
|
||||
IntStream.rangeClosed(1, 1_000_000)
|
||||
.forEach(i -> {
|
||||
PreparedStatement preparedStatement1 = null;
|
||||
try {
|
||||
preparedStatement1 = connection.prepareStatement(load);
|
||||
preparedStatement1.setString(1, "firstname" + i);
|
||||
preparedStatement1.setString(2, "lastname" + i);
|
||||
preparedStatement1.setDouble(3, 100_000 + (1_000_000 - 100_000) + Math.random());
|
||||
|
||||
preparedStatement1.execute();
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static Connection connect(String url, String user, String password) throws SQLException {
|
||||
Connection connection = DriverManager.getConnection(url, user, password);
|
||||
if (connection != null) {
|
||||
System.out.println("Connected to database");
|
||||
}
|
||||
|
||||
return connection;
|
||||
}
|
||||
|
||||
}
|
@ -102,7 +102,7 @@
|
||||
<module>spring-data-solr</module>
|
||||
<module>spring-data-shardingsphere</module>
|
||||
<module>spring-hibernate-3</module>
|
||||
<!-- <module>spring-hibernate-5</module> FAILED --> <!-- long running -->
|
||||
<module>spring-hibernate-5</module>
|
||||
<module>spring-hibernate-6</module>
|
||||
<module>spring-jpa</module>
|
||||
<module>spring-jpa-2</module>
|
||||
|
@ -1,3 +1,4 @@
|
||||
## Relevant Articles
|
||||
- [Scroll API in Spring Data JPA](https://www.baeldung.com/spring-data-jpa-scroll-api)
|
||||
- [List vs. Set in @OneToMany JPA](https://www.baeldung.com/spring-jpa-onetomany-list-vs-set)
|
||||
- [N+1 Problem in Hibernate and Spring Data JPA](https://www.baeldung.com/spring-hibernate-n1-problem)
|
||||
|
@ -6,4 +6,5 @@
|
||||
- [TRUNCATE TABLE in Spring Data JPA](https://www.baeldung.com/spring-data-jpa-truncate-table)
|
||||
- [When to Use the getReferenceById() and findById() Methods in Spring Data JPA](https://www.baeldung.com/spring-data-jpa-getreferencebyid-findbyid-methods)
|
||||
- [Implementing Persistable-Only Entities in Spring Data JPA](https://www.baeldung.com/spring-data-persistable-only-entities)
|
||||
- [Storing PostgreSQL JSONB Using Spring Boot and JPA](https://www.baeldung.com/spring-boot-jpa-storing-postgresql-jsonb)
|
||||
- More articles: [[<-- prev]](../spring-data-jpa-repo-3)
|
||||
|
@ -125,6 +125,20 @@
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<argLine>
|
||||
--add-opens java.base/java.lang=ALL-UNNAMED
|
||||
</argLine>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<properties>
|
||||
<!-- Spring -->
|
||||
<org.springframework.version>5.0.2.RELEASE</org.springframework.version>
|
||||
@ -132,7 +146,7 @@
|
||||
<org.springframework.security.version>4.2.1.RELEASE</org.springframework.security.version>
|
||||
<!-- persistence -->
|
||||
<hibernate.version>5.6.15.Final</hibernate.version>
|
||||
<hibernatesearch.version>5.8.2.Final</hibernatesearch.version>
|
||||
<hibernatesearch.version>5.11.12.Final</hibernatesearch.version>
|
||||
<mysql-connector-java.version>8.2.0</mysql-connector-java.version>
|
||||
<tomcat-dbcp.version>9.0.0.M26</tomcat-dbcp.version>
|
||||
<jta.version>1.1</jta.version>
|
||||
|
@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ehcache xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="ehcache.xsd" updateCheck="true"
|
||||
monitoring="autodetect" dynamicConfig="true">
|
||||
|
||||
<diskStore path="java.io.tmpdir/ehcache" />
|
||||
|
||||
<defaultCache maxEntriesLocalHeap="10000" eternal="false"
|
||||
timeToIdleSeconds="120" timeToLiveSeconds="120" diskSpoolBufferSizeMB="30"
|
||||
maxEntriesLocalDisk="10000000" diskExpiryThreadIntervalSeconds="120"
|
||||
memoryStoreEvictionPolicy="LRU" statistics="true">
|
||||
<persistence strategy="localTempSwap" />
|
||||
</defaultCache>
|
||||
|
||||
<cache name="org.hibernate.cache.internal.StandardQueryCache"
|
||||
maxEntriesLocalHeap="5" eternal="false" timeToLiveSeconds="120">
|
||||
<persistence strategy="localTempSwap" />
|
||||
</cache>
|
||||
|
||||
</ehcache>
|
@ -7,13 +7,13 @@ import javax.persistence.*;
|
||||
@Entity
|
||||
@Table(name = "FOO")
|
||||
@Where(clause = "DELETED = 0")
|
||||
public class Foo {
|
||||
public class Fooo {
|
||||
|
||||
public Foo() {
|
||||
public Fooo() {
|
||||
super();
|
||||
}
|
||||
|
||||
public Foo(final String name) {
|
||||
public Fooo(final String name) {
|
||||
super();
|
||||
this.name = name;
|
||||
}
|
@ -14,7 +14,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
import com.baeldung.persistence.deletion.config.PersistenceJPAConfigDeletion;
|
||||
import com.baeldung.persistence.deletion.model.Bar;
|
||||
import com.baeldung.persistence.deletion.model.Baz;
|
||||
import com.baeldung.persistence.deletion.model.Foo;
|
||||
import com.baeldung.persistence.deletion.model.Fooo;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.PersistenceContext;
|
||||
@ -41,29 +41,29 @@ public class DeletionIntegrationTest {
|
||||
@Test
|
||||
@Transactional
|
||||
public final void givenEntityIsRemoved_thenItIsNotInDB() {
|
||||
Foo foo = new Foo("foo");
|
||||
entityManager.persist(foo);
|
||||
Fooo fooo = new Fooo("foo");
|
||||
entityManager.persist(fooo);
|
||||
flushAndClear();
|
||||
|
||||
foo = entityManager.find(Foo.class, foo.getId());
|
||||
assertThat(foo, notNullValue());
|
||||
fooo = entityManager.find(Fooo.class, fooo.getId());
|
||||
assertThat(fooo, notNullValue());
|
||||
|
||||
entityManager.remove(foo);
|
||||
entityManager.remove(fooo);
|
||||
flushAndClear();
|
||||
|
||||
assertThat(entityManager.find(Foo.class, foo.getId()), nullValue());
|
||||
assertThat(entityManager.find(Fooo.class, fooo.getId()), nullValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Transactional
|
||||
public final void givenEntityIsRemovedAndReferencedByAnotherEntity_thenItIsNotRemoved() {
|
||||
Bar bar = new Bar("bar");
|
||||
Foo foo = new Foo("foo");
|
||||
foo.setBar(bar);
|
||||
entityManager.persist(foo);
|
||||
Fooo fooo = new Fooo("foo");
|
||||
fooo.setBar(bar);
|
||||
entityManager.persist(fooo);
|
||||
flushAndClear();
|
||||
|
||||
foo = entityManager.find(Foo.class, foo.getId());
|
||||
fooo = entityManager.find(Fooo.class, fooo.getId());
|
||||
bar = entityManager.find(Bar.class, bar.getId());
|
||||
entityManager.remove(bar);
|
||||
flushAndClear();
|
||||
@ -71,8 +71,8 @@ public class DeletionIntegrationTest {
|
||||
bar = entityManager.find(Bar.class, bar.getId());
|
||||
assertThat(bar, notNullValue());
|
||||
|
||||
foo = entityManager.find(Foo.class, foo.getId());
|
||||
foo.setBar(null);
|
||||
fooo = entityManager.find(Fooo.class, fooo.getId());
|
||||
fooo.setBar(null);
|
||||
entityManager.remove(bar);
|
||||
flushAndClear();
|
||||
|
||||
@ -83,16 +83,16 @@ public class DeletionIntegrationTest {
|
||||
@Transactional
|
||||
public final void givenEntityIsRemoved_thenRemovalIsCascaded() {
|
||||
Bar bar = new Bar("bar");
|
||||
Foo foo = new Foo("foo");
|
||||
foo.setBar(bar);
|
||||
entityManager.persist(foo);
|
||||
Fooo fooo = new Fooo("foo");
|
||||
fooo.setBar(bar);
|
||||
entityManager.persist(fooo);
|
||||
flushAndClear();
|
||||
|
||||
foo = entityManager.find(Foo.class, foo.getId());
|
||||
entityManager.remove(foo);
|
||||
fooo = entityManager.find(Fooo.class, fooo.getId());
|
||||
entityManager.remove(fooo);
|
||||
flushAndClear();
|
||||
|
||||
assertThat(entityManager.find(Foo.class, foo.getId()), nullValue());
|
||||
assertThat(entityManager.find(Fooo.class, fooo.getId()), nullValue());
|
||||
assertThat(entityManager.find(Bar.class, bar.getId()), nullValue());
|
||||
}
|
||||
|
||||
@ -116,39 +116,39 @@ public class DeletionIntegrationTest {
|
||||
@Test
|
||||
@Transactional
|
||||
public final void givenEntityIsDeletedWithJpaBulkDeleteStatement_thenItIsNotInDB() {
|
||||
Foo foo = new Foo("foo");
|
||||
entityManager.persist(foo);
|
||||
Fooo fooo = new Fooo("foo");
|
||||
entityManager.persist(fooo);
|
||||
flushAndClear();
|
||||
|
||||
entityManager.createQuery("delete from Foo where id = :id").setParameter("id", foo.getId()).executeUpdate();
|
||||
entityManager.createQuery("delete from Foo where id = :id").setParameter("id", fooo.getId()).executeUpdate();
|
||||
|
||||
assertThat(entityManager.find(Foo.class, foo.getId()), nullValue());
|
||||
assertThat(entityManager.find(Fooo.class, fooo.getId()), nullValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Transactional
|
||||
public final void givenEntityIsDeletedWithNativeQuery_thenItIsNotInDB() {
|
||||
Foo foo = new Foo("foo");
|
||||
entityManager.persist(foo);
|
||||
Fooo fooo = new Fooo("foo");
|
||||
entityManager.persist(fooo);
|
||||
flushAndClear();
|
||||
|
||||
entityManager.createNativeQuery("delete from FOO where ID = :id").setParameter("id", foo.getId()).executeUpdate();
|
||||
entityManager.createNativeQuery("delete from FOO where ID = :id").setParameter("id", fooo.getId()).executeUpdate();
|
||||
|
||||
assertThat(entityManager.find(Foo.class, foo.getId()), nullValue());
|
||||
assertThat(entityManager.find(Fooo.class, fooo.getId()), nullValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Transactional
|
||||
public final void givenEntityIsSoftDeleted_thenItIsNotReturnedFromQueries() {
|
||||
Foo foo = new Foo("foo");
|
||||
entityManager.persist(foo);
|
||||
Fooo fooo = new Fooo("foo");
|
||||
entityManager.persist(fooo);
|
||||
flushAndClear();
|
||||
|
||||
foo = entityManager.find(Foo.class, foo.getId());
|
||||
foo.setDeleted();
|
||||
fooo = entityManager.find(Fooo.class, fooo.getId());
|
||||
fooo.setDeleted();
|
||||
flushAndClear();
|
||||
|
||||
assertThat(entityManager.find(Foo.class, foo.getId()), nullValue());
|
||||
assertThat(entityManager.find(Fooo.class, fooo.getId()), nullValue());
|
||||
}
|
||||
|
||||
private void flushAndClear() {
|
||||
|
@ -55,7 +55,7 @@
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt-api</artifactId>
|
||||
<version>0.12.3</version>
|
||||
<version>${jjwt.version}</version>
|
||||
</dependency>
|
||||
<!-- persistence -->
|
||||
<dependency>
|
||||
@ -107,6 +107,18 @@
|
||||
<artifactId>jackson-core</artifactId>
|
||||
<version>${jakson-core.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>${logback.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-core</artifactId>
|
||||
<version>${logback.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
@ -115,8 +127,11 @@
|
||||
<spring-boot.version>3.1.0</spring-boot.version>
|
||||
<!-- persistence -->
|
||||
<tomcat-dbcp.version>10.1.9</tomcat-dbcp.version>
|
||||
<jakson-databind.version>2.15.1</jakson-databind.version>
|
||||
<jakson-core.version>2.14.2</jakson-core.version>
|
||||
<jakson-databind.version>2.16.1</jakson-databind.version>
|
||||
<jakson-core.version>2.16.1</jakson-core.version>
|
||||
|
||||
<jjwt.version>0.12.3</jjwt.version>
|
||||
<logback.version>1.4.14</logback.version>
|
||||
</properties>
|
||||
|
||||
</project>
|
@ -1,5 +1,6 @@
|
||||
package com.baeldung.multitenant.config;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.jdbc.DataSourceBuilder;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
@ -18,6 +19,9 @@ import java.util.Properties;
|
||||
@Configuration
|
||||
public class MultitenantConfiguration {
|
||||
|
||||
@Value("${defaultTenant}")
|
||||
private String defaultTenant;
|
||||
|
||||
@Bean
|
||||
@ConfigurationProperties(prefix = "tenants")
|
||||
public DataSource dataSource() {
|
||||
@ -43,7 +47,7 @@ public class MultitenantConfiguration {
|
||||
}
|
||||
|
||||
AbstractRoutingDataSource dataSource = new MultitenantDataSource();
|
||||
dataSource.setDefaultTargetDataSource(resolvedDataSources.get("tenant_1"));
|
||||
dataSource.setDefaultTargetDataSource(resolvedDataSources.get(defaultTenant));
|
||||
dataSource.setTargetDataSources(resolvedDataSources);
|
||||
|
||||
dataSource.afterPropertiesSet();
|
||||
|
@ -1,26 +1,31 @@
|
||||
package com.baeldung.multitenant.security;
|
||||
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import io.jsonwebtoken.SignatureAlgorithm;
|
||||
import io.jsonwebtoken.security.Keys;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import javax.crypto.SecretKey;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
|
||||
public class AuthenticationService {
|
||||
|
||||
private static final long EXPIRATIONTIME = 864_000_00; // 1 day in milliseconds
|
||||
private static final String SIGNINGKEY = "SecretKey";
|
||||
private static final String SECRETKEY = "q3t6w9zCFJNcQfTjWnq3t6w9zCFJNcQfTjWnZr4u7xADGKaPd";
|
||||
private static final SecretKey SIGNINGKEY = Keys.hmacShaKeyFor(SECRETKEY.getBytes(StandardCharsets.UTF_8));
|
||||
private static final String PREFIX = "Bearer";
|
||||
|
||||
public static void addToken(HttpServletResponse res, String username, String tenant) {
|
||||
String JwtToken = Jwts.builder().setSubject(username)
|
||||
.setAudience(tenant)
|
||||
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATIONTIME))
|
||||
.signWith(SignatureAlgorithm.HS512, SIGNINGKEY)
|
||||
String JwtToken = Jwts.builder()
|
||||
.subject(username)
|
||||
.audience().add(tenant).and()
|
||||
.issuedAt(new Date(System.currentTimeMillis()))
|
||||
.expiration(new Date(System.currentTimeMillis() + EXPIRATIONTIME))
|
||||
.signWith(SIGNINGKEY)
|
||||
.compact();
|
||||
res.addHeader("Authorization", PREFIX + " " + JwtToken);
|
||||
}
|
||||
@ -29,9 +34,8 @@ public class AuthenticationService {
|
||||
String token = req.getHeader("Authorization");
|
||||
if (token != null) {
|
||||
String user = Jwts.parser()
|
||||
.setSigningKey(SIGNINGKEY)
|
||||
.build().parseClaimsJws(token.replace(PREFIX, ""))
|
||||
.getBody()
|
||||
.verifyWith(SIGNINGKEY)
|
||||
.build().parseClaimsJws(token.replace(PREFIX, "").trim()).getPayload()
|
||||
.getSubject();
|
||||
if (user != null) {
|
||||
return new UsernamePasswordAuthenticationToken(user, null, Collections.emptyList());
|
||||
@ -48,7 +52,7 @@ public class AuthenticationService {
|
||||
}
|
||||
String tenant = Jwts.parser()
|
||||
.setSigningKey(SIGNINGKEY)
|
||||
.build().parseClaimsJws(token.replace(PREFIX, ""))
|
||||
.build().parseClaimsJws(token.replace(PREFIX, "").trim())
|
||||
.getBody()
|
||||
.getAudience()
|
||||
.iterator()
|
||||
|
@ -4,9 +4,9 @@ import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
||||
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer;
|
||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
@ -42,16 +42,21 @@ public class SecurityConfiguration {
|
||||
return new BCryptPasswordEncoder();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
|
||||
return authenticationConfiguration.getAuthenticationManager();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||
final AuthenticationManager authenticationManager = http.getSharedObject(AuthenticationManager.class);
|
||||
final AuthenticationManager authenticationManager = authenticationManager(http.getSharedObject(AuthenticationConfiguration.class));
|
||||
http
|
||||
.authorizeHttpRequests(authorize ->
|
||||
authorize.requestMatchers("/login").permitAll().anyRequest().authenticated())
|
||||
.sessionManagement(securityContext -> securityContext.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
|
||||
.addFilterBefore(new LoginFilter("/login", authenticationManager), UsernamePasswordAuthenticationFilter.class)
|
||||
.addFilterBefore(new AuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
|
||||
.csrf(AbstractHttpConfigurer::disable)
|
||||
.csrf(csrf -> csrf.disable())
|
||||
.headers(header -> header.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable))
|
||||
.httpBasic(Customizer.withDefaults());
|
||||
|
||||
|
@ -9,3 +9,7 @@ spring.datasource.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1
|
||||
#spring.datasource.username=mysqluser
|
||||
#spring.datasource.password=mysqlpass
|
||||
#spring.datasource.url=jdbc:mysql://localhost:3306/myDb?createDatabaseIfNotExist=true
|
||||
|
||||
# MultiTenantApplication
|
||||
defaultTenant=tenant_1
|
||||
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect
|
4
pom.xml
4
pom.xml
@ -733,7 +733,7 @@
|
||||
<module>jackson-simple</module>
|
||||
<module>java-blockchain</module>
|
||||
<module>java-jdi</module>
|
||||
<!--<module>java-panama</module>--> <!--JAVA-27339-->
|
||||
<module>java-panama</module>
|
||||
<module>javafx</module>
|
||||
<module>javax-sound</module>
|
||||
<module>javaxval-2</module>
|
||||
@ -973,7 +973,7 @@
|
||||
<module>jackson-simple</module>
|
||||
<module>java-blockchain</module>
|
||||
<module>java-jdi</module>
|
||||
<!--<module>java-panama</module>--> <!--JAVA-27339-->
|
||||
<module>java-panama</module>
|
||||
<module>javafx</module>
|
||||
<module>javax-sound</module>
|
||||
<module>javaxval-2</module>
|
||||
|
@ -19,6 +19,7 @@
|
||||
<module>quarkus-jandex</module>
|
||||
<module>quarkus-vs-springboot</module>
|
||||
<module>quarkus-funqy</module>
|
||||
<!-- requires Java 21 <module>quarkus-virtual-threads</module> -->
|
||||
</modules>
|
||||
|
||||
</project>
|
4
quarkus-modules/quarkus-virtual-threads/.dockerignore
Normal file
4
quarkus-modules/quarkus-virtual-threads/.dockerignore
Normal file
@ -0,0 +1,4 @@
|
||||
*
|
||||
!target/*-runner
|
||||
!target/*-runner.jar
|
||||
!target/lib/*
|
0
quarkus-modules/quarkus-virtual-threads/README.md
Normal file
0
quarkus-modules/quarkus-virtual-threads/README.md
Normal file
160
quarkus-modules/quarkus-virtual-threads/pom.xml
Normal file
160
quarkus-modules/quarkus-virtual-threads/pom.xml
Normal file
@ -0,0 +1,160 @@
|
||||
<?xml version="1.0"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.baeldung.quarkus</groupId>
|
||||
<artifactId>quarkus-virtual-threads</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>quarkus-modules</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>${quarkus.platform.group-id}</groupId>
|
||||
<artifactId>${quarkus.platform.artifact-id}</artifactId>
|
||||
<version>${quarkus.platform.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<properties>
|
||||
<compiler-plugin.version>3.11.0</compiler-plugin.version>
|
||||
<maven.compiler.release>21</maven.compiler.release>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
|
||||
<quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id>
|
||||
<quarkus.platform.version>3.4.3</quarkus.platform.version>
|
||||
<surefire-plugin.version>3.0.0</surefire-plugin.version>
|
||||
<loom-unit.version>0.3.0</loom-unit.version>
|
||||
<panache-common-deployment.version>3.6.0</panache-common-deployment.version>
|
||||
<mockito-core.version>3.11.2</mockito-core.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-hibernate-validator</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-jdbc-postgresql</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-hibernate-orm-panache</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-resteasy-reactive-jackson</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-rest-client-reactive-jackson</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-arc</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.rest-assured</groupId>
|
||||
<artifactId>rest-assured</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>me.escoffier.loom</groupId>
|
||||
<artifactId>loom-unit</artifactId>
|
||||
<version>${loom-unit.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!-- Quarkus Test framework -->
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-junit5</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-panache-common-deployment</artifactId>
|
||||
<version>${panache-common-deployment.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>${mockito-core.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.quarkus</groupId>
|
||||
<artifactId>quarkus-panache-mock</artifactId>
|
||||
<version>${panache-common-deployment.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>${quarkus.platform.group-id}</groupId>
|
||||
<artifactId>quarkus-maven-plugin</artifactId>
|
||||
<version>${quarkus.platform.version}</version>
|
||||
<extensions>true</extensions>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>build</goal>
|
||||
<goal>generate-code</goal>
|
||||
<goal>generate-code-tests</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>${compiler-plugin.version}</version>
|
||||
<configuration>
|
||||
<compilerArgs>
|
||||
<arg>-parameters</arg>
|
||||
</compilerArgs>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>${surefire-plugin.version}</version>
|
||||
<configuration>
|
||||
<systemPropertyVariables>
|
||||
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
|
||||
<maven.home>${maven.home}</maven.home>
|
||||
</systemPropertyVariables>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>native</id>
|
||||
<activation>
|
||||
<property>
|
||||
<name>native</name>
|
||||
</property>
|
||||
</activation>
|
||||
<properties>
|
||||
<quarkus.package.type>native</quarkus.package.type>
|
||||
</properties>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
@ -0,0 +1,97 @@
|
||||
####
|
||||
# This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode
|
||||
#
|
||||
# Before building the container image run:
|
||||
#
|
||||
# ./mvnw package
|
||||
#
|
||||
# Then, build the image with:
|
||||
#
|
||||
# docker build -f src/main/docker/Dockerfile.jvm -t quarkus/virtual-threads-jvm .
|
||||
#
|
||||
# Then run the container using:
|
||||
#
|
||||
# docker run -i --rm -p 8080:8080 quarkus/virtual-threads-jvm
|
||||
#
|
||||
# If you want to include the debug port into your docker image
|
||||
# you will have to expose the debug port (default 5005 being the default) like this : EXPOSE 8080 5005.
|
||||
# Additionally you will have to set -e JAVA_DEBUG=true and -e JAVA_DEBUG_PORT=*:5005
|
||||
# when running the container
|
||||
#
|
||||
# Then run the container using :
|
||||
#
|
||||
# docker run -i --rm -p 8080:8080 quarkus/virtual-threads-jvm
|
||||
#
|
||||
# This image uses the `run-java.sh` script to run the application.
|
||||
# This scripts computes the command line to execute your Java application, and
|
||||
# includes memory/GC tuning.
|
||||
# You can configure the behavior using the following environment properties:
|
||||
# - JAVA_OPTS: JVM options passed to the `java` command (example: "-verbose:class")
|
||||
# - JAVA_OPTS_APPEND: User specified Java options to be appended to generated options
|
||||
# in JAVA_OPTS (example: "-Dsome.property=foo")
|
||||
# - JAVA_MAX_MEM_RATIO: Is used when no `-Xmx` option is given in JAVA_OPTS. This is
|
||||
# used to calculate a default maximal heap memory based on a containers restriction.
|
||||
# If used in a container without any memory constraints for the container then this
|
||||
# option has no effect. If there is a memory constraint then `-Xmx` is set to a ratio
|
||||
# of the container available memory as set here. The default is `50` which means 50%
|
||||
# of the available memory is used as an upper boundary. You can skip this mechanism by
|
||||
# setting this value to `0` in which case no `-Xmx` option is added.
|
||||
# - JAVA_INITIAL_MEM_RATIO: Is used when no `-Xms` option is given in JAVA_OPTS. This
|
||||
# is used to calculate a default initial heap memory based on the maximum heap memory.
|
||||
# If used in a container without any memory constraints for the container then this
|
||||
# option has no effect. If there is a memory constraint then `-Xms` is set to a ratio
|
||||
# of the `-Xmx` memory as set here. The default is `25` which means 25% of the `-Xmx`
|
||||
# is used as the initial heap size. You can skip this mechanism by setting this value
|
||||
# to `0` in which case no `-Xms` option is added (example: "25")
|
||||
# - JAVA_MAX_INITIAL_MEM: Is used when no `-Xms` option is given in JAVA_OPTS.
|
||||
# This is used to calculate the maximum value of the initial heap memory. If used in
|
||||
# a container without any memory constraints for the container then this option has
|
||||
# no effect. If there is a memory constraint then `-Xms` is limited to the value set
|
||||
# here. The default is 4096MB which means the calculated value of `-Xms` never will
|
||||
# be greater than 4096MB. The value of this variable is expressed in MB (example: "4096")
|
||||
# - JAVA_DIAGNOSTICS: Set this to get some diagnostics information to standard output
|
||||
# when things are happening. This option, if set to true, will set
|
||||
# `-XX:+UnlockDiagnosticVMOptions`. Disabled by default (example: "true").
|
||||
# - JAVA_DEBUG: If set remote debugging will be switched on. Disabled by default (example:
|
||||
# true").
|
||||
# - JAVA_DEBUG_PORT: Port used for remote debugging. Defaults to 5005 (example: "8787").
|
||||
# - CONTAINER_CORE_LIMIT: A calculated core limit as described in
|
||||
# https://www.kernel.org/doc/Documentation/scheduler/sched-bwc.txt. (example: "2")
|
||||
# - CONTAINER_MAX_MEMORY: Memory limit given to the container (example: "1024").
|
||||
# - GC_MIN_HEAP_FREE_RATIO: Minimum percentage of heap free after GC to avoid expansion.
|
||||
# (example: "20")
|
||||
# - GC_MAX_HEAP_FREE_RATIO: Maximum percentage of heap free after GC to avoid shrinking.
|
||||
# (example: "40")
|
||||
# - GC_TIME_RATIO: Specifies the ratio of the time spent outside the garbage collection.
|
||||
# (example: "4")
|
||||
# - GC_ADAPTIVE_SIZE_POLICY_WEIGHT: The weighting given to the current GC time versus
|
||||
# previous GC times. (example: "90")
|
||||
# - GC_METASPACE_SIZE: The initial metaspace size. (example: "20")
|
||||
# - GC_MAX_METASPACE_SIZE: The maximum metaspace size. (example: "100")
|
||||
# - GC_CONTAINER_OPTIONS: Specify Java GC to use. The value of this variable should
|
||||
# contain the necessary JRE command-line options to specify the required GC, which
|
||||
# will override the default of `-XX:+UseParallelGC` (example: -XX:+UseG1GC).
|
||||
# - HTTPS_PROXY: The location of the https proxy. (example: "myuser@127.0.0.1:8080")
|
||||
# - HTTP_PROXY: The location of the http proxy. (example: "myuser@127.0.0.1:8080")
|
||||
# - NO_PROXY: A comma separated lists of hosts, IP addresses or domains that can be
|
||||
# accessed directly. (example: "foo.example.com,bar.example.com")
|
||||
#
|
||||
###
|
||||
FROM registry.access.redhat.com/ubi8/openjdk-21:1.18
|
||||
|
||||
ENV LANGUAGE='en_US:en'
|
||||
|
||||
|
||||
# We make four distinct layers so if there are application changes the library layers can be re-used
|
||||
COPY --chown=185 target/quarkus-app/lib/ /deployments/lib/
|
||||
COPY --chown=185 target/quarkus-app/*.jar /deployments/
|
||||
COPY --chown=185 target/quarkus-app/app/ /deployments/app/
|
||||
COPY --chown=185 target/quarkus-app/quarkus/ /deployments/quarkus/
|
||||
|
||||
EXPOSE 8080
|
||||
USER 185
|
||||
ENV JAVA_OPTS_APPEND="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
|
||||
ENV JAVA_APP_JAR="/deployments/quarkus-run.jar"
|
||||
|
||||
ENTRYPOINT [ "/opt/jboss/container/java/run/run-java.sh" ]
|
||||
|
@ -0,0 +1,93 @@
|
||||
####
|
||||
# This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode
|
||||
#
|
||||
# Before building the container image run:
|
||||
#
|
||||
# ./mvnw package -Dquarkus.package.type=legacy-jar
|
||||
#
|
||||
# Then, build the image with:
|
||||
#
|
||||
# docker build -f src/main/docker/Dockerfile.legacy-jar -t quarkus/virtual-threads-legacy-jar .
|
||||
#
|
||||
# Then run the container using:
|
||||
#
|
||||
# docker run -i --rm -p 8080:8080 quarkus/virtual-threads-legacy-jar
|
||||
#
|
||||
# If you want to include the debug port into your docker image
|
||||
# you will have to expose the debug port (default 5005 being the default) like this : EXPOSE 8080 5005.
|
||||
# Additionally you will have to set -e JAVA_DEBUG=true and -e JAVA_DEBUG_PORT=*:5005
|
||||
# when running the container
|
||||
#
|
||||
# Then run the container using :
|
||||
#
|
||||
# docker run -i --rm -p 8080:8080 quarkus/virtual-threads-legacy-jar
|
||||
#
|
||||
# This image uses the `run-java.sh` script to run the application.
|
||||
# This scripts computes the command line to execute your Java application, and
|
||||
# includes memory/GC tuning.
|
||||
# You can configure the behavior using the following environment properties:
|
||||
# - JAVA_OPTS: JVM options passed to the `java` command (example: "-verbose:class")
|
||||
# - JAVA_OPTS_APPEND: User specified Java options to be appended to generated options
|
||||
# in JAVA_OPTS (example: "-Dsome.property=foo")
|
||||
# - JAVA_MAX_MEM_RATIO: Is used when no `-Xmx` option is given in JAVA_OPTS. This is
|
||||
# used to calculate a default maximal heap memory based on a containers restriction.
|
||||
# If used in a container without any memory constraints for the container then this
|
||||
# option has no effect. If there is a memory constraint then `-Xmx` is set to a ratio
|
||||
# of the container available memory as set here. The default is `50` which means 50%
|
||||
# of the available memory is used as an upper boundary. You can skip this mechanism by
|
||||
# setting this value to `0` in which case no `-Xmx` option is added.
|
||||
# - JAVA_INITIAL_MEM_RATIO: Is used when no `-Xms` option is given in JAVA_OPTS. This
|
||||
# is used to calculate a default initial heap memory based on the maximum heap memory.
|
||||
# If used in a container without any memory constraints for the container then this
|
||||
# option has no effect. If there is a memory constraint then `-Xms` is set to a ratio
|
||||
# of the `-Xmx` memory as set here. The default is `25` which means 25% of the `-Xmx`
|
||||
# is used as the initial heap size. You can skip this mechanism by setting this value
|
||||
# to `0` in which case no `-Xms` option is added (example: "25")
|
||||
# - JAVA_MAX_INITIAL_MEM: Is used when no `-Xms` option is given in JAVA_OPTS.
|
||||
# This is used to calculate the maximum value of the initial heap memory. If used in
|
||||
# a container without any memory constraints for the container then this option has
|
||||
# no effect. If there is a memory constraint then `-Xms` is limited to the value set
|
||||
# here. The default is 4096MB which means the calculated value of `-Xms` never will
|
||||
# be greater than 4096MB. The value of this variable is expressed in MB (example: "4096")
|
||||
# - JAVA_DIAGNOSTICS: Set this to get some diagnostics information to standard output
|
||||
# when things are happening. This option, if set to true, will set
|
||||
# `-XX:+UnlockDiagnosticVMOptions`. Disabled by default (example: "true").
|
||||
# - JAVA_DEBUG: If set remote debugging will be switched on. Disabled by default (example:
|
||||
# true").
|
||||
# - JAVA_DEBUG_PORT: Port used for remote debugging. Defaults to 5005 (example: "8787").
|
||||
# - CONTAINER_CORE_LIMIT: A calculated core limit as described in
|
||||
# https://www.kernel.org/doc/Documentation/scheduler/sched-bwc.txt. (example: "2")
|
||||
# - CONTAINER_MAX_MEMORY: Memory limit given to the container (example: "1024").
|
||||
# - GC_MIN_HEAP_FREE_RATIO: Minimum percentage of heap free after GC to avoid expansion.
|
||||
# (example: "20")
|
||||
# - GC_MAX_HEAP_FREE_RATIO: Maximum percentage of heap free after GC to avoid shrinking.
|
||||
# (example: "40")
|
||||
# - GC_TIME_RATIO: Specifies the ratio of the time spent outside the garbage collection.
|
||||
# (example: "4")
|
||||
# - GC_ADAPTIVE_SIZE_POLICY_WEIGHT: The weighting given to the current GC time versus
|
||||
# previous GC times. (example: "90")
|
||||
# - GC_METASPACE_SIZE: The initial metaspace size. (example: "20")
|
||||
# - GC_MAX_METASPACE_SIZE: The maximum metaspace size. (example: "100")
|
||||
# - GC_CONTAINER_OPTIONS: Specify Java GC to use. The value of this variable should
|
||||
# contain the necessary JRE command-line options to specify the required GC, which
|
||||
# will override the default of `-XX:+UseParallelGC` (example: -XX:+UseG1GC).
|
||||
# - HTTPS_PROXY: The location of the https proxy. (example: "myuser@127.0.0.1:8080")
|
||||
# - HTTP_PROXY: The location of the http proxy. (example: "myuser@127.0.0.1:8080")
|
||||
# - NO_PROXY: A comma separated lists of hosts, IP addresses or domains that can be
|
||||
# accessed directly. (example: "foo.example.com,bar.example.com")
|
||||
#
|
||||
###
|
||||
FROM registry.access.redhat.com/ubi8/openjdk-21:1.18
|
||||
|
||||
ENV LANGUAGE='en_US:en'
|
||||
|
||||
|
||||
COPY target/lib/* /deployments/lib/
|
||||
COPY target/*-runner.jar /deployments/quarkus-run.jar
|
||||
|
||||
EXPOSE 8080
|
||||
USER 185
|
||||
ENV JAVA_OPTS_APPEND="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
|
||||
ENV JAVA_APP_JAR="/deployments/quarkus-run.jar"
|
||||
|
||||
ENTRYPOINT [ "/opt/jboss/container/java/run/run-java.sh" ]
|
@ -0,0 +1,27 @@
|
||||
####
|
||||
# This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode.
|
||||
#
|
||||
# Before building the container image run:
|
||||
#
|
||||
# ./mvnw package -Dnative
|
||||
#
|
||||
# Then, build the image with:
|
||||
#
|
||||
# docker build -f src/main/docker/Dockerfile.native -t quarkus/virtual-threads .
|
||||
#
|
||||
# Then run the container using:
|
||||
#
|
||||
# docker run -i --rm -p 8080:8080 quarkus/virtual-threads
|
||||
#
|
||||
###
|
||||
FROM registry.access.redhat.com/ubi8/ubi-minimal:8.9
|
||||
WORKDIR /work/
|
||||
RUN chown 1001 /work \
|
||||
&& chmod "g+rwX" /work \
|
||||
&& chown 1001:root /work
|
||||
COPY --chown=1001:root target/*-runner /work/application
|
||||
|
||||
EXPOSE 8080
|
||||
USER 1001
|
||||
|
||||
ENTRYPOINT ["./application", "-Dquarkus.http.host=0.0.0.0"]
|
@ -0,0 +1,30 @@
|
||||
####
|
||||
# This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode.
|
||||
# It uses a micro base image, tuned for Quarkus native executables.
|
||||
# It reduces the size of the resulting container image.
|
||||
# Check https://quarkus.io/guides/quarkus-runtime-base-image for further information about this image.
|
||||
#
|
||||
# Before building the container image run:
|
||||
#
|
||||
# ./mvnw package -Dnative
|
||||
#
|
||||
# Then, build the image with:
|
||||
#
|
||||
# docker build -f src/main/docker/Dockerfile.native-micro -t quarkus/virtual-threads .
|
||||
#
|
||||
# Then run the container using:
|
||||
#
|
||||
# docker run -i --rm -p 8080:8080 quarkus/virtual-threads
|
||||
#
|
||||
###
|
||||
FROM quay.io/quarkus/quarkus-micro-image:2.0
|
||||
WORKDIR /work/
|
||||
RUN chown 1001 /work \
|
||||
&& chmod "g+rwX" /work \
|
||||
&& chown 1001:root /work
|
||||
COPY --chown=1001:root target/*-runner /work/application
|
||||
|
||||
EXPOSE 8080
|
||||
USER 1001
|
||||
|
||||
ENTRYPOINT ["./application", "-Dquarkus.http.host=0.0.0.0"]
|
@ -0,0 +1,16 @@
|
||||
package com.baeldung.quarkus;
|
||||
|
||||
import jakarta.ws.rs.GET;
|
||||
import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.Produces;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
|
||||
@Path("/hello")
|
||||
public class GreetingResource {
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.TEXT_PLAIN)
|
||||
public String hello() {
|
||||
return "Hello from RESTEasy Reactive";
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package com.baeldung.quarkus.rest;
|
||||
|
||||
import jakarta.ws.rs.GET;
|
||||
import jakarta.ws.rs.Path;
|
||||
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
|
||||
|
||||
@RegisterRestClient(configKey = "remote-service")
|
||||
public interface RemoteService {
|
||||
@GET
|
||||
@Path("/greetings")
|
||||
default String greetings(){
|
||||
return "Mocked Greeting";
|
||||
};
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package com.baeldung.quarkus.rest;
|
||||
|
||||
import io.smallrye.common.annotation.RunOnVirtualThread;
|
||||
import jakarta.ws.rs.GET;
|
||||
import jakarta.ws.rs.Path;
|
||||
import org.eclipse.microprofile.rest.client.inject.RestClient;
|
||||
|
||||
@Path("/greetings")
|
||||
public class VirtualThreadApp {
|
||||
@RestClient RemoteService service;
|
||||
@GET @RunOnVirtualThread
|
||||
public String process() {
|
||||
var response = service.greetings();
|
||||
return response.toUpperCase();
|
||||
}
|
||||
}
|
File diff suppressed because one or more lines are too long
@ -0,0 +1 @@
|
||||
remote-service/mp-rest/url=http://localhost:8080
|
@ -0,0 +1,16 @@
|
||||
package com.baeldung.quarkus;
|
||||
|
||||
import jakarta.ws.rs.GET;
|
||||
import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.Produces;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
|
||||
@Path("/hello")
|
||||
public class GreetingResource {
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.TEXT_PLAIN)
|
||||
public String hello() {
|
||||
return "Hello from RESTEasy Reactive";
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package com.baeldung.quarkus.rest;
|
||||
|
||||
import jakarta.ws.rs.GET;
|
||||
import jakarta.ws.rs.Path;
|
||||
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
|
||||
|
||||
@RegisterRestClient(configKey = "remote-service")
|
||||
public interface RemoteService {
|
||||
@GET
|
||||
@Path("/greetings")
|
||||
default String greetings(){
|
||||
return "Mocked Greeting";
|
||||
};
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package com.baeldung.quarkus.rest;
|
||||
|
||||
import io.smallrye.common.annotation.RunOnVirtualThread;
|
||||
import jakarta.ws.rs.GET;
|
||||
import jakarta.ws.rs.Path;
|
||||
import org.eclipse.microprofile.rest.client.inject.RestClient;
|
||||
|
||||
@Path("/greetings")
|
||||
public class VirtualThreadApp {
|
||||
@RestClient RemoteService service;
|
||||
@GET @RunOnVirtualThread
|
||||
public String process() {
|
||||
var response = service.greetings();
|
||||
return response.toUpperCase();
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
12079
quarkus-modules/quarkus-vs-springboot/jmeter/zip_code_database.csv
Normal file
12079
quarkus-modules/quarkus-vs-springboot/jmeter/zip_code_database.csv
Normal file
File diff suppressed because it is too large
Load Diff
12079
quarkus-modules/quarkus-vs-springboot/wrk/zip_code_database.csv
Normal file
12079
quarkus-modules/quarkus-vs-springboot/wrk/zip_code_database.csv
Normal file
File diff suppressed because it is too large
Load Diff
@ -2,4 +2,5 @@
|
||||
|
||||
- [Spring Boot With Spring Batch](https://www.baeldung.com/spring-boot-spring-batch)
|
||||
- [How to Trigger and Stop a Scheduled Spring Batch Job](https://www.baeldung.com/spring-batch-start-stop-job)
|
||||
- [Access Job Parameters From ItemReader in Spring Batch](https://www.baeldung.com/spring-batch-itemreader-access-job-parameters)
|
||||
- More articles [[<-- prev]](/spring-batch)
|
||||
|
@ -10,4 +10,5 @@ This module contains articles about Spring Boot customization 2
|
||||
- [Spring Boot Exit Codes](https://www.baeldung.com/spring-boot-exit-codes)
|
||||
- [Guide to Spring Type Conversions](https://www.baeldung.com/spring-type-conversions)
|
||||
- [Container Configuration in Spring Boot 2](https://www.baeldung.com/embeddedservletcontainercustomizer-configurableembeddedservletcontainer-spring-boot)
|
||||
- [Speed up Spring Boot Startup Time](https://www.baeldung.com/spring-boot-startup-speed)
|
||||
- [Speed up Spring Boot Startup Time](https://www.baeldung.com/spring-boot-startup-speed)
|
||||
- More articles: [[<-- prev]](/spring-boot-modules/spring-boot-basic-customization)
|
@ -9,9 +9,10 @@
|
||||
<description>Module For Spring Boot Basic Customization 2</description>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung.spring-boot-modules</groupId>
|
||||
<artifactId>spring-boot-modules</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>parent-boot-3</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<relativePath>../../parent-boot-3</relativePath>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
|
@ -7,7 +7,7 @@ import org.springframework.boot.web.servlet.ServletRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import javax.servlet.ServletContextListener;
|
||||
import jakarta.servlet.ServletContextListener;
|
||||
|
||||
@Configuration
|
||||
public class WebConf {
|
||||
|
@ -4,7 +4,7 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.servlet.*;
|
||||
import jakarta.servlet.*;
|
||||
import java.io.IOException;
|
||||
|
||||
@Component
|
||||
|
@ -3,8 +3,8 @@ package com.baeldung.dispatchservlet.listener;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.servlet.ServletContextEvent;
|
||||
import javax.servlet.ServletContextListener;
|
||||
import jakarta.servlet.ServletContextEvent;
|
||||
import jakarta.servlet.ServletContextListener;
|
||||
|
||||
public class CustomListener implements ServletContextListener {
|
||||
|
||||
|
@ -4,11 +4,11 @@ import com.baeldung.dispatchservlet.filter.CustomFilter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.annotation.WebServlet;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.annotation.WebServlet;
|
||||
import jakarta.servlet.http.HttpServlet;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
public class CustomServlet extends HttpServlet {
|
||||
|
@ -3,10 +3,10 @@ package com.baeldung.onceperrequestfilter;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
@Component
|
||||
|
@ -6,7 +6,7 @@ import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.context.request.async.DeferredResult;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
|
@ -5,10 +5,10 @@ import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
@Component
|
||||
|
@ -1,7 +1,7 @@
|
||||
package com.baeldung.typeconversion.entity;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
|
||||
@Entity
|
||||
public class Employee {
|
||||
|
@ -11,3 +11,4 @@ This module contains articles about Spring Boot customization
|
||||
- [Spring Boot: Configuring a Main Class](https://www.baeldung.com/spring-boot-main-class)
|
||||
- [How to Define a Spring Boot Filter?](https://www.baeldung.com/spring-boot-add-filter)
|
||||
- [Guide to the Favicon in Spring Boot](https://www.baeldung.com/spring-boot-favicon)
|
||||
- More articles: [[next -->]](/spring-boot-modules/spring-boot-basic-customization-2)
|
||||
|
@ -9,9 +9,10 @@
|
||||
<description>Module For Spring Boot Basic Customization</description>
|
||||
|
||||
<parent>
|
||||
<groupId>com.baeldung.spring-boot-modules</groupId>
|
||||
<artifactId>spring-boot-modules</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>parent-boot-3</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<relativePath>../../parent-boot-3</relativePath>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
@ -81,7 +82,7 @@
|
||||
</build>
|
||||
|
||||
<properties>
|
||||
<spring-boot-maven-plugin.version>1.5.2.RELEASE</spring-boot-maven-plugin.version>
|
||||
<spring-boot-maven-plugin.version>3.1.5</spring-boot-maven-plugin.version>
|
||||
<!-- The main class to start by executing "java -jar" -->
|
||||
<start-class>com.baeldung.changeport.CustomApplication</start-class>
|
||||
</properties>
|
||||
|
@ -5,9 +5,14 @@ import org.slf4j.LoggerFactory;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.servlet.*;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import jakarta.servlet.Filter;
|
||||
import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.FilterConfig;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.ServletRequest;
|
||||
import jakarta.servlet.ServletResponse;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
@ -23,7 +28,7 @@ public class RequestResponseLoggingFilter implements Filter {
|
||||
private final static Logger LOG = LoggerFactory.getLogger(RequestResponseLoggingFilter.class);
|
||||
|
||||
@Override
|
||||
public void init(final FilterConfig filterConfig) throws ServletException {
|
||||
public void init(final FilterConfig filterConfig) {
|
||||
LOG.info("Initializing filter :{}", this);
|
||||
}
|
||||
|
||||
|
@ -5,8 +5,13 @@ import org.slf4j.LoggerFactory;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.servlet.*;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.Filter;
|
||||
import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.FilterConfig;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.ServletRequest;
|
||||
import jakarta.servlet.ServletResponse;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
|
@ -5,8 +5,8 @@ import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
|
||||
import javax.servlet.RequestDispatcher;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.RequestDispatcher;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
@Controller
|
||||
public class MyErrorController implements ErrorController {
|
||||
|
@ -4,7 +4,7 @@ import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
|
||||
import javax.annotation.security.RolesAllowed;
|
||||
import jakarta.annotation.security.RolesAllowed;
|
||||
|
||||
@Profile("failureanalyzer")
|
||||
@SpringBootApplication(scanBasePackages = "com.baeldung.failureanalyzer")
|
||||
|
@ -2,7 +2,7 @@ package com.baeldung.failureanalyzer;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
@Service
|
||||
public class MyService {
|
||||
|
@ -1,2 +1 @@
|
||||
org.springframework.boot.diagnostics.FailureAnalyzer=com.baeldung.failureanalyzer.MyBeanNotOfRequiredTypeFailureAnalyzer
|
||||
|
||||
|
@ -158,7 +158,7 @@
|
||||
<properties>
|
||||
<subethasmtp.version>3.1.7</subethasmtp.version>
|
||||
<httpclient.version>4.5.8</httpclient.version>
|
||||
<spring.cloud-version>2021.0.0</spring.cloud-version>
|
||||
<spring.cloud-version>2023.0.0</spring.cloud-version>
|
||||
</properties>
|
||||
|
||||
</project>
|
BIN
spring-boot-modules/spring-boot-telegram/baeldungbot
Normal file
BIN
spring-boot-modules/spring-boot-telegram/baeldungbot
Normal file
Binary file not shown.
@ -8,4 +8,5 @@ This module contains articles about reactive Spring Boot.
|
||||
- [Spring Boot Actuator](https://www.baeldung.com/spring-boot-actuators)
|
||||
- [Reactive WebSockets with Spring 5](https://www.baeldung.com/spring-5-reactive-websockets)
|
||||
- [A Guide to Spring Session Reactive Support: WebSession](https://www.baeldung.com/spring-session-reactive)
|
||||
- [Custom JSON Deserialization Using Spring WebClient](https://www.baeldung.com/spring-webclient-json-custom-deserialization)
|
||||
- More articles: [[<-- prev]](../spring-reactive-2)
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user