diff --git a/.gitignore b/.gitignore index 08f570ad06..693a35c176 100644 --- a/.gitignore +++ b/.gitignore @@ -43,3 +43,4 @@ spring-call-getters-using-reflection/.mvn/wrapper/maven-wrapper.properties spring-check-if-a-property-is-null/.mvn/wrapper/maven-wrapper.properties *.springBeans +20171220-JMeter.csv diff --git a/algorithms/src/main/java/com/baeldung/algorithms/maze/solver/BFSMazeSolver.java b/algorithms/src/main/java/com/baeldung/algorithms/maze/solver/BFSMazeSolver.java new file mode 100644 index 0000000000..08972251b8 --- /dev/null +++ b/algorithms/src/main/java/com/baeldung/algorithms/maze/solver/BFSMazeSolver.java @@ -0,0 +1,52 @@ +package com.baeldung.algorithms.maze.solver; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +public class BFSMazeSolver { + private static final int[][] DIRECTIONS = { { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, 0 } }; + + public List solve(Maze maze) { + LinkedList nextToVisit = new LinkedList<>(); + Coordinate start = maze.getEntry(); + nextToVisit.add(start); + + while (!nextToVisit.isEmpty()) { + Coordinate cur = nextToVisit.remove(); + + if (!maze.isValidLocation(cur.getX(), cur.getY()) || maze.isExplored(cur.getX(), cur.getY())) { + continue; + } + + if (maze.isWall(cur.getX(), cur.getY())) { + maze.setVisited(cur.getX(), cur.getY(), true); + continue; + } + + if (maze.isExit(cur.getX(), cur.getY())) { + return backtrackPath(cur); + } + + for (int[] direction : DIRECTIONS) { + Coordinate coordinate = new Coordinate(cur.getX() + direction[0], cur.getY() + direction[1], cur); + nextToVisit.add(coordinate); + maze.setVisited(cur.getX(), cur.getY(), true); + } + } + return Collections.emptyList(); + } + + private List backtrackPath(Coordinate cur) { + List path = new ArrayList<>(); + Coordinate iter = cur; + + while (iter != null) { + path.add(iter); + iter = iter.parent; + } + + return path; + } +} diff --git a/algorithms/src/main/java/com/baeldung/algorithms/maze/solver/Coordinate.java b/algorithms/src/main/java/com/baeldung/algorithms/maze/solver/Coordinate.java new file mode 100644 index 0000000000..09b2ced5e6 --- /dev/null +++ b/algorithms/src/main/java/com/baeldung/algorithms/maze/solver/Coordinate.java @@ -0,0 +1,31 @@ +package com.baeldung.algorithms.maze.solver; + +public class Coordinate { + int x; + int y; + Coordinate parent; + + public Coordinate(int x, int y) { + this.x = x; + this.y = y; + this.parent = null; + } + + public Coordinate(int x, int y, Coordinate parent) { + this.x = x; + this.y = y; + this.parent = parent; + } + + int getX() { + return x; + } + + int getY() { + return y; + } + + Coordinate getParent() { + return parent; + } +} diff --git a/algorithms/src/main/java/com/baeldung/algorithms/maze/solver/DFSMazeSolver.java b/algorithms/src/main/java/com/baeldung/algorithms/maze/solver/DFSMazeSolver.java new file mode 100644 index 0000000000..f9640066b9 --- /dev/null +++ b/algorithms/src/main/java/com/baeldung/algorithms/maze/solver/DFSMazeSolver.java @@ -0,0 +1,48 @@ +package com.baeldung.algorithms.maze.solver; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class DFSMazeSolver { + private static final int[][] DIRECTIONS = { { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, 0 } }; + + public List solve(Maze maze) { + List path = new ArrayList<>(); + if (explore(maze, maze.getEntry() + .getX(), + maze.getEntry() + .getY(), + path)) { + return path; + } + return Collections.emptyList(); + } + + private boolean explore(Maze maze, int row, int col, List path) { + if (!maze.isValidLocation(row, col) || maze.isWall(row, col) || maze.isExplored(row, col)) { + return false; + } + + path.add(new Coordinate(row, col)); + maze.setVisited(row, col, true); + + if (maze.isExit(row, col)) { + return true; + } + + for (int[] direction : DIRECTIONS) { + Coordinate coordinate = getNextCoordinate(row, col, direction[0], direction[1]); + if (explore(maze, coordinate.getX(), coordinate.getY(), path)) { + return true; + } + } + + path.remove(path.size() - 1); + return false; + } + + private Coordinate getNextCoordinate(int row, int col, int i, int j) { + return new Coordinate(row + i, col + j); + } +} diff --git a/algorithms/src/main/java/com/baeldung/algorithms/maze/solver/Maze.java b/algorithms/src/main/java/com/baeldung/algorithms/maze/solver/Maze.java new file mode 100644 index 0000000000..8aaa44d9b1 --- /dev/null +++ b/algorithms/src/main/java/com/baeldung/algorithms/maze/solver/Maze.java @@ -0,0 +1,141 @@ +package com.baeldung.algorithms.maze.solver; + +import java.io.File; +import java.io.FileNotFoundException; +import java.util.Arrays; +import java.util.List; +import java.util.Scanner; + +public class Maze { + private static final int ROAD = 0; + private static final int WALL = 1; + private static final int START = 2; + private static final int EXIT = 3; + private static final int PATH = 4; + + private int[][] maze; + private boolean[][] visited; + private Coordinate start; + private Coordinate end; + + public Maze(File maze) throws FileNotFoundException { + String fileText = ""; + try (Scanner input = new Scanner(maze)) { + while (input.hasNextLine()) { + fileText += input.nextLine() + "\n"; + } + } + initializeMaze(fileText); + } + + private void initializeMaze(String text) { + if (text == null || (text = text.trim()).length() == 0) { + throw new IllegalArgumentException("empty lines data"); + } + + String[] lines = text.split("[\r]?\n"); + maze = new int[lines.length][lines[0].length()]; + visited = new boolean[lines.length][lines[0].length()]; + + for (int row = 0; row < getHeight(); row++) { + if (lines[row].length() != getWidth()) { + throw new IllegalArgumentException("line " + (row + 1) + " wrong length (was " + lines[row].length() + " but should be " + getWidth() + ")"); + } + + for (int col = 0; col < getWidth(); col++) { + if (lines[row].charAt(col) == '#') + maze[row][col] = WALL; + else if (lines[row].charAt(col) == 'S') { + maze[row][col] = START; + start = new Coordinate(row, col); + } else if (lines[row].charAt(col) == 'E') { + maze[row][col] = EXIT; + end = new Coordinate(row, col); + } else + maze[row][col] = ROAD; + } + } + } + + public int getHeight() { + return maze.length; + } + + public int getWidth() { + return maze[0].length; + } + + public Coordinate getEntry() { + return start; + } + + public Coordinate getExit() { + return end; + } + + public boolean isExit(int x, int y) { + return x == end.getX() && y == end.getY(); + } + + public boolean isStart(int x, int y) { + return x == start.getX() && y == start.getY(); + } + + public boolean isExplored(int row, int col) { + return visited[row][col]; + } + + public boolean isWall(int row, int col) { + return maze[row][col] == WALL; + } + + public void setVisited(int row, int col, boolean value) { + visited[row][col] = value; + } + + public boolean isValidLocation(int row, int col) { + if (row < 0 || row >= getHeight() || col < 0 || col >= getWidth()) { + return false; + } + return true; + } + + public void printPath(List path) { + int[][] tempMaze = Arrays.stream(maze) + .map(int[]::clone) + .toArray(int[][]::new); + for (Coordinate coordinate : path) { + if (isStart(coordinate.getX(), coordinate.getY()) || isExit(coordinate.getX(), coordinate.getY())) { + continue; + } + tempMaze[coordinate.getX()][coordinate.getY()] = PATH; + } + System.out.println(toString(tempMaze)); + } + + public String toString(int[][] maze) { + StringBuilder result = new StringBuilder(getWidth() * (getHeight() + 1)); + for (int row = 0; row < getHeight(); row++) { + for (int col = 0; col < getWidth(); col++) { + if (maze[row][col] == ROAD) { + result.append(' '); + } else if (maze[row][col] == WALL) { + result.append('#'); + } else if (maze[row][col] == START) { + result.append('S'); + } else if (maze[row][col] == EXIT) { + result.append('E'); + } else { + result.append('.'); + } + } + result.append('\n'); + } + return result.toString(); + } + + public void reset() { + for (int i = 0; i < visited.length; i++) + Arrays.fill(visited[i], false); + } +} diff --git a/algorithms/src/main/java/com/baeldung/algorithms/maze/solver/MazeDriver.java b/algorithms/src/main/java/com/baeldung/algorithms/maze/solver/MazeDriver.java new file mode 100644 index 0000000000..60263deba3 --- /dev/null +++ b/algorithms/src/main/java/com/baeldung/algorithms/maze/solver/MazeDriver.java @@ -0,0 +1,34 @@ +package com.baeldung.algorithms.maze.solver; + +import java.io.File; +import java.util.List; + +public class MazeDriver { + public static void main(String[] args) throws Exception { + File maze1 = new File("src/main/resources/maze/maze1.txt"); + File maze2 = new File("src/main/resources/maze/maze2.txt"); + + execute(maze1); + execute(maze2); + } + + private static void execute(File file) throws Exception { + Maze maze = new Maze(file); + dfs(maze); + bfs(maze); + } + + private static void bfs(Maze maze) { + BFSMazeSolver bfs = new BFSMazeSolver(); + List path = bfs.solve(maze); + maze.printPath(path); + maze.reset(); + } + + private static void dfs(Maze maze) { + DFSMazeSolver dfs = new DFSMazeSolver(); + List path = dfs.solve(maze); + maze.printPath(path); + maze.reset(); + } +} diff --git a/algorithms/src/main/resources/maze/maze1.txt b/algorithms/src/main/resources/maze/maze1.txt new file mode 100644 index 0000000000..0a6309d25b --- /dev/null +++ b/algorithms/src/main/resources/maze/maze1.txt @@ -0,0 +1,12 @@ +S ######## +# # +# ### ## # +# # # # +# # # # # +# ## ##### +# # # +# # # # # +##### #### +# # E +# # # # +########## \ No newline at end of file diff --git a/algorithms/src/main/resources/maze/maze2.txt b/algorithms/src/main/resources/maze/maze2.txt new file mode 100644 index 0000000000..22e6d0382a --- /dev/null +++ b/algorithms/src/main/resources/maze/maze2.txt @@ -0,0 +1,22 @@ +S ########################## +# # # # +# # #### ############### # +# # # # # # +# # #### # # ############### +# # # # # # # +# # # #### ### ########### # +# # # # # # +# ################## # +######### # # # # # +# # #### # ####### # # +# # ### ### # # # # # +# # ## # ##### # # +##### ####### # # # # # +# # ## ## #### # # +# ##### ####### # # +# # ############ +####### ######### # # +# # ######## # +# ####### ###### ## # E +# # # ## # +############################ \ No newline at end of file diff --git a/core-java-9/src/test/java/com/baeldung/java9/httpclient/HttpClientTest.java b/core-java-9/src/test/java/com/baeldung/java9/httpclient/HttpClientTest.java index a4c6ac0d7d..5cf3b9098f 100644 --- a/core-java-9/src/test/java/com/baeldung/java9/httpclient/HttpClientTest.java +++ b/core-java-9/src/test/java/com/baeldung/java9/httpclient/HttpClientTest.java @@ -11,6 +11,7 @@ import java.util.Arrays; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.stream.Collectors; @@ -116,18 +117,20 @@ public class HttpClientTest { .GET() .build(); + ExecutorService executorService = Executors.newFixedThreadPool(2); + CompletableFuture> response1 = HttpClient.newBuilder() - .executor(Executors.newFixedThreadPool(2)) + .executor(executorService) .build() .sendAsync(request, HttpResponse.BodyHandler.asString()); CompletableFuture> response2 = HttpClient.newBuilder() - .executor(Executors.newFixedThreadPool(2)) + .executor(executorService) .build() .sendAsync(request, HttpResponse.BodyHandler.asString()); CompletableFuture> response3 = HttpClient.newBuilder() - .executor(Executors.newFixedThreadPool(2)) + .executor(executorService) .build() .sendAsync(request, HttpResponse.BodyHandler.asString()); diff --git a/core-java-9/src/test/java/com/baeldung/java9/httpclient/SimpleHttpRequestsUnitTest.java b/core-java-9/src/test/java/com/baeldung/java9/httpclient/SimpleHttpRequestsUnitTest.java deleted file mode 100644 index 4a704139a1..0000000000 --- a/core-java-9/src/test/java/com/baeldung/java9/httpclient/SimpleHttpRequestsUnitTest.java +++ /dev/null @@ -1,126 +0,0 @@ -package com.baeldung.java9.httpclient; - -import static java.net.HttpURLConnection.HTTP_OK; -import static org.junit.Assert.assertTrue; - -import java.io.IOException; -import java.net.CookieManager; -import java.net.CookiePolicy; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.http.HttpClient; -import java.net.http.HttpHeaders; -import java.net.http.HttpRequest; -import java.net.http.HttpResponse; -import java.security.NoSuchAlgorithmException; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; - -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLParameters; - -import org.junit.Before; -import org.junit.Test; - -public class SimpleHttpRequestsUnitTest { - - private URI httpURI; - - @Before - public void init() throws URISyntaxException { - httpURI = new URI("http://www.baeldung.com/"); - } - - @Test - public void quickGet() throws IOException, InterruptedException, URISyntaxException { - HttpRequest request = HttpRequest.create(httpURI).GET(); - HttpResponse response = request.response(); - int responseStatusCode = response.statusCode(); - String responseBody = response.body(HttpResponse.asString()); - assertTrue("Get response status code is bigger then 400", responseStatusCode < 400); - } - - @Test - public void asynchronousGet() throws URISyntaxException, IOException, InterruptedException, ExecutionException { - HttpRequest request = HttpRequest.create(httpURI).GET(); - long before = System.currentTimeMillis(); - CompletableFuture futureResponse = request.responseAsync(); - futureResponse.thenAccept(response -> { - String responseBody = response.body(HttpResponse.asString()); - }); - HttpResponse resp = futureResponse.get(); - HttpHeaders hs = resp.headers(); - assertTrue("There should be more then 1 header.", hs.map().size() > 1); - } - - @Test - public void postMehtod() throws URISyntaxException, IOException, InterruptedException { - HttpRequest.Builder requestBuilder = HttpRequest.create(httpURI); - requestBuilder.body(HttpRequest.fromString("param1=foo,param2=bar")).followRedirects(HttpClient.Redirect.SECURE); - HttpRequest request = requestBuilder.POST(); - HttpResponse response = request.response(); - int statusCode = response.statusCode(); - assertTrue("HTTP return code", statusCode == HTTP_OK); - } - - @Test - public void configureHttpClient() throws NoSuchAlgorithmException, URISyntaxException, IOException, InterruptedException { - CookieManager cManager = new CookieManager(); - cManager.setCookiePolicy(CookiePolicy.ACCEPT_ORIGINAL_SERVER); - - SSLParameters sslParam = new SSLParameters(new String[] { "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256" }, new String[] { "TLSv1.2" }); - - HttpClient.Builder hcBuilder = HttpClient.create(); - hcBuilder.cookieManager(cManager).sslContext(SSLContext.getDefault()).sslParameters(sslParam); - HttpClient httpClient = hcBuilder.build(); - HttpRequest.Builder reqBuilder = httpClient.request(new URI("https://www.facebook.com")); - - HttpRequest request = reqBuilder.followRedirects(HttpClient.Redirect.ALWAYS).GET(); - HttpResponse response = request.response(); - int statusCode = response.statusCode(); - assertTrue("HTTP return code", statusCode == HTTP_OK); - } - - SSLParameters getDefaultSSLParameters() throws NoSuchAlgorithmException { - SSLParameters sslP1 = SSLContext.getDefault().getSupportedSSLParameters(); - String[] proto = sslP1.getApplicationProtocols(); - String[] cifers = sslP1.getCipherSuites(); - System.out.println(printStringArr(proto)); - System.out.println(printStringArr(cifers)); - return sslP1; - } - - String printStringArr(String... args) { - if (args == null) { - return null; - } - StringBuilder sb = new StringBuilder(); - for (String s : args) { - sb.append(s); - sb.append("\n"); - } - return sb.toString(); - } - - String printHeaders(HttpHeaders h) { - if (h == null) { - return null; - } - - StringBuilder sb = new StringBuilder(); - Map> hMap = h.map(); - for (String k : hMap.keySet()) { - sb.append(k).append(":"); - List l = hMap.get(k); - if (l != null) { - l.forEach(s -> { - sb.append(s).append(","); - }); - } - sb.append("\n"); - } - return sb.toString(); - } -} diff --git a/core-java-concurrency/src/main/java/com/baeldung/concurrent/prioritytaskexecution/Job.java b/core-java-concurrency/src/main/java/com/baeldung/concurrent/prioritytaskexecution/Job.java index a70041ed7d..9900d1c63d 100644 --- a/core-java-concurrency/src/main/java/com/baeldung/concurrent/prioritytaskexecution/Job.java +++ b/core-java-concurrency/src/main/java/com/baeldung/concurrent/prioritytaskexecution/Job.java @@ -16,7 +16,8 @@ public class Job implements Runnable { @Override public void run() { try { - System.out.println("Job:" + jobName + " Priority:" + jobPriority); + System.out.println("Job:" + jobName + + " Priority:" + jobPriority); Thread.sleep(1000); } catch (InterruptedException ignored) { } diff --git a/core-java-concurrency/src/main/java/com/baeldung/concurrent/prioritytaskexecution/PriorityJobScheduler.java b/core-java-concurrency/src/main/java/com/baeldung/concurrent/prioritytaskexecution/PriorityJobScheduler.java index 70fd1710c0..ba55696d5a 100644 --- a/core-java-concurrency/src/main/java/com/baeldung/concurrent/prioritytaskexecution/PriorityJobScheduler.java +++ b/core-java-concurrency/src/main/java/com/baeldung/concurrent/prioritytaskexecution/PriorityJobScheduler.java @@ -9,21 +9,21 @@ import java.util.concurrent.TimeUnit; public class PriorityJobScheduler { private ExecutorService priorityJobPoolExecutor; - private ExecutorService priorityJobScheduler; - private PriorityBlockingQueue priorityQueue; + private ExecutorService priorityJobScheduler = + Executors.newSingleThreadExecutor(); + private PriorityBlockingQueue priorityQueue; public PriorityJobScheduler(Integer poolSize, Integer queueSize) { priorityJobPoolExecutor = Executors.newFixedThreadPool(poolSize); - Comparator jobComparator = Comparator.comparing(Job::getJobPriority); - priorityQueue = new PriorityBlockingQueue(queueSize, - (Comparator) jobComparator); + priorityQueue = new PriorityBlockingQueue(queueSize, + Comparator.comparing(Job::getJobPriority)); - priorityJobScheduler = Executors.newSingleThreadExecutor(); priorityJobScheduler.execute(()->{ while (true) { try { priorityJobPoolExecutor.execute(priorityQueue.take()); } catch (InterruptedException e) { + // exception needs special handling break; } } diff --git a/core-java-concurrency/src/main/java/com/baeldung/concurrent/threadlifecycle/BlockedState.java b/core-java-concurrency/src/main/java/com/baeldung/concurrent/threadlifecycle/BlockedState.java new file mode 100644 index 0000000000..19c6d08c2d --- /dev/null +++ b/core-java-concurrency/src/main/java/com/baeldung/concurrent/threadlifecycle/BlockedState.java @@ -0,0 +1,31 @@ +package com.baeldung.concurrent.threadlifecycle; + +public class BlockedState { + public static void main(String[] args) throws InterruptedException { + Thread t1 = new Thread(new DemoThreadB()); + Thread t2 = new Thread(new DemoThreadB()); + + t1.start(); + t2.start(); + + Thread.sleep(1000); + + System.out.println(t2.getState()); + System.exit(0); + } +} + +class DemoThreadB implements Runnable { + @Override + public void run() { + commonResource(); + } + + public static synchronized void commonResource() { + while(true) { + // Infinite loop to mimic heavy processing + // Thread 't1' won't leave this method + // when Thread 't2' enters this + } + } +} \ No newline at end of file diff --git a/core-java-concurrency/src/main/java/com/baeldung/concurrent/threadlifecycle/NewState.java b/core-java-concurrency/src/main/java/com/baeldung/concurrent/threadlifecycle/NewState.java new file mode 100644 index 0000000000..b524cc5ec7 --- /dev/null +++ b/core-java-concurrency/src/main/java/com/baeldung/concurrent/threadlifecycle/NewState.java @@ -0,0 +1,14 @@ +package com.baeldung.concurrent.threadlifecycle; + +public class NewState implements Runnable { + public static void main(String[] args) { + Runnable runnable = new NewState(); + Thread t = new Thread(runnable); + System.out.println(t.getState()); + } + + @Override + public void run() { + + } +} \ No newline at end of file diff --git a/core-java-concurrency/src/main/java/com/baeldung/concurrent/threadlifecycle/RunnableState.java b/core-java-concurrency/src/main/java/com/baeldung/concurrent/threadlifecycle/RunnableState.java new file mode 100644 index 0000000000..4aa8b36a76 --- /dev/null +++ b/core-java-concurrency/src/main/java/com/baeldung/concurrent/threadlifecycle/RunnableState.java @@ -0,0 +1,15 @@ +package com.baeldung.concurrent.threadlifecycle; + +public class RunnableState implements Runnable { + public static void main(String[] args) { + Runnable runnable = new NewState(); + Thread t = new Thread(runnable); + t.start(); + System.out.println(t.getState()); + } + + @Override + public void run() { + + } +} \ No newline at end of file diff --git a/core-java-concurrency/src/main/java/com/baeldung/concurrent/threadlifecycle/TerminatedState.java b/core-java-concurrency/src/main/java/com/baeldung/concurrent/threadlifecycle/TerminatedState.java new file mode 100644 index 0000000000..7c8884dc22 --- /dev/null +++ b/core-java-concurrency/src/main/java/com/baeldung/concurrent/threadlifecycle/TerminatedState.java @@ -0,0 +1,15 @@ +package com.baeldung.concurrent.threadlifecycle; + +public class TerminatedState implements Runnable { + public static void main(String[] args) throws InterruptedException { + Thread t1 = new Thread(new TerminatedState()); + t1.start(); + Thread.sleep(1000); + System.out.println(t1.getState()); + } + + @Override + public void run() { + // No processing in this block + } +} \ No newline at end of file diff --git a/core-java-concurrency/src/main/java/com/baeldung/concurrent/threadlifecycle/TimedWaitingState.java b/core-java-concurrency/src/main/java/com/baeldung/concurrent/threadlifecycle/TimedWaitingState.java new file mode 100644 index 0000000000..8d005352eb --- /dev/null +++ b/core-java-concurrency/src/main/java/com/baeldung/concurrent/threadlifecycle/TimedWaitingState.java @@ -0,0 +1,25 @@ +package com.baeldung.concurrent.threadlifecycle; + +public class TimedWaitingState { + public static void main(String[] args) throws InterruptedException { + DemoThread obj1 = new DemoThread(); + Thread t1 = new Thread(obj1); + t1.start(); + // The following sleep will give enough time for ThreadScheduler + // to start processing of thread t1 + Thread.sleep(1000); + System.out.println(t1.getState()); + } +} + +class DemoThread implements Runnable { + @Override + public void run() { + try { + Thread.sleep(5000); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + e.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/core-java-concurrency/src/main/java/com/baeldung/concurrent/threadlifecycle/WaitingState.java b/core-java-concurrency/src/main/java/com/baeldung/concurrent/threadlifecycle/WaitingState.java new file mode 100644 index 0000000000..98a6844309 --- /dev/null +++ b/core-java-concurrency/src/main/java/com/baeldung/concurrent/threadlifecycle/WaitingState.java @@ -0,0 +1,35 @@ +package com.baeldung.concurrent.threadlifecycle; + +public class WaitingState implements Runnable { + public static Thread t1; + + public static void main(String[] args) { + t1 = new Thread(new WaitingState()); + t1.start(); + } + + public void run() { + Thread t2 = new Thread(new DemoThreadWS()); + t2.start(); + + try { + t2.join(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + e.printStackTrace(); + } + } +} + +class DemoThreadWS implements Runnable { + public void run() { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + e.printStackTrace(); + } + + System.out.println(WaitingState.t1.getState()); + } +} \ No newline at end of file diff --git a/core-java-concurrency/src/test/java/com/baeldung/concurrent/prioritytaskexecution/PriorityJobSchedulerUnitTest.java b/core-java-concurrency/src/test/java/com/baeldung/concurrent/prioritytaskexecution/PriorityJobSchedulerUnitTest.java index 902bada3a2..1e67fe45c1 100644 --- a/core-java-concurrency/src/test/java/com/baeldung/concurrent/prioritytaskexecution/PriorityJobSchedulerUnitTest.java +++ b/core-java-concurrency/src/test/java/com/baeldung/concurrent/prioritytaskexecution/PriorityJobSchedulerUnitTest.java @@ -30,7 +30,9 @@ public class PriorityJobSchedulerUnitTest { // delay to avoid job sleep (added for demo) being interrupted try { Thread.sleep(2000); - } catch (InterruptedException ignored) { + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RuntimeException(e); } pjs.closeScheduler(); diff --git a/core-java/src/main/java/com/baeldung/string/Palindrome.java b/core-java/src/main/java/com/baeldung/string/Palindrome.java new file mode 100644 index 0000000000..97d4d36d07 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/string/Palindrome.java @@ -0,0 +1,66 @@ +package com.baeldung.string; + +import java.util.stream.IntStream; + +public class Palindrome { + + public boolean isPalindrome(String text) { + String clean = text.replaceAll("\\s+", "").toLowerCase(); + int length = clean.length(); + int forward = 0; + int backward = length - 1; + while (backward > forward) { + char forwardChar = clean.charAt(forward++); + char backwardChar = clean.charAt(backward--); + if (forwardChar != backwardChar) + return false; + } + return true; + } + + public boolean isPalindromeReverseTheString(String text) { + StringBuilder reverse = new StringBuilder(); + String clean = text.replaceAll("\\s+", "").toLowerCase(); + char[] plain = clean.toCharArray(); + for (int i = plain.length - 1; i >= 0; i--) + reverse.append(plain[i]); + return (reverse.toString()).equals(clean); + } + + public boolean isPalindromeUsingStringBuilder(String text) { + String clean = text.replaceAll("\\s+", "").toLowerCase(); + StringBuilder plain = new StringBuilder(clean); + StringBuilder reverse = plain.reverse(); + return (reverse.toString()).equals(clean); + } + + public boolean isPalindromeUsingStringBuffer(String text) { + String clean = text.replaceAll("\\s+", "").toLowerCase(); + StringBuffer plain = new StringBuffer(clean); + StringBuffer reverse = plain.reverse(); + return (reverse.toString()).equals(clean); + } + + public boolean isPalindromeRecursive(String text) { + String clean = text.replaceAll("\\s+", "").toLowerCase(); + return recursivePalindrome(clean, 0, clean.length() - 1); + } + + private boolean recursivePalindrome(String text, int forward, int backward) { + if (forward == backward) + return true; + if ((text.charAt(forward)) != (text.charAt(backward))) + return false; + if (forward < backward + 1) { + return recursivePalindrome(text, forward + 1, backward - 1); + } + + return true; + } + + public boolean isPalindromeUsingIntStream(String text) { + String temp = text.replaceAll("\\s+", "").toLowerCase(); + return IntStream.range(0, temp.length() / 2) + .noneMatch(i -> temp.charAt(i) != temp.charAt(temp.length() - i - 1)); + } +} diff --git a/core-java/src/test/java/com/baeldung/string/PalindromeTest.java b/core-java/src/test/java/com/baeldung/string/PalindromeTest.java new file mode 100644 index 0000000000..bc6fee2cd9 --- /dev/null +++ b/core-java/src/test/java/com/baeldung/string/PalindromeTest.java @@ -0,0 +1,97 @@ +package com.baeldung.string; + +import static org.junit.Assert.*; +import org.junit.Test; + +public class PalindromeTest { + + private String[] words = { + "Anna", + "Civic", + "Kayak", + "Level", + "Madam", + }; + + private String[] sentences = { + "Sore was I ere I saw Eros", + "Euston saw I was not Sue", + "Too hot to hoot", + "No mists or frost Simon", + "Stella won no wallets" + }; + + private Palindrome palindrome = new Palindrome(); + + @Test + public void whenWord_shouldBePalindrome() { + for (String word : words) + assertTrue(palindrome.isPalindrome(word)); + } + + @Test + public void whenSentence_shouldBePalindrome() { + for (String sentence : sentences) + assertTrue(palindrome.isPalindrome(sentence)); + } + + @Test + public void whenReverseWord_shouldBePalindrome() { + for (String word : words) + assertTrue(palindrome.isPalindromeReverseTheString(word)); + } + + @Test + public void whenReverseSentence_shouldBePalindrome() { + for (String sentence : sentences) + assertTrue(palindrome.isPalindromeReverseTheString(sentence)); + } + + @Test + public void whenStringBuilderWord_shouldBePalindrome() { + for (String word : words) + assertTrue(palindrome.isPalindromeUsingStringBuilder(word)); + } + + @Test + public void whenStringBuilderSentence_shouldBePalindrome() { + for (String sentence : sentences) + assertTrue(palindrome.isPalindromeUsingStringBuilder(sentence)); + } + + @Test + public void whenStringBufferWord_shouldBePalindrome() { + for (String word : words) + assertTrue(palindrome.isPalindromeUsingStringBuffer(word)); + } + + @Test + public void whenStringBufferSentence_shouldBePalindrome() { + for (String sentence : sentences) + assertTrue(palindrome.isPalindromeUsingStringBuffer(sentence)); + } + + @Test + public void whenPalindromeRecursive_wordShouldBePalindrome() { + for (String word : words) + assertTrue(palindrome.isPalindromeRecursive(word)); + } + + @Test + public void whenPalindromeRecursive_sentenceShouldBePalindrome() { + for (String sentence : sentences) + assertTrue(palindrome.isPalindromeRecursive(sentence)); + } + + @Test + public void whenPalindromeStreams_wordShouldBePalindrome() { + for (String word : words) + assertTrue(palindrome.isPalindromeUsingIntStream(word)); + } + + @Test + public void whenPalindromeStreams_sentenceShouldBePalindrome() { + for (String sentence : sentences) + assertTrue(palindrome.isPalindromeUsingIntStream(sentence)); + } +} diff --git a/core-kotlin/src/test/kotlin/com/baeldung/kotlin/InfixFunctionsTest.kt b/core-kotlin/src/test/kotlin/com/baeldung/kotlin/InfixFunctionsTest.kt new file mode 100644 index 0000000000..fc4286460a --- /dev/null +++ b/core-kotlin/src/test/kotlin/com/baeldung/kotlin/InfixFunctionsTest.kt @@ -0,0 +1,51 @@ +package com.baeldung.kotlin + +import org.junit.Assert +import org.junit.Test + +class InfixFunctionsTest { + @Test + fun testColours() { + val color = 0x123456 + val red = (color and 0xff0000) shr 16 + val green = (color and 0x00ff00) shr 8 + val blue = (color and 0x0000ff) shr 0 + + Assert.assertEquals(0x12, red) + Assert.assertEquals(0x34, green) + Assert.assertEquals(0x56, blue) + } + + @Test + fun testNewAssertions() { + class Assertion(private val target: T) { + infix fun isEqualTo(other: T) { + Assert.assertEquals(other, target) + } + + infix fun isDifferentFrom(other: T) { + Assert.assertNotEquals(other, target) + } + } + + val result = Assertion(5) + + result isEqualTo 5 + + // The following two lines are expected to fail + // result isEqualTo 6 + // result isDifferentFrom 5 + } + + @Test + fun testNewStringMethod() { + infix fun String.substringMatches(r: Regex) : List { + return r.findAll(this) + .map { it.value } + .toList() + } + + val matches = "a bc def" substringMatches ".*? ".toRegex() + Assert.assertEquals(listOf("a ", "bc "), matches) + } +} diff --git a/core-kotlin/src/test/kotlin/com/baeldung/kotlin/stdlib/RegexTest.kt b/core-kotlin/src/test/kotlin/com/baeldung/kotlin/stdlib/RegexTest.kt new file mode 100644 index 0000000000..eeb587ee22 --- /dev/null +++ b/core-kotlin/src/test/kotlin/com/baeldung/kotlin/stdlib/RegexTest.kt @@ -0,0 +1,128 @@ +package com.baeldung.kotlin.stdlib + +import org.junit.Test +import java.beans.ExceptionListener +import java.beans.XMLEncoder +import java.io.* +import java.lang.Exception +import kotlin.test.* +import kotlin.text.RegexOption.* + +class RegexTest { + + @Test + fun whenRegexIsInstantiated_thenIsEqualToToRegexMethod() { + val pattern = """a([bc]+)d?\\""" + + assertEquals(Regex.fromLiteral(pattern).pattern, pattern) + assertEquals(pattern, Regex(pattern).pattern) + assertEquals(pattern, pattern.toRegex().pattern) + } + + @Test + fun whenRegexMatches_thenResultIsTrue() { + val regex = """a([bc]+)d?""".toRegex() + + assertTrue(regex.containsMatchIn("xabcdy")) + assertTrue(regex.matches("abcd")) + assertFalse(regex matches "xabcdy") + } + + @Test + fun givenCompletelyMatchingRegex_whenMatchResult_thenDestructuring() { + val regex = """a([bc]+)d?""".toRegex() + + assertNull(regex.matchEntire("xabcdy")) + + val matchResult = regex.matchEntire("abbccbbd") + + assertNotNull(matchResult) + assertEquals(matchResult!!.value, matchResult.groupValues[0]) + assertEquals(matchResult.destructured.toList(), matchResult.groupValues.drop(1)) + assertEquals("bbccbb", matchResult.destructured.component1()) + assertNull(matchResult.next()) + } + + @Test + fun givenPartiallyMatchingRegex_whenMatchResult_thenGroups() { + val regex = """a([bc]+)d?""".toRegex() + var matchResult = regex.find("abcb abbd") + + assertNotNull(matchResult) + assertEquals(matchResult!!.value, matchResult.groupValues[0]) + assertEquals("abcb", matchResult.value) + assertEquals(IntRange(0, 3), matchResult.range) + assertEquals(listOf("abcb", "bcb"), matchResult.groupValues) + assertEquals(matchResult.destructured.toList(), matchResult.groupValues.drop(1)) + + matchResult = matchResult.next() + + assertNotNull(matchResult) + assertEquals("abbd", matchResult!!.value) + assertEquals("bb", matchResult.groupValues[1]) + + matchResult = matchResult.next() + + assertNull(matchResult) + } + + @Test + fun givenPartiallyMatchingRegex_whenMatchResult_thenDestructuring() { + val regex = """([\w\s]+) is (\d+) years old""".toRegex() + val matchResult = regex.find("Mickey Mouse is 95 years old") + val (name, age) = matchResult!!.destructured + + assertEquals("Mickey Mouse", name) + assertEquals("95", age) + } + + @Test + fun givenNonMatchingRegex_whenFindCalled_thenNull() { + val regex = """a([bc]+)d?""".toRegex() + val matchResult = regex.find("foo") + + assertNull(matchResult) + } + + @Test + fun givenNonMatchingRegex_whenFindAllCalled_thenEmptySet() { + val regex = """a([bc]+)d?""".toRegex() + val matchResults = regex.findAll("foo") + + assertNotNull(matchResults) + assertTrue(matchResults.none()) + } + + @Test + fun whenReplace_thenReplacement() { + val regex = """(red|green|blue)""".toRegex() + val beautiful = "Roses are red, Violets are blue" + val grim = regex.replace(beautiful, "dark") + val shiny = regex.replaceFirst(beautiful, "rainbow") + + assertEquals("Roses are dark, Violets are dark", grim) + assertEquals("Roses are rainbow, Violets are blue", shiny) + } + + @Test + fun whenComplexReplace_thenReplacement() { + val regex = """(red|green|blue)""".toRegex() + val beautiful = "Roses are red, Violets are blue" + val reallyBeautiful = regex.replace(beautiful) { + matchResult -> matchResult.value.toUpperCase() + "!" + } + + assertEquals("Roses are RED!, Violets are BLUE!", reallyBeautiful) + } + + @Test + fun whenSplit_thenList() { + val regex = """\W+""".toRegex() + val beautiful = "Roses are red, Violets are blue" + + assertEquals(listOf("Roses", "are", "red", "Violets", "are", "blue"), regex.split(beautiful)) + assertEquals(listOf("Roses", "are", "red", "Violets are blue"), regex.split(beautiful, 4)) + assertEquals(regex.toPattern().split(beautiful).asList(), regex.split(beautiful)) + } + +} \ No newline at end of file diff --git a/hibernate5/src/main/java/com/baeldung/hibernate/HibernateUtil.java b/hibernate5/src/main/java/com/baeldung/hibernate/HibernateUtil.java index 25fc0d7b02..130edec8cc 100644 --- a/hibernate5/src/main/java/com/baeldung/hibernate/HibernateUtil.java +++ b/hibernate5/src/main/java/com/baeldung/hibernate/HibernateUtil.java @@ -81,6 +81,7 @@ public class HibernateUtil { metadataSources.addAnnotatedClass(Bag.class); metadataSources.addAnnotatedClass(PointEntity.class); metadataSources.addAnnotatedClass(PolygonEntity.class); + metadataSources.addAnnotatedClass(com.baeldung.hibernate.pojo.Person.class); Metadata metadata = metadataSources.buildMetadata(); return metadata.getSessionFactoryBuilder() diff --git a/hibernate5/src/main/java/com/baeldung/hibernate/converters/PersonNameConverter.java b/hibernate5/src/main/java/com/baeldung/hibernate/converters/PersonNameConverter.java new file mode 100644 index 0000000000..c8b3397b09 --- /dev/null +++ b/hibernate5/src/main/java/com/baeldung/hibernate/converters/PersonNameConverter.java @@ -0,0 +1,43 @@ +package com.baeldung.hibernate.converters; + +import javax.persistence.AttributeConverter; +import javax.persistence.Converter; + +import com.baeldung.hibernate.pojo.PersonName; + +@Converter +public class PersonNameConverter implements AttributeConverter { + + private static final String SEPARATOR = ", "; + + @Override + public String convertToDatabaseColumn(PersonName person) { + StringBuilder sb = new StringBuilder(); + if (person.getSurname() != null) { + sb.append(person.getSurname()); + sb.append(SEPARATOR); + } + + if (person.getName() != null) { + sb.append(person.getName()); + } + + return sb.toString(); + } + + @Override + public PersonName convertToEntityAttribute(String dbPerson) { + String[] pieces = dbPerson.split(SEPARATOR); + + if (pieces == null || pieces.length != 2) { + return null; + } + + PersonName personName = new PersonName(); + personName.setSurname(pieces[0]); + personName.setName(pieces[1]); + + return personName; + } + +} diff --git a/hibernate5/src/main/java/com/baeldung/hibernate/pojo/Person.java b/hibernate5/src/main/java/com/baeldung/hibernate/pojo/Person.java new file mode 100644 index 0000000000..390a5954ed --- /dev/null +++ b/hibernate5/src/main/java/com/baeldung/hibernate/pojo/Person.java @@ -0,0 +1,32 @@ +package com.baeldung.hibernate.pojo; + +import javax.persistence.Convert; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +import com.baeldung.hibernate.converters.PersonNameConverter; + +@Entity(name = "PersonTable") +public class Person { + + @Id + @GeneratedValue + private Long id; + + @Convert(converter = PersonNameConverter.class) + private PersonName personName; + + public PersonName getPersonName() { + return personName; + } + + public void setPersonName(PersonName personName) { + this.personName = personName; + } + + public Long getId() { + return id; + } + +} diff --git a/hibernate5/src/main/java/com/baeldung/hibernate/pojo/PersonName.java b/hibernate5/src/main/java/com/baeldung/hibernate/pojo/PersonName.java new file mode 100644 index 0000000000..335fe73f75 --- /dev/null +++ b/hibernate5/src/main/java/com/baeldung/hibernate/pojo/PersonName.java @@ -0,0 +1,29 @@ +package com.baeldung.hibernate.pojo; + +import java.io.Serializable; + +public class PersonName implements Serializable { + + private static final long serialVersionUID = 7883094644631050150L; + + private String name; + + private String surname; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getSurname() { + return surname; + } + + public void setSurname(String surname) { + this.surname = surname; + } + +} diff --git a/hibernate5/src/test/java/com/baeldung/hibernate/converter/PersonNameConverterTest.java b/hibernate5/src/test/java/com/baeldung/hibernate/converter/PersonNameConverterTest.java new file mode 100644 index 0000000000..aec2311294 --- /dev/null +++ b/hibernate5/src/test/java/com/baeldung/hibernate/converter/PersonNameConverterTest.java @@ -0,0 +1,74 @@ +package com.baeldung.hibernate.converter; + +import java.io.IOException; + +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import com.baeldung.hibernate.HibernateUtil; +import com.baeldung.hibernate.pojo.Person; +import com.baeldung.hibernate.pojo.PersonName; + +import static org.junit.Assert.assertEquals; + +public class PersonNameConverterTest { + + private Session session; + private Transaction transaction; + + @Before + public void setUp() throws IOException { + session = HibernateUtil.getSessionFactory() + .openSession(); + transaction = session.beginTransaction(); + + session.createNativeQuery("delete from personTable") + .executeUpdate(); + + transaction.commit(); + transaction = session.beginTransaction(); + } + + @After + public void tearDown() { + transaction.rollback(); + session.close(); + } + + @Test + public void givenPersonName_WhenSaving_ThenNameAndSurnameConcat() { + final String name = "name"; + final String surname = "surname"; + + PersonName personName = new PersonName(); + personName.setName(name); + personName.setSurname(surname); + + Person person = new Person(); + person.setPersonName(personName); + + Long id = (Long) session.save(person); + + session.flush(); + session.clear(); + + String dbPersonName = (String) session.createNativeQuery("select p.personName from PersonTable p where p.id = :id") + .setParameter("id", id) + .getSingleResult(); + + assertEquals(surname + ", " + name, dbPersonName); + + Person dbPerson = session.createNativeQuery("select * from PersonTable p where p.id = :id", Person.class) + .setParameter("id", id) + .getSingleResult(); + + assertEquals(dbPerson.getPersonName() + .getName(), name); + assertEquals(dbPerson.getPersonName() + .getSurname(), surname); + } + +} diff --git a/jackson/pom.xml b/jackson/pom.xml index 001fde5021..2587e61ac1 100644 --- a/jackson/pom.xml +++ b/jackson/pom.xml @@ -129,7 +129,7 @@ - 2.9.2 + 2.9.4 19.0 diff --git a/javaxval/pom.xml b/javaxval/pom.xml index 6a83a25f01..a05ee43aaf 100644 --- a/javaxval/pom.xml +++ b/javaxval/pom.xml @@ -6,10 +6,11 @@ 0.1-SNAPSHOT - 2.0.0.Final - 6.0.2.Final + 2.0.1.Final + 6.0.7.Final 3.0.0 2.2.6 + 5.0.2.RELEASE @@ -21,12 +22,6 @@ - - javax.validation - validation-api - ${validation-api.version} - - org.hibernate hibernate-validator @@ -50,6 +45,16 @@ javax.el ${javax.el.version} + + org.springframework + spring-context + ${org.springframework.version} + + + org.springframework + spring-test + ${org.springframework.version} + diff --git a/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/MethodValidationConfig.java b/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/MethodValidationConfig.java new file mode 100644 index 0000000000..206a145337 --- /dev/null +++ b/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/MethodValidationConfig.java @@ -0,0 +1,38 @@ +package org.baeldung.javaxval.methodvalidation; + +import org.baeldung.javaxval.methodvalidation.model.Customer; +import org.baeldung.javaxval.methodvalidation.model.Reservation; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Scope; +import org.springframework.validation.beanvalidation.MethodValidationPostProcessor; + +import java.time.LocalDate; + +@Configuration +@ComponentScan({ "org.baeldung.javaxval.methodvalidation.model" }) +public class MethodValidationConfig { + + @Bean + public MethodValidationPostProcessor methodValidationPostProcessor() { + return new MethodValidationPostProcessor(); + } + + @Bean("customer") + @Scope(BeanDefinition.SCOPE_PROTOTYPE) + public Customer customer(String firstName, String lastName) { + + Customer customer = new Customer(firstName, lastName); + return customer; + } + + @Bean("reservation") + @Scope(BeanDefinition.SCOPE_PROTOTYPE) + public Reservation reservation(LocalDate begin, LocalDate end, Customer customer, int room) { + + Reservation reservation = new Reservation(begin, end, customer, room); + return reservation; + } +} diff --git a/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/constraints/ConsistentDateParameterValidator.java b/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/constraints/ConsistentDateParameterValidator.java new file mode 100644 index 0000000000..f1c97760d7 --- /dev/null +++ b/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/constraints/ConsistentDateParameterValidator.java @@ -0,0 +1,25 @@ +package org.baeldung.javaxval.methodvalidation.constraints; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; +import javax.validation.constraintvalidation.SupportedValidationTarget; +import javax.validation.constraintvalidation.ValidationTarget; +import java.time.LocalDate; + +@SupportedValidationTarget(ValidationTarget.PARAMETERS) +public class ConsistentDateParameterValidator implements ConstraintValidator { + + @Override + public boolean isValid(Object[] value, ConstraintValidatorContext context) { + + if (value[0] == null || value[1] == null) { + return true; + } + + if (!(value[0] instanceof LocalDate) || !(value[1] instanceof LocalDate)) { + throw new IllegalArgumentException("Illegal method signature, expected two parameters of type LocalDate."); + } + + return ((LocalDate) value[0]).isAfter(LocalDate.now()) && ((LocalDate) value[0]).isBefore((LocalDate) value[1]); + } +} diff --git a/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/constraints/ConsistentDateParameters.java b/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/constraints/ConsistentDateParameters.java new file mode 100644 index 0000000000..6b321f545c --- /dev/null +++ b/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/constraints/ConsistentDateParameters.java @@ -0,0 +1,23 @@ +package org.baeldung.javaxval.methodvalidation.constraints; + +import javax.validation.Constraint; +import javax.validation.Payload; +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +@Constraint(validatedBy = ConsistentDateParameterValidator.class) +@Target({ METHOD, CONSTRUCTOR }) +@Retention(RUNTIME) +@Documented +public @interface ConsistentDateParameters { + + String message() default "End date must be after begin date and both must be in the future"; + + Class[] groups() default {}; + + Class[] payload() default {}; +} diff --git a/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/constraints/ValidReservation.java b/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/constraints/ValidReservation.java new file mode 100644 index 0000000000..f9cdea1483 --- /dev/null +++ b/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/constraints/ValidReservation.java @@ -0,0 +1,24 @@ +package org.baeldung.javaxval.methodvalidation.constraints; + +import javax.validation.Constraint; +import javax.validation.Payload; +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.CONSTRUCTOR; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +@Constraint(validatedBy = ValidReservationValidator.class) +@Target({ METHOD, CONSTRUCTOR }) +@Retention(RUNTIME) +@Documented +public @interface ValidReservation { + + String message() default "End date must be after begin date and both must be in the future, room number must be bigger than 0"; + + Class[] groups() default {}; + + Class[] payload() default {}; +} diff --git a/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/constraints/ValidReservationValidator.java b/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/constraints/ValidReservationValidator.java new file mode 100644 index 0000000000..7b730480ed --- /dev/null +++ b/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/constraints/ValidReservationValidator.java @@ -0,0 +1,32 @@ +package org.baeldung.javaxval.methodvalidation.constraints; + +import org.baeldung.javaxval.methodvalidation.model.Reservation; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; +import java.time.LocalDate; + +public class ValidReservationValidator implements ConstraintValidator { + + @Override + public boolean isValid(Reservation reservation, ConstraintValidatorContext context) { + + if (reservation == null) { + return true; + } + + if (!(reservation instanceof Reservation)) { + throw new IllegalArgumentException("Illegal method signature, expected parameter of type Reservation."); + } + + if (reservation.getBegin() == null || reservation.getEnd() == null || reservation.getCustomer() == null) { + return false; + } + + return (reservation.getBegin() + .isAfter(LocalDate.now()) + && reservation.getBegin() + .isBefore(reservation.getEnd()) + && reservation.getRoom() > 0); + } +} diff --git a/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/model/Customer.java b/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/model/Customer.java new file mode 100644 index 0000000000..fe9ad7080e --- /dev/null +++ b/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/model/Customer.java @@ -0,0 +1,41 @@ +package org.baeldung.javaxval.methodvalidation.model; + +import org.springframework.validation.annotation.Validated; + +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +@Validated +public class Customer { + + @Size(min = 5, max = 200) + private String firstName; + + @Size(min = 5, max = 200) + private String lastName; + + public Customer(@Size(min = 5, max = 200) @NotNull String firstName, @Size(min = 5, max = 200) @NotNull String lastName) { + this.firstName = firstName; + this.lastName = lastName; + } + + public Customer() { + + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } +} diff --git a/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/model/Reservation.java b/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/model/Reservation.java new file mode 100644 index 0000000000..a8c01d2be1 --- /dev/null +++ b/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/model/Reservation.java @@ -0,0 +1,64 @@ +package org.baeldung.javaxval.methodvalidation.model; + +import org.baeldung.javaxval.methodvalidation.constraints.ConsistentDateParameters; +import org.baeldung.javaxval.methodvalidation.constraints.ValidReservation; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import javax.validation.constraints.Positive; +import java.time.LocalDate; + +@Validated +public class Reservation { + + private LocalDate begin; + + private LocalDate end; + + @Valid + private Customer customer; + + @Positive + private int room; + + @ConsistentDateParameters + @ValidReservation + public Reservation(LocalDate begin, LocalDate end, Customer customer, int room) { + this.begin = begin; + this.end = end; + this.customer = customer; + this.room = room; + } + + public LocalDate getBegin() { + return begin; + } + + public void setBegin(LocalDate begin) { + this.begin = begin; + } + + public LocalDate getEnd() { + return end; + } + + public void setEnd(LocalDate end) { + this.end = end; + } + + public Customer getCustomer() { + return customer; + } + + public void setCustomer(Customer customer) { + this.customer = customer; + } + + public int getRoom() { + return room; + } + + public void setRoom(int room) { + this.room = room; + } +} diff --git a/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/model/ReservationManagement.java b/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/model/ReservationManagement.java new file mode 100644 index 0000000000..f6fec1a15d --- /dev/null +++ b/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/model/ReservationManagement.java @@ -0,0 +1,50 @@ +package org.baeldung.javaxval.methodvalidation.model; + +import org.baeldung.javaxval.methodvalidation.constraints.ConsistentDateParameters; +import org.baeldung.javaxval.methodvalidation.constraints.ValidReservation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Controller; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import javax.validation.constraints.*; +import java.time.LocalDate; +import java.util.List; + +@Controller +@Validated +public class ReservationManagement { + + @Autowired + private ApplicationContext applicationContext; + + @ConsistentDateParameters + public void createReservation(LocalDate begin, LocalDate end, @NotNull Customer customer) { + + // ... + } + + public void createReservation(@NotNull @Future LocalDate begin, @Min(1) int duration, @NotNull Customer customer) { + + // ... + } + + public void createReservation(@Valid Reservation reservation) { + + // ... + } + + @NotNull + @Size(min = 1) + public List<@NotNull Customer> getAllCustomers() { + + return null; + } + + @Valid + public Reservation getReservationById(int id) { + + return null; + } +} diff --git a/javaxval/src/test/java/org/baeldung/javaxval/methodvalidation/ContainerValidationIntegrationTest.java b/javaxval/src/test/java/org/baeldung/javaxval/methodvalidation/ContainerValidationIntegrationTest.java new file mode 100644 index 0000000000..2363bf8f5d --- /dev/null +++ b/javaxval/src/test/java/org/baeldung/javaxval/methodvalidation/ContainerValidationIntegrationTest.java @@ -0,0 +1,97 @@ +package org.baeldung.javaxval.methodvalidation; + +import org.baeldung.javaxval.methodvalidation.model.Customer; +import org.baeldung.javaxval.methodvalidation.model.Reservation; +import org.baeldung.javaxval.methodvalidation.model.ReservationManagement; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.support.AnnotationConfigContextLoader; + +import javax.validation.ConstraintViolationException; +import java.time.LocalDate; +import java.util.List; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = { MethodValidationConfig.class }, loader = AnnotationConfigContextLoader.class) +public class ContainerValidationIntegrationTest { + + @Autowired + ReservationManagement reservationManagement; + + @Rule + public final ExpectedException exception = ExpectedException.none(); + + @Test + public void whenValidationWithInvalidMethodParameters_thenConstraintViolationException() { + + exception.expect(ConstraintViolationException.class); + reservationManagement.createReservation(LocalDate.now(), 0, null); + } + + @Test + public void whenValidationWithValidMethodParameters_thenNoException() { + + reservationManagement.createReservation(LocalDate.now() + .plusDays(1), 1, new Customer("William", "Smith")); + } + + @Test + public void whenCrossParameterValidationWithInvalidParameters_thenConstraintViolationException() { + + exception.expect(ConstraintViolationException.class); + reservationManagement.createReservation(LocalDate.now(), LocalDate.now(), null); + } + + @Test + public void whenCrossParameterValidationWithValidParameters_thenNoException() { + + reservationManagement.createReservation(LocalDate.now() + .plusDays(1), + LocalDate.now() + .plusDays(2), + new Customer("William", "Smith")); + } + + @Test + public void whenValidationWithInvalidReturnValue_thenConstraintViolationException() { + + exception.expect(ConstraintViolationException.class); + List list = reservationManagement.getAllCustomers(); + } + + @Test + public void whenValidationWithInvalidCascadedValue_thenConstraintViolationException() { + + Customer customer = new Customer(); + customer.setFirstName("John"); + customer.setLastName("Doe"); + Reservation reservation = new Reservation(LocalDate.now() + .plusDays(1), + LocalDate.now() + .plusDays(2), + customer, 1); + + exception.expect(ConstraintViolationException.class); + reservationManagement.createReservation(reservation); + } + + @Test + public void whenValidationWithValidCascadedValue_thenCNoException() { + + Customer customer = new Customer(); + customer.setFirstName("William"); + customer.setLastName("Smith"); + Reservation reservation = new Reservation(LocalDate.now() + .plusDays(1), + LocalDate.now() + .plusDays(2), + customer, 1); + + reservationManagement.createReservation(reservation); + } +} diff --git a/javaxval/src/test/java/org/baeldung/javaxval/methodvalidation/ValidationIntegrationTest.java b/javaxval/src/test/java/org/baeldung/javaxval/methodvalidation/ValidationIntegrationTest.java new file mode 100644 index 0000000000..6b53d3a107 --- /dev/null +++ b/javaxval/src/test/java/org/baeldung/javaxval/methodvalidation/ValidationIntegrationTest.java @@ -0,0 +1,209 @@ +package org.baeldung.javaxval.methodvalidation; + +import org.baeldung.javaxval.methodvalidation.model.Customer; +import org.baeldung.javaxval.methodvalidation.model.Reservation; +import org.baeldung.javaxval.methodvalidation.model.ReservationManagement; +import org.junit.Before; +import org.junit.Test; +import static org.junit.Assert.*; + +import javax.validation.ConstraintViolation; +import javax.validation.Validation; +import javax.validation.ValidatorFactory; +import javax.validation.executable.ExecutableValidator; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.time.LocalDate; +import java.util.Collections; +import java.util.Set; + +public class ValidationIntegrationTest { + + private ExecutableValidator executableValidator; + + @Before + public void getExecutableValidator() { + + ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); + this.executableValidator = factory.getValidator() + .forExecutables(); + } + + @Test + public void whenValidationWithInvalidMethodParameters_thenCorrectNumberOfVoilations() throws NoSuchMethodException { + + ReservationManagement object = new ReservationManagement(); + Method method = ReservationManagement.class.getMethod("createReservation", LocalDate.class, int.class, Customer.class); + Object[] parameterValues = { LocalDate.now(), 0, null }; + Set> violations = executableValidator.validateParameters(object, method, parameterValues); + + assertEquals(3, violations.size()); + } + + @Test + public void whenValidationWithValidMethodParameters_thenZeroVoilations() throws NoSuchMethodException { + + ReservationManagement object = new ReservationManagement(); + Method method = ReservationManagement.class.getMethod("createReservation", LocalDate.class, int.class, Customer.class); + Object[] parameterValues = { LocalDate.now() + .plusDays(1), 1, new Customer("John", "Doe") }; + Set> violations = executableValidator.validateParameters(object, method, parameterValues); + + assertEquals(0, violations.size()); + } + + @Test + public void whenCrossParameterValidationWithInvalidParameters_thenCorrectNumberOfVoilations() throws NoSuchMethodException { + + ReservationManagement object = new ReservationManagement(); + Method method = ReservationManagement.class.getMethod("createReservation", LocalDate.class, LocalDate.class, Customer.class); + Object[] parameterValues = { LocalDate.now(), LocalDate.now(), new Customer("John", "Doe") }; + Set> violations = executableValidator.validateParameters(object, method, parameterValues); + + assertEquals(1, violations.size()); + } + + @Test + public void whenCrossParameterValidationWithValidParameters_thenZeroVoilations() throws NoSuchMethodException { + + ReservationManagement object = new ReservationManagement(); + Method method = ReservationManagement.class.getMethod("createReservation", LocalDate.class, LocalDate.class, Customer.class); + Object[] parameterValues = { LocalDate.now() + .plusDays(1), + LocalDate.now() + .plusDays(2), + new Customer("John", "Doe") }; + Set> violations = executableValidator.validateParameters(object, method, parameterValues); + + assertEquals(0, violations.size()); + } + + @Test + public void whenValidationWithInvalidConstructorParameters_thenCorrectNumberOfVoilations() throws NoSuchMethodException { + + Constructor constructor = Customer.class.getConstructor(String.class, String.class); + Object[] parameterValues = { "John", "Doe" }; + Set> violations = executableValidator.validateConstructorParameters(constructor, parameterValues); + + assertEquals(2, violations.size()); + } + + @Test + public void whenValidationWithValidConstructorParameters_thenZeroVoilations() throws NoSuchMethodException { + + Constructor constructor = Customer.class.getConstructor(String.class, String.class); + Object[] parameterValues = { "William", "Smith" }; + Set> violations = executableValidator.validateConstructorParameters(constructor, parameterValues); + + assertEquals(0, violations.size()); + } + + @Test + public void whenCrossParameterValidationWithInvalidConstructorParameters_thenCorrectNumberOfVoilations() throws NoSuchMethodException { + + Constructor constructor = Reservation.class.getConstructor(LocalDate.class, LocalDate.class, Customer.class, int.class); + Object[] parameterValues = { LocalDate.now(), LocalDate.now(), new Customer("William", "Smith"), 1 }; + Set> violations = executableValidator.validateConstructorParameters(constructor, parameterValues); + + assertEquals(1, violations.size()); + } + + @Test + public void whenCrossParameterValidationWithValidConstructorParameters_thenZeroVoilations() throws NoSuchMethodException { + + Constructor constructor = Reservation.class.getConstructor(LocalDate.class, LocalDate.class, Customer.class, int.class); + Object[] parameterValues = { LocalDate.now() + .plusDays(1), + LocalDate.now() + .plusDays(2), + new Customer("William", "Smith"), 1 }; + Set> violations = executableValidator.validateConstructorParameters(constructor, parameterValues); + + assertEquals(0, violations.size()); + } + + @Test + public void whenValidationWithInvalidReturnValue_thenCorrectNumberOfVoilations() throws NoSuchMethodException { + + ReservationManagement object = new ReservationManagement(); + Method method = ReservationManagement.class.getMethod("getAllCustomers"); + Object returnValue = Collections. emptyList(); + Set> violations = executableValidator.validateReturnValue(object, method, returnValue); + + assertEquals(1, violations.size()); + } + + @Test + public void whenValidationWithValidReturnValue_thenZeroVoilations() throws NoSuchMethodException { + + ReservationManagement object = new ReservationManagement(); + Method method = ReservationManagement.class.getMethod("getAllCustomers"); + Object returnValue = Collections.singletonList(new Customer("William", "Smith")); + Set> violations = executableValidator.validateReturnValue(object, method, returnValue); + + assertEquals(0, violations.size()); + } + + @Test + public void whenValidationWithInvalidConstructorReturnValue_thenCorrectNumberOfVoilations() throws NoSuchMethodException { + + Constructor constructor = Reservation.class.getConstructor(LocalDate.class, LocalDate.class, Customer.class, int.class); + Reservation createdObject = new Reservation(LocalDate.now(), LocalDate.now(), new Customer("William", "Smith"), 0); + Set> violations = executableValidator.validateConstructorReturnValue(constructor, createdObject); + + assertEquals(1, violations.size()); + } + + @Test + public void whenValidationWithValidConstructorReturnValue_thenZeroVoilations() throws NoSuchMethodException { + + Constructor constructor = Reservation.class.getConstructor(LocalDate.class, LocalDate.class, Customer.class, int.class); + Reservation createdObject = new Reservation(LocalDate.now() + .plusDays(1), + LocalDate.now() + .plusDays(2), + new Customer("William", "Smith"), 1); + Set> violations = executableValidator.validateConstructorReturnValue(constructor, createdObject); + + assertEquals(0, violations.size()); + } + + @Test + public void whenValidationWithInvalidCascadedValue_thenCorrectNumberOfVoilations() throws NoSuchMethodException { + + ReservationManagement object = new ReservationManagement(); + Method method = ReservationManagement.class.getMethod("createReservation", Reservation.class); + Customer customer = new Customer(); + customer.setFirstName("John"); + customer.setLastName("Doe"); + Reservation reservation = new Reservation(LocalDate.now() + .plusDays(1), + LocalDate.now() + .plusDays(2), + customer, 1); + Object[] parameterValues = { reservation }; + Set> violations = executableValidator.validateParameters(object, method, parameterValues); + + assertEquals(2, violations.size()); + } + + @Test + public void whenValidationWithValidCascadedValue_thenCorrectNumberOfVoilations() throws NoSuchMethodException { + + ReservationManagement object = new ReservationManagement(); + Method method = ReservationManagement.class.getMethod("createReservation", Reservation.class); + Customer customer = new Customer(); + customer.setFirstName("William"); + customer.setLastName("Smith"); + Reservation reservation = new Reservation(LocalDate.now() + .plusDays(1), + LocalDate.now() + .plusDays(2), + customer, 1); + Object[] parameterValues = { reservation }; + Set> violations = executableValidator.validateParameters(object, method, parameterValues); + + assertEquals(0, violations.size()); + } + +} diff --git a/jgroups/src/main/java/com/baeldung/jgroups/JGroupsMessenger.java b/jgroups/src/main/java/com/baeldung/jgroups/JGroupsMessenger.java index 2a8df8a9ab..70eacabf1e 100644 --- a/jgroups/src/main/java/com/baeldung/jgroups/JGroupsMessenger.java +++ b/jgroups/src/main/java/com/baeldung/jgroups/JGroupsMessenger.java @@ -100,21 +100,16 @@ public class JGroupsMessenger extends ReceiverAdapter { System.out.println("Received initial view:"); newView.forEach(System.out::println); } else { - // Compare to last view System.out.println("Received new view."); List
newMembers = View.newMembers(lastView, newView); - if (newMembers.size() > 0) { - System.out.println("New members: "); - newMembers.forEach(System.out::println); - } + System.out.println("New members: "); + newMembers.forEach(System.out::println); List
exMembers = View.leftMembers(lastView, newView); - if (exMembers.size() > 0) { - System.out.println("Exited members:"); - exMembers.forEach(System.out::println); - } + System.out.println("Exited members:"); + exMembers.forEach(System.out::println); } lastView = newView; } @@ -122,7 +117,7 @@ public class JGroupsMessenger extends ReceiverAdapter { /** * Loop on console input until we see 'x' to exit */ - private void processInput() { + private void processInput() throws Exception { BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); while (running) { @@ -138,13 +133,8 @@ public class JGroupsMessenger extends ReceiverAdapter { running = false; continue; } else if (!destinationName.isEmpty()) { - Optional
optDestination = getAddress(destinationName); - if (optDestination.isPresent()) { - destination = optDestination.get(); - } else { - System.out.println("Destination not found, try again."); - continue; - } + destination = getAddress(destinationName) + . orElseThrow(() -> new Exception("Destination not found")); } // Accept a string to send diff --git a/libraries/README.md b/libraries/README.md index d001f13698..fbf2b4e876 100644 --- a/libraries/README.md +++ b/libraries/README.md @@ -59,6 +59,7 @@ - [Intro to JDO Queries 2/2](http://www.baeldung.com/jdo-queries) - [Guide to google-http-client](http://www.baeldung.com/google-http-client) - [Interact with Google Sheets from Java](http://www.baeldung.com/google-sheets-java-client) +- [Programatically Create, Configure, and Run a Tomcat Server] (http://www.baeldung.com/tomcat-programmatic-setup) diff --git a/libraries/pom.xml b/libraries/pom.xml index e8f7c470a3..64cc9c6a84 100644 --- a/libraries/pom.xml +++ b/libraries/pom.xml @@ -649,6 +649,11 @@ google-http-client-gson ${googleclient.version} + + org.infinispan + infinispan-core + ${infinispan.version} + @@ -716,6 +721,13 @@ test test + + + + org.apache.tomcat + tomcat-catalina + ${tomcat.version} + org.milyn milyn-smooks-all @@ -802,6 +814,8 @@ 1.0.0 1.7.0 3.0.14 + 8.5.24 2.2.0 + 9.1.5.Final - \ No newline at end of file + diff --git a/libraries/src/main/java/com/baeldung/infinispan/CacheConfiguration.java b/libraries/src/main/java/com/baeldung/infinispan/CacheConfiguration.java new file mode 100644 index 0000000000..bf214458f3 --- /dev/null +++ b/libraries/src/main/java/com/baeldung/infinispan/CacheConfiguration.java @@ -0,0 +1,85 @@ +package com.baeldung.infinispan; + +import com.baeldung.infinispan.listener.CacheListener; +import org.infinispan.Cache; +import org.infinispan.configuration.cache.Configuration; +import org.infinispan.configuration.cache.ConfigurationBuilder; +import org.infinispan.eviction.EvictionType; +import org.infinispan.manager.DefaultCacheManager; +import org.infinispan.transaction.LockingMode; +import org.infinispan.transaction.TransactionMode; + +import java.util.concurrent.TimeUnit; + +public class CacheConfiguration { + + public static final String SIMPLE_HELLO_WORLD_CACHE = "simple-hello-world-cache"; + public static final String EXPIRING_HELLO_WORLD_CACHE = "expiring-hello-world-cache"; + public static final String EVICTING_HELLO_WORLD_CACHE = "evicting-hello-world-cache"; + public static final String PASSIVATING_HELLO_WORLD_CACHE = "passivating-hello-world-cache"; + public static final String TRANSACTIONAL_CACHE = "transactional-cache"; + + public DefaultCacheManager cacheManager() { + DefaultCacheManager cacheManager = new DefaultCacheManager(); + return cacheManager; + } + + public Cache transactionalCache(DefaultCacheManager cacheManager, CacheListener listener) { + return this.buildCache(TRANSACTIONAL_CACHE, cacheManager, listener, transactionalConfiguration()); + } + + public Cache simpleHelloWorldCache(DefaultCacheManager cacheManager, CacheListener listener) { + return this.buildCache(SIMPLE_HELLO_WORLD_CACHE, cacheManager, listener, new ConfigurationBuilder().build()); + } + + public Cache expiringHelloWorldCache(DefaultCacheManager cacheManager, CacheListener listener) { + return this.buildCache(EXPIRING_HELLO_WORLD_CACHE, cacheManager, listener, expiringConfiguration()); + } + + public Cache evictingHelloWorldCache(DefaultCacheManager cacheManager, CacheListener listener) { + return this.buildCache(EVICTING_HELLO_WORLD_CACHE, cacheManager, listener, evictingConfiguration()); + } + + public Cache passivatingHelloWorldCache(DefaultCacheManager cacheManager, CacheListener listener) { + return this.buildCache(PASSIVATING_HELLO_WORLD_CACHE, cacheManager, listener, passivatingConfiguration()); + } + + private Cache buildCache(String cacheName, DefaultCacheManager cacheManager, + CacheListener listener, Configuration configuration) { + + cacheManager.defineConfiguration(cacheName, configuration); + Cache cache = cacheManager.getCache(cacheName); + cache.addListener(listener); + return cache; + } + + private Configuration expiringConfiguration() { + return new ConfigurationBuilder().expiration().lifespan(1, TimeUnit.SECONDS) + .build(); + } + + private Configuration evictingConfiguration() { + return new ConfigurationBuilder() + .memory().evictionType(EvictionType.COUNT).size(1) + .build(); + } + + private Configuration passivatingConfiguration() { + return new ConfigurationBuilder() + .memory().evictionType(EvictionType.COUNT).size(1) + .persistence() + .passivation(true) + .addSingleFileStore() + .purgeOnStartup(true) + .location(System.getProperty("java.io.tmpdir")) + .build(); + } + + private Configuration transactionalConfiguration() { + return new ConfigurationBuilder() + .transaction().transactionMode(TransactionMode.TRANSACTIONAL) + .lockingMode(LockingMode.PESSIMISTIC) + .build(); + } + +} diff --git a/libraries/src/main/java/com/baeldung/infinispan/listener/CacheListener.java b/libraries/src/main/java/com/baeldung/infinispan/listener/CacheListener.java new file mode 100644 index 0000000000..2f6536ad87 --- /dev/null +++ b/libraries/src/main/java/com/baeldung/infinispan/listener/CacheListener.java @@ -0,0 +1,55 @@ +package com.baeldung.infinispan.listener; + +import org.infinispan.notifications.Listener; +import org.infinispan.notifications.cachelistener.annotation.*; +import org.infinispan.notifications.cachelistener.event.*; + +@Listener +public class CacheListener { + + @CacheEntryCreated + public void entryCreated(CacheEntryCreatedEvent event) { + this.printLog("Adding key '" + event.getKey() + "' to cache", event); + } + + @CacheEntryExpired + public void entryExpired(CacheEntryExpiredEvent event) { + this.printLog("Expiring key '" + event.getKey() + "' from cache", event); + } + + @CacheEntryVisited + public void entryVisited(CacheEntryVisitedEvent event) { + this.printLog("Key '" + event.getKey() + "' was visited", event); + } + + @CacheEntryActivated + public void entryActivated(CacheEntryActivatedEvent event) { + this.printLog("Activating key '" + event.getKey() + "' on cache", event); + } + + @CacheEntryPassivated + public void entryPassivated(CacheEntryPassivatedEvent event) { + this.printLog("Passivating key '" + event.getKey() + "' from cache", event); + } + + @CacheEntryLoaded + public void entryLoaded(CacheEntryLoadedEvent event) { + this.printLog("Loading key '" + event.getKey() + "' to cache", event); + } + + @CacheEntriesEvicted + public void entriesEvicted(CacheEntriesEvictedEvent event) { + final StringBuilder builder = new StringBuilder(); + event.getEntries().entrySet().forEach((e) -> + builder.append(e.getKey() + ", ") + ); + System.out.println("Evicting following entries from cache: " + builder.toString()); + } + + private void printLog(String log, CacheEntryEvent event) { + if (!event.isPre()) { + System.out.println(log); + } + } + +} diff --git a/libraries/src/main/java/com/baeldung/infinispan/repository/HelloWorldRepository.java b/libraries/src/main/java/com/baeldung/infinispan/repository/HelloWorldRepository.java new file mode 100644 index 0000000000..85c0d539a3 --- /dev/null +++ b/libraries/src/main/java/com/baeldung/infinispan/repository/HelloWorldRepository.java @@ -0,0 +1,15 @@ +package com.baeldung.infinispan.repository; + +public class HelloWorldRepository { + + public String getHelloWorld() { + try { + System.out.println("Executing some heavy query"); + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + return "Hello World!"; + } + +} diff --git a/libraries/src/main/java/com/baeldung/infinispan/service/HelloWorldService.java b/libraries/src/main/java/com/baeldung/infinispan/service/HelloWorldService.java new file mode 100644 index 0000000000..0d1ffb4168 --- /dev/null +++ b/libraries/src/main/java/com/baeldung/infinispan/service/HelloWorldService.java @@ -0,0 +1,90 @@ +package com.baeldung.infinispan.service; + +import com.baeldung.infinispan.listener.CacheListener; +import com.baeldung.infinispan.repository.HelloWorldRepository; +import org.infinispan.Cache; + +import java.util.concurrent.TimeUnit; + +public class HelloWorldService { + + private final HelloWorldRepository repository; + + private final Cache simpleHelloWorldCache; + private final Cache expiringHelloWorldCache; + private final Cache evictingHelloWorldCache; + private final Cache passivatingHelloWorldCache; + + public HelloWorldService(HelloWorldRepository repository, CacheListener listener, + Cache simpleHelloWorldCache, + Cache expiringHelloWorldCache, + Cache evictingHelloWorldCache, + Cache passivatingHelloWorldCache) { + + this.repository = repository; + + this.simpleHelloWorldCache = simpleHelloWorldCache; + this.expiringHelloWorldCache = expiringHelloWorldCache; + this.evictingHelloWorldCache = evictingHelloWorldCache; + this.passivatingHelloWorldCache = passivatingHelloWorldCache; + } + + public String findSimpleHelloWorld() { + String cacheKey = "simple-hello"; + String helloWorld = simpleHelloWorldCache.get(cacheKey); + if (helloWorld == null) { + helloWorld = repository.getHelloWorld(); + simpleHelloWorldCache.put(cacheKey, helloWorld); + } + return helloWorld; + } + + public String findExpiringHelloWorld() { + String cacheKey = "expiring-hello"; + String helloWorld = simpleHelloWorldCache.get(cacheKey); + if (helloWorld == null) { + helloWorld = repository.getHelloWorld(); + simpleHelloWorldCache.put(cacheKey, helloWorld, 1, TimeUnit.SECONDS); + } + return helloWorld; + } + + public String findIdleHelloWorld() { + String cacheKey = "idle-hello"; + String helloWorld = simpleHelloWorldCache.get(cacheKey); + if (helloWorld == null) { + helloWorld = repository.getHelloWorld(); + simpleHelloWorldCache.put(cacheKey, helloWorld, -1, TimeUnit.SECONDS, 10, TimeUnit.SECONDS); + } + return helloWorld; + } + + public String findSimpleHelloWorldInExpiringCache() { + String cacheKey = "simple-hello"; + String helloWorld = expiringHelloWorldCache.get(cacheKey); + if (helloWorld == null) { + helloWorld = repository.getHelloWorld(); + expiringHelloWorldCache.put(cacheKey, helloWorld); + } + return helloWorld; + } + + public String findEvictingHelloWorld(String key) { + String value = evictingHelloWorldCache.get(key); + if(value == null) { + value = repository.getHelloWorld(); + evictingHelloWorldCache.put(key, value); + } + return value; + } + + public String findPassivatingHelloWorld(String key) { + String value = passivatingHelloWorldCache.get(key); + if(value == null) { + value = repository.getHelloWorld(); + passivatingHelloWorldCache.put(key, value); + } + return value; + } + +} diff --git a/libraries/src/main/java/com/baeldung/infinispan/service/TransactionalService.java b/libraries/src/main/java/com/baeldung/infinispan/service/TransactionalService.java new file mode 100644 index 0000000000..b0dbf5475f --- /dev/null +++ b/libraries/src/main/java/com/baeldung/infinispan/service/TransactionalService.java @@ -0,0 +1,57 @@ +package com.baeldung.infinispan.service; + +import org.infinispan.Cache; +import org.springframework.util.StopWatch; + +import javax.transaction.TransactionManager; + +public class TransactionalService { + + private final Cache transactionalCache; + + private static final String KEY = "key"; + + public TransactionalService(Cache transactionalCache) { + this.transactionalCache = transactionalCache; + + transactionalCache.put(KEY, 0); + } + + public Integer getQuickHowManyVisits() { + try { + TransactionManager tm = transactionalCache.getAdvancedCache().getTransactionManager(); + tm.begin(); + Integer howManyVisits = transactionalCache.get(KEY); + howManyVisits++; + System.out.println("Ill try to set HowManyVisits to " + howManyVisits); + StopWatch watch = new StopWatch(); + watch.start(); + transactionalCache.put(KEY, howManyVisits); + watch.stop(); + System.out.println("I was able to set HowManyVisits to " + howManyVisits + + " after waiting " + watch.getTotalTimeSeconds() + " seconds"); + + tm.commit(); + return howManyVisits; + } catch (Exception e) { + e.printStackTrace(); + return 0; + } + } + + public void startBackgroundBatch() { + try { + TransactionManager tm = transactionalCache.getAdvancedCache().getTransactionManager(); + tm.begin(); + transactionalCache.put(KEY, 1000); + System.out.println("HowManyVisits should now be 1000, " + + "but we are holding the transaction"); + Thread.sleep(1000L); + tm.rollback(); + System.out.println("The slow batch suffered a rollback"); + } catch (Exception e) { + e.printStackTrace(); + } + } + +} diff --git a/libraries/src/main/java/com/baeldung/tomcat/MyFilter.java b/libraries/src/main/java/com/baeldung/tomcat/MyFilter.java new file mode 100644 index 0000000000..9cf4a0ed95 --- /dev/null +++ b/libraries/src/main/java/com/baeldung/tomcat/MyFilter.java @@ -0,0 +1,31 @@ +package com.baeldung.tomcat; + +import javax.servlet.*; +import javax.servlet.annotation.WebFilter; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * Created by adi on 1/14/18. + */ +@WebFilter(urlPatterns = "/my-servlet/*") +public class MyFilter implements Filter { + + @Override + public void init(FilterConfig filterConfig) { + + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + System.out.println("Filtering stuff..."); + HttpServletResponse httpResponse = (HttpServletResponse) response; + httpResponse.addHeader("myHeader", "myHeaderValue"); + chain.doFilter(request, httpResponse); + } + + @Override + public void destroy() { + + } +} diff --git a/libraries/src/main/java/com/baeldung/tomcat/MyServlet.java b/libraries/src/main/java/com/baeldung/tomcat/MyServlet.java new file mode 100644 index 0000000000..4bbf3c03a7 --- /dev/null +++ b/libraries/src/main/java/com/baeldung/tomcat/MyServlet.java @@ -0,0 +1,25 @@ +package com.baeldung.tomcat; + +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * Created by adi on 1/10/18. + */ +@WebServlet( + name = "com.baeldung.tomcat.programmatic.MyServlet", + urlPatterns = {"/my-servlet"} +) +public class MyServlet extends HttpServlet { + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { + resp.setStatus(HttpServletResponse.SC_OK); + resp.getWriter().write("test"); + resp.getWriter().flush(); + resp.getWriter().close(); + } +} diff --git a/libraries/src/main/java/com/baeldung/tomcat/ProgrammaticTomcat.java b/libraries/src/main/java/com/baeldung/tomcat/ProgrammaticTomcat.java new file mode 100644 index 0000000000..b84b6b5c6d --- /dev/null +++ b/libraries/src/main/java/com/baeldung/tomcat/ProgrammaticTomcat.java @@ -0,0 +1,63 @@ +package com.baeldung.tomcat; + +import org.apache.catalina.Context; +import org.apache.catalina.LifecycleException; +import org.apache.catalina.startup.Tomcat; +import org.apache.tomcat.util.descriptor.web.FilterDef; +import org.apache.tomcat.util.descriptor.web.FilterMap; + +import java.io.File; + +/** + * Created by adi on 1/10/18. + */ +public class ProgrammaticTomcat { + + private Tomcat tomcat = null; + + //uncomment for live test + // public static void main(String[] args) throws LifecycleException, ServletException, URISyntaxException, IOException { + // startTomcat(); + // } + + public void startTomcat() throws LifecycleException { + tomcat = new Tomcat(); + tomcat.setPort(8080); + tomcat.setHostname("localhost"); + String appBase = "."; + tomcat + .getHost() + .setAppBase(appBase); + + File docBase = new File(System.getProperty("java.io.tmpdir")); + Context context = tomcat.addContext("", docBase.getAbsolutePath()); + + //add a servlet + Class servletClass = MyServlet.class; + Tomcat.addServlet(context, servletClass.getSimpleName(), servletClass.getName()); + context.addServletMappingDecoded("/my-servlet/*", servletClass.getSimpleName()); + + //add a filter and filterMapping + Class filterClass = MyFilter.class; + FilterDef myFilterDef = new FilterDef(); + myFilterDef.setFilterClass(filterClass.getName()); + myFilterDef.setFilterName(filterClass.getSimpleName()); + context.addFilterDef(myFilterDef); + + FilterMap myFilterMap = new FilterMap(); + myFilterMap.setFilterName(filterClass.getSimpleName()); + myFilterMap.addURLPattern("/my-servlet/*"); + context.addFilterMap(myFilterMap); + + tomcat.start(); + //uncomment for live test + // tomcat + // .getServer() + // .await(); + } + + public void stopTomcat() throws LifecycleException { + tomcat.stop(); + tomcat.destroy(); + } +} diff --git a/libraries/src/test/java/com/baeldung/infinispan/ConfigurationTest.java b/libraries/src/test/java/com/baeldung/infinispan/ConfigurationTest.java new file mode 100644 index 0000000000..b05314491b --- /dev/null +++ b/libraries/src/test/java/com/baeldung/infinispan/ConfigurationTest.java @@ -0,0 +1,56 @@ +package com.baeldung.infinispan; + +import com.baeldung.infinispan.listener.CacheListener; +import com.baeldung.infinispan.repository.HelloWorldRepository; +import com.baeldung.infinispan.service.HelloWorldService; +import com.baeldung.infinispan.service.TransactionalService; +import org.infinispan.Cache; +import org.infinispan.manager.DefaultCacheManager; +import org.junit.After; +import org.junit.Before; + +public class ConfigurationTest { + + private DefaultCacheManager cacheManager; + + private HelloWorldRepository repository = new HelloWorldRepository(); + + protected HelloWorldService helloWorldService; + protected TransactionalService transactionalService; + + @Before + public void setup() { + CacheConfiguration configuration = new CacheConfiguration(); + CacheListener listener = new CacheListener(); + + cacheManager = configuration.cacheManager(); + + Cache transactionalCache = + configuration.transactionalCache(cacheManager, listener); + + Cache simpleHelloWorldCache = + configuration.simpleHelloWorldCache(cacheManager, listener); + + Cache expiringHelloWorldCache = + configuration.expiringHelloWorldCache(cacheManager, listener); + + Cache evictingHelloWorldCache = + configuration.evictingHelloWorldCache(cacheManager, listener); + + Cache passivatingHelloWorldCache = + configuration.passivatingHelloWorldCache(cacheManager, listener); + + this.helloWorldService = new HelloWorldService(repository, + listener, simpleHelloWorldCache, expiringHelloWorldCache, evictingHelloWorldCache, + passivatingHelloWorldCache); + + this.transactionalService = new TransactionalService(transactionalCache); + + } + + @After + public void tearDown() { + cacheManager.stop(); + } + +} diff --git a/libraries/src/test/java/com/baeldung/infinispan/service/HelloWorldServiceUnitTest.java b/libraries/src/test/java/com/baeldung/infinispan/service/HelloWorldServiceUnitTest.java new file mode 100644 index 0000000000..bda2e6886b --- /dev/null +++ b/libraries/src/test/java/com/baeldung/infinispan/service/HelloWorldServiceUnitTest.java @@ -0,0 +1,105 @@ +package com.baeldung.infinispan.service; + +import com.baeldung.infinispan.ConfigurationTest; +import org.junit.Test; + +import static org.assertj.core.api.Java6Assertions.assertThat; + +public class HelloWorldServiceUnitTest extends ConfigurationTest { + + @Test + public void whenGetIsCalledTwoTimes_thenTheSecondShouldHitTheCache() { + long milis = System.currentTimeMillis(); + helloWorldService.findSimpleHelloWorld(); + long executionTime = System.currentTimeMillis() - milis; + + assertThat(executionTime).isGreaterThanOrEqualTo(1000); + + milis = System.currentTimeMillis(); + helloWorldService.findSimpleHelloWorld(); + executionTime = System.currentTimeMillis() - milis; + + assertThat(executionTime).isLessThan(100); + } + + @Test + public void whenGetIsCalledTwoTimesQuickly_thenTheSecondShouldHitTheCache() { + long milis = System.currentTimeMillis(); + helloWorldService.findExpiringHelloWorld(); + long executionTime = System.currentTimeMillis() - milis; + + assertThat(executionTime).isGreaterThanOrEqualTo(1000); + + milis = System.currentTimeMillis(); + helloWorldService.findExpiringHelloWorld(); + executionTime = System.currentTimeMillis() - milis; + + assertThat(executionTime).isLessThan(100); + } + + @Test + public void whenGetIsCalledTwoTimesSparsely_thenNeitherShouldHitTheCache() + throws InterruptedException { + + long milis = System.currentTimeMillis(); + helloWorldService.findSimpleHelloWorldInExpiringCache(); + long executionTime = System.currentTimeMillis() - milis; + + assertThat(executionTime).isGreaterThanOrEqualTo(1000); + + Thread.sleep(1100); + + milis = System.currentTimeMillis(); + helloWorldService.findSimpleHelloWorldInExpiringCache(); + executionTime = System.currentTimeMillis() - milis; + + assertThat(executionTime).isGreaterThanOrEqualTo(1000); + } + + @Test + public void givenOneEntryIsConfigured_whenTwoAreAdded_thenFirstShouldntBeAvailable() + throws InterruptedException { + + long milis = System.currentTimeMillis(); + helloWorldService.findEvictingHelloWorld("key 1"); + long executionTime = System.currentTimeMillis() - milis; + + assertThat(executionTime).isGreaterThanOrEqualTo(1000); + + milis = System.currentTimeMillis(); + helloWorldService.findEvictingHelloWorld("key 2"); + executionTime = System.currentTimeMillis() - milis; + + assertThat(executionTime).isGreaterThanOrEqualTo(1000); + + milis = System.currentTimeMillis(); + helloWorldService.findEvictingHelloWorld("key 1"); + executionTime = System.currentTimeMillis() - milis; + + assertThat(executionTime).isGreaterThanOrEqualTo(1000); + } + + @Test + public void givenOneEntryIsConfigured_whenTwoAreAdded_thenTheFirstShouldBeAvailable() + throws InterruptedException { + + long milis = System.currentTimeMillis(); + helloWorldService.findPassivatingHelloWorld("key 1"); + long executionTime = System.currentTimeMillis() - milis; + + assertThat(executionTime).isGreaterThanOrEqualTo(1000); + + milis = System.currentTimeMillis(); + helloWorldService.findPassivatingHelloWorld("key 2"); + executionTime = System.currentTimeMillis() - milis; + + assertThat(executionTime).isGreaterThanOrEqualTo(1000); + + milis = System.currentTimeMillis(); + helloWorldService.findPassivatingHelloWorld("key 1"); + executionTime = System.currentTimeMillis() - milis; + + assertThat(executionTime).isLessThan(100); + } + +} diff --git a/libraries/src/test/java/com/baeldung/infinispan/service/TransactionalServiceUnitTest.java b/libraries/src/test/java/com/baeldung/infinispan/service/TransactionalServiceUnitTest.java new file mode 100644 index 0000000000..f529222079 --- /dev/null +++ b/libraries/src/test/java/com/baeldung/infinispan/service/TransactionalServiceUnitTest.java @@ -0,0 +1,24 @@ +package com.baeldung.infinispan.service; + +import com.baeldung.infinispan.ConfigurationTest; +import org.junit.Test; + +import static org.assertj.core.api.Java6Assertions.assertThat; + +public class TransactionalServiceUnitTest extends ConfigurationTest { + + @Test + public void whenLockingAnEntry_thenItShouldBeInaccessible() throws InterruptedException { + Runnable backGroundJob = () -> transactionalService.startBackgroundBatch(); + Thread backgroundThread = new Thread(backGroundJob); + transactionalService.getQuickHowManyVisits(); + backgroundThread.start(); + Thread.sleep(100); //lets wait our thread warm up + long milis = System.currentTimeMillis(); + transactionalService.getQuickHowManyVisits(); + long executionTime = System.currentTimeMillis() - milis; + + assertThat(executionTime).isGreaterThan(500).isLessThan(1000); + } + +} diff --git a/libraries/src/test/java/com/baeldung/tomcat/ProgrammaticTomcatTest.java b/libraries/src/test/java/com/baeldung/tomcat/ProgrammaticTomcatTest.java new file mode 100644 index 0000000000..d559c3d408 --- /dev/null +++ b/libraries/src/test/java/com/baeldung/tomcat/ProgrammaticTomcatTest.java @@ -0,0 +1,62 @@ +package com.baeldung.tomcat; + +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.util.EntityUtils; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.BlockJUnit4ClassRunner; + + +import static junit.framework.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +/** + * Created by adi on 1/14/18. + */ +@RunWith(BlockJUnit4ClassRunner.class) +public class ProgrammaticTomcatTest { + + private ProgrammaticTomcat tomcat = new ProgrammaticTomcat(); + + @Before + public void setUp() throws Exception { + tomcat.startTomcat(); + } + + @After + public void tearDown() throws Exception { + tomcat.stopTomcat(); + } + + @Test + public void givenTomcatStarted_whenAccessServlet_responseIsTestAndResponseHeaderIsSet() throws Exception { + CloseableHttpClient httpClient = HttpClientBuilder + .create() + .build(); + HttpGet getServlet = new HttpGet("http://localhost:8080/my-servlet"); + + HttpResponse response = httpClient.execute(getServlet); + assertEquals(HttpStatus.SC_OK, response + .getStatusLine() + .getStatusCode()); + + String myHeaderValue = response + .getFirstHeader("myHeader") + .getValue(); + assertEquals("myHeaderValue", myHeaderValue); + + HttpEntity responseEntity = response.getEntity(); + assertNotNull(responseEntity); + + String responseString = EntityUtils.toString(responseEntity, "UTF-8"); + assertEquals("test", responseString); + } + +} diff --git a/logging-modules/README.md b/logging-modules/README.md index 8ae7316047..6de71adb43 100644 --- a/logging-modules/README.md +++ b/logging-modules/README.md @@ -4,3 +4,4 @@ ### Relevant Articles: - [Creating a Custom Logback Appender](http://www.baeldung.com/custom-logback-appender) +- [Get Log Output in JSON Format](http://www.baeldung.com/java-log-json-output) diff --git a/mesos-marathon/README.md b/mesos-marathon/README.md index 3223eb2478..1d4d4995a8 100644 --- a/mesos-marathon/README.md +++ b/mesos-marathon/README.md @@ -1,3 +1,5 @@ ### Relevant articles - [Simple Jenkins Pipeline with Marathon and Mesos](http://www.baeldung.com/jenkins-pipeline-with-marathon-mesos) + + To run the pipeline, please modify the dockerise.sh file with your own useranema and password for docker login. diff --git a/persistence-modules/spring-data-redis/pom.xml b/persistence-modules/spring-data-redis/pom.xml index 6cb49f11cf..0b9075147d 100644 --- a/persistence-modules/spring-data-redis/pom.xml +++ b/persistence-modules/spring-data-redis/pom.xml @@ -16,11 +16,13 @@ UTF-8 - 4.3.7.RELEASE - 1.8.1.RELEASE + 5.0.3.RELEASE + 2.0.3.RELEASE 3.2.4 2.9.0 0.10.0 + 2.0.3.RELEASE + @@ -73,6 +75,12 @@ nosqlunit-redis ${nosqlunit.version} + + + org.springframework.data + spring-data-commons + ${spring-data-commons.version} + diff --git a/persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/redis/config/RedisConfig.java b/persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/redis/config/RedisConfig.java index 4fd83a2bb6..4ea8bb4bc0 100644 --- a/persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/redis/config/RedisConfig.java +++ b/persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/redis/config/RedisConfig.java @@ -1,8 +1,5 @@ package com.baeldung.spring.data.redis.config; -import com.baeldung.spring.data.redis.queue.MessagePublisher; -import com.baeldung.spring.data.redis.queue.RedisMessagePublisher; -import com.baeldung.spring.data.redis.queue.RedisMessageSubscriber; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @@ -11,10 +8,16 @@ import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.listener.ChannelTopic; import org.springframework.data.redis.listener.RedisMessageListenerContainer; import org.springframework.data.redis.listener.adapter.MessageListenerAdapter; +import org.springframework.data.redis.repository.configuration.EnableRedisRepositories; import org.springframework.data.redis.serializer.GenericToStringSerializer; +import com.baeldung.spring.data.redis.queue.MessagePublisher; +import com.baeldung.spring.data.redis.queue.RedisMessagePublisher; +import com.baeldung.spring.data.redis.queue.RedisMessageSubscriber; + @Configuration @ComponentScan("com.baeldung.spring.data.redis") +@EnableRedisRepositories(basePackages = "com.baeldung.spring.data.redis.repo") public class RedisConfig { @Bean diff --git a/persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/redis/model/Student.java b/persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/redis/model/Student.java index 10ba0f5ef4..b97ed23387 100644 --- a/persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/redis/model/Student.java +++ b/persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/redis/model/Student.java @@ -2,6 +2,9 @@ package com.baeldung.spring.data.redis.model; import java.io.Serializable; +import org.springframework.data.redis.core.RedisHash; + +@RedisHash("Student") public class Student implements Serializable { public enum Gender { diff --git a/persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/redis/repo/StudentRepository.java b/persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/redis/repo/StudentRepository.java index 250c227f00..39f13bb6a7 100644 --- a/persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/redis/repo/StudentRepository.java +++ b/persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/redis/repo/StudentRepository.java @@ -1,18 +1,9 @@ package com.baeldung.spring.data.redis.repo; +import org.springframework.data.repository.CrudRepository; +import org.springframework.stereotype.Repository; + import com.baeldung.spring.data.redis.model.Student; -import java.util.Map; - -public interface StudentRepository { - - void saveStudent(Student person); - - void updateStudent(Student student); - - Student findStudent(String id); - - Map findAllStudents(); - - void deleteStudent(String id); -} +@Repository +public interface StudentRepository extends CrudRepository {} diff --git a/persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/redis/repo/StudentRepositoryImpl.java b/persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/redis/repo/StudentRepositoryImpl.java deleted file mode 100644 index f13bef0f54..0000000000 --- a/persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/redis/repo/StudentRepositoryImpl.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.baeldung.spring.data.redis.repo; - -import com.baeldung.spring.data.redis.model.Student; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.redis.core.HashOperations; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.stereotype.Repository; - -import javax.annotation.PostConstruct; -import java.util.Map; - -@Repository -public class StudentRepositoryImpl implements StudentRepository { - - private static final String KEY = "Student"; - - private RedisTemplate redisTemplate; - private HashOperations hashOperations; - - @Autowired - public StudentRepositoryImpl(RedisTemplate redisTemplate) { - this.redisTemplate = redisTemplate; - } - - @PostConstruct - private void init() { - hashOperations = redisTemplate.opsForHash(); - } - - public void saveStudent(final Student student) { - hashOperations.put(KEY, student.getId(), student); - } - - public void updateStudent(final Student student) { - hashOperations.put(KEY, student.getId(), student); - } - - public Student findStudent(final String id) { - return (Student) hashOperations.get(KEY, id); - } - - public Map findAllStudents() { - return hashOperations.entries(KEY); - } - - public void deleteStudent(final String id) { - hashOperations.delete(KEY, id); - } -} diff --git a/persistence-modules/spring-data-redis/src/test/java/com/baeldung/spring/data/redis/repo/StudentRepositoryIntegrationTest.java b/persistence-modules/spring-data-redis/src/test/java/com/baeldung/spring/data/redis/repo/StudentRepositoryIntegrationTest.java index 1028c0bc24..66ef3c21b2 100644 --- a/persistence-modules/spring-data-redis/src/test/java/com/baeldung/spring/data/redis/repo/StudentRepositoryIntegrationTest.java +++ b/persistence-modules/spring-data-redis/src/test/java/com/baeldung/spring/data/redis/repo/StudentRepositoryIntegrationTest.java @@ -1,17 +1,20 @@ package com.baeldung.spring.data.redis.repo; -import com.baeldung.spring.data.redis.config.RedisConfig; -import com.baeldung.spring.data.redis.model.Student; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import java.util.Map; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; +import com.baeldung.spring.data.redis.config.RedisConfig; +import com.baeldung.spring.data.redis.model.Student; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = RedisConfig.class) @@ -23,18 +26,18 @@ public class StudentRepositoryIntegrationTest { @Test public void whenSavingStudent_thenAvailableOnRetrieval() throws Exception { final Student student = new Student("Eng2015001", "John Doe", Student.Gender.MALE, 1); - studentRepository.saveStudent(student); - final Student retrievedStudent = studentRepository.findStudent(student.getId()); + studentRepository.save(student); + final Student retrievedStudent = studentRepository.findById(student.getId()).get(); assertEquals(student.getId(), retrievedStudent.getId()); } @Test public void whenUpdatingStudent_thenAvailableOnRetrieval() throws Exception { final Student student = new Student("Eng2015001", "John Doe", Student.Gender.MALE, 1); - studentRepository.saveStudent(student); + studentRepository.save(student); student.setName("Richard Watson"); - studentRepository.saveStudent(student); - final Student retrievedStudent = studentRepository.findStudent(student.getId()); + studentRepository.save(student); + final Student retrievedStudent = studentRepository.findById(student.getId()).get(); assertEquals(student.getName(), retrievedStudent.getName()); } @@ -42,18 +45,19 @@ public class StudentRepositoryIntegrationTest { public void whenSavingStudents_thenAllShouldAvailableOnRetrieval() throws Exception { final Student engStudent = new Student("Eng2015001", "John Doe", Student.Gender.MALE, 1); final Student medStudent = new Student("Med2015001", "Gareth Houston", Student.Gender.MALE, 2); - studentRepository.saveStudent(engStudent); - studentRepository.saveStudent(medStudent); - final Map retrievedStudent = studentRepository.findAllStudents(); - assertEquals(retrievedStudent.size(), 2); + studentRepository.save(engStudent); + studentRepository.save(medStudent); + List students = new ArrayList<>(); + studentRepository.findAll().forEach(students::add); + assertEquals(students.size(), 2); } @Test public void whenDeletingStudent_thenNotAvailableOnRetrieval() throws Exception { final Student student = new Student("Eng2015001", "John Doe", Student.Gender.MALE, 1); - studentRepository.saveStudent(student); - studentRepository.deleteStudent(student.getId()); - final Student retrievedStudent = studentRepository.findStudent(student.getId()); + studentRepository.save(student); + studentRepository.deleteById(student.getId()); + final Student retrievedStudent = studentRepository.findById(student.getId()).orElse(null); assertNull(retrievedStudent); } } \ No newline at end of file diff --git a/persistence-modules/spring-jpa/pom.xml b/persistence-modules/spring-jpa/pom.xml index 04c64fafc3..bc0b2381f3 100644 --- a/persistence-modules/spring-jpa/pom.xml +++ b/persistence-modules/spring-jpa/pom.xml @@ -13,7 +13,7 @@ com.baeldung parent-modules 1.0.0-SNAPSHOT - ../ + ../../ diff --git a/persistence-modules/spring-jpa/src/main/java/org/baeldung/inmemory/persistence/dao/StudentRepository.java b/persistence-modules/spring-jpa/src/main/java/org/baeldung/inmemory/persistence/dao/StudentRepository.java index bfcf6f5cdc..f856b78c52 100644 --- a/persistence-modules/spring-jpa/src/main/java/org/baeldung/inmemory/persistence/dao/StudentRepository.java +++ b/persistence-modules/spring-jpa/src/main/java/org/baeldung/inmemory/persistence/dao/StudentRepository.java @@ -2,6 +2,17 @@ package org.baeldung.inmemory.persistence.dao; import org.baeldung.inmemory.persistence.model.Student; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +import java.util.List; public interface StudentRepository extends JpaRepository { + + @Query("SELECT s FROM Student s JOIN s.tags t WHERE t = LOWER(:tag)") + List retrieveByTag(@Param("tag") String tag); + + @Query("SELECT s FROM Student s JOIN s.tags t WHERE s.name = LOWER(:name) AND t = LOWER(:tag)") + List retrieveByNameFilterByTag(@Param("name") String name, @Param("tag") String tag); + } diff --git a/persistence-modules/spring-jpa/src/main/java/org/baeldung/inmemory/persistence/model/Student.java b/persistence-modules/spring-jpa/src/main/java/org/baeldung/inmemory/persistence/model/Student.java index b50fe9122e..2e4e3ea2cb 100644 --- a/persistence-modules/spring-jpa/src/main/java/org/baeldung/inmemory/persistence/model/Student.java +++ b/persistence-modules/spring-jpa/src/main/java/org/baeldung/inmemory/persistence/model/Student.java @@ -1,7 +1,10 @@ package org.baeldung.inmemory.persistence.model; +import javax.persistence.ElementCollection; import javax.persistence.Entity; import javax.persistence.Id; +import java.util.ArrayList; +import java.util.List; @Entity public class Student { @@ -10,6 +13,9 @@ public class Student { private long id; private String name; + @ElementCollection + private List tags = new ArrayList<>(); + public Student() { } @@ -35,4 +41,11 @@ public class Student { this.name = name; } + public List getTags() { + return tags; + } + + public void setTags(List tags) { + this.tags.addAll(tags); + } } diff --git a/persistence-modules/spring-jpa/src/test/java/org/baeldung/persistence/repository/InMemoryDBIntegrationTest.java b/persistence-modules/spring-jpa/src/test/java/org/baeldung/persistence/repository/InMemoryDBIntegrationTest.java index 8380ab5434..28d7e3772c 100644 --- a/persistence-modules/spring-jpa/src/test/java/org/baeldung/persistence/repository/InMemoryDBIntegrationTest.java +++ b/persistence-modules/spring-jpa/src/test/java/org/baeldung/persistence/repository/InMemoryDBIntegrationTest.java @@ -12,6 +12,9 @@ import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; +import java.util.Arrays; +import java.util.List; + import static org.junit.Assert.assertEquals; @RunWith(SpringJUnit4ClassRunner.class) @@ -34,4 +37,46 @@ public class InMemoryDBIntegrationTest { assertEquals("name incorrect", NAME, student2.getName()); } + @Test + public void givenStudentWithTags_whenSave_thenGetByTagOk(){ + Student student = new Student(ID, NAME); + student.setTags(Arrays.asList("full time", "computer science")); + studentRepository.save(student); + + Student student2 = studentRepository.retrieveByTag("full time").get(0); + assertEquals("name incorrect", NAME, student2.getName()); + } + + @Test + public void givenMultipleStudentsWithTags_whenSave_thenGetByTagReturnsCorrectCount(){ + Student student = new Student(0, "Larry"); + student.setTags(Arrays.asList("full time", "computer science")); + studentRepository.save(student); + + Student student2 = new Student(1, "Curly"); + student2.setTags(Arrays.asList("part time", "rocket science")); + studentRepository.save(student2); + + Student student3 = new Student(2, "Moe"); + student3.setTags(Arrays.asList("full time", "philosophy")); + studentRepository.save(student3); + + Student student4 = new Student(3, "Shemp"); + student4.setTags(Arrays.asList("part time", "mathematics")); + studentRepository.save(student4); + + List students = studentRepository.retrieveByTag("full time"); + assertEquals("size incorrect", 2, students.size()); + } + + @Test + public void givenStudentWithTags_whenSave_thenGetByNameAndTagOk(){ + Student student = new Student(ID, NAME); + student.setTags(Arrays.asList("full time", "computer science")); + studentRepository.save(student); + + Student student2 = studentRepository.retrieveByNameFilterByTag("John", "full time").get(0); + assertEquals("name incorrect", NAME, student2.getName()); + } + } diff --git a/pom.xml b/pom.xml index ca6d4afe82..fc0c8f8ba7 100644 --- a/pom.xml +++ b/pom.xml @@ -49,7 +49,9 @@ core-java core-java-io core-java-8 + couchbase deltaspike diff --git a/reactor-core/pom.xml b/reactor-core/pom.xml index 12f481c96f..d387471d56 100644 --- a/reactor-core/pom.xml +++ b/reactor-core/pom.xml @@ -26,11 +26,17 @@ ${assertj.version} test - + + + io.projectreactor + reactor-test + ${reactor-core.version} + test + - 3.0.5.RELEASE + 3.1.3.RELEASE 3.6.1 diff --git a/reactor-core/src/test/java/com/baeldung/reactor/core/CombiningPublishersTest.java b/reactor-core/src/test/java/com/baeldung/reactor/core/CombiningPublishersTest.java new file mode 100644 index 0000000000..9d5d094875 --- /dev/null +++ b/reactor-core/src/test/java/com/baeldung/reactor/core/CombiningPublishersTest.java @@ -0,0 +1,182 @@ +package com.baeldung.reactor.core; + +import java.time.Duration; + +import org.junit.Test; + +import reactor.core.publisher.Flux; +import reactor.test.StepVerifier; + +public class CombiningPublishersTest { + + private static Integer min = 1; + private static Integer max = 5; + + private static Flux evenNumbers = Flux.range(min, max).filter(x -> x % 2 == 0); + private static Flux oddNumbers = Flux.range(min, max).filter(x -> x % 2 > 0); + + + @Test + public void testMerge() { + Flux fluxOfIntegers = Flux.merge( + evenNumbers, + oddNumbers); + + StepVerifier.create(fluxOfIntegers) + .expectNext(2) + .expectNext(4) + .expectNext(1) + .expectNext(3) + .expectNext(5) + .expectComplete() + .verify(); + } + + @Test + public void testMergeWithDelayedElements() { + Flux fluxOfIntegers = Flux.merge( + evenNumbers.delayElements(Duration.ofMillis(500L)), + oddNumbers.delayElements(Duration.ofMillis(300L))); + + StepVerifier.create(fluxOfIntegers) + .expectNext(1) + .expectNext(2) + .expectNext(3) + .expectNext(5) + .expectNext(4) + .expectComplete() + .verify(); + } + + @Test + public void testConcat() { + Flux fluxOfIntegers = Flux.concat( + evenNumbers.delayElements(Duration.ofMillis(500L)), + oddNumbers.delayElements(Duration.ofMillis(300L))); + + StepVerifier.create(fluxOfIntegers) + .expectNext(2) + .expectNext(4) + .expectNext(1) + .expectNext(3) + .expectNext(5) + .expectComplete() + .verify(); + } + + @Test + public void testConcatWith() { + Flux fluxOfIntegers = evenNumbers + .concatWith(oddNumbers); + + StepVerifier.create(fluxOfIntegers) + .expectNext(2) + .expectNext(4) + .expectNext(1) + .expectNext(3) + .expectNext(5) + .expectComplete() + .verify(); + } + + @Test + public void testCombineLatest() { + Flux fluxOfIntegers = Flux.combineLatest( + evenNumbers, + oddNumbers, + (a, b) -> a + b); + + StepVerifier.create(fluxOfIntegers) + .expectNext(5) + .expectNext(7) + .expectNext(9) + .expectComplete() + .verify(); + + } + + @Test + public void testCombineLatest1() { + StepVerifier.create(Flux.combineLatest(obj -> (int) obj[1], evenNumbers, oddNumbers)) + .expectNext(1) + .expectNext(3) + .expectNext(5) + .verifyComplete(); + } + + @Test + public void testMergeSequential() { + Flux fluxOfIntegers = Flux.mergeSequential( + evenNumbers, + oddNumbers); + + StepVerifier.create(fluxOfIntegers) + .expectNext(2) + .expectNext(4) + .expectNext(1) + .expectNext(3) + .expectNext(5) + .expectComplete() + .verify(); + } + + + @Test + public void testMergeDelayError() { + Flux fluxOfIntegers = Flux.mergeDelayError(1, + evenNumbers.delayElements(Duration.ofMillis(500L)), + oddNumbers.delayElements(Duration.ofMillis(300L))); + + StepVerifier.create(fluxOfIntegers) + .expectNext(1) + .expectNext(2) + .expectNext(3) + .expectNext(5) + .expectNext(4) + .expectComplete() + .verify(); + } + + @Test + public void testMergeWith() { + Flux fluxOfIntegers = evenNumbers.mergeWith(oddNumbers); + + StepVerifier.create(fluxOfIntegers) + .expectNext(2) + .expectNext(4) + .expectNext(1) + .expectNext(3) + .expectNext(5) + .expectComplete() + .verify(); + } + + @Test + public void testZip() { + Flux fluxOfIntegers = Flux.zip( + evenNumbers, + oddNumbers, + (a, b) -> a + b); + + StepVerifier.create(fluxOfIntegers) + .expectNext(3) + .expectNext(7) + .expectComplete() + .verify(); + } + + @Test + public void testZipWith() { + Flux fluxOfIntegers = evenNumbers + .zipWith(oddNumbers, + (a, b) -> a * b); + + StepVerifier.create(fluxOfIntegers) + .expectNext(2) + .expectNext(12) + .expectComplete() + .verify(); + } + + +} diff --git a/spring-5-security/src/main/java/com/baeldung/dsl/ClientErrorLoggingDsl.java b/spring-5-security/src/main/java/com/baeldung/dsl/ClientErrorLoggingDsl.java new file mode 100644 index 0000000000..6c7c0d2717 --- /dev/null +++ b/spring-5-security/src/main/java/com/baeldung/dsl/ClientErrorLoggingDsl.java @@ -0,0 +1,32 @@ +package com.baeldung.dsl; + +import java.util.List; + +import org.springframework.http.HttpStatus; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; +import org.springframework.security.web.access.intercept.FilterSecurityInterceptor; + +public class ClientErrorLoggingDsl extends AbstractHttpConfigurer { + + private List errorCodes; + + public ClientErrorLoggingDsl(List errorCodes) { + this.errorCodes = errorCodes; + } + + public ClientErrorLoggingDsl() { + + } + + @Override + public void init(HttpSecurity http) throws Exception { + // initialization code + } + + @Override + public void configure(HttpSecurity http) throws Exception { + http.addFilterAfter(new ClientErrorLoggingFilter(errorCodes), FilterSecurityInterceptor.class); + } + +} diff --git a/spring-5-security/src/main/java/com/baeldung/dsl/ClientErrorLoggingFilter.java b/spring-5-security/src/main/java/com/baeldung/dsl/ClientErrorLoggingFilter.java new file mode 100644 index 0000000000..56f7cea3b8 --- /dev/null +++ b/spring-5-security/src/main/java/com/baeldung/dsl/ClientErrorLoggingFilter.java @@ -0,0 +1,54 @@ +package com.baeldung.dsl; + +import java.io.IOException; +import java.util.List; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletResponse; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.springframework.http.HttpStatus; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.web.filter.GenericFilterBean; + +public class ClientErrorLoggingFilter extends GenericFilterBean { + + private static final Logger logger = LogManager.getLogger(ClientErrorLoggingFilter.class); + + private List errorCodes; + + public ClientErrorLoggingFilter(List errorCodes) { + this.errorCodes = errorCodes; + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + + Authentication auth = SecurityContextHolder.getContext() + .getAuthentication(); + + if (auth != null) { + int status = ((HttpServletResponse) response).getStatus(); + if (status >= 400 && status < 500) { + if (errorCodes == null) { + logger.debug("User " + auth.getName() + " encountered error " + status); + } else { + if (errorCodes.stream() + .filter(s -> s.value() == status) + .findFirst() + .isPresent()) { + logger.debug("User " + auth.getName() + " encountered error " + status); + } + } + } + } + + chain.doFilter(request, response); + } + +} diff --git a/spring-5-security/src/main/java/com/baeldung/dsl/CustomDslApplication.java b/spring-5-security/src/main/java/com/baeldung/dsl/CustomDslApplication.java new file mode 100644 index 0000000000..3e58bccaf4 --- /dev/null +++ b/spring-5-security/src/main/java/com/baeldung/dsl/CustomDslApplication.java @@ -0,0 +1,13 @@ +package com.baeldung.dsl; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class CustomDslApplication { + + public static void main(String[] args) { + SpringApplication.run(CustomDslApplication.class, args); + } + +} diff --git a/spring-5-security/src/main/java/com/baeldung/dsl/MyController.java b/spring-5-security/src/main/java/com/baeldung/dsl/MyController.java new file mode 100644 index 0000000000..c69046afb5 --- /dev/null +++ b/spring-5-security/src/main/java/com/baeldung/dsl/MyController.java @@ -0,0 +1,14 @@ +package com.baeldung.dsl; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class MyController { + + @GetMapping("/admin") + public String getAdminPage() { + return "Hello Admin"; + } + +} diff --git a/spring-5-security/src/main/java/com/baeldung/dsl/SecurityConfig.java b/spring-5-security/src/main/java/com/baeldung/dsl/SecurityConfig.java new file mode 100644 index 0000000000..4494aaa131 --- /dev/null +++ b/spring-5-security/src/main/java/com/baeldung/dsl/SecurityConfig.java @@ -0,0 +1,50 @@ +package com.baeldung.dsl; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; + +@Configuration +public class SecurityConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http.authorizeRequests() + .antMatchers("/admin*") + .hasAnyRole("ADMIN") + .anyRequest() + .authenticated() + .and() + .formLogin() + .and() + .apply(clientErrorLogging()); + } + + @Bean + public ClientErrorLoggingDsl clientErrorLogging() { + return new ClientErrorLoggingDsl(); + } + + @Override + protected void configure(AuthenticationManagerBuilder auth) throws Exception { + auth.inMemoryAuthentication() + .passwordEncoder(passwordEncoder()) + .withUser("user1") + .password(passwordEncoder().encode("user")) + .roles("USER") + .and() + .withUser("admin") + .password(passwordEncoder().encode("admin")) + .roles("ADMIN"); + } + + @Bean + public PasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } + +} diff --git a/spring-5-security/src/main/resources/application.properties b/spring-5-security/src/main/resources/application.properties index ccec014c2b..781ee76826 100644 --- a/spring-5-security/src/main/resources/application.properties +++ b/spring-5-security/src/main/resources/application.properties @@ -1,3 +1,5 @@ server.port=8081 -logging.level.root=INFO \ No newline at end of file +logging.level.root=INFO + +logging.level.com.baeldung.dsl.ClientErrorLoggingFilter=DEBUG diff --git a/spring-5/src/main/java/com/baeldung/execption/ActorController.java b/spring-5/src/main/java/com/baeldung/execption/ActorController.java new file mode 100644 index 0000000000..6c9c46253a --- /dev/null +++ b/spring-5/src/main/java/com/baeldung/execption/ActorController.java @@ -0,0 +1,41 @@ +package com.baeldung.execption; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.server.ResponseStatusException; + +@RestController +public class ActorController { + + @Autowired + ActorService actorService; + + @GetMapping("/actor/{id}") + public String getActorName(@PathVariable("id") int id) { + try { + return actorService.getActor(id); + } catch (ActorNotFoundException ex) { + throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Actor Not Found", ex); + } + } + + @DeleteMapping("/actor/{id}") + public String getActor(@PathVariable("id") int id) { + return actorService.removeActor(id); + } + + @PutMapping("/actor/{id}/{name}") + public String updateActorName(@PathVariable("id") int id, @PathVariable("name") String name) { + try { + return actorService.updateActor(id, name); + } catch (ActorNotFoundException ex) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Provide correct Actor Id", ex); + } + } + +} diff --git a/spring-5/src/main/java/com/baeldung/execption/ActorNotFoundException.java b/spring-5/src/main/java/com/baeldung/execption/ActorNotFoundException.java new file mode 100644 index 0000000000..642c075b5d --- /dev/null +++ b/spring-5/src/main/java/com/baeldung/execption/ActorNotFoundException.java @@ -0,0 +1,13 @@ +package com.baeldung.execption; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(code = HttpStatus.NOT_FOUND, reason = "Actor Not Found") +public class ActorNotFoundException extends Exception { + private static final long serialVersionUID = 1L; + + public ActorNotFoundException(String errorMessage) { + super(errorMessage); + } +} diff --git a/spring-5/src/main/java/com/baeldung/execption/ActorService.java b/spring-5/src/main/java/com/baeldung/execption/ActorService.java new file mode 100644 index 0000000000..956fa92015 --- /dev/null +++ b/spring-5/src/main/java/com/baeldung/execption/ActorService.java @@ -0,0 +1,35 @@ +package com.baeldung.execption; + +import java.util.Arrays; +import java.util.List; + +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Service; +import org.springframework.web.server.ResponseStatusException; + +@Service +public class ActorService { + List actors = Arrays.asList("Jack Nicholson", "Marlon Brando", "Robert De Niro", "Al Pacino", "Tom Hanks"); + + public String getActor(int index) throws ActorNotFoundException { + if (index >= actors.size()) { + throw new ActorNotFoundException("Actor Not Found in Repsoitory"); + } + return actors.get(index); + } + + public String updateActor(int index, String actorName) throws ActorNotFoundException { + if (index >= actors.size()) { + throw new ActorNotFoundException("Actor Not Found in Repsoitory"); + } + actors.set(index, actorName); + return actorName; + } + + public String removeActor(int index) { + if (index >= actors.size()) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Actor Not Found in Repsoitory"); + } + return actors.remove(index); + } +} diff --git a/spring-5/src/main/java/com/baeldung/execption/SpringExceptionApplication.java b/spring-5/src/main/java/com/baeldung/execption/SpringExceptionApplication.java new file mode 100644 index 0000000000..287356256c --- /dev/null +++ b/spring-5/src/main/java/com/baeldung/execption/SpringExceptionApplication.java @@ -0,0 +1,14 @@ +package com.baeldung.execption; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration; +import org.springframework.context.annotation.ComponentScan; + +@SpringBootApplication(exclude = SecurityAutoConfiguration.class) +@ComponentScan(basePackages = { "com.baeldung.execption" }) +public class SpringExceptionApplication { + public static void main(String[] args) { + SpringApplication.run(SpringExceptionApplication.class, args); + } +} \ No newline at end of file diff --git a/spring-cloud/spring-cloud-security/oauth2client/pom.xml b/spring-cloud/spring-cloud-security/auth-client/pom.xml similarity index 97% rename from spring-cloud/spring-cloud-security/oauth2client/pom.xml rename to spring-cloud/spring-cloud-security/auth-client/pom.xml index fd1c6964e1..5213b93f9a 100644 --- a/spring-cloud/spring-cloud-security/oauth2client/pom.xml +++ b/spring-cloud/spring-cloud-security/auth-client/pom.xml @@ -3,11 +3,11 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 com.baeldung - oauth2client + auth-client 0.0.1-SNAPSHOT jar - oauth2client + auth-client Demo project for Spring Boot diff --git a/spring-cloud/spring-cloud-security/oauth2client/src/main/java/com/baeldung/CloudSite.java b/spring-cloud/spring-cloud-security/auth-client/src/main/java/com/baeldung/CloudSite.java similarity index 100% rename from spring-cloud/spring-cloud-security/oauth2client/src/main/java/com/baeldung/CloudSite.java rename to spring-cloud/spring-cloud-security/auth-client/src/main/java/com/baeldung/CloudSite.java diff --git a/spring-cloud/spring-cloud-security/oauth2client/src/main/java/com/baeldung/config/SiteSecurityConfigurer.java b/spring-cloud/spring-cloud-security/auth-client/src/main/java/com/baeldung/config/SiteSecurityConfigurer.java similarity index 100% rename from spring-cloud/spring-cloud-security/oauth2client/src/main/java/com/baeldung/config/SiteSecurityConfigurer.java rename to spring-cloud/spring-cloud-security/auth-client/src/main/java/com/baeldung/config/SiteSecurityConfigurer.java diff --git a/spring-cloud/spring-cloud-security/oauth2client/src/main/java/com/baeldung/controller/CloudSiteController.java b/spring-cloud/spring-cloud-security/auth-client/src/main/java/com/baeldung/controller/CloudSiteController.java similarity index 100% rename from spring-cloud/spring-cloud-security/oauth2client/src/main/java/com/baeldung/controller/CloudSiteController.java rename to spring-cloud/spring-cloud-security/auth-client/src/main/java/com/baeldung/controller/CloudSiteController.java diff --git a/spring-cloud/spring-cloud-security/oauth2client/src/main/java/com/baeldung/filters/SimpleFilter.java b/spring-cloud/spring-cloud-security/auth-client/src/main/java/com/baeldung/filters/SimpleFilter.java similarity index 100% rename from spring-cloud/spring-cloud-security/oauth2client/src/main/java/com/baeldung/filters/SimpleFilter.java rename to spring-cloud/spring-cloud-security/auth-client/src/main/java/com/baeldung/filters/SimpleFilter.java diff --git a/spring-cloud/spring-cloud-security/oauth2client/src/main/resources/application.properties b/spring-cloud/spring-cloud-security/auth-client/src/main/resources/application.properties similarity index 100% rename from spring-cloud/spring-cloud-security/oauth2client/src/main/resources/application.properties rename to spring-cloud/spring-cloud-security/auth-client/src/main/resources/application.properties diff --git a/spring-cloud/spring-cloud-security/oauth2client/src/main/resources/application.yml b/spring-cloud/spring-cloud-security/auth-client/src/main/resources/application.yml similarity index 100% rename from spring-cloud/spring-cloud-security/oauth2client/src/main/resources/application.yml rename to spring-cloud/spring-cloud-security/auth-client/src/main/resources/application.yml diff --git a/spring-cloud/spring-cloud-security/oauth2client/src/main/resources/templates/personinfo.html b/spring-cloud/spring-cloud-security/auth-client/src/main/resources/templates/personinfo.html similarity index 100% rename from spring-cloud/spring-cloud-security/oauth2client/src/main/resources/templates/personinfo.html rename to spring-cloud/spring-cloud-security/auth-client/src/main/resources/templates/personinfo.html diff --git a/spring-cloud/spring-cloud-security/oauth2client/src/test/java/com/example/springoath2/Springoath2ApplicationTests.java b/spring-cloud/spring-cloud-security/auth-client/src/test/java/com/example/springoath2/Springoath2ApplicationTests.java similarity index 100% rename from spring-cloud/spring-cloud-security/oauth2client/src/test/java/com/example/springoath2/Springoath2ApplicationTests.java rename to spring-cloud/spring-cloud-security/auth-client/src/test/java/com/example/springoath2/Springoath2ApplicationTests.java diff --git a/spring-cloud/spring-cloud-security/personresource/pom.xml b/spring-cloud/spring-cloud-security/auth-resource/pom.xml similarity index 96% rename from spring-cloud/spring-cloud-security/personresource/pom.xml rename to spring-cloud/spring-cloud-security/auth-resource/pom.xml index ca1ff82515..2c54d24e7d 100644 --- a/spring-cloud/spring-cloud-security/personresource/pom.xml +++ b/spring-cloud/spring-cloud-security/auth-resource/pom.xml @@ -4,11 +4,11 @@ 4.0.0 com.baeldung - personresource + auth-resource 0.0.1-SNAPSHOT jar - personresource + auth-resource Demo project for Spring Boot diff --git a/spring-cloud/spring-cloud-security/personresource/src/main/java/com/baeldung/Application.java b/spring-cloud/spring-cloud-security/auth-resource/src/main/java/com/baeldung/Application.java similarity index 100% rename from spring-cloud/spring-cloud-security/personresource/src/main/java/com/baeldung/Application.java rename to spring-cloud/spring-cloud-security/auth-resource/src/main/java/com/baeldung/Application.java diff --git a/spring-cloud/spring-cloud-security/personresource/src/main/java/com/baeldung/config/ResourceConfigurer.java b/spring-cloud/spring-cloud-security/auth-resource/src/main/java/com/baeldung/config/ResourceConfigurer.java similarity index 100% rename from spring-cloud/spring-cloud-security/personresource/src/main/java/com/baeldung/config/ResourceConfigurer.java rename to spring-cloud/spring-cloud-security/auth-resource/src/main/java/com/baeldung/config/ResourceConfigurer.java diff --git a/spring-cloud/spring-cloud-security/personresource/src/main/java/com/baeldung/controller/PersonInfoController.java b/spring-cloud/spring-cloud-security/auth-resource/src/main/java/com/baeldung/controller/PersonInfoController.java similarity index 100% rename from spring-cloud/spring-cloud-security/personresource/src/main/java/com/baeldung/controller/PersonInfoController.java rename to spring-cloud/spring-cloud-security/auth-resource/src/main/java/com/baeldung/controller/PersonInfoController.java diff --git a/spring-cloud/spring-cloud-security/personresource/src/main/java/com/baeldung/model/Person.java b/spring-cloud/spring-cloud-security/auth-resource/src/main/java/com/baeldung/model/Person.java similarity index 100% rename from spring-cloud/spring-cloud-security/personresource/src/main/java/com/baeldung/model/Person.java rename to spring-cloud/spring-cloud-security/auth-resource/src/main/java/com/baeldung/model/Person.java diff --git a/spring-cloud/spring-cloud-security/personresource/src/main/resources/application.yml b/spring-cloud/spring-cloud-security/auth-resource/src/main/resources/application.yml similarity index 100% rename from spring-cloud/spring-cloud-security/personresource/src/main/resources/application.yml rename to spring-cloud/spring-cloud-security/auth-resource/src/main/resources/application.yml diff --git a/spring-cloud/spring-cloud-security/personresource/src/test/java/com/baeldung/service/personservice/PersonserviceApplicationTests.java b/spring-cloud/spring-cloud-security/auth-resource/src/test/java/com/baeldung/service/personservice/PersonserviceApplicationTests.java similarity index 100% rename from spring-cloud/spring-cloud-security/personresource/src/test/java/com/baeldung/service/personservice/PersonserviceApplicationTests.java rename to spring-cloud/spring-cloud-security/auth-resource/src/test/java/com/baeldung/service/personservice/PersonserviceApplicationTests.java diff --git a/spring-cloud/spring-cloud-security/authserver/pom.xml b/spring-cloud/spring-cloud-security/auth-server/pom.xml similarity index 97% rename from spring-cloud/spring-cloud-security/authserver/pom.xml rename to spring-cloud/spring-cloud-security/auth-server/pom.xml index ed88ac046b..ab30f3f2ec 100644 --- a/spring-cloud/spring-cloud-security/authserver/pom.xml +++ b/spring-cloud/spring-cloud-security/auth-server/pom.xml @@ -4,7 +4,7 @@ 4.0.0 com.baeldung - authserver + auth-server 0.0.1-SNAPSHOT diff --git a/spring-cloud/spring-cloud-security/authserver/src/main/java/com/baeldung/AuthServer.java b/spring-cloud/spring-cloud-security/auth-server/src/main/java/com/baeldung/AuthServer.java similarity index 100% rename from spring-cloud/spring-cloud-security/authserver/src/main/java/com/baeldung/AuthServer.java rename to spring-cloud/spring-cloud-security/auth-server/src/main/java/com/baeldung/AuthServer.java diff --git a/spring-cloud/spring-cloud-security/authserver/src/main/java/com/baeldung/config/AuthServerConfigurer.java b/spring-cloud/spring-cloud-security/auth-server/src/main/java/com/baeldung/config/AuthServerConfigurer.java similarity index 100% rename from spring-cloud/spring-cloud-security/authserver/src/main/java/com/baeldung/config/AuthServerConfigurer.java rename to spring-cloud/spring-cloud-security/auth-server/src/main/java/com/baeldung/config/AuthServerConfigurer.java diff --git a/spring-cloud/spring-cloud-security/authserver/src/main/java/com/baeldung/config/ResourceServerConfigurer.java b/spring-cloud/spring-cloud-security/auth-server/src/main/java/com/baeldung/config/ResourceServerConfigurer.java similarity index 100% rename from spring-cloud/spring-cloud-security/authserver/src/main/java/com/baeldung/config/ResourceServerConfigurer.java rename to spring-cloud/spring-cloud-security/auth-server/src/main/java/com/baeldung/config/ResourceServerConfigurer.java diff --git a/spring-cloud/spring-cloud-security/authserver/src/main/java/com/baeldung/config/WebMvcConfigurer.java b/spring-cloud/spring-cloud-security/auth-server/src/main/java/com/baeldung/config/WebMvcConfigurer.java similarity index 100% rename from spring-cloud/spring-cloud-security/authserver/src/main/java/com/baeldung/config/WebMvcConfigurer.java rename to spring-cloud/spring-cloud-security/auth-server/src/main/java/com/baeldung/config/WebMvcConfigurer.java diff --git a/spring-cloud/spring-cloud-security/authserver/src/main/java/com/baeldung/config/WebSecurityConfigurer.java b/spring-cloud/spring-cloud-security/auth-server/src/main/java/com/baeldung/config/WebSecurityConfigurer.java similarity index 100% rename from spring-cloud/spring-cloud-security/authserver/src/main/java/com/baeldung/config/WebSecurityConfigurer.java rename to spring-cloud/spring-cloud-security/auth-server/src/main/java/com/baeldung/config/WebSecurityConfigurer.java diff --git a/spring-cloud/spring-cloud-security/authserver/src/main/java/com/baeldung/controller/ResourceController.java b/spring-cloud/spring-cloud-security/auth-server/src/main/java/com/baeldung/controller/ResourceController.java similarity index 100% rename from spring-cloud/spring-cloud-security/authserver/src/main/java/com/baeldung/controller/ResourceController.java rename to spring-cloud/spring-cloud-security/auth-server/src/main/java/com/baeldung/controller/ResourceController.java diff --git a/spring-cloud/spring-cloud-security/authserver/src/main/resources/application.yml b/spring-cloud/spring-cloud-security/auth-server/src/main/resources/application.yml similarity index 100% rename from spring-cloud/spring-cloud-security/authserver/src/main/resources/application.yml rename to spring-cloud/spring-cloud-security/auth-server/src/main/resources/application.yml diff --git a/spring-cloud/spring-cloud-security/authserver/src/main/resources/certificate/mykeystore.jks b/spring-cloud/spring-cloud-security/auth-server/src/main/resources/certificate/mykeystore.jks similarity index 100% rename from spring-cloud/spring-cloud-security/authserver/src/main/resources/certificate/mykeystore.jks rename to spring-cloud/spring-cloud-security/auth-server/src/main/resources/certificate/mykeystore.jks diff --git a/spring-cloud/spring-cloud-security/authserver/src/main/resources/templates/login.html b/spring-cloud/spring-cloud-security/auth-server/src/main/resources/templates/login.html similarity index 100% rename from spring-cloud/spring-cloud-security/authserver/src/main/resources/templates/login.html rename to spring-cloud/spring-cloud-security/auth-server/src/main/resources/templates/login.html diff --git a/spring-dispatcher-servlet/src/main/java/com/baeldung/springdispatcherservlet/controller/MultipartController.java b/spring-dispatcher-servlet/src/main/java/com/baeldung/springdispatcherservlet/controller/MultipartController.java index 1cc8261f7c..a693bf039f 100644 --- a/spring-dispatcher-servlet/src/main/java/com/baeldung/springdispatcherservlet/controller/MultipartController.java +++ b/spring-dispatcher-servlet/src/main/java/com/baeldung/springdispatcherservlet/controller/MultipartController.java @@ -25,14 +25,20 @@ public class MultipartController { try { InputStream in = file.getInputStream(); String path = new File(".").getAbsolutePath(); - FileOutputStream f = new FileOutputStream(path.substring(0, path.length()-1)+ "/uploads/" + file.getOriginalFilename()); - int ch; - while ((ch = in.read()) != -1) { - f.write(ch); + FileOutputStream f = new FileOutputStream(path.substring(0, path.length() - 1) + "/uploads/" + file.getOriginalFilename()); + try { + int ch; + while ((ch = in.read()) != -1) { + f.write(ch); + } + modelAndView.getModel().put("message", "File uploaded successfully!"); + } catch (Exception e) { + System.out.println("Exception uploading multipart: " + e); + } finally { + f.flush(); + f.close(); + in.close(); } - f.flush(); - f.close(); - modelAndView.getModel().put("message", "File uploaded successfully!"); } catch (Exception e) { System.out.println("Exception uploading multipart: " + e); } diff --git a/spring-integration/pom.xml b/spring-integration/pom.xml index 4e210122b0..27cc7381e3 100644 --- a/spring-integration/pom.xml +++ b/spring-integration/pom.xml @@ -18,7 +18,7 @@ UTF-8 - 4.3.5.RELEASE + 5.0.1.RELEASE 1.1.4.RELEASE 1.4.7 1.1.1 @@ -68,7 +68,7 @@ org.springframework.integration spring-integration-core - ${spring.integration.version} + ${spring.version} javax.activation @@ -84,17 +84,17 @@ org.springframework.integration spring-integration-twitter - ${spring.integration.version} + ${spring.version} org.springframework.integration spring-integration-mail - ${spring.integration.version} + ${spring.version} org.springframework.integration spring-integration-ftp - ${spring.integration.version} + ${spring.version} org.springframework.social @@ -104,7 +104,36 @@ org.springframework.integration spring-integration-file - ${spring.integration.version} + ${spring.version} + + + + org.springframework.security + spring-security-core + ${spring.version} + + + org.springframework.security + spring-security-config + ${spring.version} + + + org.springframework.integration + spring-integration-security + ${spring.version} + + + + org.springframework.security + spring-security-test + ${spring.version} + test + + + org.springframework + spring-test + ${spring.version} + test junit diff --git a/spring-integration/src/main/java/com/baeldung/si/security/MessageConsumer.java b/spring-integration/src/main/java/com/baeldung/si/security/MessageConsumer.java new file mode 100644 index 0000000000..af925c63a7 --- /dev/null +++ b/spring-integration/src/main/java/com/baeldung/si/security/MessageConsumer.java @@ -0,0 +1,45 @@ +package com.baeldung.si.security; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.logging.Logger; + +import org.springframework.integration.annotation.ServiceActivator; +import org.springframework.messaging.Message; +import org.springframework.stereotype.Service; + +@Service +public class MessageConsumer { + + private String messageContent; + + private Map messagePSContent = new ConcurrentHashMap<>(); + + public String getMessageContent() { + return messageContent; + } + + public void setMessageContent(String messageContent) { + this.messageContent = messageContent; + } + + public Map getMessagePSContent() { + return messagePSContent; + } + + public void setMessagePSContent(Map messagePSContent) { + this.messagePSContent = messagePSContent; + } + + @ServiceActivator(inputChannel = "endDirectChannel") + public void endDirectFlow(Message message) { + setMessageContent(message.getPayload().toString()); + } + + @ServiceActivator(inputChannel = "finalPSResult") + public void endPSFlow(Message message) { + Logger.getAnonymousLogger().info(Thread.currentThread().getName() + " has completed ---------------------------"); + messagePSContent.put(Thread.currentThread().getName(), (String) message.getPayload()); + } + +} diff --git a/spring-integration/src/main/java/com/baeldung/si/security/SecuredDirectChannel.java b/spring-integration/src/main/java/com/baeldung/si/security/SecuredDirectChannel.java new file mode 100644 index 0000000000..964a07d7d7 --- /dev/null +++ b/spring-integration/src/main/java/com/baeldung/si/security/SecuredDirectChannel.java @@ -0,0 +1,50 @@ +package com.baeldung.si.security; + +import java.util.logging.Logger; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.integration.annotation.ServiceActivator; +import org.springframework.integration.channel.DirectChannel; +import org.springframework.integration.config.EnableIntegration; +import org.springframework.integration.security.channel.ChannelSecurityInterceptor; +import org.springframework.integration.security.channel.SecuredChannel; +import org.springframework.messaging.Message; +import org.springframework.security.access.AccessDecisionManager; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.authentication.AuthenticationManager; + +@Configuration +@EnableIntegration +public class SecuredDirectChannel { + + @Bean(name = "startDirectChannel") + @SecuredChannel(interceptor = "channelSecurityInterceptor", sendAccess = { "ROLE_VIEWER", "jane" }) + public DirectChannel startDirectChannel() { + return new DirectChannel(); + } + + @ServiceActivator(inputChannel = "startDirectChannel", outputChannel = "endDirectChannel") + @PreAuthorize("hasRole('ROLE_LOGGER')") + public Message logMessage(Message message) { + Logger.getAnonymousLogger().info(message.toString()); + return message; + } + + @Bean(name = "endDirectChannel") + @SecuredChannel(interceptor = "channelSecurityInterceptor", sendAccess = { "ROLE_EDITOR" }) + public DirectChannel endDirectChannel() { + return new DirectChannel(); + } + + @Autowired + @Bean + public ChannelSecurityInterceptor channelSecurityInterceptor(AuthenticationManager authenticationManager, AccessDecisionManager customAccessDecisionManager) { + ChannelSecurityInterceptor channelSecurityInterceptor = new ChannelSecurityInterceptor(); + channelSecurityInterceptor.setAuthenticationManager(authenticationManager); + channelSecurityInterceptor.setAccessDecisionManager(customAccessDecisionManager); + return channelSecurityInterceptor; + } + +} diff --git a/spring-integration/src/main/java/com/baeldung/si/security/SecurityConfig.java b/spring-integration/src/main/java/com/baeldung/si/security/SecurityConfig.java new file mode 100644 index 0000000000..9c5b38b909 --- /dev/null +++ b/spring-integration/src/main/java/com/baeldung/si/security/SecurityConfig.java @@ -0,0 +1,46 @@ +package com.baeldung.si.security; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.integration.security.channel.ChannelSecurityInterceptor; +import org.springframework.security.access.AccessDecisionManager; +import org.springframework.security.access.AccessDecisionVoter; +import org.springframework.security.access.vote.AffirmativeBased; +import org.springframework.security.access.vote.RoleVoter; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration; + +@Configuration +@EnableGlobalMethodSecurity(prePostEnabled = true) +public class SecurityConfig extends GlobalMethodSecurityConfiguration { + + @Override + @Bean + public AuthenticationManager authenticationManager() throws Exception { + return super.authenticationManager(); + } + + @Bean + public AccessDecisionManager customAccessDecisionManager() { + List> decisionVoters = new ArrayList<>(); + decisionVoters.add(new RoleVoter()); + decisionVoters.add(new UsernameAccessDecisionVoter()); + AccessDecisionManager accessDecisionManager = new AffirmativeBased(decisionVoters); + return accessDecisionManager; + } + + @Autowired + @Bean + public ChannelSecurityInterceptor channelSecurityInterceptor(AuthenticationManager authenticationManager, AccessDecisionManager customAccessDecisionManager) { + ChannelSecurityInterceptor channelSecurityInterceptor = new ChannelSecurityInterceptor(); + channelSecurityInterceptor.setAuthenticationManager(authenticationManager); + channelSecurityInterceptor.setAccessDecisionManager(customAccessDecisionManager); + return channelSecurityInterceptor; + } + +} diff --git a/spring-integration/src/main/java/com/baeldung/si/security/SecurityPubSubChannel.java b/spring-integration/src/main/java/com/baeldung/si/security/SecurityPubSubChannel.java new file mode 100644 index 0000000000..11409bb89b --- /dev/null +++ b/spring-integration/src/main/java/com/baeldung/si/security/SecurityPubSubChannel.java @@ -0,0 +1,82 @@ +package com.baeldung.si.security; + +import java.util.stream.Collectors; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.integration.annotation.ServiceActivator; +import org.springframework.integration.channel.DirectChannel; +import org.springframework.integration.channel.PublishSubscribeChannel; +import org.springframework.integration.config.EnableIntegration; +import org.springframework.integration.config.GlobalChannelInterceptor; +import org.springframework.integration.security.channel.SecuredChannel; +import org.springframework.integration.security.channel.SecurityContextPropagationChannelInterceptor; +import org.springframework.integration.support.DefaultMessageBuilderFactory; +import org.springframework.integration.support.MessageBuilder; +import org.springframework.messaging.Message; +import org.springframework.messaging.support.ChannelInterceptor; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; + +@Configuration +@EnableIntegration +public class SecurityPubSubChannel { + + @Bean(name = "startPSChannel") + @SecuredChannel(interceptor = "channelSecurityInterceptor", sendAccess = "ROLE_VIEWER") + public PublishSubscribeChannel startChannel() { + return new PublishSubscribeChannel(executor()); + } + + @ServiceActivator(inputChannel = "startPSChannel", outputChannel = "finalPSResult") + @PreAuthorize("hasRole('ROLE_LOGGER')") + public Message changeMessageToRole(Message message) { + return buildNewMessage(getRoles(), message); + } + + @ServiceActivator(inputChannel = "startPSChannel", outputChannel = "finalPSResult") + @PreAuthorize("hasRole('ROLE_VIEWER')") + public Message changeMessageToUserName(Message message) { + return buildNewMessage(getUsername(), message); + } + + @Bean(name = "finalPSResult") + public DirectChannel finalPSResult() { + return new DirectChannel(); + } + + @Bean + @GlobalChannelInterceptor(patterns = { "startPSChannel", "endDirectChannel" }) + public ChannelInterceptor securityContextPropagationInterceptor() { + return new SecurityContextPropagationChannelInterceptor(); + } + + @Bean + public ThreadPoolTaskExecutor executor() { + ThreadPoolTaskExecutor pool = new ThreadPoolTaskExecutor(); + pool.setCorePoolSize(10); + pool.setMaxPoolSize(10); + pool.setWaitForTasksToCompleteOnShutdown(true); + return pool; + } + + public String getRoles() { + SecurityContext securityContext = SecurityContextHolder.getContext(); + return securityContext.getAuthentication().getAuthorities().stream().map(auth -> auth.getAuthority()).collect(Collectors.joining(",")); + } + + public String getUsername() { + SecurityContext securityContext = SecurityContextHolder.getContext(); + return securityContext.getAuthentication().getName(); + } + + public Message buildNewMessage(String content, Message message) { + DefaultMessageBuilderFactory builderFactory = new DefaultMessageBuilderFactory(); + MessageBuilder messageBuilder = builderFactory.withPayload(content); + messageBuilder.copyHeaders(message.getHeaders()); + return messageBuilder.build(); + } + +} diff --git a/spring-integration/src/main/java/com/baeldung/si/security/UsernameAccessDecisionVoter.java b/spring-integration/src/main/java/com/baeldung/si/security/UsernameAccessDecisionVoter.java new file mode 100644 index 0000000000..052f79ddf7 --- /dev/null +++ b/spring-integration/src/main/java/com/baeldung/si/security/UsernameAccessDecisionVoter.java @@ -0,0 +1,45 @@ +package com.baeldung.si.security; + +import java.util.Collection; + +import org.springframework.security.access.AccessDecisionVoter; +import org.springframework.security.access.ConfigAttribute; +import org.springframework.security.core.Authentication; + +public class UsernameAccessDecisionVoter implements AccessDecisionVoter { + private String rolePrefix = "ROLE_"; + + @Override + public boolean supports(ConfigAttribute attribute) { + if ((attribute.getAttribute() != null) + && !attribute.getAttribute().startsWith(rolePrefix)) { + return true; + }else { + return false; + } + } + + @Override + public boolean supports(Class clazz) { + return true; + } + + @Override + public int vote(Authentication authentication, Object object, Collection attributes) { + if (authentication == null) { + return ACCESS_DENIED; + } + String name = authentication.getName(); + int result = ACCESS_ABSTAIN; + for (ConfigAttribute attribute : attributes) { + if (this.supports(attribute)) { + result = ACCESS_DENIED; + if (attribute.getAttribute().equals(name)) { + return ACCESS_GRANTED; + } + } + } + return result; + } + +} diff --git a/spring-integration/src/test/java/com/baeldung/si/TestSpringIntegrationSecurity.java b/spring-integration/src/test/java/com/baeldung/si/TestSpringIntegrationSecurity.java new file mode 100644 index 0000000000..9ae82af2dc --- /dev/null +++ b/spring-integration/src/test/java/com/baeldung/si/TestSpringIntegrationSecurity.java @@ -0,0 +1,81 @@ +package com.baeldung.si; + +import static org.junit.Assert.assertEquals; + +import org.hamcrest.core.IsInstanceOf; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.messaging.SubscribableChannel; +import org.springframework.messaging.support.GenericMessage; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.baeldung.si.security.MessageConsumer; +import com.baeldung.si.security.SecuredDirectChannel; +import com.baeldung.si.security.SecurityConfig; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = { SecurityConfig.class, SecuredDirectChannel.class, MessageConsumer.class }) +public class TestSpringIntegrationSecurity { + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + @Autowired + SubscribableChannel startDirectChannel; + + @Autowired + MessageConsumer messageConsumer; + + final String DIRECT_CHANNEL_MESSAGE = "Direct channel message"; + + @Test(expected = AuthenticationCredentialsNotFoundException.class) + public void givenNoUser_whenSendToDirectChannel_thenCredentialNotFound() { + startDirectChannel.send(new GenericMessage(DIRECT_CHANNEL_MESSAGE)); + } + + @Test + @WithMockUser(username = "jane", roles = { "LOGGER" }) + public void givenRoleLogger_whenSendMessageToDirectChannel_thenAccessDenied() { + expectedException.expectCause(IsInstanceOf. instanceOf(AccessDeniedException.class)); + + startDirectChannel.send(new GenericMessage(DIRECT_CHANNEL_MESSAGE)); + } + + @Test + @WithMockUser(username = "jane") + public void givenJane_whenSendMessageToDirectChannel_thenAccessDenied() { + expectedException.expectCause(IsInstanceOf. instanceOf(AccessDeniedException.class)); + + startDirectChannel.send(new GenericMessage(DIRECT_CHANNEL_MESSAGE)); + } + + @Test + @WithMockUser(roles = { "VIEWER" }) + public void givenRoleViewer_whenSendToDirectChannel_thenAccessDenied() { + expectedException.expectCause(IsInstanceOf. instanceOf(AccessDeniedException.class)); + + startDirectChannel.send(new GenericMessage(DIRECT_CHANNEL_MESSAGE)); + } + + @Test + @WithMockUser(roles = { "LOGGER", "VIEWER", "EDITOR" }) + public void givenRoleLoggerAndUser_whenSendMessageToDirectChannel_thenFlowCompletedSuccessfully() { + startDirectChannel.send(new GenericMessage(DIRECT_CHANNEL_MESSAGE)); + assertEquals(DIRECT_CHANNEL_MESSAGE, messageConsumer.getMessageContent()); + } + + @Test + @WithMockUser(username = "jane", roles = { "LOGGER", "EDITOR" }) + public void givenJaneLoggerEditor_whenSendToDirectChannel_thenFlowCompleted() { + startDirectChannel.send(new GenericMessage(DIRECT_CHANNEL_MESSAGE)); + assertEquals(DIRECT_CHANNEL_MESSAGE, messageConsumer.getMessageContent()); + } + +} \ No newline at end of file diff --git a/spring-integration/src/test/java/com/baeldung/si/TestSpringIntegrationSecurityExecutor.java b/spring-integration/src/test/java/com/baeldung/si/TestSpringIntegrationSecurityExecutor.java new file mode 100644 index 0000000000..b06136a7ca --- /dev/null +++ b/spring-integration/src/test/java/com/baeldung/si/TestSpringIntegrationSecurityExecutor.java @@ -0,0 +1,68 @@ +package com.baeldung.si; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.messaging.SubscribableChannel; +import org.springframework.messaging.support.GenericMessage; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.baeldung.si.security.MessageConsumer; +import com.baeldung.si.security.SecurityConfig; +import com.baeldung.si.security.SecurityPubSubChannel; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = { SecurityPubSubChannel.class, MessageConsumer.class, SecurityConfig.class }) +public class TestSpringIntegrationSecurityExecutor { + + @Autowired + SubscribableChannel startPSChannel; + + @Autowired + MessageConsumer messageConsumer; + + @Autowired + ThreadPoolTaskExecutor executor; + + final String DIRECT_CHANNEL_MESSAGE = "Direct channel message"; + + @Before + public void clearData() { + messageConsumer.setMessagePSContent(new ConcurrentHashMap<>()); + executor.setWaitForTasksToCompleteOnShutdown(true); + } + + @Test + @WithMockUser(username = "user", roles = { "VIEWER" }) + public void givenRoleUser_whenSendMessageToPSChannel_thenNoMessageArrived() throws IllegalStateException, InterruptedException { + startPSChannel.send(new GenericMessage(DIRECT_CHANNEL_MESSAGE)); + + executor.getThreadPoolExecutor().awaitTermination(2, TimeUnit.SECONDS); + + assertEquals(1, messageConsumer.getMessagePSContent().size()); + assertTrue(messageConsumer.getMessagePSContent().values().contains("user")); + } + + @Test + @WithMockUser(username = "user", roles = { "LOGGER", "VIEWER" }) + public void givenRoleUserAndLogger_whenSendMessageToPSChannel_then2GetMessages() throws IllegalStateException, InterruptedException { + startPSChannel.send(new GenericMessage(DIRECT_CHANNEL_MESSAGE)); + + executor.getThreadPoolExecutor().awaitTermination(2, TimeUnit.SECONDS); + + assertEquals(2, messageConsumer.getMessagePSContent().size()); + assertTrue(messageConsumer.getMessagePSContent().values().contains("user")); + assertTrue(messageConsumer.getMessagePSContent().values().contains("ROLE_LOGGER,ROLE_VIEWER")); + } + +} diff --git a/spring-mvc-java/pom.xml b/spring-mvc-java/pom.xml index b939f0496d..9d90ba2dbf 100644 --- a/spring-mvc-java/pom.xml +++ b/spring-mvc-java/pom.xml @@ -297,7 +297,7 @@ 4.3.4.RELEASE 4.2.0.RELEASE 2.1.5.RELEASE - 2.8.5 + 2.9.4 5.2.5.Final diff --git a/spring-mvc-simple/src/main/java/com/baeldung/spring/configuration/ApplicationConfiguration.java b/spring-mvc-simple/src/main/java/com/baeldung/spring/configuration/ApplicationConfiguration.java index b9a8336bf2..69c45d90b3 100644 --- a/spring-mvc-simple/src/main/java/com/baeldung/spring/configuration/ApplicationConfiguration.java +++ b/spring-mvc-simple/src/main/java/com/baeldung/spring/configuration/ApplicationConfiguration.java @@ -1,14 +1,21 @@ package com.baeldung.spring.configuration; +import com.baeldung.spring.controller.rss.ArticleRssFeedViewResolver; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.web.multipart.MultipartResolver; import org.springframework.web.multipart.commons.CommonsMultipartResolver; +import org.springframework.web.servlet.ViewResolver; import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.springframework.web.servlet.view.ContentNegotiatingViewResolver; import org.springframework.web.servlet.view.InternalResourceViewResolver; +import org.springframework.web.accept.ContentNegotiationManager; + +import java.util.List; +import java.util.ArrayList; @Configuration @EnableWebMvc @@ -21,11 +28,19 @@ class ApplicationConfiguration implements WebMvcConfigurer { } @Bean - public InternalResourceViewResolver jspViewResolver() { - InternalResourceViewResolver bean = new InternalResourceViewResolver(); - bean.setPrefix("/WEB-INF/views/"); - bean.setSuffix(".jsp"); - return bean; + public ContentNegotiatingViewResolver viewResolver(ContentNegotiationManager cnManager) { + ContentNegotiatingViewResolver cnvResolver = new ContentNegotiatingViewResolver(); + cnvResolver.setContentNegotiationManager(cnManager); + List resolvers = new ArrayList<>(); + + InternalResourceViewResolver bean = new InternalResourceViewResolver("/WEB-INF/views/",".jsp"); + ArticleRssFeedViewResolver articleRssFeedViewResolver = new ArticleRssFeedViewResolver(); + + resolvers.add(bean); + resolvers.add(articleRssFeedViewResolver); + + cnvResolver.setViewResolvers(resolvers); + return cnvResolver; } @Bean diff --git a/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/rss/ArticleRssController.java b/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/rss/ArticleRssController.java index 1f51b238ac..8f23076e8e 100644 --- a/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/rss/ArticleRssController.java +++ b/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/rss/ArticleRssController.java @@ -1,14 +1,59 @@ package com.baeldung.spring.controller.rss; +import com.rometools.rome.feed.synd.*; +import com.rometools.rome.io.FeedException; +import com.rometools.rome.io.SyndFeedOutput; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; @Controller public class ArticleRssController { - @GetMapping(value = "/rss", produces = "application/*") - public String articleFeed() { + @GetMapping(value = "/rssMvc") + public String articleMvcFeed() { return "articleFeedView"; } + @GetMapping(value = "/rssRest", produces = "application/rss+xml") + @ResponseBody + public String articleRestFeed() throws FeedException { + SyndFeed feed = new SyndFeedImpl(); + feed.setFeedType("rss_2.0"); + feed.setLink("http://localhost:8080/spring-mvc-simple/rss"); + feed.setTitle("Article Feed"); + feed.setDescription("Article Feed Description"); + feed.setPublishedDate(new Date()); + + List list = new ArrayList(); + + SyndEntry item1 = new SyndEntryImpl(); + item1.setLink("http://www.baeldung.com/netty-exception-handling"); + item1.setTitle("Exceptions in Netty"); + SyndContent description1 = new SyndContentImpl(); + description1.setValue("In this quick article, we’ll be looking at exception handling in Netty."); + item1.setDescription(description1); + item1.setPublishedDate(new Date()); + item1.setAuthor("Carlos"); + + SyndEntry item2 = new SyndEntryImpl(); + item2.setLink("http://www.baeldung.com/cockroachdb-java"); + item2.setTitle("Guide to CockroachDB in Java"); + SyndContent description2 = new SyndContentImpl(); + description2.setValue("This tutorial is an introductory guide to using CockroachDB with Java."); + item2.setDescription(description2); + item2.setPublishedDate(new Date()); + item2.setAuthor("Baeldung"); + + list.add(item1); + list.add(item2); + feed.setEntries(list); + + return new SyndFeedOutput().outputString(feed); + } + } diff --git a/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/rss/ArticleRssFeedViewResolver.java b/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/rss/ArticleRssFeedViewResolver.java new file mode 100644 index 0000000000..6be06c4812 --- /dev/null +++ b/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/rss/ArticleRssFeedViewResolver.java @@ -0,0 +1,15 @@ +package com.baeldung.spring.controller.rss; + +import org.springframework.web.servlet.View; +import org.springframework.web.servlet.ViewResolver; + +import java.util.Locale; + +public class ArticleRssFeedViewResolver implements ViewResolver { + + @Override + public View resolveViewName(String s, Locale locale) throws Exception { + ArticleFeedView articleFeedView = new ArticleFeedView(); + return articleFeedView; + } +} diff --git a/testing-modules/testing/README.md b/testing-modules/testing/README.md index 3511bb1bb9..2894da3496 100644 --- a/testing-modules/testing/README.md +++ b/testing-modules/testing/README.md @@ -17,3 +17,4 @@ - [Introduction to Jukito](http://www.baeldung.com/jukito) - [Custom JUnit 4 Test Runners](http://www.baeldung.com/junit-4-custom-runners) - [Guide to JSpec](http://www.baeldung.com/jspec) +- [Custom Assertions with AssertJ](http://www.baeldung.com/assertj-custom-assertion) diff --git a/testing-modules/testing/pom.xml b/testing-modules/testing/pom.xml index c76045380b..91792a4681 100644 --- a/testing-modules/testing/pom.xml +++ b/testing-modules/testing/pom.xml @@ -173,7 +173,7 @@ 0.7.7.201606060606 21.0 3.1.0 - 3.6.1 + 3.9.0 2.1.0 0.32 1.1.0 diff --git a/testing-modules/testing/src/main/java/com/baeldung/testing/assertj/Member.java b/testing-modules/testing/src/main/java/com/baeldung/testing/assertj/Member.java new file mode 100644 index 0000000000..a0b3d0daac --- /dev/null +++ b/testing-modules/testing/src/main/java/com/baeldung/testing/assertj/Member.java @@ -0,0 +1,19 @@ +package com.baeldung.testing.assertj; + +public class Member { + private String name; + private int age; + + public Member(String name, int age) { + this.name = name; + this.age = age; + } + + public String getName() { + return name; + } + + public int getAge() { + return age; + } +} diff --git a/testing-modules/testing/src/test/java/com/baeldung/testing/assertj/AssertJConditionUnitTest.java b/testing-modules/testing/src/test/java/com/baeldung/testing/assertj/AssertJConditionUnitTest.java new file mode 100644 index 0000000000..153af828f1 --- /dev/null +++ b/testing-modules/testing/src/test/java/com/baeldung/testing/assertj/AssertJConditionUnitTest.java @@ -0,0 +1,72 @@ +package com.baeldung.testing.assertj; + +import static org.assertj.core.api.Assertions.allOf; +import static org.assertj.core.api.Assertions.anyOf; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.not; +import static org.junit.Assert.fail; + +import java.util.ArrayList; +import java.util.List; + +import org.assertj.core.api.Condition; +import org.junit.Test; + +public class AssertJConditionUnitTest { + private Condition senior = new Condition<>(m -> m.getAge() >= 60, "senior"); + private Condition nameJohn = new Condition<>(m -> m.getName().equalsIgnoreCase("John"), "name John"); + + @Test + public void whenUsingMemberAgeCondition_thenCorrect() { + Member member = new Member("John", 65); + assertThat(member).is(senior); + + try { + assertThat(member).isNot(senior); + fail(); + } catch (AssertionError e) { + assertThat(e).hasMessageContaining("not to be "); + } + } + + @Test + public void whenUsingMemberNameCondition_thenCorrect() { + Member member = new Member("Jane", 60); + assertThat(member).doesNotHave(nameJohn); + + try { + assertThat(member).has(nameJohn); + fail(); + } catch (AssertionError e) { + assertThat(e).hasMessageContaining("to have:\n "); + } + } + + @Test + public void whenCollectionConditionsAreSatisfied_thenCorrect() { + List members = new ArrayList<>(); + members.add(new Member("Alice", 50)); + members.add(new Member("Bob", 60)); + + assertThat(members).haveExactly(1, senior); + assertThat(members).doNotHave(nameJohn); + } + + @Test + public void whenCombiningAllOfConditions_thenCorrect() { + Member john = new Member("John", 60); + Member jane = new Member("Jane", 50); + + assertThat(john).is(allOf(senior, nameJohn)); + assertThat(jane).is(allOf(not(nameJohn), not(senior))); + } + + @Test + public void whenCombiningAnyOfConditions_thenCorrect() { + Member john = new Member("John", 50); + Member jane = new Member("Jane", 60); + + assertThat(john).is(anyOf(senior, nameJohn)); + assertThat(jane).is(anyOf(nameJohn, senior)); + } +} diff --git a/testing-modules/testing/src/test/java/com/baeldung/testing/assertj/exceptions/Java7StyleAssertions.java b/testing-modules/testing/src/test/java/com/baeldung/testing/assertj/exceptions/Java7StyleAssertions.java new file mode 100644 index 0000000000..07a5be1118 --- /dev/null +++ b/testing-modules/testing/src/test/java/com/baeldung/testing/assertj/exceptions/Java7StyleAssertions.java @@ -0,0 +1,24 @@ +package com.baeldung.testing.assertj.exceptions; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; +import static org.assertj.core.api.Assertions.failBecauseExceptionWasNotThrown; + +import org.junit.Test; + +public class Java7StyleAssertions { + + @Test + public void whenDividingByZero_thenArithmeticException() { + try { + int numerator = 10; + int denominator = 0; + int quotient = numerator / denominator; + fail("ArithmeticException expected because dividing by zero yields an ArithmeticException."); + failBecauseExceptionWasNotThrown(ArithmeticException.class); + } catch (Exception e) { + assertThat(e).hasMessage("/ by zero"); + assertThat(e).isInstanceOf(ArithmeticException.class); + } + } +} diff --git a/testing-modules/testing/src/test/java/com/baeldung/testing/assertj/exceptions/Java8StyleAssertions.java b/testing-modules/testing/src/test/java/com/baeldung/testing/assertj/exceptions/Java8StyleAssertions.java new file mode 100644 index 0000000000..973b921654 --- /dev/null +++ b/testing-modules/testing/src/test/java/com/baeldung/testing/assertj/exceptions/Java8StyleAssertions.java @@ -0,0 +1,66 @@ +package com.baeldung.testing.assertj.exceptions; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.assertj.core.api.Assertions.catchThrowable; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import org.junit.Test; + +public class Java8StyleAssertions { + + @Test + public void whenGettingOutOfBoundsItem_thenIndexOutOfBoundsException() { + assertThatThrownBy(() -> { + ArrayList myStringList = new ArrayList(Arrays.asList("Strine one", "String two")); + myStringList.get(2); + }).isInstanceOf(IndexOutOfBoundsException.class) + .hasMessageStartingWith("Index: 2") + .hasMessageContaining("2") + .hasMessageEndingWith("Size: 2") + .hasMessageContaining("Index: 2, Size: 2") + .hasMessage("Index: %s, Size: %s", 2, 2) + .hasMessageMatching("Index: \\d+, Size: \\d+") + .hasNoCause(); + } + + @Test + public void whenWrappingException_thenCauseInstanceOfWrappedExceptionType() { + assertThatThrownBy(() -> { + try { + throw new IOException(); + } catch (IOException e) { + throw new RuntimeException(e); + } + }).isInstanceOf(RuntimeException.class) + .hasCauseInstanceOf(IOException.class) + .hasStackTraceContaining("IOException"); + } + + @Test + public void whenDividingByZero_thenArithmeticException() { + assertThatExceptionOfType(ArithmeticException.class).isThrownBy(() -> { + int numerator = 10; + int denominator = 0; + int quotient = numerator / denominator; + }) + .withMessageContaining("/ by zero"); + + // Alternatively: + + // when + Throwable thrown = catchThrowable(() -> { + int numerator = 10; + int denominator = 0; + int quotient = numerator / denominator; + }); + + // then + assertThat(thrown).isInstanceOf(ArithmeticException.class) + .hasMessageContaining("/ by zero"); + + } +}