fix conflicts
This commit is contained in:
commit
ff242a01ae
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -649,6 +649,11 @@
|
|||||||
<artifactId>google-http-client-gson</artifactId>
|
<artifactId>google-http-client-gson</artifactId>
|
||||||
<version>${googleclient.version}</version>
|
<version>${googleclient.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.infinispan</groupId>
|
||||||
|
<artifactId>infinispan-core</artifactId>
|
||||||
|
<version>${infinispan.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!--Java Docker API Client-->
|
<!--Java Docker API Client-->
|
||||||
<dependency>
|
<dependency>
|
||||||
@ -716,6 +721,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 +814,8 @@
|
|||||||
<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>
|
||||||
|
<infinispan.version>9.1.5.Final</infinispan.version>
|
||||||
</properties>
|
</properties>
|
||||||
</project>
|
</project>
|
||||||
|
@ -0,0 +1,85 @@
|
|||||||
|
package com.baeldung.infinispan;
|
||||||
|
|
||||||
|
import com.baeldung.infinispan.listener.CacheListener;
|
||||||
|
import org.infinispan.Cache;
|
||||||
|
import org.infinispan.configuration.cache.Configuration;
|
||||||
|
import org.infinispan.configuration.cache.ConfigurationBuilder;
|
||||||
|
import org.infinispan.eviction.EvictionType;
|
||||||
|
import org.infinispan.manager.DefaultCacheManager;
|
||||||
|
import org.infinispan.transaction.LockingMode;
|
||||||
|
import org.infinispan.transaction.TransactionMode;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
public class CacheConfiguration {
|
||||||
|
|
||||||
|
public static final String SIMPLE_HELLO_WORLD_CACHE = "simple-hello-world-cache";
|
||||||
|
public static final String EXPIRING_HELLO_WORLD_CACHE = "expiring-hello-world-cache";
|
||||||
|
public static final String EVICTING_HELLO_WORLD_CACHE = "evicting-hello-world-cache";
|
||||||
|
public static final String PASSIVATING_HELLO_WORLD_CACHE = "passivating-hello-world-cache";
|
||||||
|
public static final String TRANSACTIONAL_CACHE = "transactional-cache";
|
||||||
|
|
||||||
|
public DefaultCacheManager cacheManager() {
|
||||||
|
DefaultCacheManager cacheManager = new DefaultCacheManager();
|
||||||
|
return cacheManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Cache<String, Integer> transactionalCache(DefaultCacheManager cacheManager, CacheListener listener) {
|
||||||
|
return this.buildCache(TRANSACTIONAL_CACHE, cacheManager, listener, transactionalConfiguration());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Cache<String, String> simpleHelloWorldCache(DefaultCacheManager cacheManager, CacheListener listener) {
|
||||||
|
return this.buildCache(SIMPLE_HELLO_WORLD_CACHE, cacheManager, listener, new ConfigurationBuilder().build());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Cache<String, String> expiringHelloWorldCache(DefaultCacheManager cacheManager, CacheListener listener) {
|
||||||
|
return this.buildCache(EXPIRING_HELLO_WORLD_CACHE, cacheManager, listener, expiringConfiguration());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Cache<String, String> evictingHelloWorldCache(DefaultCacheManager cacheManager, CacheListener listener) {
|
||||||
|
return this.buildCache(EVICTING_HELLO_WORLD_CACHE, cacheManager, listener, evictingConfiguration());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Cache<String, String> passivatingHelloWorldCache(DefaultCacheManager cacheManager, CacheListener listener) {
|
||||||
|
return this.buildCache(PASSIVATING_HELLO_WORLD_CACHE, cacheManager, listener, passivatingConfiguration());
|
||||||
|
}
|
||||||
|
|
||||||
|
private <K, V> Cache<K, V> buildCache(String cacheName, DefaultCacheManager cacheManager,
|
||||||
|
CacheListener listener, Configuration configuration) {
|
||||||
|
|
||||||
|
cacheManager.defineConfiguration(cacheName, configuration);
|
||||||
|
Cache<K, V> cache = cacheManager.getCache(cacheName);
|
||||||
|
cache.addListener(listener);
|
||||||
|
return cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Configuration expiringConfiguration() {
|
||||||
|
return new ConfigurationBuilder().expiration().lifespan(1, TimeUnit.SECONDS)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Configuration evictingConfiguration() {
|
||||||
|
return new ConfigurationBuilder()
|
||||||
|
.memory().evictionType(EvictionType.COUNT).size(1)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Configuration passivatingConfiguration() {
|
||||||
|
return new ConfigurationBuilder()
|
||||||
|
.memory().evictionType(EvictionType.COUNT).size(1)
|
||||||
|
.persistence()
|
||||||
|
.passivation(true)
|
||||||
|
.addSingleFileStore()
|
||||||
|
.purgeOnStartup(true)
|
||||||
|
.location(System.getProperty("java.io.tmpdir"))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Configuration transactionalConfiguration() {
|
||||||
|
return new ConfigurationBuilder()
|
||||||
|
.transaction().transactionMode(TransactionMode.TRANSACTIONAL)
|
||||||
|
.lockingMode(LockingMode.PESSIMISTIC)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,55 @@
|
|||||||
|
package com.baeldung.infinispan.listener;
|
||||||
|
|
||||||
|
import org.infinispan.notifications.Listener;
|
||||||
|
import org.infinispan.notifications.cachelistener.annotation.*;
|
||||||
|
import org.infinispan.notifications.cachelistener.event.*;
|
||||||
|
|
||||||
|
@Listener
|
||||||
|
public class CacheListener {
|
||||||
|
|
||||||
|
@CacheEntryCreated
|
||||||
|
public void entryCreated(CacheEntryCreatedEvent<String, String> event) {
|
||||||
|
this.printLog("Adding key '" + event.getKey() + "' to cache", event);
|
||||||
|
}
|
||||||
|
|
||||||
|
@CacheEntryExpired
|
||||||
|
public void entryExpired(CacheEntryExpiredEvent<String, String> event) {
|
||||||
|
this.printLog("Expiring key '" + event.getKey() + "' from cache", event);
|
||||||
|
}
|
||||||
|
|
||||||
|
@CacheEntryVisited
|
||||||
|
public void entryVisited(CacheEntryVisitedEvent<String, String> event) {
|
||||||
|
this.printLog("Key '" + event.getKey() + "' was visited", event);
|
||||||
|
}
|
||||||
|
|
||||||
|
@CacheEntryActivated
|
||||||
|
public void entryActivated(CacheEntryActivatedEvent<String, String> event) {
|
||||||
|
this.printLog("Activating key '" + event.getKey() + "' on cache", event);
|
||||||
|
}
|
||||||
|
|
||||||
|
@CacheEntryPassivated
|
||||||
|
public void entryPassivated(CacheEntryPassivatedEvent<String, String> event) {
|
||||||
|
this.printLog("Passivating key '" + event.getKey() + "' from cache", event);
|
||||||
|
}
|
||||||
|
|
||||||
|
@CacheEntryLoaded
|
||||||
|
public void entryLoaded(CacheEntryLoadedEvent<String, String> event) {
|
||||||
|
this.printLog("Loading key '" + event.getKey() + "' to cache", event);
|
||||||
|
}
|
||||||
|
|
||||||
|
@CacheEntriesEvicted
|
||||||
|
public void entriesEvicted(CacheEntriesEvictedEvent<String, String> event) {
|
||||||
|
final StringBuilder builder = new StringBuilder();
|
||||||
|
event.getEntries().entrySet().forEach((e) ->
|
||||||
|
builder.append(e.getKey() + ", ")
|
||||||
|
);
|
||||||
|
System.out.println("Evicting following entries from cache: " + builder.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void printLog(String log, CacheEntryEvent event) {
|
||||||
|
if (!event.isPre()) {
|
||||||
|
System.out.println(log);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
package com.baeldung.infinispan.repository;
|
||||||
|
|
||||||
|
public class HelloWorldRepository {
|
||||||
|
|
||||||
|
public String getHelloWorld() {
|
||||||
|
try {
|
||||||
|
System.out.println("Executing some heavy query");
|
||||||
|
Thread.sleep(1000);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return "Hello World!";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,90 @@
|
|||||||
|
package com.baeldung.infinispan.service;
|
||||||
|
|
||||||
|
import com.baeldung.infinispan.listener.CacheListener;
|
||||||
|
import com.baeldung.infinispan.repository.HelloWorldRepository;
|
||||||
|
import org.infinispan.Cache;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
public class HelloWorldService {
|
||||||
|
|
||||||
|
private final HelloWorldRepository repository;
|
||||||
|
|
||||||
|
private final Cache<String, String> simpleHelloWorldCache;
|
||||||
|
private final Cache<String, String> expiringHelloWorldCache;
|
||||||
|
private final Cache<String, String> evictingHelloWorldCache;
|
||||||
|
private final Cache<String, String> passivatingHelloWorldCache;
|
||||||
|
|
||||||
|
public HelloWorldService(HelloWorldRepository repository, CacheListener listener,
|
||||||
|
Cache<String, String> simpleHelloWorldCache,
|
||||||
|
Cache<String, String> expiringHelloWorldCache,
|
||||||
|
Cache<String, String> evictingHelloWorldCache,
|
||||||
|
Cache<String, String> passivatingHelloWorldCache) {
|
||||||
|
|
||||||
|
this.repository = repository;
|
||||||
|
|
||||||
|
this.simpleHelloWorldCache = simpleHelloWorldCache;
|
||||||
|
this.expiringHelloWorldCache = expiringHelloWorldCache;
|
||||||
|
this.evictingHelloWorldCache = evictingHelloWorldCache;
|
||||||
|
this.passivatingHelloWorldCache = passivatingHelloWorldCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String findSimpleHelloWorld() {
|
||||||
|
String cacheKey = "simple-hello";
|
||||||
|
String helloWorld = simpleHelloWorldCache.get(cacheKey);
|
||||||
|
if (helloWorld == null) {
|
||||||
|
helloWorld = repository.getHelloWorld();
|
||||||
|
simpleHelloWorldCache.put(cacheKey, helloWorld);
|
||||||
|
}
|
||||||
|
return helloWorld;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String findExpiringHelloWorld() {
|
||||||
|
String cacheKey = "expiring-hello";
|
||||||
|
String helloWorld = simpleHelloWorldCache.get(cacheKey);
|
||||||
|
if (helloWorld == null) {
|
||||||
|
helloWorld = repository.getHelloWorld();
|
||||||
|
simpleHelloWorldCache.put(cacheKey, helloWorld, 1, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
return helloWorld;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String findIdleHelloWorld() {
|
||||||
|
String cacheKey = "idle-hello";
|
||||||
|
String helloWorld = simpleHelloWorldCache.get(cacheKey);
|
||||||
|
if (helloWorld == null) {
|
||||||
|
helloWorld = repository.getHelloWorld();
|
||||||
|
simpleHelloWorldCache.put(cacheKey, helloWorld, -1, TimeUnit.SECONDS, 10, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
return helloWorld;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String findSimpleHelloWorldInExpiringCache() {
|
||||||
|
String cacheKey = "simple-hello";
|
||||||
|
String helloWorld = expiringHelloWorldCache.get(cacheKey);
|
||||||
|
if (helloWorld == null) {
|
||||||
|
helloWorld = repository.getHelloWorld();
|
||||||
|
expiringHelloWorldCache.put(cacheKey, helloWorld);
|
||||||
|
}
|
||||||
|
return helloWorld;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String findEvictingHelloWorld(String key) {
|
||||||
|
String value = evictingHelloWorldCache.get(key);
|
||||||
|
if(value == null) {
|
||||||
|
value = repository.getHelloWorld();
|
||||||
|
evictingHelloWorldCache.put(key, value);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String findPassivatingHelloWorld(String key) {
|
||||||
|
String value = passivatingHelloWorldCache.get(key);
|
||||||
|
if(value == null) {
|
||||||
|
value = repository.getHelloWorld();
|
||||||
|
passivatingHelloWorldCache.put(key, value);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,57 @@
|
|||||||
|
package com.baeldung.infinispan.service;
|
||||||
|
|
||||||
|
import org.infinispan.Cache;
|
||||||
|
import org.springframework.util.StopWatch;
|
||||||
|
|
||||||
|
import javax.transaction.TransactionManager;
|
||||||
|
|
||||||
|
public class TransactionalService {
|
||||||
|
|
||||||
|
private final Cache<String, Integer> transactionalCache;
|
||||||
|
|
||||||
|
private static final String KEY = "key";
|
||||||
|
|
||||||
|
public TransactionalService(Cache<String, Integer> transactionalCache) {
|
||||||
|
this.transactionalCache = transactionalCache;
|
||||||
|
|
||||||
|
transactionalCache.put(KEY, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getQuickHowManyVisits() {
|
||||||
|
try {
|
||||||
|
TransactionManager tm = transactionalCache.getAdvancedCache().getTransactionManager();
|
||||||
|
tm.begin();
|
||||||
|
Integer howManyVisits = transactionalCache.get(KEY);
|
||||||
|
howManyVisits++;
|
||||||
|
System.out.println("Ill try to set HowManyVisits to " + howManyVisits);
|
||||||
|
StopWatch watch = new StopWatch();
|
||||||
|
watch.start();
|
||||||
|
transactionalCache.put(KEY, howManyVisits);
|
||||||
|
watch.stop();
|
||||||
|
System.out.println("I was able to set HowManyVisits to " + howManyVisits +
|
||||||
|
" after waiting " + watch.getTotalTimeSeconds() + " seconds");
|
||||||
|
|
||||||
|
tm.commit();
|
||||||
|
return howManyVisits;
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void startBackgroundBatch() {
|
||||||
|
try {
|
||||||
|
TransactionManager tm = transactionalCache.getAdvancedCache().getTransactionManager();
|
||||||
|
tm.begin();
|
||||||
|
transactionalCache.put(KEY, 1000);
|
||||||
|
System.out.println("HowManyVisits should now be 1000, " +
|
||||||
|
"but we are holding the transaction");
|
||||||
|
Thread.sleep(1000L);
|
||||||
|
tm.rollback();
|
||||||
|
System.out.println("The slow batch suffered a rollback");
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
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,56 @@
|
|||||||
|
package com.baeldung.infinispan;
|
||||||
|
|
||||||
|
import com.baeldung.infinispan.listener.CacheListener;
|
||||||
|
import com.baeldung.infinispan.repository.HelloWorldRepository;
|
||||||
|
import com.baeldung.infinispan.service.HelloWorldService;
|
||||||
|
import com.baeldung.infinispan.service.TransactionalService;
|
||||||
|
import org.infinispan.Cache;
|
||||||
|
import org.infinispan.manager.DefaultCacheManager;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
|
||||||
|
public class ConfigurationTest {
|
||||||
|
|
||||||
|
private DefaultCacheManager cacheManager;
|
||||||
|
|
||||||
|
private HelloWorldRepository repository = new HelloWorldRepository();
|
||||||
|
|
||||||
|
protected HelloWorldService helloWorldService;
|
||||||
|
protected TransactionalService transactionalService;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup() {
|
||||||
|
CacheConfiguration configuration = new CacheConfiguration();
|
||||||
|
CacheListener listener = new CacheListener();
|
||||||
|
|
||||||
|
cacheManager = configuration.cacheManager();
|
||||||
|
|
||||||
|
Cache<String, Integer> transactionalCache =
|
||||||
|
configuration.transactionalCache(cacheManager, listener);
|
||||||
|
|
||||||
|
Cache<String, String> simpleHelloWorldCache =
|
||||||
|
configuration.simpleHelloWorldCache(cacheManager, listener);
|
||||||
|
|
||||||
|
Cache<String, String> expiringHelloWorldCache =
|
||||||
|
configuration.expiringHelloWorldCache(cacheManager, listener);
|
||||||
|
|
||||||
|
Cache<String, String> evictingHelloWorldCache =
|
||||||
|
configuration.evictingHelloWorldCache(cacheManager, listener);
|
||||||
|
|
||||||
|
Cache<String, String> passivatingHelloWorldCache =
|
||||||
|
configuration.passivatingHelloWorldCache(cacheManager, listener);
|
||||||
|
|
||||||
|
this.helloWorldService = new HelloWorldService(repository,
|
||||||
|
listener, simpleHelloWorldCache, expiringHelloWorldCache, evictingHelloWorldCache,
|
||||||
|
passivatingHelloWorldCache);
|
||||||
|
|
||||||
|
this.transactionalService = new TransactionalService(transactionalCache);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void tearDown() {
|
||||||
|
cacheManager.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,105 @@
|
|||||||
|
package com.baeldung.infinispan.service;
|
||||||
|
|
||||||
|
import com.baeldung.infinispan.ConfigurationTest;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Java6Assertions.assertThat;
|
||||||
|
|
||||||
|
public class HelloWorldServiceUnitTest extends ConfigurationTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenGetIsCalledTwoTimes_thenTheSecondShouldHitTheCache() {
|
||||||
|
long milis = System.currentTimeMillis();
|
||||||
|
helloWorldService.findSimpleHelloWorld();
|
||||||
|
long executionTime = System.currentTimeMillis() - milis;
|
||||||
|
|
||||||
|
assertThat(executionTime).isGreaterThanOrEqualTo(1000);
|
||||||
|
|
||||||
|
milis = System.currentTimeMillis();
|
||||||
|
helloWorldService.findSimpleHelloWorld();
|
||||||
|
executionTime = System.currentTimeMillis() - milis;
|
||||||
|
|
||||||
|
assertThat(executionTime).isLessThan(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenGetIsCalledTwoTimesQuickly_thenTheSecondShouldHitTheCache() {
|
||||||
|
long milis = System.currentTimeMillis();
|
||||||
|
helloWorldService.findExpiringHelloWorld();
|
||||||
|
long executionTime = System.currentTimeMillis() - milis;
|
||||||
|
|
||||||
|
assertThat(executionTime).isGreaterThanOrEqualTo(1000);
|
||||||
|
|
||||||
|
milis = System.currentTimeMillis();
|
||||||
|
helloWorldService.findExpiringHelloWorld();
|
||||||
|
executionTime = System.currentTimeMillis() - milis;
|
||||||
|
|
||||||
|
assertThat(executionTime).isLessThan(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenGetIsCalledTwoTimesSparsely_thenNeitherShouldHitTheCache()
|
||||||
|
throws InterruptedException {
|
||||||
|
|
||||||
|
long milis = System.currentTimeMillis();
|
||||||
|
helloWorldService.findSimpleHelloWorldInExpiringCache();
|
||||||
|
long executionTime = System.currentTimeMillis() - milis;
|
||||||
|
|
||||||
|
assertThat(executionTime).isGreaterThanOrEqualTo(1000);
|
||||||
|
|
||||||
|
Thread.sleep(1100);
|
||||||
|
|
||||||
|
milis = System.currentTimeMillis();
|
||||||
|
helloWorldService.findSimpleHelloWorldInExpiringCache();
|
||||||
|
executionTime = System.currentTimeMillis() - milis;
|
||||||
|
|
||||||
|
assertThat(executionTime).isGreaterThanOrEqualTo(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenOneEntryIsConfigured_whenTwoAreAdded_thenFirstShouldntBeAvailable()
|
||||||
|
throws InterruptedException {
|
||||||
|
|
||||||
|
long milis = System.currentTimeMillis();
|
||||||
|
helloWorldService.findEvictingHelloWorld("key 1");
|
||||||
|
long executionTime = System.currentTimeMillis() - milis;
|
||||||
|
|
||||||
|
assertThat(executionTime).isGreaterThanOrEqualTo(1000);
|
||||||
|
|
||||||
|
milis = System.currentTimeMillis();
|
||||||
|
helloWorldService.findEvictingHelloWorld("key 2");
|
||||||
|
executionTime = System.currentTimeMillis() - milis;
|
||||||
|
|
||||||
|
assertThat(executionTime).isGreaterThanOrEqualTo(1000);
|
||||||
|
|
||||||
|
milis = System.currentTimeMillis();
|
||||||
|
helloWorldService.findEvictingHelloWorld("key 1");
|
||||||
|
executionTime = System.currentTimeMillis() - milis;
|
||||||
|
|
||||||
|
assertThat(executionTime).isGreaterThanOrEqualTo(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenOneEntryIsConfigured_whenTwoAreAdded_thenTheFirstShouldBeAvailable()
|
||||||
|
throws InterruptedException {
|
||||||
|
|
||||||
|
long milis = System.currentTimeMillis();
|
||||||
|
helloWorldService.findPassivatingHelloWorld("key 1");
|
||||||
|
long executionTime = System.currentTimeMillis() - milis;
|
||||||
|
|
||||||
|
assertThat(executionTime).isGreaterThanOrEqualTo(1000);
|
||||||
|
|
||||||
|
milis = System.currentTimeMillis();
|
||||||
|
helloWorldService.findPassivatingHelloWorld("key 2");
|
||||||
|
executionTime = System.currentTimeMillis() - milis;
|
||||||
|
|
||||||
|
assertThat(executionTime).isGreaterThanOrEqualTo(1000);
|
||||||
|
|
||||||
|
milis = System.currentTimeMillis();
|
||||||
|
helloWorldService.findPassivatingHelloWorld("key 1");
|
||||||
|
executionTime = System.currentTimeMillis() - milis;
|
||||||
|
|
||||||
|
assertThat(executionTime).isLessThan(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
package com.baeldung.infinispan.service;
|
||||||
|
|
||||||
|
import com.baeldung.infinispan.ConfigurationTest;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Java6Assertions.assertThat;
|
||||||
|
|
||||||
|
public class TransactionalServiceUnitTest extends ConfigurationTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenLockingAnEntry_thenItShouldBeInaccessible() throws InterruptedException {
|
||||||
|
Runnable backGroundJob = () -> transactionalService.startBackgroundBatch();
|
||||||
|
Thread backgroundThread = new Thread(backGroundJob);
|
||||||
|
transactionalService.getQuickHowManyVisits();
|
||||||
|
backgroundThread.start();
|
||||||
|
Thread.sleep(100); //lets wait our thread warm up
|
||||||
|
long milis = System.currentTimeMillis();
|
||||||
|
transactionalService.getQuickHowManyVisits();
|
||||||
|
long executionTime = System.currentTimeMillis() - milis;
|
||||||
|
|
||||||
|
assertThat(executionTime).isGreaterThan(500).isLessThan(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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>
|
||||||
|
|
||||||
|
|
@ -25,14 +25,20 @@ public class MultipartController {
|
|||||||
try {
|
try {
|
||||||
InputStream in = file.getInputStream();
|
InputStream in = file.getInputStream();
|
||||||
String path = new File(".").getAbsolutePath();
|
String path = new File(".").getAbsolutePath();
|
||||||
FileOutputStream f = new FileOutputStream(path.substring(0, path.length()-1)+ "/uploads/" + file.getOriginalFilename());
|
FileOutputStream f = new FileOutputStream(path.substring(0, path.length() - 1) + "/uploads/" + file.getOriginalFilename());
|
||||||
int ch;
|
try {
|
||||||
while ((ch = in.read()) != -1) {
|
int ch;
|
||||||
f.write(ch);
|
while ((ch = in.read()) != -1) {
|
||||||
|
f.write(ch);
|
||||||
|
}
|
||||||
|
modelAndView.getModel().put("message", "File uploaded successfully!");
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.out.println("Exception uploading multipart: " + e);
|
||||||
|
} finally {
|
||||||
|
f.flush();
|
||||||
|
f.close();
|
||||||
|
in.close();
|
||||||
}
|
}
|
||||||
f.flush();
|
|
||||||
f.close();
|
|
||||||
modelAndView.getModel().put("message", "File uploaded successfully!");
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
System.out.println("Exception uploading multipart: " + e);
|
System.out.println("Exception uploading multipart: " + e);
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<spring.integration.version>4.3.5.RELEASE</spring.integration.version>
|
<spring.version>5.0.1.RELEASE</spring.version>
|
||||||
<spring-social.version>1.1.4.RELEASE</spring-social.version>
|
<spring-social.version>1.1.4.RELEASE</spring-social.version>
|
||||||
<javax-mail.version>1.4.7</javax-mail.version>
|
<javax-mail.version>1.4.7</javax-mail.version>
|
||||||
<javax-activation.version>1.1.1</javax-activation.version>
|
<javax-activation.version>1.1.1</javax-activation.version>
|
||||||
@ -68,7 +68,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.integration</groupId>
|
<groupId>org.springframework.integration</groupId>
|
||||||
<artifactId>spring-integration-core</artifactId>
|
<artifactId>spring-integration-core</artifactId>
|
||||||
<version>${spring.integration.version}</version>
|
<version>${spring.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>javax.activation</groupId>
|
<groupId>javax.activation</groupId>
|
||||||
@ -84,17 +84,17 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.integration</groupId>
|
<groupId>org.springframework.integration</groupId>
|
||||||
<artifactId>spring-integration-twitter</artifactId>
|
<artifactId>spring-integration-twitter</artifactId>
|
||||||
<version>${spring.integration.version}</version>
|
<version>${spring.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.integration</groupId>
|
<groupId>org.springframework.integration</groupId>
|
||||||
<artifactId>spring-integration-mail</artifactId>
|
<artifactId>spring-integration-mail</artifactId>
|
||||||
<version>${spring.integration.version}</version>
|
<version>${spring.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.integration</groupId>
|
<groupId>org.springframework.integration</groupId>
|
||||||
<artifactId>spring-integration-ftp</artifactId>
|
<artifactId>spring-integration-ftp</artifactId>
|
||||||
<version>${spring.integration.version}</version>
|
<version>${spring.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.social</groupId>
|
<groupId>org.springframework.social</groupId>
|
||||||
@ -104,7 +104,36 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.integration</groupId>
|
<groupId>org.springframework.integration</groupId>
|
||||||
<artifactId>spring-integration-file</artifactId>
|
<artifactId>spring-integration-file</artifactId>
|
||||||
<version>${spring.integration.version}</version>
|
<version>${spring.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.security</groupId>
|
||||||
|
<artifactId>spring-security-core</artifactId>
|
||||||
|
<version>${spring.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.security</groupId>
|
||||||
|
<artifactId>spring-security-config</artifactId>
|
||||||
|
<version>${spring.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.integration</groupId>
|
||||||
|
<artifactId>spring-integration-security</artifactId>
|
||||||
|
<version>${spring.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.security</groupId>
|
||||||
|
<artifactId>spring-security-test</artifactId>
|
||||||
|
<version>${spring.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-test</artifactId>
|
||||||
|
<version>${spring.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>junit</groupId>
|
||||||
|
@ -0,0 +1,45 @@
|
|||||||
|
package com.baeldung.si.security;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import org.springframework.integration.annotation.ServiceActivator;
|
||||||
|
import org.springframework.messaging.Message;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class MessageConsumer {
|
||||||
|
|
||||||
|
private String messageContent;
|
||||||
|
|
||||||
|
private Map<String, String> messagePSContent = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
public String getMessageContent() {
|
||||||
|
return messageContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMessageContent(String messageContent) {
|
||||||
|
this.messageContent = messageContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, String> getMessagePSContent() {
|
||||||
|
return messagePSContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMessagePSContent(Map<String, String> messagePSContent) {
|
||||||
|
this.messagePSContent = messagePSContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ServiceActivator(inputChannel = "endDirectChannel")
|
||||||
|
public void endDirectFlow(Message<?> message) {
|
||||||
|
setMessageContent(message.getPayload().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@ServiceActivator(inputChannel = "finalPSResult")
|
||||||
|
public void endPSFlow(Message<?> message) {
|
||||||
|
Logger.getAnonymousLogger().info(Thread.currentThread().getName() + " has completed ---------------------------");
|
||||||
|
messagePSContent.put(Thread.currentThread().getName(), (String) message.getPayload());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
package com.baeldung.si.security;
|
||||||
|
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.integration.annotation.ServiceActivator;
|
||||||
|
import org.springframework.integration.channel.DirectChannel;
|
||||||
|
import org.springframework.integration.config.EnableIntegration;
|
||||||
|
import org.springframework.integration.security.channel.ChannelSecurityInterceptor;
|
||||||
|
import org.springframework.integration.security.channel.SecuredChannel;
|
||||||
|
import org.springframework.messaging.Message;
|
||||||
|
import org.springframework.security.access.AccessDecisionManager;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableIntegration
|
||||||
|
public class SecuredDirectChannel {
|
||||||
|
|
||||||
|
@Bean(name = "startDirectChannel")
|
||||||
|
@SecuredChannel(interceptor = "channelSecurityInterceptor", sendAccess = { "ROLE_VIEWER", "jane" })
|
||||||
|
public DirectChannel startDirectChannel() {
|
||||||
|
return new DirectChannel();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ServiceActivator(inputChannel = "startDirectChannel", outputChannel = "endDirectChannel")
|
||||||
|
@PreAuthorize("hasRole('ROLE_LOGGER')")
|
||||||
|
public Message<?> logMessage(Message<?> message) {
|
||||||
|
Logger.getAnonymousLogger().info(message.toString());
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean(name = "endDirectChannel")
|
||||||
|
@SecuredChannel(interceptor = "channelSecurityInterceptor", sendAccess = { "ROLE_EDITOR" })
|
||||||
|
public DirectChannel endDirectChannel() {
|
||||||
|
return new DirectChannel();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@Bean
|
||||||
|
public ChannelSecurityInterceptor channelSecurityInterceptor(AuthenticationManager authenticationManager, AccessDecisionManager customAccessDecisionManager) {
|
||||||
|
ChannelSecurityInterceptor channelSecurityInterceptor = new ChannelSecurityInterceptor();
|
||||||
|
channelSecurityInterceptor.setAuthenticationManager(authenticationManager);
|
||||||
|
channelSecurityInterceptor.setAccessDecisionManager(customAccessDecisionManager);
|
||||||
|
return channelSecurityInterceptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
package com.baeldung.si.security;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.integration.security.channel.ChannelSecurityInterceptor;
|
||||||
|
import org.springframework.security.access.AccessDecisionManager;
|
||||||
|
import org.springframework.security.access.AccessDecisionVoter;
|
||||||
|
import org.springframework.security.access.vote.AffirmativeBased;
|
||||||
|
import org.springframework.security.access.vote.RoleVoter;
|
||||||
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
|
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
||||||
|
import org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||||
|
public class SecurityConfig extends GlobalMethodSecurityConfiguration {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Bean
|
||||||
|
public AuthenticationManager authenticationManager() throws Exception {
|
||||||
|
return super.authenticationManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public AccessDecisionManager customAccessDecisionManager() {
|
||||||
|
List<AccessDecisionVoter<? extends Object>> decisionVoters = new ArrayList<>();
|
||||||
|
decisionVoters.add(new RoleVoter());
|
||||||
|
decisionVoters.add(new UsernameAccessDecisionVoter());
|
||||||
|
AccessDecisionManager accessDecisionManager = new AffirmativeBased(decisionVoters);
|
||||||
|
return accessDecisionManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@Bean
|
||||||
|
public ChannelSecurityInterceptor channelSecurityInterceptor(AuthenticationManager authenticationManager, AccessDecisionManager customAccessDecisionManager) {
|
||||||
|
ChannelSecurityInterceptor channelSecurityInterceptor = new ChannelSecurityInterceptor();
|
||||||
|
channelSecurityInterceptor.setAuthenticationManager(authenticationManager);
|
||||||
|
channelSecurityInterceptor.setAccessDecisionManager(customAccessDecisionManager);
|
||||||
|
return channelSecurityInterceptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,82 @@
|
|||||||
|
package com.baeldung.si.security;
|
||||||
|
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.integration.annotation.ServiceActivator;
|
||||||
|
import org.springframework.integration.channel.DirectChannel;
|
||||||
|
import org.springframework.integration.channel.PublishSubscribeChannel;
|
||||||
|
import org.springframework.integration.config.EnableIntegration;
|
||||||
|
import org.springframework.integration.config.GlobalChannelInterceptor;
|
||||||
|
import org.springframework.integration.security.channel.SecuredChannel;
|
||||||
|
import org.springframework.integration.security.channel.SecurityContextPropagationChannelInterceptor;
|
||||||
|
import org.springframework.integration.support.DefaultMessageBuilderFactory;
|
||||||
|
import org.springframework.integration.support.MessageBuilder;
|
||||||
|
import org.springframework.messaging.Message;
|
||||||
|
import org.springframework.messaging.support.ChannelInterceptor;
|
||||||
|
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.security.core.context.SecurityContext;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableIntegration
|
||||||
|
public class SecurityPubSubChannel {
|
||||||
|
|
||||||
|
@Bean(name = "startPSChannel")
|
||||||
|
@SecuredChannel(interceptor = "channelSecurityInterceptor", sendAccess = "ROLE_VIEWER")
|
||||||
|
public PublishSubscribeChannel startChannel() {
|
||||||
|
return new PublishSubscribeChannel(executor());
|
||||||
|
}
|
||||||
|
|
||||||
|
@ServiceActivator(inputChannel = "startPSChannel", outputChannel = "finalPSResult")
|
||||||
|
@PreAuthorize("hasRole('ROLE_LOGGER')")
|
||||||
|
public Message<?> changeMessageToRole(Message<?> message) {
|
||||||
|
return buildNewMessage(getRoles(), message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ServiceActivator(inputChannel = "startPSChannel", outputChannel = "finalPSResult")
|
||||||
|
@PreAuthorize("hasRole('ROLE_VIEWER')")
|
||||||
|
public Message<?> changeMessageToUserName(Message<?> message) {
|
||||||
|
return buildNewMessage(getUsername(), message);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean(name = "finalPSResult")
|
||||||
|
public DirectChannel finalPSResult() {
|
||||||
|
return new DirectChannel();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@GlobalChannelInterceptor(patterns = { "startPSChannel", "endDirectChannel" })
|
||||||
|
public ChannelInterceptor securityContextPropagationInterceptor() {
|
||||||
|
return new SecurityContextPropagationChannelInterceptor();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ThreadPoolTaskExecutor executor() {
|
||||||
|
ThreadPoolTaskExecutor pool = new ThreadPoolTaskExecutor();
|
||||||
|
pool.setCorePoolSize(10);
|
||||||
|
pool.setMaxPoolSize(10);
|
||||||
|
pool.setWaitForTasksToCompleteOnShutdown(true);
|
||||||
|
return pool;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRoles() {
|
||||||
|
SecurityContext securityContext = SecurityContextHolder.getContext();
|
||||||
|
return securityContext.getAuthentication().getAuthorities().stream().map(auth -> auth.getAuthority()).collect(Collectors.joining(","));
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
SecurityContext securityContext = SecurityContextHolder.getContext();
|
||||||
|
return securityContext.getAuthentication().getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Message<String> buildNewMessage(String content, Message<?> message) {
|
||||||
|
DefaultMessageBuilderFactory builderFactory = new DefaultMessageBuilderFactory();
|
||||||
|
MessageBuilder<String> messageBuilder = builderFactory.withPayload(content);
|
||||||
|
messageBuilder.copyHeaders(message.getHeaders());
|
||||||
|
return messageBuilder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
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