BAEL-1517: Resolve merge conflicts
This commit is contained in:
		
						commit
						aa4392972c
					
				
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -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 | ||||
|  | ||||
| @ -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<Coordinate> solve(Maze maze) { | ||||
|         LinkedList<Coordinate> 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<Coordinate> backtrackPath(Coordinate cur) { | ||||
|         List<Coordinate> path = new ArrayList<>(); | ||||
|         Coordinate iter = cur; | ||||
| 
 | ||||
|         while (iter != null) { | ||||
|             path.add(iter); | ||||
|             iter = iter.parent; | ||||
|         } | ||||
| 
 | ||||
|         return path; | ||||
|     } | ||||
| } | ||||
| @ -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; | ||||
|     } | ||||
| } | ||||
| @ -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<Coordinate> solve(Maze maze) { | ||||
|         List<Coordinate> 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<Coordinate> 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); | ||||
|     } | ||||
| } | ||||
| @ -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<Coordinate> 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); | ||||
|     } | ||||
| } | ||||
| @ -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<Coordinate> path = bfs.solve(maze); | ||||
|         maze.printPath(path); | ||||
|         maze.reset(); | ||||
|     } | ||||
| 
 | ||||
|     private static void dfs(Maze maze) { | ||||
|         DFSMazeSolver dfs = new DFSMazeSolver(); | ||||
|         List<Coordinate> path = dfs.solve(maze); | ||||
|         maze.printPath(path); | ||||
|         maze.reset(); | ||||
|     } | ||||
| } | ||||
| @ -120,10 +120,10 @@ public class DancingLinks { | ||||
|     } | ||||
| 
 | ||||
|     private static void printSolution(int[][] result) { | ||||
|         int N = result.length; | ||||
|         int size = result.length; | ||||
|         for (int[] aResult : result) { | ||||
|             StringBuilder ret = new StringBuilder(); | ||||
|             for (int j = 0; j < N; j++) { | ||||
|             for (int j = 0; j < size; j++) { | ||||
|                 ret.append(aResult[j]).append(" "); | ||||
|             } | ||||
|             System.out.println(ret); | ||||
|  | ||||
| @ -39,70 +39,83 @@ public class DancingLinksAlgorithm { | ||||
|     } | ||||
| 
 | ||||
|     private boolean[][] createExactCoverBoard() { | ||||
|         boolean[][] R = new boolean[BOARD_SIZE * BOARD_SIZE * MAX_VALUE][BOARD_SIZE * BOARD_SIZE * CONSTRAINTS]; | ||||
|         boolean[][] coverBoard = new boolean[BOARD_SIZE * BOARD_SIZE * MAX_VALUE][BOARD_SIZE * BOARD_SIZE * CONSTRAINTS]; | ||||
| 
 | ||||
|         int hBase = 0; | ||||
|         hBase = checkCellConstraint(coverBoard, hBase); | ||||
|         hBase = checkRowConstraint(coverBoard, hBase); | ||||
|         hBase = checkColumnConstraint(coverBoard, hBase); | ||||
|         checkSubsectionConstraint(coverBoard, hBase); | ||||
|          | ||||
|         // Cell constraint. | ||||
|         for (int r = COVER_START_INDEX; r <= BOARD_SIZE; r++) { | ||||
|             for (int c = COVER_START_INDEX; c <= BOARD_SIZE; c++, hBase++) { | ||||
|                 for (int n = COVER_START_INDEX; n <= BOARD_SIZE; n++) { | ||||
|                     int index = getIndex(r, c, n); | ||||
|                     R[index][hBase] = true; | ||||
|                 } | ||||
|             } | ||||
|         return coverBoard; | ||||
|     } | ||||
| 
 | ||||
|         // Row constrain. | ||||
|         for (int r = COVER_START_INDEX; r <= BOARD_SIZE; r++) { | ||||
|             for (int n = COVER_START_INDEX; n <= BOARD_SIZE; n++, hBase++) { | ||||
|                 for (int c1 = COVER_START_INDEX; c1 <= BOARD_SIZE; c1++) { | ||||
|                     int index = getIndex(r, c1, n); | ||||
|                     R[index][hBase] = true; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // Column constraint. | ||||
|         for (int c = COVER_START_INDEX; c <= BOARD_SIZE; c++) { | ||||
|             for (int n = COVER_START_INDEX; n <= BOARD_SIZE; n++, hBase++) { | ||||
|                 for (int r1 = COVER_START_INDEX; r1 <= BOARD_SIZE; r1++) { | ||||
|                     int index = getIndex(r1, c, n); | ||||
|                     R[index][hBase] = true; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // Subsection constraint | ||||
|     private int checkSubsectionConstraint(boolean[][] coverBoard, int hBase) { | ||||
|         for (int br = COVER_START_INDEX; br <= BOARD_SIZE; br += SUBSECTION_SIZE) { | ||||
|             for (int bc = COVER_START_INDEX; bc <= BOARD_SIZE; bc += SUBSECTION_SIZE) { | ||||
|                 for (int n = COVER_START_INDEX; n <= BOARD_SIZE; n++, hBase++) { | ||||
|                     for (int rDelta = 0; rDelta < SUBSECTION_SIZE; rDelta++) { | ||||
|                         for (int cDelta = 0; cDelta < SUBSECTION_SIZE; cDelta++) { | ||||
|                             int index = getIndex(br + rDelta, bc + cDelta, n); | ||||
|                             R[index][hBase] = true; | ||||
|                             coverBoard[index][hBase] = true; | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return R; | ||||
|         return hBase; | ||||
|     } | ||||
| 
 | ||||
|     private int checkColumnConstraint(boolean[][] coverBoard, int hBase) { | ||||
|         for (int c = COVER_START_INDEX; c <= BOARD_SIZE; c++) { | ||||
|             for (int n = COVER_START_INDEX; n <= BOARD_SIZE; n++, hBase++) { | ||||
|                 for (int r1 = COVER_START_INDEX; r1 <= BOARD_SIZE; r1++) { | ||||
|                     int index = getIndex(r1, c, n); | ||||
|                     coverBoard[index][hBase] = true; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return hBase; | ||||
|     } | ||||
| 
 | ||||
|     private int checkRowConstraint(boolean[][] coverBoard, int hBase) { | ||||
|         for (int r = COVER_START_INDEX; r <= BOARD_SIZE; r++) { | ||||
|             for (int n = COVER_START_INDEX; n <= BOARD_SIZE; n++, hBase++) { | ||||
|                 for (int c1 = COVER_START_INDEX; c1 <= BOARD_SIZE; c1++) { | ||||
|                     int index = getIndex(r, c1, n); | ||||
|                     coverBoard[index][hBase] = true; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return hBase; | ||||
|     } | ||||
| 
 | ||||
|     private int checkCellConstraint(boolean[][] coverBoard, int hBase) { | ||||
|         for (int r = COVER_START_INDEX; r <= BOARD_SIZE; r++) { | ||||
|             for (int c = COVER_START_INDEX; c <= BOARD_SIZE; c++, hBase++) { | ||||
|                 for (int n = COVER_START_INDEX; n <= BOARD_SIZE; n++) { | ||||
|                     int index = getIndex(r, c, n); | ||||
|                     coverBoard[index][hBase] = true; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return hBase; | ||||
|     } | ||||
| 
 | ||||
|     private boolean[][] initializeExactCoverBoard(int[][] board) { | ||||
|         boolean[][] R = createExactCoverBoard(); | ||||
|         boolean[][] coverBoard = createExactCoverBoard(); | ||||
|         for (int i = COVER_START_INDEX; i <= BOARD_SIZE; i++) { | ||||
|             for (int j = COVER_START_INDEX; j <= BOARD_SIZE; j++) { | ||||
|                 int n = board[i - 1][j - 1]; | ||||
|                 if (n != NO_VALUE) { | ||||
|                     for (int num = MIN_VALUE; num <= MAX_VALUE; num++) { | ||||
|                         if (num != n) { | ||||
|                             Arrays.fill(R[getIndex(i, j, num)], false); | ||||
|                             Arrays.fill(coverBoard[getIndex(i, j, num)], false); | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return R; | ||||
|         return coverBoard; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										12
									
								
								algorithms/src/main/resources/maze/maze1.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								algorithms/src/main/resources/maze/maze1.txt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | ||||
| S ######## | ||||
| #        # | ||||
| # ### ## # | ||||
| # #    # # | ||||
| # #  # # # | ||||
| # ## ##### | ||||
| # #      # | ||||
| # # #  # # | ||||
| ##### #### | ||||
| #   #    E | ||||
| # #    # # | ||||
| ########## | ||||
							
								
								
									
										22
									
								
								algorithms/src/main/resources/maze/maze2.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								algorithms/src/main/resources/maze/maze2.txt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | ||||
| S ########################## | ||||
| # #      #                 # | ||||
| # # ####   ############### # | ||||
| # # #    # #               # | ||||
| # # #### # # ############### | ||||
| # # #    # # #             # | ||||
| # # # #### ### ########### # | ||||
| # # # #        #           # | ||||
| #       ################## # | ||||
| #########    # # #       # # | ||||
| # #       #### # ####### # # | ||||
| # # ### ###  # # #       # # | ||||
| #   #       ##   # ##### # # | ||||
| ##### #######  # #     # # # | ||||
| #     #       ## ## #### # # | ||||
| # ##### #######     #      # | ||||
| #       #       ############ | ||||
| ####### #########        # # | ||||
| #       #         ######## # | ||||
| # ####### ###### ##   #    E | ||||
| #         #         #   ## # | ||||
| ############################ | ||||
| @ -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<HttpResponse<String>> response1 = HttpClient.newBuilder() | ||||
|             .executor(Executors.newFixedThreadPool(2)) | ||||
|             .executor(executorService) | ||||
|             .build() | ||||
|             .sendAsync(request, HttpResponse.BodyHandler.asString()); | ||||
| 
 | ||||
|         CompletableFuture<HttpResponse<String>> response2 = HttpClient.newBuilder() | ||||
|             .executor(Executors.newFixedThreadPool(2)) | ||||
|             .executor(executorService) | ||||
|             .build() | ||||
|             .sendAsync(request, HttpResponse.BodyHandler.asString()); | ||||
| 
 | ||||
|         CompletableFuture<HttpResponse<String>> response3 = HttpClient.newBuilder() | ||||
|             .executor(Executors.newFixedThreadPool(2)) | ||||
|             .executor(executorService) | ||||
|             .build() | ||||
|             .sendAsync(request, HttpResponse.BodyHandler.asString()); | ||||
| 
 | ||||
|  | ||||
| @ -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) { | ||||
|         } | ||||
|  | ||||
| @ -9,21 +9,21 @@ import java.util.concurrent.TimeUnit; | ||||
| public class PriorityJobScheduler { | ||||
| 
 | ||||
|     private ExecutorService priorityJobPoolExecutor; | ||||
|     private ExecutorService priorityJobScheduler; | ||||
|     private PriorityBlockingQueue<Runnable> priorityQueue; | ||||
|     private ExecutorService priorityJobScheduler =  | ||||
|       Executors.newSingleThreadExecutor(); | ||||
|     private PriorityBlockingQueue<Job> priorityQueue; | ||||
| 
 | ||||
|     public PriorityJobScheduler(Integer poolSize, Integer queueSize) { | ||||
|         priorityJobPoolExecutor = Executors.newFixedThreadPool(poolSize); | ||||
|         Comparator<? super Job> jobComparator = Comparator.comparing(Job::getJobPriority); | ||||
|         priorityQueue = new PriorityBlockingQueue<Runnable>(queueSize,  | ||||
|           (Comparator<? super Runnable>) jobComparator); | ||||
|         priorityQueue = new PriorityBlockingQueue<Job>(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; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
| @ -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(); | ||||
|  | ||||
| @ -1,28 +1,16 @@ | ||||
| package com.baeldung.javac; | ||||
| 
 | ||||
| import java.io.Serializable; | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
| 
 | ||||
| public class Data implements Serializable { | ||||
|     static List<String> textList = new ArrayList(); | ||||
| public class Data { | ||||
|     List<String> textList = new ArrayList(); | ||||
| 
 | ||||
|     private static void addText() { | ||||
|         textList.add("baeldung"); | ||||
|         textList.add("."); | ||||
|         textList.add("com"); | ||||
|     public void addText(String text) { | ||||
|         textList.add(text); | ||||
|     } | ||||
| 
 | ||||
|     public List getTextList() { | ||||
|         this.addText(); | ||||
|         List<String> result = new ArrayList<String>(); | ||||
|         String firstElement = (String) textList.get(0); | ||||
|         switch (firstElement) { | ||||
|         case "baeldung": | ||||
|             result.add("baeldung"); | ||||
|         case "com": | ||||
|             result.add("com"); | ||||
|         } | ||||
|         return result; | ||||
|         return this.textList; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										62
									
								
								core-java/src/main/java/com/baeldung/string/Palindrome.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								core-java/src/main/java/com/baeldung/string/Palindrome.java
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,62 @@ | ||||
| package com.baeldung.string; | ||||
| 
 | ||||
| import java.util.stream.IntStream; | ||||
| 
 | ||||
| public class Palindrome { | ||||
| 
 | ||||
|     public boolean isPalindrome(String text) { | ||||
|         text = text.replaceAll("\\s+", "") | ||||
|             .toLowerCase(); | ||||
|         int length = text.length(); | ||||
|         int forward = 0; | ||||
|         int backward = length - 1; | ||||
|         boolean palindrome = true; | ||||
|         while (backward > forward) { | ||||
|             char forwardChar = text.charAt(forward++); | ||||
|             char backwardChar = text.charAt(backward--); | ||||
|             if (forwardChar != backwardChar) | ||||
|                 return false; | ||||
|         } | ||||
|         return palindrome; | ||||
|     } | ||||
| 
 | ||||
|     public boolean isPalindromeReverseTheString(String text) { | ||||
|         String reverse = ""; | ||||
|         text = text.replaceAll("\\s+", "").toLowerCase(); | ||||
|         char[] plain = text.toCharArray(); | ||||
|         for (int i = plain.length - 1; i >= 0; i--) | ||||
|             reverse += plain[i]; | ||||
|         return reverse.equals(text); | ||||
|     } | ||||
| 
 | ||||
|     public boolean isPalindromeUsingStringBuilder(String text) { | ||||
|         StringBuilder plain = new StringBuilder(text); | ||||
|         StringBuilder reverse = plain.reverse(); | ||||
|         return reverse.equals(plain); | ||||
|     } | ||||
| 
 | ||||
|     public boolean isPalindromeUsingStringBuffer(String text) { | ||||
|         StringBuffer plain = new StringBuffer(text); | ||||
|         StringBuffer reverse = plain.reverse(); | ||||
|         return reverse.equals(plain); | ||||
|     } | ||||
| 
 | ||||
|     public boolean isPalindromeRecursive(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 isPalindromeRecursive(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)); | ||||
|     } | ||||
|      | ||||
| } | ||||
							
								
								
									
										108
									
								
								core-java/src/test/java/com/baeldung/string/PalindromeTest.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								core-java/src/test/java/com/baeldung/string/PalindromeTest.java
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,108 @@ | ||||
| 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) { | ||||
|             word = word.replaceAll("\\s+", "").toLowerCase(); | ||||
|             int backward = word.length()-1; | ||||
|              | ||||
|             assertTrue(palindrome.isPalindromeRecursive(word,0,backward)); | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     @Test | ||||
|     public void whenPalindromeRecursive_sentenceShouldBePalindrome() { | ||||
|         for(String sentence:sentences) { | ||||
|             sentence = sentence.replaceAll("\\s+", "").toLowerCase(); | ||||
|             int backward = sentence.length()-1; | ||||
|              | ||||
|             assertTrue(palindrome.isPalindromeRecursive(sentence,0,backward)); | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     @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)); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -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<T>(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<String> { | ||||
|             return r.findAll(this) | ||||
|                     .map { it.value } | ||||
|                     .toList() | ||||
|         } | ||||
| 
 | ||||
|         val matches = "a bc def" substringMatches ".*? ".toRegex() | ||||
|         Assert.assertEquals(listOf("a ", "bc "), matches) | ||||
|     } | ||||
| } | ||||
| @ -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)) | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -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() | ||||
|  | ||||
| @ -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<PersonName, String> { | ||||
| 
 | ||||
|     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; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -9,7 +9,7 @@ import org.hibernate.Interceptor; | ||||
| import org.hibernate.Transaction; | ||||
| import org.hibernate.type.Type; | ||||
| 
 | ||||
| public class CustomInterceptorImpl implements Interceptor { | ||||
| public class CustomInterceptorImpl implements Interceptor, Serializable { | ||||
| 
 | ||||
|     @Override | ||||
|     public boolean onLoad(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) throws CallbackException { | ||||
|  | ||||
| @ -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; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -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; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -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); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -2,7 +2,6 @@ | ||||
| 
 | ||||
| ### Relevant Article: | ||||
| - [Introduction to using InfluxDB with Java](http://www.baeldung.com/using-influxdb-with-java/) | ||||
| - [Using InfluxDB with Java](http://www.baeldung.com/java-influxdb) | ||||
| 
 | ||||
| ### Overview | ||||
| This Maven project contains the Java code for the article linked above. | ||||
|  | ||||
| @ -8,7 +8,6 @@ import org.influxdb.dto.*; | ||||
| import org.influxdb.impl.InfluxDBResultMapper; | ||||
| import org.junit.Test; | ||||
| 
 | ||||
| import java.io.IOException; | ||||
| import java.util.List; | ||||
| import java.util.concurrent.TimeUnit; | ||||
| 
 | ||||
| @ -103,7 +102,7 @@ public class InfluxDBConnectionLiveTest { | ||||
|         // another brief pause. | ||||
|         Thread.sleep(10); | ||||
| 
 | ||||
|         List<MemoryPoint> memoryPointList = getPoints(connection, "Select * from memory", "baeldung"); | ||||
|         List<com.baeldung.influxdb.MemoryPoint> memoryPointList = getPoints(connection, "Select * from memory", "baeldung"); | ||||
| 
 | ||||
|         assertEquals(10, memoryPointList.size()); | ||||
| 
 | ||||
|  | ||||
| @ -129,7 +129,7 @@ | ||||
| 
 | ||||
|     <properties> | ||||
|         <!-- marshalling --> | ||||
|         <jackson.version>2.9.2</jackson.version> | ||||
|         <jackson.version>2.9.4</jackson.version> | ||||
| 
 | ||||
|         <!-- util --> | ||||
|         <guava.version>19.0</guava.version> | ||||
|  | ||||
| @ -6,10 +6,11 @@ | ||||
|     <version>0.1-SNAPSHOT</version> | ||||
| 
 | ||||
|     <properties> | ||||
|         <validation-api.version>2.0.0.Final</validation-api.version> | ||||
|         <hibernate-validator.version>6.0.2.Final</hibernate-validator.version> | ||||
|         <validation-api.version>2.0.1.Final</validation-api.version> | ||||
|         <hibernate-validator.version>6.0.7.Final</hibernate-validator.version> | ||||
|         <javax.el-api.version>3.0.0</javax.el-api.version> | ||||
|         <javax.el.version>2.2.6</javax.el.version> | ||||
|         <org.springframework.version>5.0.2.RELEASE</org.springframework.version> | ||||
|     </properties> | ||||
| 
 | ||||
| 
 | ||||
| @ -21,12 +22,6 @@ | ||||
| 
 | ||||
|     <dependencies> | ||||
| 
 | ||||
|         <dependency> | ||||
|             <groupId>javax.validation</groupId> | ||||
|             <artifactId>validation-api</artifactId> | ||||
|             <version>${validation-api.version}</version> | ||||
|         </dependency> | ||||
| 
 | ||||
|         <dependency> | ||||
|             <groupId>org.hibernate</groupId> | ||||
|             <artifactId>hibernate-validator</artifactId> | ||||
| @ -50,6 +45,16 @@ | ||||
|             <artifactId>javax.el</artifactId> | ||||
|             <version>${javax.el.version}</version> | ||||
|         </dependency> | ||||
|         <dependency> | ||||
|             <groupId>org.springframework</groupId> | ||||
|             <artifactId>spring-context</artifactId> | ||||
|             <version>${org.springframework.version}</version> | ||||
|         </dependency> | ||||
|         <dependency> | ||||
|             <groupId>org.springframework</groupId> | ||||
|             <artifactId>spring-test</artifactId> | ||||
|             <version>${org.springframework.version}</version> | ||||
|         </dependency> | ||||
| 
 | ||||
|     </dependencies> | ||||
| 
 | ||||
|  | ||||
| @ -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; | ||||
|     } | ||||
| } | ||||
| @ -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<ConsistentDateParameters, Object[]> { | ||||
| 
 | ||||
|     @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]); | ||||
|     } | ||||
| } | ||||
| @ -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<? extends Payload>[] payload() default {}; | ||||
| } | ||||
| @ -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<? extends Payload>[] payload() default {}; | ||||
| } | ||||
| @ -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<ValidReservation, Reservation> { | ||||
| 
 | ||||
|     @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); | ||||
|     } | ||||
| } | ||||
| @ -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; | ||||
|     } | ||||
| } | ||||
| @ -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; | ||||
|     } | ||||
| } | ||||
| @ -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; | ||||
|     } | ||||
| } | ||||
| @ -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<Customer> 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); | ||||
|     } | ||||
| } | ||||
| @ -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<ConstraintViolation<ReservationManagement>> 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<ConstraintViolation<ReservationManagement>> 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<ConstraintViolation<ReservationManagement>> 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<ConstraintViolation<ReservationManagement>> violations = executableValidator.validateParameters(object, method, parameterValues); | ||||
| 
 | ||||
|         assertEquals(0, violations.size()); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void whenValidationWithInvalidConstructorParameters_thenCorrectNumberOfVoilations() throws NoSuchMethodException { | ||||
| 
 | ||||
|         Constructor<Customer> constructor = Customer.class.getConstructor(String.class, String.class); | ||||
|         Object[] parameterValues = { "John", "Doe" }; | ||||
|         Set<ConstraintViolation<Customer>> violations = executableValidator.validateConstructorParameters(constructor, parameterValues); | ||||
| 
 | ||||
|         assertEquals(2, violations.size()); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void whenValidationWithValidConstructorParameters_thenZeroVoilations() throws NoSuchMethodException { | ||||
| 
 | ||||
|         Constructor<Customer> constructor = Customer.class.getConstructor(String.class, String.class); | ||||
|         Object[] parameterValues = { "William", "Smith" }; | ||||
|         Set<ConstraintViolation<Customer>> violations = executableValidator.validateConstructorParameters(constructor, parameterValues); | ||||
| 
 | ||||
|         assertEquals(0, violations.size()); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void whenCrossParameterValidationWithInvalidConstructorParameters_thenCorrectNumberOfVoilations() throws NoSuchMethodException { | ||||
| 
 | ||||
|         Constructor<Reservation> constructor = Reservation.class.getConstructor(LocalDate.class, LocalDate.class, Customer.class, int.class); | ||||
|         Object[] parameterValues = { LocalDate.now(), LocalDate.now(), new Customer("William", "Smith"), 1 }; | ||||
|         Set<ConstraintViolation<Reservation>> violations = executableValidator.validateConstructorParameters(constructor, parameterValues); | ||||
| 
 | ||||
|         assertEquals(1, violations.size()); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void whenCrossParameterValidationWithValidConstructorParameters_thenZeroVoilations() throws NoSuchMethodException { | ||||
| 
 | ||||
|         Constructor<Reservation> 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<ConstraintViolation<Reservation>> 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.<Customer> emptyList(); | ||||
|         Set<ConstraintViolation<ReservationManagement>> 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<ConstraintViolation<ReservationManagement>> violations = executableValidator.validateReturnValue(object, method, returnValue); | ||||
| 
 | ||||
|         assertEquals(0, violations.size()); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void whenValidationWithInvalidConstructorReturnValue_thenCorrectNumberOfVoilations() throws NoSuchMethodException { | ||||
| 
 | ||||
|         Constructor<Reservation> 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<ConstraintViolation<Reservation>> violations = executableValidator.validateConstructorReturnValue(constructor, createdObject); | ||||
| 
 | ||||
|         assertEquals(1, violations.size()); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void whenValidationWithValidConstructorReturnValue_thenZeroVoilations() throws NoSuchMethodException { | ||||
| 
 | ||||
|         Constructor<Reservation> 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<ConstraintViolation<Reservation>> 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<ConstraintViolation<ReservationManagement>> 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<ConstraintViolation<ReservationManagement>> violations = executableValidator.validateParameters(object, method, parameterValues); | ||||
| 
 | ||||
|         assertEquals(0, violations.size()); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										15
									
								
								jgroups/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								jgroups/README.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | ||||
| ## Reliable Messaging with JGroups Tutorial Project | ||||
| 
 | ||||
| ### Relevant Article: | ||||
| - [Reliable Messaging with JGroups](http://www.baeldung.com/reliable-messaging-with-jgroups/) | ||||
| 
 | ||||
| ### Overview | ||||
| This Maven project contains the Java code for the article linked above. | ||||
| 
 | ||||
| ### Package Organization | ||||
| Java classes for the intro tutorial are in the org.baeldung.jgroups package. | ||||
| 
 | ||||
| 
 | ||||
| ### Running the tests | ||||
| 
 | ||||
| ``` | ||||
							
								
								
									
										36
									
								
								jgroups/pom.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								jgroups/pom.xml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,36 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||||
|     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||||
|     <modelVersion>4.0.0</modelVersion> | ||||
|     <artifactId>jgroups</artifactId> | ||||
|     <version>0.1-SNAPSHOT</version> | ||||
|     <packaging>jar</packaging> | ||||
|     <name>jgroups</name> | ||||
|     <description>Reliable Messaging with JGroups Tutorial</description> | ||||
| 
 | ||||
|     <parent> | ||||
|         <groupId>com.baeldung</groupId> | ||||
|         <artifactId>parent-modules</artifactId> | ||||
|         <version>1.0.0-SNAPSHOT</version> | ||||
|     </parent> | ||||
| 
 | ||||
|     <dependencies> | ||||
|         <dependency> | ||||
|             <groupId>org.jgroups</groupId> | ||||
|             <artifactId>jgroups</artifactId> | ||||
|             <version>4.0.10.Final</version> | ||||
|         </dependency> | ||||
| 
 | ||||
|         <dependency> | ||||
|             <groupId>commons-cli</groupId> | ||||
|             <artifactId>commons-cli</artifactId> | ||||
|             <version>1.4</version> | ||||
|         </dependency> | ||||
|     </dependencies> | ||||
| 
 | ||||
|     <properties> | ||||
|         <java.version>1.8</java.version> | ||||
|         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | ||||
|     </properties> | ||||
| 
 | ||||
| </project> | ||||
							
								
								
									
										212
									
								
								jgroups/src/main/java/com/baeldung/jgroups/JGroupsMessenger.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										212
									
								
								jgroups/src/main/java/com/baeldung/jgroups/JGroupsMessenger.java
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,212 @@ | ||||
| package com.baeldung.jgroups; | ||||
| 
 | ||||
| import org.apache.commons.cli.*; | ||||
| import org.jgroups.*; | ||||
| import org.jgroups.util.Util; | ||||
| 
 | ||||
| import java.io.*; | ||||
| import java.util.List; | ||||
| import java.util.Optional; | ||||
| 
 | ||||
| public class JGroupsMessenger extends ReceiverAdapter { | ||||
| 
 | ||||
|     private JChannel channel; | ||||
|     private String userName; | ||||
|     private String clusterName; | ||||
|     private View lastView; | ||||
|     private boolean running = true; | ||||
| 
 | ||||
|     // Our shared state | ||||
|     private Integer messageCount = 0; | ||||
| 
 | ||||
|     /** | ||||
|      * Connect to a JGroups cluster using command line options | ||||
|      * @param args command line arguments | ||||
|      * @throws Exception | ||||
|      */ | ||||
|     private void start(String[] args) throws Exception { | ||||
|         processCommandline(args); | ||||
| 
 | ||||
|         // Create the channel | ||||
|         // This file could be moved, or made a command line option. | ||||
|         channel = new JChannel("src/main/resources/udp.xml"); | ||||
| 
 | ||||
|         // Set a name | ||||
|         channel.name(userName); | ||||
| 
 | ||||
|         // Register for callbacks | ||||
|         channel.setReceiver(this); | ||||
| 
 | ||||
|         // Ignore our messages | ||||
|         channel.setDiscardOwnMessages(true); | ||||
| 
 | ||||
|         // Connect | ||||
|         channel.connect(clusterName); | ||||
| 
 | ||||
|         // Start state transfer | ||||
|         channel.getState(null, 0); | ||||
| 
 | ||||
|         // Do the things | ||||
|         processInput(); | ||||
| 
 | ||||
|         // Clean up | ||||
|         channel.close(); | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Quick and dirty implementaton of commons cli for command line args | ||||
|      * @param args the command line args | ||||
|      * @throws ParseException | ||||
|      */ | ||||
|     private void processCommandline(String[] args) throws ParseException { | ||||
| 
 | ||||
|         // Options, parser, friendly help | ||||
|         Options options = new Options(); | ||||
|         CommandLineParser parser = new DefaultParser(); | ||||
|         HelpFormatter formatter = new HelpFormatter(); | ||||
| 
 | ||||
|         options.addOption("u", "user", true, "User name") | ||||
|             .addOption("c", "cluster", true, "Cluster name"); | ||||
| 
 | ||||
|         CommandLine line = parser.parse(options, args); | ||||
| 
 | ||||
|         if (line.hasOption("user")) { | ||||
|             userName = line.getOptionValue("user"); | ||||
|         } else { | ||||
|             formatter.printHelp("JGroupsMessenger: need a user name.\n", options); | ||||
|             System.exit(-1); | ||||
|         } | ||||
| 
 | ||||
|         if (line.hasOption("cluster")) { | ||||
|             clusterName = line.getOptionValue("cluster"); | ||||
|         } else { | ||||
|             formatter.printHelp("JGroupsMessenger: need a cluster name.\n", options); | ||||
|             System.exit(-1); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // Start it up | ||||
|     public static void main(String[] args) throws Exception { | ||||
|         new JGroupsMessenger().start(args); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     @Override | ||||
|     public void viewAccepted(View newView) { | ||||
| 
 | ||||
|         // Save view if this is the first | ||||
|         if (lastView == null) { | ||||
|             System.out.println("Received initial view:"); | ||||
|             newView.forEach(System.out::println); | ||||
|         } else { | ||||
|             // Compare to last view | ||||
|             System.out.println("Received new view."); | ||||
| 
 | ||||
|             List<Address> newMembers = View.newMembers(lastView, newView); | ||||
|             System.out.println("New members: "); | ||||
|             newMembers.forEach(System.out::println); | ||||
| 
 | ||||
|             List<Address> exMembers = View.leftMembers(lastView, newView); | ||||
|             System.out.println("Exited members:"); | ||||
|             exMembers.forEach(System.out::println); | ||||
|         } | ||||
|         lastView = newView; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Loop on console input until we see 'x' to exit | ||||
|      */ | ||||
|     private void processInput() throws Exception { | ||||
| 
 | ||||
|         BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); | ||||
|         while (running) { | ||||
|             try { | ||||
| 
 | ||||
|                 // Get a destination, <enter> means broadcast | ||||
|                 Address destination = null; | ||||
|                 System.out.print("Enter a destination: "); | ||||
|                 System.out.flush(); | ||||
|                 String destinationName = in.readLine().toLowerCase(); | ||||
| 
 | ||||
|                 if (destinationName.equals("x")) { | ||||
|                     running = false; | ||||
|                     continue; | ||||
|                 } else if (!destinationName.isEmpty()) { | ||||
|                     destination = getAddress(destinationName) | ||||
|                       . orElseThrow(() -> new Exception("Destination not found")); | ||||
|                 } | ||||
| 
 | ||||
|                 // Accept a string to send | ||||
|                 System.out.print("Enter a message: "); | ||||
|                 System.out.flush(); | ||||
|                 String line = in.readLine().toLowerCase(); | ||||
|                 sendMessage(destination, line); | ||||
|             } catch (IOException ioe) { | ||||
|                 running = false; | ||||
|             } | ||||
|         } | ||||
|         System.out.println("Exiting."); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Send message from here | ||||
|      * @param destination the destination | ||||
|      * @param messageString the message | ||||
|      */ | ||||
|     private void sendMessage(Address destination, String messageString) { | ||||
|         try { | ||||
|             System.out.println("Sending " + messageString + " to " + destination); | ||||
|             Message message = new Message(destination, messageString); | ||||
|             channel.send(message); | ||||
|         } catch (Exception exception) { | ||||
|             System.err.println("Exception sending message: " + exception.getMessage()); | ||||
|             running = false; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void receive(Message message) { | ||||
|         // Print source and dest with message | ||||
|         String line = "Message received from: " + message.getSrc() + " to: " + message.getDest() + " -> " + message.getObject(); | ||||
| 
 | ||||
|         // Only track the count of broadcast messages | ||||
|         // Tracking direct message would make for a pointless state | ||||
|         if (message.getDest() == null) { | ||||
|             messageCount++; | ||||
|             System.out.println("Message count: " + messageCount); | ||||
|         } | ||||
| 
 | ||||
|         System.out.println(line); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void getState(OutputStream output) throws Exception { | ||||
|         // Serialize into the stream | ||||
|         Util.objectToStream(messageCount, new DataOutputStream(output)); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void setState(InputStream input) { | ||||
| 
 | ||||
|         // NOTE: since we know that incrementing the count and transferring the state | ||||
|         // is done inside the JChannel's thread, we don't have to worry about synchronizing | ||||
|         // messageCount. For production code it should be synchronized! | ||||
|         try { | ||||
|             // Deserialize | ||||
|             messageCount = Util.objectFromStream(new DataInputStream(input)); | ||||
|         } catch (Exception e) { | ||||
|             System.out.println("Error deserialing state!"); | ||||
|         } | ||||
|         System.out.println(messageCount + " is the current messagecount."); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     private Optional<Address> getAddress(String name) { | ||||
|         View view = channel.view(); | ||||
|         return view.getMembers().stream().filter(address -> name.equals(address.toString())).findFirst(); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										48
									
								
								jgroups/src/main/resources/udp.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								jgroups/src/main/resources/udp.xml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,48 @@ | ||||
| <config xmlns="urn:org:jgroups" | ||||
|         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||||
|         xsi:schemaLocation="urn:org:jgroups http://www.jgroups.org/schema/jgroups.xsd"> | ||||
|     <UDP | ||||
|          mcast_port="${jgroups.udp.mcast_port:45588}" | ||||
|          ip_ttl="4" | ||||
|          tos="8" | ||||
|          ucast_recv_buf_size="5M" | ||||
|          ucast_send_buf_size="5M" | ||||
|          mcast_recv_buf_size="5M" | ||||
|          mcast_send_buf_size="5M" | ||||
|          max_bundle_size="64K" | ||||
|          enable_diagnostics="true" | ||||
|          thread_naming_pattern="cl" | ||||
| 
 | ||||
|          thread_pool.min_threads="0" | ||||
|          thread_pool.max_threads="20" | ||||
|          thread_pool.keep_alive_time="30000"/> | ||||
| 
 | ||||
|     <PING /> | ||||
|     <MERGE3 max_interval="30000" | ||||
|             min_interval="10000"/> | ||||
|     <FD_SOCK/> | ||||
|     <FD_ALL/> | ||||
|     <VERIFY_SUSPECT timeout="1500"  /> | ||||
|     <BARRIER /> | ||||
|     <pbcast.NAKACK2 xmit_interval="500" | ||||
|                     xmit_table_num_rows="100" | ||||
|                     xmit_table_msgs_per_row="2000" | ||||
|                     xmit_table_max_compaction_time="30000" | ||||
|                     use_mcast_xmit="false" | ||||
|                     discard_delivered_msgs="true"/> | ||||
|     <UNICAST3 xmit_interval="500" | ||||
|               xmit_table_num_rows="100" | ||||
|               xmit_table_msgs_per_row="2000" | ||||
|               xmit_table_max_compaction_time="60000" | ||||
|               conn_expiry_timeout="0"/> | ||||
|     <pbcast.STABLE desired_avg_gossip="50000" | ||||
|                    max_bytes="4M"/> | ||||
|     <pbcast.GMS print_local_addr="true" join_timeout="2000"/> | ||||
|     <UFC max_credits="2M" | ||||
|          min_threshold="0.4"/> | ||||
|     <MFC max_credits="2M" | ||||
|          min_threshold="0.4"/> | ||||
|     <FRAG2 frag_size="60K"  /> | ||||
|     <RSVP resend_interval="2000" timeout="10000"/> | ||||
|     <pbcast.STATE_TRANSFER /> | ||||
| </config> | ||||
| @ -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) | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
| @ -716,6 +716,13 @@ | ||||
|             <classifier>test</classifier> | ||||
|             <scope>test</scope> | ||||
|         </dependency> | ||||
| 
 | ||||
|         <!-- tomcat --> | ||||
|         <dependency> | ||||
|             <groupId>org.apache.tomcat</groupId> | ||||
|             <artifactId>tomcat-catalina</artifactId> | ||||
|             <version>${tomcat.version}</version> | ||||
|         </dependency> | ||||
|         <dependency> | ||||
|             <groupId>org.milyn</groupId> | ||||
|             <artifactId>milyn-smooks-all</artifactId> | ||||
| @ -802,6 +809,7 @@ | ||||
|         <kafka.version>1.0.0</kafka.version> | ||||
|         <smooks.version>1.7.0</smooks.version> | ||||
|         <docker.version>3.0.14</docker.version> | ||||
|         <tomcat.version>8.5.24</tomcat.version> | ||||
|         <async.http.client.version>2.2.0</async.http.client.version> | ||||
|     </properties> | ||||
| </project> | ||||
							
								
								
									
										31
									
								
								libraries/src/main/java/com/baeldung/tomcat/MyFilter.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								libraries/src/main/java/com/baeldung/tomcat/MyFilter.java
									
									
									
									
									
										Normal file
									
								
							| @ -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() { | ||||
| 
 | ||||
|     } | ||||
| } | ||||
							
								
								
									
										25
									
								
								libraries/src/main/java/com/baeldung/tomcat/MyServlet.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								libraries/src/main/java/com/baeldung/tomcat/MyServlet.java
									
									
									
									
									
										Normal file
									
								
							| @ -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(); | ||||
|     } | ||||
| } | ||||
| @ -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(); | ||||
|     } | ||||
| } | ||||
| @ -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); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -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) | ||||
|  | ||||
| @ -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. | ||||
|  | ||||
| @ -16,11 +16,13 @@ | ||||
| 
 | ||||
|     <properties> | ||||
|         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | ||||
|         <spring.version>4.3.7.RELEASE</spring.version> | ||||
|         <spring-data-redis>1.8.1.RELEASE</spring-data-redis> | ||||
|         <spring.version>5.0.3.RELEASE</spring.version> | ||||
|         <spring-data-redis>2.0.3.RELEASE</spring-data-redis> | ||||
|         <cglib.version>3.2.4</cglib.version> | ||||
|         <jedis.version>2.9.0</jedis.version> | ||||
|         <nosqlunit.version>0.10.0</nosqlunit.version> | ||||
|         <spring-data-commons.version>2.0.3.RELEASE</spring-data-commons.version> | ||||
|          | ||||
|     </properties> | ||||
| 
 | ||||
|     <dependencies> | ||||
| @ -73,6 +75,12 @@ | ||||
|             <artifactId>nosqlunit-redis</artifactId> | ||||
|             <version>${nosqlunit.version}</version> | ||||
|         </dependency> | ||||
|          | ||||
|         <dependency> | ||||
|     		<groupId>org.springframework.data</groupId> | ||||
|     		<artifactId>spring-data-commons</artifactId> | ||||
|     		<version>${spring-data-commons.version}</version> | ||||
| 		</dependency> | ||||
|     </dependencies> | ||||
| 
 | ||||
| </project> | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -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 { | ||||
|  | ||||
| @ -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<Object, Object> findAllStudents(); | ||||
| 
 | ||||
|     void deleteStudent(String id); | ||||
| } | ||||
| @Repository | ||||
| public interface StudentRepository extends CrudRepository<Student, String> {} | ||||
|  | ||||
| @ -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<String, Object> redisTemplate; | ||||
|     private HashOperations hashOperations; | ||||
| 
 | ||||
|     @Autowired | ||||
|     public StudentRepositoryImpl(RedisTemplate<String, Object> 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<Object, Object> findAllStudents() { | ||||
|         return hashOperations.entries(KEY); | ||||
|     } | ||||
| 
 | ||||
|     public void deleteStudent(final String id) { | ||||
|         hashOperations.delete(KEY, id); | ||||
|     } | ||||
| } | ||||
| @ -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<Object, Object> retrievedStudent = studentRepository.findAllStudents(); | ||||
|         assertEquals(retrievedStudent.size(), 2); | ||||
|         studentRepository.save(engStudent); | ||||
|         studentRepository.save(medStudent); | ||||
|         List<Student> 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); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										3
									
								
								pom.xml
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								pom.xml
									
									
									
									
									
								
							| @ -49,7 +49,9 @@ | ||||
|         <module>core-java</module> | ||||
|         <module>core-java-io</module> | ||||
|         <module>core-java-8</module> | ||||
| 		<!-- | ||||
|         <module>core-java-concurrency</module> | ||||
| 		--> | ||||
|         <module>couchbase</module> | ||||
| 
 | ||||
|         <module>deltaspike</module> | ||||
| @ -93,6 +95,7 @@ | ||||
|         <module>javax-servlets</module> | ||||
|         <module>javaxval</module> | ||||
|         <module>jaxb</module> | ||||
|         <module>jgroups</module> | ||||
|         <module>jee-7</module> | ||||
|         <!-- <module>jhipster/jhipster-monolithic</module> --> | ||||
|         <module>jjwt</module> | ||||
|  | ||||
| @ -27,10 +27,16 @@ | ||||
|             <scope>test</scope> | ||||
|         </dependency> | ||||
| 	 | ||||
| 	<dependency> | ||||
|             <groupId>io.projectreactor</groupId> | ||||
| 	    <artifactId>reactor-test</artifactId> | ||||
|             <version>${reactor-core.version}</version> | ||||
| 	    <scope>test</scope> | ||||
| 	</dependency> | ||||
|     </dependencies> | ||||
| 
 | ||||
|     <properties> | ||||
|         <reactor-core.version>3.0.5.RELEASE</reactor-core.version> | ||||
|         <reactor-core.version>3.1.3.RELEASE</reactor-core.version> | ||||
|         <assertj.version>3.6.1</assertj.version> | ||||
|     </properties> | ||||
| 
 | ||||
|  | ||||
| @ -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<Integer> evenNumbers = Flux.range(min, max).filter(x -> x % 2 == 0); | ||||
|     private static Flux<Integer> oddNumbers = Flux.range(min, max).filter(x -> x % 2 > 0); | ||||
|      | ||||
|      | ||||
|     @Test | ||||
|     public void testMerge() { | ||||
|         Flux<Integer> 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<Integer> 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<Integer> 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<Integer> fluxOfIntegers = evenNumbers | ||||
|                 .concatWith(oddNumbers); | ||||
|          | ||||
|         StepVerifier.create(fluxOfIntegers) | ||||
|         .expectNext(2) | ||||
|         .expectNext(4) | ||||
|         .expectNext(1) | ||||
|         .expectNext(3) | ||||
|         .expectNext(5) | ||||
|         .expectComplete() | ||||
|         .verify(); | ||||
|     } | ||||
|      | ||||
|     @Test | ||||
|     public void testCombineLatest() { | ||||
|         Flux<Integer> 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<Integer> 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<Integer> 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<Integer> fluxOfIntegers = evenNumbers.mergeWith(oddNumbers); | ||||
|          | ||||
|         StepVerifier.create(fluxOfIntegers) | ||||
|         .expectNext(2) | ||||
|         .expectNext(4) | ||||
|         .expectNext(1) | ||||
|         .expectNext(3) | ||||
|         .expectNext(5) | ||||
|         .expectComplete() | ||||
|         .verify(); | ||||
|     } | ||||
|      | ||||
|     @Test | ||||
|     public void testZip() { | ||||
|         Flux<Integer> fluxOfIntegers = Flux.zip( | ||||
|                 evenNumbers,  | ||||
|                 oddNumbers,  | ||||
|                 (a, b) -> a + b); | ||||
|          | ||||
|         StepVerifier.create(fluxOfIntegers) | ||||
|         .expectNext(3) | ||||
|         .expectNext(7) | ||||
|         .expectComplete() | ||||
|         .verify(); | ||||
|     } | ||||
|      | ||||
|     @Test | ||||
|     public void testZipWith() { | ||||
|         Flux<Integer> fluxOfIntegers = evenNumbers | ||||
|                 .zipWith(oddNumbers,  | ||||
|                 (a, b) -> a * b); | ||||
|          | ||||
|         StepVerifier.create(fluxOfIntegers) | ||||
|         .expectNext(2) | ||||
|         .expectNext(12) | ||||
|         .expectComplete() | ||||
|         .verify(); | ||||
|     } | ||||
|      | ||||
|      | ||||
| } | ||||
| @ -3,11 +3,11 @@ | ||||
| 	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||||
| 	<modelVersion>4.0.0</modelVersion> | ||||
| 	<groupId>com.baeldung</groupId> | ||||
| 	<artifactId>oauth2client</artifactId> | ||||
| 	<artifactId>auth-client</artifactId> | ||||
| 	<version>0.0.1-SNAPSHOT</version> | ||||
| 	<packaging>jar</packaging> | ||||
| 
 | ||||
| 	<name>oauth2client</name> | ||||
| 	<name>auth-client</name> | ||||
| 	<description>Demo project for Spring Boot</description> | ||||
| 
 | ||||
| 	<parent> | ||||
| @ -4,11 +4,11 @@ | ||||
| 	<modelVersion>4.0.0</modelVersion> | ||||
| 
 | ||||
| 	<groupId>com.baeldung</groupId> | ||||
| 	<artifactId>personresource</artifactId> | ||||
| 	<artifactId>auth-resource</artifactId> | ||||
| 	<version>0.0.1-SNAPSHOT</version> | ||||
| 	<packaging>jar</packaging> | ||||
| 
 | ||||
| 	<name>personresource</name> | ||||
| 	<name>auth-resource</name> | ||||
| 	<description>Demo project for Spring Boot</description> | ||||
| 
 | ||||
| 	<parent> | ||||
| @ -4,7 +4,7 @@ | ||||
| 	<modelVersion>4.0.0</modelVersion> | ||||
| 
 | ||||
| 	<groupId>com.baeldung</groupId> | ||||
| 	<artifactId>authserver</artifactId> | ||||
| 	<artifactId>auth-server</artifactId> | ||||
| 	<version>0.0.1-SNAPSHOT</version> | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										14
									
								
								spring-data-spring-security/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								spring-data-spring-security/README.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,14 @@ | ||||
| # About this project | ||||
| This project contains examples from the [Spring Data with Spring Security](http://www.baeldung.com/spring-data-with-spring-security) article from Baeldung. | ||||
| 
 | ||||
| # Running the project | ||||
| The application uses [Spring Boot](http://projects.spring.io/spring-boot/), so it is easy to run. You can start it any of a few ways: | ||||
| * Run the `main` method from `SpringDataRestApplication` | ||||
| * Use the Maven Spring Boot plugin: `mvn spring-boot:run` | ||||
| * Package the application as a JAR and run it using `java -jar spring-data-spring-security.jar` | ||||
| 
 | ||||
| # Viewing the running application | ||||
| To view the running application, visit [http://localhost:8080](http://localhost:8080) in your browser | ||||
| 
 | ||||
| ###Relevant Articles: | ||||
| - [Spring Data with Spring Security](http://www.baeldung.com/spring-data-with-spring-security) | ||||
							
								
								
									
										67
									
								
								spring-data-spring-security/pom.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								spring-data-spring-security/pom.xml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,67 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||||
| 	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||||
| 	<modelVersion>4.0.0</modelVersion> | ||||
| 
 | ||||
| 	<groupId>com.baeldung</groupId> | ||||
| 	<artifactId>spring-data-spring-security</artifactId> | ||||
| 	<version>1.0</version> | ||||
| 	<packaging>jar</packaging> | ||||
| 
 | ||||
| 	<name>intro-spring-data-spring-security</name> | ||||
| 	<description>Spring Data with Spring Security</description> | ||||
| 
 | ||||
| 	<parent> | ||||
| 		<artifactId>parent-boot-5</artifactId> | ||||
| 		<groupId>com.baeldung</groupId> | ||||
| 		<version>0.0.1-SNAPSHOT</version> | ||||
| 		<relativePath>../parent-boot-5</relativePath> | ||||
| 	</parent> | ||||
| 
 | ||||
| 	<dependencies> | ||||
| 		<dependency> | ||||
| 			<groupId>org.springframework.boot</groupId> | ||||
| 			<artifactId>spring-boot-starter</artifactId> | ||||
| 		</dependency> | ||||
| 		<dependency> | ||||
| 			<groupId>org.springframework.boot</groupId> | ||||
| 			<artifactId>spring-boot-starter-web</artifactId> | ||||
| 		</dependency> | ||||
| 		<dependency> | ||||
| 			<groupId>org.springframework.boot</groupId> | ||||
| 			<artifactId>spring-boot-starter-data-jpa</artifactId> | ||||
| 		</dependency> | ||||
| 		<dependency> | ||||
| 			<groupId>org.springframework.security</groupId> | ||||
| 			<artifactId>spring-security-data</artifactId> | ||||
| 		</dependency> | ||||
| 		<dependency> | ||||
| 			<groupId>org.springframework.boot</groupId> | ||||
| 			<artifactId>spring-boot-starter-security</artifactId> | ||||
| 		</dependency> | ||||
| 		<dependency> | ||||
| 			<groupId>org.springframework.security</groupId> | ||||
| 			<artifactId>spring-security-test</artifactId> | ||||
| 			<scope>test</scope> | ||||
| 		</dependency> | ||||
| 		<dependency> | ||||
| 			<groupId>org.apache.tomcat.embed</groupId> | ||||
| 			<artifactId>tomcat-embed-jasper</artifactId> | ||||
| 			<!-- <scope>provided</scope> --> | ||||
| 		</dependency> | ||||
| 		<dependency> | ||||
| 			<groupId>com.h2database</groupId> | ||||
| 			<artifactId>h2</artifactId> | ||||
| 		</dependency> | ||||
| 		<dependency> | ||||
| 			<groupId>javax.servlet</groupId> | ||||
| 			<artifactId>jstl</artifactId> | ||||
| 		</dependency> | ||||
| 	</dependencies> | ||||
| 
 | ||||
| 	<build> | ||||
| 		<finalName>${project.artifactId}</finalName> | ||||
| 	</build> | ||||
| 
 | ||||
| 
 | ||||
| </project> | ||||
| @ -0,0 +1,64 @@ | ||||
| package com.baeldung; | ||||
| 
 | ||||
| import java.util.Properties; | ||||
| 
 | ||||
| import javax.sql.DataSource; | ||||
| 
 | ||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.boot.autoconfigure.SpringBootApplication; | ||||
| import org.springframework.context.annotation.Bean; | ||||
| import org.springframework.context.annotation.Import; | ||||
| import org.springframework.context.annotation.PropertySource; | ||||
| import org.springframework.core.env.Environment; | ||||
| import org.springframework.data.jpa.repository.config.EnableJpaRepositories; | ||||
| import org.springframework.jdbc.datasource.DriverManagerDataSource; | ||||
| import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; | ||||
| import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; | ||||
| import org.springframework.web.servlet.config.annotation.EnableWebMvc; | ||||
| import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; | ||||
| 
 | ||||
| @SpringBootApplication | ||||
| @PropertySource("classpath:persistence-h2.properties") | ||||
| @EnableJpaRepositories(basePackages = { "com.baeldung.data.repositories" }) | ||||
| @EnableWebMvc | ||||
| @Import(SpringSecurityConfig.class) | ||||
| public class AppConfig extends WebMvcConfigurerAdapter { | ||||
| 
 | ||||
|     @Autowired | ||||
|     private Environment env; | ||||
| 
 | ||||
|     @Bean | ||||
|     public DataSource dataSource() { | ||||
|         final DriverManagerDataSource dataSource = new DriverManagerDataSource(); | ||||
|         dataSource.setDriverClassName(env.getProperty("driverClassName")); | ||||
|         dataSource.setUrl(env.getProperty("url")); | ||||
|         dataSource.setUsername(env.getProperty("user")); | ||||
|         dataSource.setPassword(env.getProperty("password")); | ||||
|         return dataSource; | ||||
|     } | ||||
| 
 | ||||
|     @Bean | ||||
|     public LocalContainerEntityManagerFactoryBean entityManagerFactory() { | ||||
|         final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean(); | ||||
|         em.setDataSource(dataSource()); | ||||
|         em.setPackagesToScan(new String[] { "com.baeldung.models" }); | ||||
|         em.setJpaVendorAdapter(new HibernateJpaVendorAdapter()); | ||||
|         em.setJpaProperties(additionalProperties()); | ||||
|         return em; | ||||
|     } | ||||
| 
 | ||||
|     final Properties additionalProperties() { | ||||
|         final Properties hibernateProperties = new Properties(); | ||||
|         if (env.getProperty("hibernate.hbm2ddl.auto") != null) { | ||||
|             hibernateProperties.setProperty("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto")); | ||||
|         } | ||||
|         if (env.getProperty("hibernate.dialect") != null) { | ||||
|             hibernateProperties.setProperty("hibernate.dialect", env.getProperty("hibernate.dialect")); | ||||
|         } | ||||
|         if (env.getProperty("hibernate.show_sql") != null) { | ||||
|             hibernateProperties.setProperty("hibernate.show_sql", env.getProperty("hibernate.show_sql")); | ||||
|         } | ||||
|         return hibernateProperties; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,89 @@ | ||||
| package com.baeldung; | ||||
| 
 | ||||
| import javax.annotation.PostConstruct; | ||||
| import javax.sql.DataSource; | ||||
| 
 | ||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.context.annotation.Bean; | ||||
| import org.springframework.context.annotation.ComponentScan; | ||||
| import org.springframework.context.annotation.Configuration; | ||||
| import org.springframework.security.authentication.dao.DaoAuthenticationProvider; | ||||
| 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.builders.WebSecurity; | ||||
| import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; | ||||
| import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; | ||||
| import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; | ||||
| import org.springframework.security.crypto.password.PasswordEncoder; | ||||
| import org.springframework.security.data.repository.query.SecurityEvaluationContextExtension; | ||||
| import org.springframework.web.context.WebApplicationContext; | ||||
| 
 | ||||
| import com.baeldung.security.AuthenticationSuccessHandlerImpl; | ||||
| import com.baeldung.security.CustomUserDetailsService; | ||||
| 
 | ||||
| @Configuration | ||||
| @EnableWebSecurity | ||||
| @ComponentScan("com.baeldung.security") | ||||
| public class SpringSecurityConfig extends WebSecurityConfigurerAdapter { | ||||
| 
 | ||||
|     @Autowired | ||||
|     private WebApplicationContext applicationContext; | ||||
|     private CustomUserDetailsService userDetailsService; | ||||
|     @Autowired | ||||
|     private AuthenticationSuccessHandlerImpl successHandler; | ||||
|     @Autowired | ||||
|     private DataSource dataSource; | ||||
| 
 | ||||
|     @PostConstruct | ||||
|     public void completeSetup() { | ||||
|         userDetailsService = applicationContext.getBean(CustomUserDetailsService.class); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     protected void configure(final AuthenticationManagerBuilder auth) throws Exception { | ||||
|         auth.userDetailsService(userDetailsService) | ||||
|             .passwordEncoder(encoder()) | ||||
|             .and() | ||||
|             .authenticationProvider(authenticationProvider()) | ||||
|             .jdbcAuthentication() | ||||
|             .dataSource(dataSource); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void configure(WebSecurity web) throws Exception { | ||||
|         web.ignoring() | ||||
|             .antMatchers("/resources/**"); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     protected void configure(final HttpSecurity http) throws Exception { | ||||
|         http.authorizeRequests() | ||||
|             .antMatchers("/login") | ||||
|             .permitAll() | ||||
|             .and() | ||||
|             .formLogin() | ||||
|             .permitAll() | ||||
|             .successHandler(successHandler) | ||||
|             .and() | ||||
|             .csrf() | ||||
|             .disable(); | ||||
|     } | ||||
| 
 | ||||
|     @Bean | ||||
|     public DaoAuthenticationProvider authenticationProvider() { | ||||
|         final DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider(); | ||||
|         authProvider.setUserDetailsService(userDetailsService); | ||||
|         authProvider.setPasswordEncoder(encoder()); | ||||
|         return authProvider; | ||||
|     } | ||||
| 
 | ||||
|     @Bean | ||||
|     public PasswordEncoder encoder() { | ||||
|         return new BCryptPasswordEncoder(11); | ||||
|     } | ||||
| 
 | ||||
|     @Bean | ||||
|     public SecurityEvaluationContextExtension securityEvaluationContextExtension() { | ||||
|         return new SecurityEvaluationContextExtension(); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,14 @@ | ||||
| package com.baeldung.data.repositories; | ||||
| 
 | ||||
| import org.springframework.data.domain.Page; | ||||
| import org.springframework.data.domain.Pageable; | ||||
| import org.springframework.data.jpa.repository.Query; | ||||
| import org.springframework.data.repository.PagingAndSortingRepository; | ||||
| 
 | ||||
| import com.baeldung.models.Tweet; | ||||
| 
 | ||||
| public interface TweetRepository extends PagingAndSortingRepository<Tweet, Long> { | ||||
| 
 | ||||
|     @Query("select twt from Tweet twt  JOIN twt.likes as lk where lk = ?#{ principal?.username } or twt.owner = ?#{ principal?.username }") | ||||
|     Page<Tweet> getMyTweetsAndTheOnesILiked(Pageable pageable); | ||||
| } | ||||
| @ -0,0 +1,27 @@ | ||||
| package com.baeldung.data.repositories; | ||||
| 
 | ||||
| import java.util.Date; | ||||
| import java.util.List; | ||||
| 
 | ||||
| import org.springframework.data.domain.Page; | ||||
| import org.springframework.data.domain.Pageable; | ||||
| import org.springframework.data.jpa.repository.Modifying; | ||||
| import org.springframework.data.jpa.repository.Query; | ||||
| import org.springframework.data.repository.CrudRepository; | ||||
| import org.springframework.data.repository.query.Param; | ||||
| import org.springframework.stereotype.Repository; | ||||
| import org.springframework.transaction.annotation.Transactional; | ||||
| 
 | ||||
| import com.baeldung.models.AppUser; | ||||
| import com.baeldung.models.Tweet; | ||||
| 
 | ||||
| public interface UserRepository extends CrudRepository<AppUser, Long> { | ||||
|     AppUser findByUsername(String username); | ||||
| 
 | ||||
|     List<AppUser> findByName(String name); | ||||
| 
 | ||||
|     @Query("UPDATE AppUser u SET u.lastLogin=:lastLogin WHERE u.username = ?#{ principal?.username }") | ||||
|     @Modifying | ||||
|     @Transactional | ||||
|     public void updateLastLogin(@Param("lastLogin") Date lastLogin); | ||||
| } | ||||
| @ -0,0 +1,83 @@ | ||||
| package com.baeldung.models; | ||||
| 
 | ||||
| import java.util.Date; | ||||
| 
 | ||||
| import javax.persistence.Column; | ||||
| import javax.persistence.Entity; | ||||
| import javax.persistence.GeneratedValue; | ||||
| import javax.persistence.GenerationType; | ||||
| import javax.persistence.Id; | ||||
| import javax.persistence.Table; | ||||
| 
 | ||||
| @Entity | ||||
| @Table(name = "users") | ||||
| public class AppUser { | ||||
| 
 | ||||
|     @Id | ||||
|     @GeneratedValue(strategy = GenerationType.SEQUENCE) | ||||
|     private long id; | ||||
| 
 | ||||
|     private String name; | ||||
|     @Column(unique = true) | ||||
|     private String username; | ||||
|     private String password; | ||||
|     private boolean enabled = true; | ||||
|     private Date lastLogin; | ||||
| 
 | ||||
|     private AppUser() { | ||||
|     } | ||||
| 
 | ||||
|     public AppUser(String name, String email, String password) { | ||||
|         this.username = email; | ||||
|         this.name = name; | ||||
|         this.password = password; | ||||
|     } | ||||
| 
 | ||||
|     public long getId() { | ||||
|         return id; | ||||
|     } | ||||
| 
 | ||||
|     public void setId(long id) { | ||||
|         this.id = id; | ||||
|     } | ||||
| 
 | ||||
|     public String getName() { | ||||
|         return name; | ||||
|     } | ||||
| 
 | ||||
|     public void setName(String name) { | ||||
|         this.name = name; | ||||
|     } | ||||
| 
 | ||||
|     public String getUsername() { | ||||
|         return username; | ||||
|     } | ||||
| 
 | ||||
|     public void setUsername(String username) { | ||||
|         this.username = username; | ||||
|     } | ||||
| 
 | ||||
|     public String getPassword() { | ||||
|         return password; | ||||
|     } | ||||
| 
 | ||||
|     public void setPassword(String password) { | ||||
|         this.password = password; | ||||
|     } | ||||
| 
 | ||||
|     public boolean isEnabled() { | ||||
|         return enabled; | ||||
|     } | ||||
| 
 | ||||
|     public void setEnabled(boolean enabled) { | ||||
|         this.enabled = enabled; | ||||
|     } | ||||
| 
 | ||||
|     public Date getLastLogin() { | ||||
|         return lastLogin; | ||||
|     } | ||||
| 
 | ||||
|     public void setLastLogin(Date lastLogin) { | ||||
|         this.lastLogin = lastLogin; | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,63 @@ | ||||
| package com.baeldung.models; | ||||
| 
 | ||||
| import java.util.HashSet; | ||||
| import java.util.Set; | ||||
| 
 | ||||
| import javax.persistence.ElementCollection; | ||||
| import javax.persistence.Entity; | ||||
| import javax.persistence.FetchType; | ||||
| import javax.persistence.GeneratedValue; | ||||
| import javax.persistence.GenerationType; | ||||
| import javax.persistence.Id; | ||||
| 
 | ||||
| @Entity | ||||
| public class Tweet { | ||||
|     @Id | ||||
|     @GeneratedValue(strategy = GenerationType.SEQUENCE) | ||||
|     private long id; | ||||
|     private String tweet; | ||||
|     private String owner; | ||||
|     @ElementCollection(targetClass = String.class, fetch = FetchType.EAGER) | ||||
|     private Set<String> likes = new HashSet(); | ||||
| 
 | ||||
|     public long getId() { | ||||
|         return id; | ||||
|     } | ||||
| 
 | ||||
|     public void setId(long id) { | ||||
|         this.id = id; | ||||
|     } | ||||
| 
 | ||||
|     private Tweet() { | ||||
|     } | ||||
| 
 | ||||
|     public Tweet(String tweet, String owner) { | ||||
|         this.tweet = tweet; | ||||
|         this.owner = owner; | ||||
|     } | ||||
| 
 | ||||
|     public String getTweet() { | ||||
|         return tweet; | ||||
|     } | ||||
| 
 | ||||
|     public void setTweet(String tweet) { | ||||
|         this.tweet = tweet; | ||||
|     } | ||||
| 
 | ||||
|     public String getOwner() { | ||||
|         return owner; | ||||
|     } | ||||
| 
 | ||||
|     public void setOwner(String owner) { | ||||
|         this.owner = owner; | ||||
|     } | ||||
| 
 | ||||
|     public Set<String> getLikes() { | ||||
|         return likes; | ||||
|     } | ||||
| 
 | ||||
|     public void setLikes(Set<String> likes) { | ||||
|         this.likes = likes; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,67 @@ | ||||
| package com.baeldung.security; | ||||
| 
 | ||||
| import java.util.Collection; | ||||
| import java.util.Collections; | ||||
| import java.util.List; | ||||
| 
 | ||||
| import org.springframework.security.core.GrantedAuthority; | ||||
| import org.springframework.security.core.authority.SimpleGrantedAuthority; | ||||
| import org.springframework.security.core.userdetails.UserDetails; | ||||
| 
 | ||||
| import com.baeldung.models.AppUser; | ||||
| 
 | ||||
| public class AppUserPrincipal implements UserDetails { | ||||
| 
 | ||||
|     private final AppUser user; | ||||
| 
 | ||||
|     // | ||||
| 
 | ||||
|     public AppUserPrincipal(AppUser user) { | ||||
|         this.user = user; | ||||
|     } | ||||
| 
 | ||||
|     // | ||||
| 
 | ||||
|     @Override | ||||
|     public String getUsername() { | ||||
|         return user.getUsername(); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public String getPassword() { | ||||
|         return user.getPassword(); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public Collection<? extends GrantedAuthority> getAuthorities() { | ||||
|         final List<GrantedAuthority> authorities = Collections.singletonList(new SimpleGrantedAuthority("User")); | ||||
|         return authorities; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public boolean isAccountNonExpired() { | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public boolean isAccountNonLocked() { | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public boolean isCredentialsNonExpired() { | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public boolean isEnabled() { | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     // | ||||
| 
 | ||||
|     public AppUser getAppUser() { | ||||
|         return user; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,28 @@ | ||||
| package com.baeldung.security; | ||||
| 
 | ||||
| import java.io.IOException; | ||||
| import java.util.Date; | ||||
| 
 | ||||
| import javax.servlet.ServletException; | ||||
| import javax.servlet.http.HttpServletRequest; | ||||
| import javax.servlet.http.HttpServletResponse; | ||||
| 
 | ||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.security.core.Authentication; | ||||
| import org.springframework.security.web.authentication.AuthenticationSuccessHandler; | ||||
| import org.springframework.stereotype.Component; | ||||
| 
 | ||||
| import com.baeldung.data.repositories.UserRepository; | ||||
| 
 | ||||
| @Component | ||||
| public class AuthenticationSuccessHandlerImpl implements AuthenticationSuccessHandler { | ||||
| 
 | ||||
|     @Autowired | ||||
|     private UserRepository userRepository; | ||||
| 
 | ||||
|     @Override | ||||
|     public void onAuthenticationSuccess(HttpServletRequest arg0, HttpServletResponse arg1, Authentication arg2) throws IOException, ServletException { | ||||
|         userRepository.updateLastLogin(new Date()); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,40 @@ | ||||
| package com.baeldung.security; | ||||
| 
 | ||||
| import javax.annotation.PostConstruct; | ||||
| 
 | ||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.security.core.userdetails.UserDetails; | ||||
| import org.springframework.security.core.userdetails.UserDetailsService; | ||||
| import org.springframework.security.core.userdetails.UsernameNotFoundException; | ||||
| import org.springframework.stereotype.Service; | ||||
| import org.springframework.web.context.WebApplicationContext; | ||||
| 
 | ||||
| import com.baeldung.data.repositories.UserRepository; | ||||
| import com.baeldung.models.AppUser; | ||||
| 
 | ||||
| @Service | ||||
| public class CustomUserDetailsService implements UserDetailsService { | ||||
| 
 | ||||
|     @Autowired | ||||
|     private WebApplicationContext applicationContext; | ||||
|     private UserRepository userRepository; | ||||
| 
 | ||||
|     public CustomUserDetailsService() { | ||||
|         super(); | ||||
|     } | ||||
| 
 | ||||
|     @PostConstruct | ||||
|     public void completeSetup() { | ||||
|         userRepository = applicationContext.getBean(UserRepository.class); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public UserDetails loadUserByUsername(final String username) { | ||||
|         final AppUser appUser = userRepository.findByUsername(username); | ||||
|         if (appUser == null) { | ||||
|             throw new UsernameNotFoundException(username); | ||||
|         } | ||||
|         return new AppUserPrincipal(appUser); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,63 @@ | ||||
| package com.baeldung.util; | ||||
| 
 | ||||
| import java.util.ArrayList; | ||||
| import java.util.Collection; | ||||
| import java.util.List; | ||||
| import java.util.Random; | ||||
| import java.util.stream.Collectors; | ||||
| import java.util.stream.IntStream; | ||||
| 
 | ||||
| import org.springframework.security.core.GrantedAuthority; | ||||
| import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; | ||||
| 
 | ||||
| import com.baeldung.models.AppUser; | ||||
| import com.baeldung.models.Tweet; | ||||
| 
 | ||||
| public class DummyContentUtil { | ||||
|      | ||||
|     public static final List<AppUser> generateDummyUsers() { | ||||
|         List<AppUser> appUsers = new ArrayList<>(); | ||||
|         BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); | ||||
|         appUsers.add(new AppUser("Lionel Messi", "lionel@messi.com", passwordEncoder.encode("li1234"))); | ||||
|         appUsers.add(new AppUser("Cristiano Ronaldo", "cristiano@ronaldo.com", passwordEncoder.encode("c1234"))); | ||||
|         appUsers.add(new AppUser("Neymar Dos Santos", "neymar@neymar.com", passwordEncoder.encode("n1234"))); | ||||
|         appUsers.add(new AppUser("Luiz Suarez", "luiz@suarez.com", passwordEncoder.encode("lu1234"))); | ||||
|         appUsers.add(new AppUser("Andres Iniesta", "andres@iniesta.com", passwordEncoder.encode("a1234"))); | ||||
|         appUsers.add(new AppUser("Ivan Rakitic", "ivan@rakitic.com", passwordEncoder.encode("i1234"))); | ||||
|         appUsers.add(new AppUser("Ousman Dembele", "ousman@dembele.com", passwordEncoder.encode("o1234"))); | ||||
|         appUsers.add(new AppUser("Sergio Busquet", "sergio@busquet.com", passwordEncoder.encode("s1234"))); | ||||
|         appUsers.add(new AppUser("Gerard Pique", "gerard@pique.com", passwordEncoder.encode("g1234"))); | ||||
|         appUsers.add(new AppUser("Ter Stergen", "ter@stergen.com", passwordEncoder.encode("t1234"))); | ||||
|         return appUsers; | ||||
|     } | ||||
| 
 | ||||
|     public static final List<Tweet> generateDummyTweets(List<AppUser> users) { | ||||
|         List<Tweet> tweets = new ArrayList<>(); | ||||
|         Random random = new Random(); | ||||
|         IntStream.range(0, 9) | ||||
|             .sequential() | ||||
|             .forEach(i -> { | ||||
|                 Tweet twt = new Tweet(String.format("Tweet %d", i), users.get(random.nextInt(users.size())) | ||||
|                     .getUsername()); | ||||
|                 twt.getLikes() | ||||
|                     .addAll(users.subList(0, random.nextInt(users.size())) | ||||
|                         .stream() | ||||
|                         .map(AppUser::getUsername) | ||||
|                         .collect(Collectors.toSet())); | ||||
|                 tweets.add(twt); | ||||
|             }); | ||||
|         return tweets; | ||||
|     } | ||||
| 
 | ||||
|     public static Collection<GrantedAuthority> getAuthorities() { | ||||
|         Collection<GrantedAuthority> grantedAuthorities = new ArrayList<GrantedAuthority>(); | ||||
|         GrantedAuthority grantedAuthority = new GrantedAuthority() { | ||||
|             public String getAuthority() { | ||||
|                 return "ROLE_USER"; | ||||
|             } | ||||
|         }; | ||||
|         grantedAuthorities.add(grantedAuthority); | ||||
|         return grantedAuthorities; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,8 @@ | ||||
| driverClassName=org.h2.Driver | ||||
| url=jdbc:h2:mem:myDb;DB_CLOSE_DELAY=-1 | ||||
| username=sa | ||||
| password= | ||||
| 
 | ||||
| hibernate.dialect=org.hibernate.dialect.H2Dialect | ||||
| hibernate.show_sql=false | ||||
| hibernate.hbm2ddl.auto=create-drop | ||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user