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 | spring-check-if-a-property-is-null/.mvn/wrapper/maven-wrapper.properties | ||||||
| *.springBeans | *.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(); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -101,4 +101,4 @@ public class BacktrackingAlgorithm { | |||||||
|         } |         } | ||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -120,10 +120,10 @@ public class DancingLinks { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private static void printSolution(int[][] result) { |     private static void printSolution(int[][] result) { | ||||||
|         int N = result.length; |         int size = result.length; | ||||||
|         for (int[] aResult : result) { |         for (int[] aResult : result) { | ||||||
|             StringBuilder ret = new StringBuilder(); |             StringBuilder ret = new StringBuilder(); | ||||||
|             for (int j = 0; j < N; j++) { |             for (int j = 0; j < size; j++) { | ||||||
|                 ret.append(aResult[j]).append(" "); |                 ret.append(aResult[j]).append(" "); | ||||||
|             } |             } | ||||||
|             System.out.println(ret); |             System.out.println(ret); | ||||||
|  | |||||||
| @ -39,70 +39,83 @@ public class DancingLinksAlgorithm { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private boolean[][] createExactCoverBoard() { |     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; |         int hBase = 0; | ||||||
|  |         hBase = checkCellConstraint(coverBoard, hBase); | ||||||
|  |         hBase = checkRowConstraint(coverBoard, hBase); | ||||||
|  |         hBase = checkColumnConstraint(coverBoard, hBase); | ||||||
|  |         checkSubsectionConstraint(coverBoard, hBase); | ||||||
|  |          | ||||||
|  |         return coverBoard; | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|         // Cell constraint. |     private int checkSubsectionConstraint(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); |  | ||||||
|                     R[index][hBase] = true; |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         // 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 |  | ||||||
|         for (int br = COVER_START_INDEX; br <= BOARD_SIZE; br += SUBSECTION_SIZE) { |         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 bc = COVER_START_INDEX; bc <= BOARD_SIZE; bc += SUBSECTION_SIZE) { | ||||||
|                 for (int n = COVER_START_INDEX; n <= BOARD_SIZE; n++, hBase++) { |                 for (int n = COVER_START_INDEX; n <= BOARD_SIZE; n++, hBase++) { | ||||||
|                     for (int rDelta = 0; rDelta < SUBSECTION_SIZE; rDelta++) { |                     for (int rDelta = 0; rDelta < SUBSECTION_SIZE; rDelta++) { | ||||||
|                         for (int cDelta = 0; cDelta < SUBSECTION_SIZE; cDelta++) { |                         for (int cDelta = 0; cDelta < SUBSECTION_SIZE; cDelta++) { | ||||||
|                             int index = getIndex(br + rDelta, bc + cDelta, n); |                             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) { |     private boolean[][] initializeExactCoverBoard(int[][] board) { | ||||||
|         boolean[][] R = createExactCoverBoard(); |         boolean[][] coverBoard = createExactCoverBoard(); | ||||||
|         for (int i = COVER_START_INDEX; i <= BOARD_SIZE; i++) { |         for (int i = COVER_START_INDEX; i <= BOARD_SIZE; i++) { | ||||||
|             for (int j = COVER_START_INDEX; j <= BOARD_SIZE; j++) { |             for (int j = COVER_START_INDEX; j <= BOARD_SIZE; j++) { | ||||||
|                 int n = board[i - 1][j - 1]; |                 int n = board[i - 1][j - 1]; | ||||||
|                 if (n != NO_VALUE) { |                 if (n != NO_VALUE) { | ||||||
|                     for (int num = MIN_VALUE; num <= MAX_VALUE; num++) { |                     for (int num = MIN_VALUE; num <= MAX_VALUE; num++) { | ||||||
|                         if (num != n) { |                         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.List; | ||||||
| import java.util.concurrent.CompletableFuture; | import java.util.concurrent.CompletableFuture; | ||||||
| import java.util.concurrent.ExecutionException; | import java.util.concurrent.ExecutionException; | ||||||
|  | import java.util.concurrent.ExecutorService; | ||||||
| import java.util.concurrent.Executors; | import java.util.concurrent.Executors; | ||||||
| import java.util.stream.Collectors; | import java.util.stream.Collectors; | ||||||
| 
 | 
 | ||||||
| @ -116,18 +117,20 @@ public class HttpClientTest { | |||||||
|             .GET() |             .GET() | ||||||
|             .build(); |             .build(); | ||||||
| 
 | 
 | ||||||
|  |         ExecutorService executorService = Executors.newFixedThreadPool(2); | ||||||
|  | 
 | ||||||
|         CompletableFuture<HttpResponse<String>> response1 = HttpClient.newBuilder() |         CompletableFuture<HttpResponse<String>> response1 = HttpClient.newBuilder() | ||||||
|             .executor(Executors.newFixedThreadPool(2)) |             .executor(executorService) | ||||||
|             .build() |             .build() | ||||||
|             .sendAsync(request, HttpResponse.BodyHandler.asString()); |             .sendAsync(request, HttpResponse.BodyHandler.asString()); | ||||||
| 
 | 
 | ||||||
|         CompletableFuture<HttpResponse<String>> response2 = HttpClient.newBuilder() |         CompletableFuture<HttpResponse<String>> response2 = HttpClient.newBuilder() | ||||||
|             .executor(Executors.newFixedThreadPool(2)) |             .executor(executorService) | ||||||
|             .build() |             .build() | ||||||
|             .sendAsync(request, HttpResponse.BodyHandler.asString()); |             .sendAsync(request, HttpResponse.BodyHandler.asString()); | ||||||
| 
 | 
 | ||||||
|         CompletableFuture<HttpResponse<String>> response3 = HttpClient.newBuilder() |         CompletableFuture<HttpResponse<String>> response3 = HttpClient.newBuilder() | ||||||
|             .executor(Executors.newFixedThreadPool(2)) |             .executor(executorService) | ||||||
|             .build() |             .build() | ||||||
|             .sendAsync(request, HttpResponse.BodyHandler.asString()); |             .sendAsync(request, HttpResponse.BodyHandler.asString()); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -16,7 +16,8 @@ public class Job implements Runnable { | |||||||
|     @Override |     @Override | ||||||
|     public void run() { |     public void run() { | ||||||
|         try { |         try { | ||||||
|             System.out.println("Job:" + jobName + " Priority:" + jobPriority); |             System.out.println("Job:" + jobName +  | ||||||
|  |               " Priority:" + jobPriority); | ||||||
|             Thread.sleep(1000); |             Thread.sleep(1000); | ||||||
|         } catch (InterruptedException ignored) { |         } catch (InterruptedException ignored) { | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -9,21 +9,21 @@ import java.util.concurrent.TimeUnit; | |||||||
| public class PriorityJobScheduler { | public class PriorityJobScheduler { | ||||||
| 
 | 
 | ||||||
|     private ExecutorService priorityJobPoolExecutor; |     private ExecutorService priorityJobPoolExecutor; | ||||||
|     private ExecutorService priorityJobScheduler; |     private ExecutorService priorityJobScheduler =  | ||||||
|     private PriorityBlockingQueue<Runnable> priorityQueue; |       Executors.newSingleThreadExecutor(); | ||||||
|  |     private PriorityBlockingQueue<Job> priorityQueue; | ||||||
| 
 | 
 | ||||||
|     public PriorityJobScheduler(Integer poolSize, Integer queueSize) { |     public PriorityJobScheduler(Integer poolSize, Integer queueSize) { | ||||||
|         priorityJobPoolExecutor = Executors.newFixedThreadPool(poolSize); |         priorityJobPoolExecutor = Executors.newFixedThreadPool(poolSize); | ||||||
|         Comparator<? super Job> jobComparator = Comparator.comparing(Job::getJobPriority); |         priorityQueue = new PriorityBlockingQueue<Job>(queueSize,  | ||||||
|         priorityQueue = new PriorityBlockingQueue<Runnable>(queueSize,  |           Comparator.comparing(Job::getJobPriority)); | ||||||
|           (Comparator<? super Runnable>) jobComparator); |  | ||||||
| 
 | 
 | ||||||
|         priorityJobScheduler = Executors.newSingleThreadExecutor(); |  | ||||||
|         priorityJobScheduler.execute(()->{ |         priorityJobScheduler.execute(()->{ | ||||||
|             while (true) { |             while (true) { | ||||||
|                 try { |                 try { | ||||||
|                     priorityJobPoolExecutor.execute(priorityQueue.take()); |                     priorityJobPoolExecutor.execute(priorityQueue.take()); | ||||||
|                 } catch (InterruptedException e) { |                 } catch (InterruptedException e) { | ||||||
|  |                     // exception needs special handling | ||||||
|                     break; |                     break; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  | |||||||
| @ -30,7 +30,9 @@ public class PriorityJobSchedulerUnitTest { | |||||||
|         // delay to avoid job sleep (added for demo) being interrupted |         // delay to avoid job sleep (added for demo) being interrupted | ||||||
|         try { |         try { | ||||||
|             Thread.sleep(2000); |             Thread.sleep(2000); | ||||||
|         } catch (InterruptedException ignored) { |         } catch (InterruptedException e) { | ||||||
|  |             Thread.currentThread().interrupt(); | ||||||
|  |             throw new RuntimeException(e); | ||||||
|         } |         } | ||||||
|          |          | ||||||
|         pjs.closeScheduler(); |         pjs.closeScheduler(); | ||||||
|  | |||||||
| @ -1,28 +1,16 @@ | |||||||
| package com.baeldung.javac; | package com.baeldung.javac; | ||||||
| 
 | 
 | ||||||
| import java.io.Serializable; |  | ||||||
| import java.util.ArrayList; | import java.util.ArrayList; | ||||||
| import java.util.List; | import java.util.List; | ||||||
| 
 | 
 | ||||||
| public class Data implements Serializable { | public class Data { | ||||||
|     static List<String> textList = new ArrayList(); |     List<String> textList = new ArrayList(); | ||||||
| 
 | 
 | ||||||
|     private static void addText() { |     public void addText(String text) { | ||||||
|         textList.add("baeldung"); |         textList.add(text); | ||||||
|         textList.add("."); |  | ||||||
|         textList.add("com"); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public List getTextList() { |     public List getTextList() { | ||||||
|         this.addText(); |         return this.textList; | ||||||
|         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; |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
							
								
								
									
										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(Bag.class); | ||||||
|         metadataSources.addAnnotatedClass(PointEntity.class); |         metadataSources.addAnnotatedClass(PointEntity.class); | ||||||
|         metadataSources.addAnnotatedClass(PolygonEntity.class); |         metadataSources.addAnnotatedClass(PolygonEntity.class); | ||||||
|  |         metadataSources.addAnnotatedClass(com.baeldung.hibernate.pojo.Person.class); | ||||||
| 
 | 
 | ||||||
|         Metadata metadata = metadataSources.buildMetadata(); |         Metadata metadata = metadataSources.buildMetadata(); | ||||||
|         return metadata.getSessionFactoryBuilder() |         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.Transaction; | ||||||
| import org.hibernate.type.Type; | import org.hibernate.type.Type; | ||||||
| 
 | 
 | ||||||
| public class CustomInterceptorImpl implements Interceptor { | public class CustomInterceptorImpl implements Interceptor, Serializable { | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     public boolean onLoad(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) throws CallbackException { |     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: | ### Relevant Article: | ||||||
| - [Introduction to using InfluxDB with Java](http://www.baeldung.com/using-influxdb-with-java/) | - [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 | ### Overview | ||||||
| This Maven project contains the Java code for the article linked above. | 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.influxdb.impl.InfluxDBResultMapper; | ||||||
| import org.junit.Test; | import org.junit.Test; | ||||||
| 
 | 
 | ||||||
| import java.io.IOException; |  | ||||||
| import java.util.List; | import java.util.List; | ||||||
| import java.util.concurrent.TimeUnit; | import java.util.concurrent.TimeUnit; | ||||||
| 
 | 
 | ||||||
| @ -103,7 +102,7 @@ public class InfluxDBConnectionLiveTest { | |||||||
|         // another brief pause. |         // another brief pause. | ||||||
|         Thread.sleep(10); |         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()); |         assertEquals(10, memoryPointList.size()); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -129,7 +129,7 @@ | |||||||
| 
 | 
 | ||||||
|     <properties> |     <properties> | ||||||
|         <!-- marshalling --> |         <!-- marshalling --> | ||||||
|         <jackson.version>2.9.2</jackson.version> |         <jackson.version>2.9.4</jackson.version> | ||||||
| 
 | 
 | ||||||
|         <!-- util --> |         <!-- util --> | ||||||
|         <guava.version>19.0</guava.version> |         <guava.version>19.0</guava.version> | ||||||
|  | |||||||
| @ -6,10 +6,11 @@ | |||||||
|     <version>0.1-SNAPSHOT</version> |     <version>0.1-SNAPSHOT</version> | ||||||
| 
 | 
 | ||||||
|     <properties> |     <properties> | ||||||
|         <validation-api.version>2.0.0.Final</validation-api.version> |         <validation-api.version>2.0.1.Final</validation-api.version> | ||||||
|         <hibernate-validator.version>6.0.2.Final</hibernate-validator.version> |         <hibernate-validator.version>6.0.7.Final</hibernate-validator.version> | ||||||
|         <javax.el-api.version>3.0.0</javax.el-api.version> |         <javax.el-api.version>3.0.0</javax.el-api.version> | ||||||
|         <javax.el.version>2.2.6</javax.el.version> |         <javax.el.version>2.2.6</javax.el.version> | ||||||
|  |         <org.springframework.version>5.0.2.RELEASE</org.springframework.version> | ||||||
|     </properties> |     </properties> | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @ -21,12 +22,6 @@ | |||||||
| 
 | 
 | ||||||
|     <dependencies> |     <dependencies> | ||||||
| 
 | 
 | ||||||
|         <dependency> |  | ||||||
|             <groupId>javax.validation</groupId> |  | ||||||
|             <artifactId>validation-api</artifactId> |  | ||||||
|             <version>${validation-api.version}</version> |  | ||||||
|         </dependency> |  | ||||||
| 
 |  | ||||||
|         <dependency> |         <dependency> | ||||||
|             <groupId>org.hibernate</groupId> |             <groupId>org.hibernate</groupId> | ||||||
|             <artifactId>hibernate-validator</artifactId> |             <artifactId>hibernate-validator</artifactId> | ||||||
| @ -50,6 +45,16 @@ | |||||||
|             <artifactId>javax.el</artifactId> |             <artifactId>javax.el</artifactId> | ||||||
|             <version>${javax.el.version}</version> |             <version>${javax.el.version}</version> | ||||||
|         </dependency> |         </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> |     </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) | - [Intro to JDO Queries 2/2](http://www.baeldung.com/jdo-queries) | ||||||
| - [Guide to google-http-client](http://www.baeldung.com/google-http-client) | - [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) | - [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> |             <classifier>test</classifier> | ||||||
|             <scope>test</scope> |             <scope>test</scope> | ||||||
|         </dependency> |         </dependency> | ||||||
|  | 
 | ||||||
|  |         <!-- tomcat --> | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>org.apache.tomcat</groupId> | ||||||
|  |             <artifactId>tomcat-catalina</artifactId> | ||||||
|  |             <version>${tomcat.version}</version> | ||||||
|  |         </dependency> | ||||||
|         <dependency> |         <dependency> | ||||||
|             <groupId>org.milyn</groupId> |             <groupId>org.milyn</groupId> | ||||||
|             <artifactId>milyn-smooks-all</artifactId> |             <artifactId>milyn-smooks-all</artifactId> | ||||||
| @ -802,6 +809,7 @@ | |||||||
|         <kafka.version>1.0.0</kafka.version> |         <kafka.version>1.0.0</kafka.version> | ||||||
|         <smooks.version>1.7.0</smooks.version> |         <smooks.version>1.7.0</smooks.version> | ||||||
|         <docker.version>3.0.14</docker.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> |         <async.http.client.version>2.2.0</async.http.client.version> | ||||||
|     </properties> |     </properties> | ||||||
| </project> | </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: | ### Relevant Articles: | ||||||
| 
 | 
 | ||||||
| - [Creating a Custom Logback Appender](http://www.baeldung.com/custom-logback-appender) | - [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 | ### Relevant articles | ||||||
| 
 | 
 | ||||||
| - [Simple Jenkins Pipeline with Marathon and Mesos](http://www.baeldung.com/jenkins-pipeline-with-marathon-mesos) | - [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> |     <properties> | ||||||
|         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> |         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | ||||||
|         <spring.version>4.3.7.RELEASE</spring.version> |         <spring.version>5.0.3.RELEASE</spring.version> | ||||||
|         <spring-data-redis>1.8.1.RELEASE</spring-data-redis> |         <spring-data-redis>2.0.3.RELEASE</spring-data-redis> | ||||||
|         <cglib.version>3.2.4</cglib.version> |         <cglib.version>3.2.4</cglib.version> | ||||||
|         <jedis.version>2.9.0</jedis.version> |         <jedis.version>2.9.0</jedis.version> | ||||||
|         <nosqlunit.version>0.10.0</nosqlunit.version> |         <nosqlunit.version>0.10.0</nosqlunit.version> | ||||||
|  |         <spring-data-commons.version>2.0.3.RELEASE</spring-data-commons.version> | ||||||
|  |          | ||||||
|     </properties> |     </properties> | ||||||
| 
 | 
 | ||||||
|     <dependencies> |     <dependencies> | ||||||
| @ -73,6 +75,12 @@ | |||||||
|             <artifactId>nosqlunit-redis</artifactId> |             <artifactId>nosqlunit-redis</artifactId> | ||||||
|             <version>${nosqlunit.version}</version> |             <version>${nosqlunit.version}</version> | ||||||
|         </dependency> |         </dependency> | ||||||
|  |          | ||||||
|  |         <dependency> | ||||||
|  |     		<groupId>org.springframework.data</groupId> | ||||||
|  |     		<artifactId>spring-data-commons</artifactId> | ||||||
|  |     		<version>${spring-data-commons.version}</version> | ||||||
|  | 		</dependency> | ||||||
|     </dependencies> |     </dependencies> | ||||||
| 
 | 
 | ||||||
| </project> | </project> | ||||||
|  | |||||||
| @ -1,8 +1,5 @@ | |||||||
| package com.baeldung.spring.data.redis.config; | 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.Bean; | ||||||
| import org.springframework.context.annotation.ComponentScan; | import org.springframework.context.annotation.ComponentScan; | ||||||
| import org.springframework.context.annotation.Configuration; | 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.ChannelTopic; | ||||||
| import org.springframework.data.redis.listener.RedisMessageListenerContainer; | import org.springframework.data.redis.listener.RedisMessageListenerContainer; | ||||||
| import org.springframework.data.redis.listener.adapter.MessageListenerAdapter; | import org.springframework.data.redis.listener.adapter.MessageListenerAdapter; | ||||||
|  | import org.springframework.data.redis.repository.configuration.EnableRedisRepositories; | ||||||
| import org.springframework.data.redis.serializer.GenericToStringSerializer; | 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 | @Configuration | ||||||
| @ComponentScan("com.baeldung.spring.data.redis") | @ComponentScan("com.baeldung.spring.data.redis") | ||||||
|  | @EnableRedisRepositories(basePackages = "com.baeldung.spring.data.redis.repo") | ||||||
| public class RedisConfig { | public class RedisConfig { | ||||||
| 
 | 
 | ||||||
|     @Bean |     @Bean | ||||||
|  | |||||||
| @ -2,6 +2,9 @@ package com.baeldung.spring.data.redis.model; | |||||||
| 
 | 
 | ||||||
| import java.io.Serializable; | import java.io.Serializable; | ||||||
| 
 | 
 | ||||||
|  | import org.springframework.data.redis.core.RedisHash; | ||||||
|  | 
 | ||||||
|  | @RedisHash("Student") | ||||||
| public class Student implements Serializable { | public class Student implements Serializable { | ||||||
| 
 | 
 | ||||||
|     public enum Gender { |     public enum Gender { | ||||||
|  | |||||||
| @ -1,18 +1,9 @@ | |||||||
| package com.baeldung.spring.data.redis.repo; | 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 com.baeldung.spring.data.redis.model.Student; | ||||||
| 
 | 
 | ||||||
| import java.util.Map; | @Repository | ||||||
| 
 | public interface StudentRepository extends CrudRepository<Student, String> {} | ||||||
| public interface StudentRepository { |  | ||||||
| 
 |  | ||||||
|     void saveStudent(Student person); |  | ||||||
| 
 |  | ||||||
|     void updateStudent(Student student); |  | ||||||
| 
 |  | ||||||
|     Student findStudent(String id); |  | ||||||
| 
 |  | ||||||
|     Map<Object, Object> findAllStudents(); |  | ||||||
| 
 |  | ||||||
|     void deleteStudent(String id); |  | ||||||
| } |  | ||||||
|  | |||||||
| @ -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; | package com.baeldung.spring.data.redis.repo; | ||||||
| 
 | 
 | ||||||
| import com.baeldung.spring.data.redis.config.RedisConfig; | import static org.junit.Assert.assertEquals; | ||||||
| import com.baeldung.spring.data.redis.model.Student; | 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.Test; | ||||||
| import org.junit.runner.RunWith; | import org.junit.runner.RunWith; | ||||||
| import org.springframework.beans.factory.annotation.Autowired; | import org.springframework.beans.factory.annotation.Autowired; | ||||||
| import org.springframework.test.context.ContextConfiguration; | import org.springframework.test.context.ContextConfiguration; | ||||||
| import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; | ||||||
| 
 | 
 | ||||||
| import java.util.Map; | 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; |  | ||||||
| 
 | 
 | ||||||
| @RunWith(SpringJUnit4ClassRunner.class) | @RunWith(SpringJUnit4ClassRunner.class) | ||||||
| @ContextConfiguration(classes = RedisConfig.class) | @ContextConfiguration(classes = RedisConfig.class) | ||||||
| @ -23,18 +26,18 @@ public class StudentRepositoryIntegrationTest { | |||||||
|     @Test |     @Test | ||||||
|     public void whenSavingStudent_thenAvailableOnRetrieval() throws Exception { |     public void whenSavingStudent_thenAvailableOnRetrieval() throws Exception { | ||||||
|         final Student student = new Student("Eng2015001", "John Doe", Student.Gender.MALE, 1); |         final Student student = new Student("Eng2015001", "John Doe", Student.Gender.MALE, 1); | ||||||
|         studentRepository.saveStudent(student); |         studentRepository.save(student); | ||||||
|         final Student retrievedStudent = studentRepository.findStudent(student.getId()); |         final Student retrievedStudent = studentRepository.findById(student.getId()).get(); | ||||||
|         assertEquals(student.getId(), retrievedStudent.getId()); |         assertEquals(student.getId(), retrievedStudent.getId()); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Test |     @Test | ||||||
|     public void whenUpdatingStudent_thenAvailableOnRetrieval() throws Exception { |     public void whenUpdatingStudent_thenAvailableOnRetrieval() throws Exception { | ||||||
|         final Student student = new Student("Eng2015001", "John Doe", Student.Gender.MALE, 1); |         final Student student = new Student("Eng2015001", "John Doe", Student.Gender.MALE, 1); | ||||||
|         studentRepository.saveStudent(student); |         studentRepository.save(student); | ||||||
|         student.setName("Richard Watson"); |         student.setName("Richard Watson"); | ||||||
|         studentRepository.saveStudent(student); |         studentRepository.save(student); | ||||||
|         final Student retrievedStudent = studentRepository.findStudent(student.getId()); |         final Student retrievedStudent = studentRepository.findById(student.getId()).get(); | ||||||
|         assertEquals(student.getName(), retrievedStudent.getName()); |         assertEquals(student.getName(), retrievedStudent.getName()); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -42,18 +45,19 @@ public class StudentRepositoryIntegrationTest { | |||||||
|     public void whenSavingStudents_thenAllShouldAvailableOnRetrieval() throws Exception { |     public void whenSavingStudents_thenAllShouldAvailableOnRetrieval() throws Exception { | ||||||
|         final Student engStudent = new Student("Eng2015001", "John Doe", Student.Gender.MALE, 1); |         final Student engStudent = new Student("Eng2015001", "John Doe", Student.Gender.MALE, 1); | ||||||
|         final Student medStudent = new Student("Med2015001", "Gareth Houston", Student.Gender.MALE, 2); |         final Student medStudent = new Student("Med2015001", "Gareth Houston", Student.Gender.MALE, 2); | ||||||
|         studentRepository.saveStudent(engStudent); |         studentRepository.save(engStudent); | ||||||
|         studentRepository.saveStudent(medStudent); |         studentRepository.save(medStudent); | ||||||
|         final Map<Object, Object> retrievedStudent = studentRepository.findAllStudents(); |         List<Student> students = new ArrayList<>(); | ||||||
|         assertEquals(retrievedStudent.size(), 2); |         studentRepository.findAll().forEach(students::add); | ||||||
|  |         assertEquals(students.size(), 2); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Test |     @Test | ||||||
|     public void whenDeletingStudent_thenNotAvailableOnRetrieval() throws Exception { |     public void whenDeletingStudent_thenNotAvailableOnRetrieval() throws Exception { | ||||||
|         final Student student = new Student("Eng2015001", "John Doe", Student.Gender.MALE, 1); |         final Student student = new Student("Eng2015001", "John Doe", Student.Gender.MALE, 1); | ||||||
|         studentRepository.saveStudent(student); |         studentRepository.save(student); | ||||||
|         studentRepository.deleteStudent(student.getId()); |         studentRepository.deleteById(student.getId()); | ||||||
|         final Student retrievedStudent = studentRepository.findStudent(student.getId()); |         final Student retrievedStudent = studentRepository.findById(student.getId()).orElse(null); | ||||||
|         assertNull(retrievedStudent); |         assertNull(retrievedStudent); | ||||||
|     } |     } | ||||||
| } | } | ||||||
							
								
								
									
										3
									
								
								pom.xml
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								pom.xml
									
									
									
									
									
								
							| @ -49,7 +49,9 @@ | |||||||
|         <module>core-java</module> |         <module>core-java</module> | ||||||
|         <module>core-java-io</module> |         <module>core-java-io</module> | ||||||
|         <module>core-java-8</module> |         <module>core-java-8</module> | ||||||
|  | 		<!-- | ||||||
|         <module>core-java-concurrency</module> |         <module>core-java-concurrency</module> | ||||||
|  | 		--> | ||||||
|         <module>couchbase</module> |         <module>couchbase</module> | ||||||
| 
 | 
 | ||||||
|         <module>deltaspike</module> |         <module>deltaspike</module> | ||||||
| @ -93,6 +95,7 @@ | |||||||
|         <module>javax-servlets</module> |         <module>javax-servlets</module> | ||||||
|         <module>javaxval</module> |         <module>javaxval</module> | ||||||
|         <module>jaxb</module> |         <module>jaxb</module> | ||||||
|  |         <module>jgroups</module> | ||||||
|         <module>jee-7</module> |         <module>jee-7</module> | ||||||
|         <!-- <module>jhipster/jhipster-monolithic</module> --> |         <!-- <module>jhipster/jhipster-monolithic</module> --> | ||||||
|         <module>jjwt</module> |         <module>jjwt</module> | ||||||
|  | |||||||
| @ -26,11 +26,17 @@ | |||||||
|             <version>${assertj.version}</version> |             <version>${assertj.version}</version> | ||||||
|             <scope>test</scope> |             <scope>test</scope> | ||||||
|         </dependency> |         </dependency> | ||||||
| 
 | 	 | ||||||
|  | 	<dependency> | ||||||
|  |             <groupId>io.projectreactor</groupId> | ||||||
|  | 	    <artifactId>reactor-test</artifactId> | ||||||
|  |             <version>${reactor-core.version}</version> | ||||||
|  | 	    <scope>test</scope> | ||||||
|  | 	</dependency> | ||||||
|     </dependencies> |     </dependencies> | ||||||
| 
 | 
 | ||||||
|     <properties> |     <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> |         <assertj.version>3.6.1</assertj.version> | ||||||
|     </properties> |     </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"> | 	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> | 	<modelVersion>4.0.0</modelVersion> | ||||||
| 	<groupId>com.baeldung</groupId> | 	<groupId>com.baeldung</groupId> | ||||||
| 	<artifactId>oauth2client</artifactId> | 	<artifactId>auth-client</artifactId> | ||||||
| 	<version>0.0.1-SNAPSHOT</version> | 	<version>0.0.1-SNAPSHOT</version> | ||||||
| 	<packaging>jar</packaging> | 	<packaging>jar</packaging> | ||||||
| 
 | 
 | ||||||
| 	<name>oauth2client</name> | 	<name>auth-client</name> | ||||||
| 	<description>Demo project for Spring Boot</description> | 	<description>Demo project for Spring Boot</description> | ||||||
| 
 | 
 | ||||||
| 	<parent> | 	<parent> | ||||||
| @ -4,11 +4,11 @@ | |||||||
| 	<modelVersion>4.0.0</modelVersion> | 	<modelVersion>4.0.0</modelVersion> | ||||||
| 
 | 
 | ||||||
| 	<groupId>com.baeldung</groupId> | 	<groupId>com.baeldung</groupId> | ||||||
| 	<artifactId>personresource</artifactId> | 	<artifactId>auth-resource</artifactId> | ||||||
| 	<version>0.0.1-SNAPSHOT</version> | 	<version>0.0.1-SNAPSHOT</version> | ||||||
| 	<packaging>jar</packaging> | 	<packaging>jar</packaging> | ||||||
| 
 | 
 | ||||||
| 	<name>personresource</name> | 	<name>auth-resource</name> | ||||||
| 	<description>Demo project for Spring Boot</description> | 	<description>Demo project for Spring Boot</description> | ||||||
| 
 | 
 | ||||||
| 	<parent> | 	<parent> | ||||||
| @ -4,7 +4,7 @@ | |||||||
| 	<modelVersion>4.0.0</modelVersion> | 	<modelVersion>4.0.0</modelVersion> | ||||||
| 
 | 
 | ||||||
| 	<groupId>com.baeldung</groupId> | 	<groupId>com.baeldung</groupId> | ||||||
| 	<artifactId>authserver</artifactId> | 	<artifactId>auth-server</artifactId> | ||||||
| 	<version>0.0.1-SNAPSHOT</version> | 	<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; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
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