commit
1f45a316cc
|
@ -43,3 +43,4 @@ spring-call-getters-using-reflection/.mvn/wrapper/maven-wrapper.properties
|
|||
spring-check-if-a-property-is-null/.mvn/wrapper/maven-wrapper.properties
|
||||
*.springBeans
|
||||
|
||||
20171220-JMeter.csv
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
package com.baeldung.algorithms.maze.solver;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
public class BFSMazeSolver {
|
||||
private static final int[][] DIRECTIONS = { { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, 0 } };
|
||||
|
||||
public List<Coordinate> solve(Maze maze) {
|
||||
LinkedList<Coordinate> nextToVisit = new LinkedList<>();
|
||||
Coordinate start = maze.getEntry();
|
||||
nextToVisit.add(start);
|
||||
|
||||
while (!nextToVisit.isEmpty()) {
|
||||
Coordinate cur = nextToVisit.remove();
|
||||
|
||||
if (!maze.isValidLocation(cur.getX(), cur.getY()) || maze.isExplored(cur.getX(), cur.getY())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (maze.isWall(cur.getX(), cur.getY())) {
|
||||
maze.setVisited(cur.getX(), cur.getY(), true);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (maze.isExit(cur.getX(), cur.getY())) {
|
||||
return backtrackPath(cur);
|
||||
}
|
||||
|
||||
for (int[] direction : DIRECTIONS) {
|
||||
Coordinate coordinate = new Coordinate(cur.getX() + direction[0], cur.getY() + direction[1], cur);
|
||||
nextToVisit.add(coordinate);
|
||||
maze.setVisited(cur.getX(), cur.getY(), true);
|
||||
}
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private List<Coordinate> backtrackPath(Coordinate cur) {
|
||||
List<Coordinate> path = new ArrayList<>();
|
||||
Coordinate iter = cur;
|
||||
|
||||
while (iter != null) {
|
||||
path.add(iter);
|
||||
iter = iter.parent;
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package com.baeldung.algorithms.maze.solver;
|
||||
|
||||
public class Coordinate {
|
||||
int x;
|
||||
int y;
|
||||
Coordinate parent;
|
||||
|
||||
public Coordinate(int x, int y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.parent = null;
|
||||
}
|
||||
|
||||
public Coordinate(int x, int y, Coordinate parent) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
int getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
int getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
Coordinate getParent() {
|
||||
return parent;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package com.baeldung.algorithms.maze.solver;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class DFSMazeSolver {
|
||||
private static final int[][] DIRECTIONS = { { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, 0 } };
|
||||
|
||||
public List<Coordinate> solve(Maze maze) {
|
||||
List<Coordinate> path = new ArrayList<>();
|
||||
if (explore(maze, maze.getEntry()
|
||||
.getX(),
|
||||
maze.getEntry()
|
||||
.getY(),
|
||||
path)) {
|
||||
return path;
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private boolean explore(Maze maze, int row, int col, List<Coordinate> path) {
|
||||
if (!maze.isValidLocation(row, col) || maze.isWall(row, col) || maze.isExplored(row, col)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
path.add(new Coordinate(row, col));
|
||||
maze.setVisited(row, col, true);
|
||||
|
||||
if (maze.isExit(row, col)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (int[] direction : DIRECTIONS) {
|
||||
Coordinate coordinate = getNextCoordinate(row, col, direction[0], direction[1]);
|
||||
if (explore(maze, coordinate.getX(), coordinate.getY(), path)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
path.remove(path.size() - 1);
|
||||
return false;
|
||||
}
|
||||
|
||||
private Coordinate getNextCoordinate(int row, int col, int i, int j) {
|
||||
return new Coordinate(row + i, col + j);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,141 @@
|
|||
package com.baeldung.algorithms.maze.solver;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Scanner;
|
||||
|
||||
public class Maze {
|
||||
private static final int ROAD = 0;
|
||||
private static final int WALL = 1;
|
||||
private static final int START = 2;
|
||||
private static final int EXIT = 3;
|
||||
private static final int PATH = 4;
|
||||
|
||||
private int[][] maze;
|
||||
private boolean[][] visited;
|
||||
private Coordinate start;
|
||||
private Coordinate end;
|
||||
|
||||
public Maze(File maze) throws FileNotFoundException {
|
||||
String fileText = "";
|
||||
try (Scanner input = new Scanner(maze)) {
|
||||
while (input.hasNextLine()) {
|
||||
fileText += input.nextLine() + "\n";
|
||||
}
|
||||
}
|
||||
initializeMaze(fileText);
|
||||
}
|
||||
|
||||
private void initializeMaze(String text) {
|
||||
if (text == null || (text = text.trim()).length() == 0) {
|
||||
throw new IllegalArgumentException("empty lines data");
|
||||
}
|
||||
|
||||
String[] lines = text.split("[\r]?\n");
|
||||
maze = new int[lines.length][lines[0].length()];
|
||||
visited = new boolean[lines.length][lines[0].length()];
|
||||
|
||||
for (int row = 0; row < getHeight(); row++) {
|
||||
if (lines[row].length() != getWidth()) {
|
||||
throw new IllegalArgumentException("line " + (row + 1) + " wrong length (was " + lines[row].length() + " but should be " + getWidth() + ")");
|
||||
}
|
||||
|
||||
for (int col = 0; col < getWidth(); col++) {
|
||||
if (lines[row].charAt(col) == '#')
|
||||
maze[row][col] = WALL;
|
||||
else if (lines[row].charAt(col) == 'S') {
|
||||
maze[row][col] = START;
|
||||
start = new Coordinate(row, col);
|
||||
} else if (lines[row].charAt(col) == 'E') {
|
||||
maze[row][col] = EXIT;
|
||||
end = new Coordinate(row, col);
|
||||
} else
|
||||
maze[row][col] = ROAD;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
return maze.length;
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
return maze[0].length;
|
||||
}
|
||||
|
||||
public Coordinate getEntry() {
|
||||
return start;
|
||||
}
|
||||
|
||||
public Coordinate getExit() {
|
||||
return end;
|
||||
}
|
||||
|
||||
public boolean isExit(int x, int y) {
|
||||
return x == end.getX() && y == end.getY();
|
||||
}
|
||||
|
||||
public boolean isStart(int x, int y) {
|
||||
return x == start.getX() && y == start.getY();
|
||||
}
|
||||
|
||||
public boolean isExplored(int row, int col) {
|
||||
return visited[row][col];
|
||||
}
|
||||
|
||||
public boolean isWall(int row, int col) {
|
||||
return maze[row][col] == WALL;
|
||||
}
|
||||
|
||||
public void setVisited(int row, int col, boolean value) {
|
||||
visited[row][col] = value;
|
||||
}
|
||||
|
||||
public boolean isValidLocation(int row, int col) {
|
||||
if (row < 0 || row >= getHeight() || col < 0 || col >= getWidth()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void printPath(List<Coordinate> path) {
|
||||
int[][] tempMaze = Arrays.stream(maze)
|
||||
.map(int[]::clone)
|
||||
.toArray(int[][]::new);
|
||||
for (Coordinate coordinate : path) {
|
||||
if (isStart(coordinate.getX(), coordinate.getY()) || isExit(coordinate.getX(), coordinate.getY())) {
|
||||
continue;
|
||||
}
|
||||
tempMaze[coordinate.getX()][coordinate.getY()] = PATH;
|
||||
}
|
||||
System.out.println(toString(tempMaze));
|
||||
}
|
||||
|
||||
public String toString(int[][] maze) {
|
||||
StringBuilder result = new StringBuilder(getWidth() * (getHeight() + 1));
|
||||
for (int row = 0; row < getHeight(); row++) {
|
||||
for (int col = 0; col < getWidth(); col++) {
|
||||
if (maze[row][col] == ROAD) {
|
||||
result.append(' ');
|
||||
} else if (maze[row][col] == WALL) {
|
||||
result.append('#');
|
||||
} else if (maze[row][col] == START) {
|
||||
result.append('S');
|
||||
} else if (maze[row][col] == EXIT) {
|
||||
result.append('E');
|
||||
} else {
|
||||
result.append('.');
|
||||
}
|
||||
}
|
||||
result.append('\n');
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
for (int i = 0; i < visited.length; i++)
|
||||
Arrays.fill(visited[i], false);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package com.baeldung.algorithms.maze.solver;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
public class MazeDriver {
|
||||
public static void main(String[] args) throws Exception {
|
||||
File maze1 = new File("src/main/resources/maze/maze1.txt");
|
||||
File maze2 = new File("src/main/resources/maze/maze2.txt");
|
||||
|
||||
execute(maze1);
|
||||
execute(maze2);
|
||||
}
|
||||
|
||||
private static void execute(File file) throws Exception {
|
||||
Maze maze = new Maze(file);
|
||||
dfs(maze);
|
||||
bfs(maze);
|
||||
}
|
||||
|
||||
private static void bfs(Maze maze) {
|
||||
BFSMazeSolver bfs = new BFSMazeSolver();
|
||||
List<Coordinate> path = bfs.solve(maze);
|
||||
maze.printPath(path);
|
||||
maze.reset();
|
||||
}
|
||||
|
||||
private static void dfs(Maze maze) {
|
||||
DFSMazeSolver dfs = new DFSMazeSolver();
|
||||
List<Coordinate> path = dfs.solve(maze);
|
||||
maze.printPath(path);
|
||||
maze.reset();
|
||||
}
|
||||
}
|
|
@ -40,15 +40,15 @@ public class BacktrackingAlgorithm {
|
|||
}
|
||||
|
||||
private boolean solve(int[][] board) {
|
||||
for (int r = BOARD_START_INDEX; r < BOARD_SIZE; r++) {
|
||||
for (int c = BOARD_START_INDEX; c < BOARD_SIZE; c++) {
|
||||
if (board[r][c] == NO_VALUE) {
|
||||
for (int row = BOARD_START_INDEX; row < BOARD_SIZE; row++) {
|
||||
for (int column = BOARD_START_INDEX; column < BOARD_SIZE; column++) {
|
||||
if (board[row][column] == NO_VALUE) {
|
||||
for (int k = MIN_VALUE; k <= MAX_VALUE; k++) {
|
||||
board[r][c] = k;
|
||||
if (isValid(board, r, c) && solve(board)) {
|
||||
board[row][column] = k;
|
||||
if (isValid(board, row, column) && solve(board)) {
|
||||
return true;
|
||||
}
|
||||
board[r][c] = NO_VALUE;
|
||||
board[row][column] = NO_VALUE;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -57,48 +57,48 @@ public class BacktrackingAlgorithm {
|
|||
return true;
|
||||
}
|
||||
|
||||
private boolean isValid(int[][] board, int r, int c) {
|
||||
return rowConstraint(board, r) &&
|
||||
columnConstraint(board, c) &&
|
||||
subsectionConstraint(board, r, c);
|
||||
private boolean isValid(int[][] board, int row, int column) {
|
||||
return rowConstraint(board, row) &&
|
||||
columnConstraint(board, column) &&
|
||||
subsectionConstraint(board, row, column);
|
||||
}
|
||||
|
||||
private boolean subsectionConstraint(int[][] board, int r, int c) {
|
||||
private boolean subsectionConstraint(int[][] board, int row, int column) {
|
||||
boolean[] constraint = new boolean[BOARD_SIZE];
|
||||
int subsectionRowStart = (r / SUBSECTION_SIZE) * SUBSECTION_SIZE;
|
||||
int subsectionRowStart = (row / SUBSECTION_SIZE) * SUBSECTION_SIZE;
|
||||
int subsectionRowEnd = subsectionRowStart + SUBSECTION_SIZE;
|
||||
|
||||
int subsectionColumnStart = (c / SUBSECTION_SIZE) * SUBSECTION_SIZE;
|
||||
int subsectionColumnStart = (column / SUBSECTION_SIZE) * SUBSECTION_SIZE;
|
||||
int subsectionColumnEnd = subsectionColumnStart + SUBSECTION_SIZE;
|
||||
|
||||
for (int i = subsectionRowStart; i < subsectionRowEnd; i++) {
|
||||
for (int j = subsectionColumnStart; j < subsectionColumnEnd; j++) {
|
||||
if (!checkConstraint(board, i, constraint, j)) return false;
|
||||
for (int r = subsectionRowStart; r < subsectionRowEnd; r++) {
|
||||
for (int c = subsectionColumnStart; c < subsectionColumnEnd; c++) {
|
||||
if (!checkConstraint(board, r, constraint, c)) return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean columnConstraint(int[][] board, int c) {
|
||||
private boolean columnConstraint(int[][] board, int column) {
|
||||
boolean[] constraint = new boolean[BOARD_SIZE];
|
||||
return IntStream.range(BOARD_START_INDEX, BOARD_SIZE)
|
||||
.allMatch(i -> checkConstraint(board, i, constraint, c));
|
||||
.allMatch(row -> checkConstraint(board, row, constraint, column));
|
||||
}
|
||||
|
||||
private boolean rowConstraint(int[][] board, int r) {
|
||||
private boolean rowConstraint(int[][] board, int row) {
|
||||
boolean[] constraint = new boolean[BOARD_SIZE];
|
||||
return IntStream.range(BOARD_START_INDEX, BOARD_SIZE)
|
||||
.allMatch(i -> checkConstraint(board, r, constraint, i));
|
||||
.allMatch(column -> checkConstraint(board, row, constraint, column));
|
||||
}
|
||||
|
||||
private boolean checkConstraint(int[][] board, int r, boolean[] constraint, int c) {
|
||||
if (board[r][c] != NO_VALUE) {
|
||||
if (!constraint[board[r][c] - 1]) {
|
||||
constraint[board[r][c] - 1] = true;
|
||||
private boolean checkConstraint(int[][] board, int row, boolean[] constraint, int column) {
|
||||
if (board[row][column] != NO_VALUE) {
|
||||
if (!constraint[board[row][column] - 1]) {
|
||||
constraint[board[row][column] - 1] = true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -120,10 +120,10 @@ public class DancingLinks {
|
|||
}
|
||||
|
||||
private static void printSolution(int[][] result) {
|
||||
int N = result.length;
|
||||
int size = result.length;
|
||||
for (int[] aResult : result) {
|
||||
StringBuilder ret = new StringBuilder();
|
||||
for (int j = 0; j < N; j++) {
|
||||
for (int j = 0; j < size; j++) {
|
||||
ret.append(aResult[j]).append(" ");
|
||||
}
|
||||
System.out.println(ret);
|
||||
|
|
|
@ -34,75 +34,88 @@ public class DancingLinksAlgorithm {
|
|||
dlx.runSolver();
|
||||
}
|
||||
|
||||
private int getIndex(int row, int col, int num) {
|
||||
return (row - 1) * BOARD_SIZE * BOARD_SIZE + (col - 1) * BOARD_SIZE + (num - 1);
|
||||
private int getIndex(int row, int column, int num) {
|
||||
return (row - 1) * BOARD_SIZE * BOARD_SIZE + (column - 1) * BOARD_SIZE + (num - 1);
|
||||
}
|
||||
|
||||
private boolean[][] createExactCoverBoard() {
|
||||
boolean[][] R = new boolean[BOARD_SIZE * BOARD_SIZE * MAX_VALUE][BOARD_SIZE * BOARD_SIZE * CONSTRAINTS];
|
||||
boolean[][] coverBoard = new boolean[BOARD_SIZE * BOARD_SIZE * MAX_VALUE][BOARD_SIZE * BOARD_SIZE * CONSTRAINTS];
|
||||
|
||||
int hBase = 0;
|
||||
hBase = checkCellConstraint(coverBoard, hBase);
|
||||
hBase = checkRowConstraint(coverBoard, hBase);
|
||||
hBase = checkColumnConstraint(coverBoard, hBase);
|
||||
checkSubsectionConstraint(coverBoard, hBase);
|
||||
|
||||
return coverBoard;
|
||||
}
|
||||
|
||||
// Cell constraint.
|
||||
for (int r = COVER_START_INDEX; r <= BOARD_SIZE; r++) {
|
||||
for (int c = COVER_START_INDEX; c <= BOARD_SIZE; c++, hBase++) {
|
||||
for (int n = COVER_START_INDEX; n <= BOARD_SIZE; n++) {
|
||||
int index = getIndex(r, c, n);
|
||||
R[index][hBase] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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 bc = COVER_START_INDEX; bc <= BOARD_SIZE; bc += SUBSECTION_SIZE) {
|
||||
private int checkSubsectionConstraint(boolean[][] coverBoard, int hBase) {
|
||||
for (int row = COVER_START_INDEX; row <= BOARD_SIZE; row += SUBSECTION_SIZE) {
|
||||
for (int column = COVER_START_INDEX; column <= BOARD_SIZE; column += SUBSECTION_SIZE) {
|
||||
for (int n = COVER_START_INDEX; n <= BOARD_SIZE; n++, hBase++) {
|
||||
for (int rDelta = 0; rDelta < SUBSECTION_SIZE; rDelta++) {
|
||||
for (int cDelta = 0; cDelta < SUBSECTION_SIZE; cDelta++) {
|
||||
int index = getIndex(br + rDelta, bc + cDelta, n);
|
||||
R[index][hBase] = true;
|
||||
for (int rowDelta = 0; rowDelta < SUBSECTION_SIZE; rowDelta++) {
|
||||
for (int columnDelta = 0; columnDelta < SUBSECTION_SIZE; columnDelta++) {
|
||||
int index = getIndex(row + rowDelta, column + columnDelta, n);
|
||||
coverBoard[index][hBase] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return R;
|
||||
return hBase;
|
||||
}
|
||||
|
||||
private int checkColumnConstraint(boolean[][] coverBoard, int hBase) {
|
||||
for (int column = COVER_START_INDEX; column <= BOARD_SIZE; column++) {
|
||||
for (int n = COVER_START_INDEX; n <= BOARD_SIZE; n++, hBase++) {
|
||||
for (int row = COVER_START_INDEX; row <= BOARD_SIZE; row++) {
|
||||
int index = getIndex(row, column, n);
|
||||
coverBoard[index][hBase] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return hBase;
|
||||
}
|
||||
|
||||
private int checkRowConstraint(boolean[][] coverBoard, int hBase) {
|
||||
for (int row = COVER_START_INDEX; row <= BOARD_SIZE; row++) {
|
||||
for (int n = COVER_START_INDEX; n <= BOARD_SIZE; n++, hBase++) {
|
||||
for (int column = COVER_START_INDEX; column <= BOARD_SIZE; column++) {
|
||||
int index = getIndex(row, column, n);
|
||||
coverBoard[index][hBase] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return hBase;
|
||||
}
|
||||
|
||||
private int checkCellConstraint(boolean[][] coverBoard, int hBase) {
|
||||
for (int row = COVER_START_INDEX; row <= BOARD_SIZE; row++) {
|
||||
for (int column = COVER_START_INDEX; column <= BOARD_SIZE; column++, hBase++) {
|
||||
for (int n = COVER_START_INDEX; n <= BOARD_SIZE; n++) {
|
||||
int index = getIndex(row, column, n);
|
||||
coverBoard[index][hBase] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return hBase;
|
||||
}
|
||||
|
||||
private boolean[][] initializeExactCoverBoard(int[][] board) {
|
||||
boolean[][] R = createExactCoverBoard();
|
||||
for (int i = COVER_START_INDEX; i <= BOARD_SIZE; i++) {
|
||||
for (int j = COVER_START_INDEX; j <= BOARD_SIZE; j++) {
|
||||
int n = board[i - 1][j - 1];
|
||||
boolean[][] coverBoard = createExactCoverBoard();
|
||||
for (int row = COVER_START_INDEX; row <= BOARD_SIZE; row++) {
|
||||
for (int column = COVER_START_INDEX; column <= BOARD_SIZE; column++) {
|
||||
int n = board[row - 1][column - 1];
|
||||
if (n != NO_VALUE) {
|
||||
for (int num = MIN_VALUE; num <= MAX_VALUE; num++) {
|
||||
if (num != n) {
|
||||
Arrays.fill(R[getIndex(i, j, num)], false);
|
||||
Arrays.fill(coverBoard[getIndex(row, column, num)], false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return R;
|
||||
return coverBoard;
|
||||
}
|
||||
}
|
|
@ -4,21 +4,21 @@ class DancingNode {
|
|||
DancingNode L, R, U, D;
|
||||
ColumnNode C;
|
||||
|
||||
DancingNode hookDown(DancingNode n1) {
|
||||
assert (this.C == n1.C);
|
||||
n1.D = this.D;
|
||||
n1.D.U = n1;
|
||||
n1.U = this;
|
||||
this.D = n1;
|
||||
return n1;
|
||||
DancingNode hookDown(DancingNode node) {
|
||||
assert (this.C == node.C);
|
||||
node.D = this.D;
|
||||
node.D.U = node;
|
||||
node.U = this;
|
||||
this.D = node;
|
||||
return node;
|
||||
}
|
||||
|
||||
DancingNode hookRight(DancingNode n1) {
|
||||
n1.R = this.R;
|
||||
n1.R.L = n1;
|
||||
n1.L = this;
|
||||
this.R = n1;
|
||||
return n1;
|
||||
DancingNode hookRight(DancingNode node) {
|
||||
node.R = this.R;
|
||||
node.R.L = node;
|
||||
node.L = this;
|
||||
this.R = node;
|
||||
return node;
|
||||
}
|
||||
|
||||
void unlinkLR() {
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
S ########
|
||||
# #
|
||||
# ### ## #
|
||||
# # # #
|
||||
# # # # #
|
||||
# ## #####
|
||||
# # #
|
||||
# # # # #
|
||||
##### ####
|
||||
# # E
|
||||
# # # #
|
||||
##########
|
|
@ -0,0 +1,22 @@
|
|||
S ##########################
|
||||
# # # #
|
||||
# # #### ############### #
|
||||
# # # # # #
|
||||
# # #### # # ###############
|
||||
# # # # # # #
|
||||
# # # #### ### ########### #
|
||||
# # # # # #
|
||||
# ################## #
|
||||
######### # # # # #
|
||||
# # #### # ####### # #
|
||||
# # ### ### # # # # #
|
||||
# # ## # ##### # #
|
||||
##### ####### # # # # #
|
||||
# # ## ## #### # #
|
||||
# ##### ####### # #
|
||||
# # ############
|
||||
####### ######### # #
|
||||
# # ######## #
|
||||
# ####### ###### ## # E
|
||||
# # # ## #
|
||||
############################
|
|
@ -0,0 +1,70 @@
|
|||
package com.baeldung.shufflingcollections;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class ShufflingCollectionsUnitTest {
|
||||
|
||||
@Test
|
||||
public void whenShufflingList_thenListIsShuffled() {
|
||||
List<String> students = Arrays.asList("Foo", "Bar", "Baz", "Qux");
|
||||
|
||||
System.out.println("List before shuffling:");
|
||||
System.out.println(students);
|
||||
|
||||
Collections.shuffle(students);
|
||||
System.out.println("List after shuffling:");
|
||||
System.out.println(students);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenShufflingMapKeys_thenValuesAreShuffled() {
|
||||
Map<Integer, String> studentsById = new HashMap<>();
|
||||
studentsById.put(1, "Foo");
|
||||
studentsById.put(2, "Bar");
|
||||
studentsById.put(3, "Baz");
|
||||
studentsById.put(4, "Qux");
|
||||
|
||||
System.out.println("Students before shuffling:");
|
||||
System.out.println(studentsById.values());
|
||||
|
||||
List<Integer> shuffledStudentIds = new ArrayList<>(studentsById.keySet());
|
||||
Collections.shuffle(shuffledStudentIds);
|
||||
|
||||
List<String> shuffledStudents = shuffledStudentIds.stream()
|
||||
.map(id -> studentsById.get(id))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
System.out.println("Students after shuffling");
|
||||
System.out.println(shuffledStudents);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenShufflingSet_thenElementsAreShuffled() {
|
||||
Set<String> students = new HashSet<>(Arrays.asList("Foo", "Bar", "Baz", "Qux"));
|
||||
|
||||
System.out.println("Set before shuffling:");
|
||||
System.out.println(students);
|
||||
|
||||
List<String> studentList = new ArrayList<>(students);
|
||||
|
||||
Collections.shuffle(studentList);
|
||||
System.out.println("Shuffled set elements:");
|
||||
System.out.println(studentList);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenShufflingWithSameRandomness_thenElementsAreShuffledDeterministically() {
|
||||
List<String> students_1 = Arrays.asList("Foo", "Bar", "Baz", "Qux");
|
||||
List<String> students_2 = Arrays.asList("Foo", "Bar", "Baz", "Qux");
|
||||
|
||||
Collections.shuffle(students_1, new Random(5));
|
||||
Collections.shuffle(students_2, new Random(5));
|
||||
|
||||
assertThat(students_1).isEqualTo(students_2);
|
||||
}
|
||||
}
|
|
@ -1,126 +0,0 @@
|
|||
package com.baeldung.java9.httpclient;
|
||||
|
||||
import static java.net.HttpURLConnection.HTTP_OK;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.CookieManager;
|
||||
import java.net.CookiePolicy;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpHeaders;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLParameters;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
public class SimpleHttpRequestsUnitTest {
|
||||
|
||||
private URI httpURI;
|
||||
|
||||
@Before
|
||||
public void init() throws URISyntaxException {
|
||||
httpURI = new URI("http://www.baeldung.com/");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void quickGet() throws IOException, InterruptedException, URISyntaxException {
|
||||
HttpRequest request = HttpRequest.create(httpURI).GET();
|
||||
HttpResponse response = request.response();
|
||||
int responseStatusCode = response.statusCode();
|
||||
String responseBody = response.body(HttpResponse.asString());
|
||||
assertTrue("Get response status code is bigger then 400", responseStatusCode < 400);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void asynchronousGet() throws URISyntaxException, IOException, InterruptedException, ExecutionException {
|
||||
HttpRequest request = HttpRequest.create(httpURI).GET();
|
||||
long before = System.currentTimeMillis();
|
||||
CompletableFuture<HttpResponse> futureResponse = request.responseAsync();
|
||||
futureResponse.thenAccept(response -> {
|
||||
String responseBody = response.body(HttpResponse.asString());
|
||||
});
|
||||
HttpResponse resp = futureResponse.get();
|
||||
HttpHeaders hs = resp.headers();
|
||||
assertTrue("There should be more then 1 header.", hs.map().size() > 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postMehtod() throws URISyntaxException, IOException, InterruptedException {
|
||||
HttpRequest.Builder requestBuilder = HttpRequest.create(httpURI);
|
||||
requestBuilder.body(HttpRequest.fromString("param1=foo,param2=bar")).followRedirects(HttpClient.Redirect.SECURE);
|
||||
HttpRequest request = requestBuilder.POST();
|
||||
HttpResponse response = request.response();
|
||||
int statusCode = response.statusCode();
|
||||
assertTrue("HTTP return code", statusCode == HTTP_OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configureHttpClient() throws NoSuchAlgorithmException, URISyntaxException, IOException, InterruptedException {
|
||||
CookieManager cManager = new CookieManager();
|
||||
cManager.setCookiePolicy(CookiePolicy.ACCEPT_ORIGINAL_SERVER);
|
||||
|
||||
SSLParameters sslParam = new SSLParameters(new String[] { "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256" }, new String[] { "TLSv1.2" });
|
||||
|
||||
HttpClient.Builder hcBuilder = HttpClient.create();
|
||||
hcBuilder.cookieManager(cManager).sslContext(SSLContext.getDefault()).sslParameters(sslParam);
|
||||
HttpClient httpClient = hcBuilder.build();
|
||||
HttpRequest.Builder reqBuilder = httpClient.request(new URI("https://www.facebook.com"));
|
||||
|
||||
HttpRequest request = reqBuilder.followRedirects(HttpClient.Redirect.ALWAYS).GET();
|
||||
HttpResponse response = request.response();
|
||||
int statusCode = response.statusCode();
|
||||
assertTrue("HTTP return code", statusCode == HTTP_OK);
|
||||
}
|
||||
|
||||
SSLParameters getDefaultSSLParameters() throws NoSuchAlgorithmException {
|
||||
SSLParameters sslP1 = SSLContext.getDefault().getSupportedSSLParameters();
|
||||
String[] proto = sslP1.getApplicationProtocols();
|
||||
String[] cifers = sslP1.getCipherSuites();
|
||||
System.out.println(printStringArr(proto));
|
||||
System.out.println(printStringArr(cifers));
|
||||
return sslP1;
|
||||
}
|
||||
|
||||
String printStringArr(String... args) {
|
||||
if (args == null) {
|
||||
return null;
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (String s : args) {
|
||||
sb.append(s);
|
||||
sb.append("\n");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
String printHeaders(HttpHeaders h) {
|
||||
if (h == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
Map<String, List<String>> hMap = h.map();
|
||||
for (String k : hMap.keySet()) {
|
||||
sb.append(k).append(":");
|
||||
List<String> l = hMap.get(k);
|
||||
if (l != null) {
|
||||
l.forEach(s -> {
|
||||
sb.append(s).append(",");
|
||||
});
|
||||
}
|
||||
sb.append("\n");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
|
@ -16,7 +16,8 @@ public class Job implements Runnable {
|
|||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
System.out.println("Job:" + jobName + " Priority:" + jobPriority);
|
||||
System.out.println("Job:" + jobName +
|
||||
" Priority:" + jobPriority);
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException ignored) {
|
||||
}
|
||||
|
|
|
@ -9,21 +9,21 @@ import java.util.concurrent.TimeUnit;
|
|||
public class PriorityJobScheduler {
|
||||
|
||||
private ExecutorService priorityJobPoolExecutor;
|
||||
private ExecutorService priorityJobScheduler;
|
||||
private PriorityBlockingQueue<Runnable> priorityQueue;
|
||||
private ExecutorService priorityJobScheduler =
|
||||
Executors.newSingleThreadExecutor();
|
||||
private PriorityBlockingQueue<Job> priorityQueue;
|
||||
|
||||
public PriorityJobScheduler(Integer poolSize, Integer queueSize) {
|
||||
priorityJobPoolExecutor = Executors.newFixedThreadPool(poolSize);
|
||||
Comparator<? super Job> jobComparator = Comparator.comparing(Job::getJobPriority);
|
||||
priorityQueue = new PriorityBlockingQueue<Runnable>(queueSize,
|
||||
(Comparator<? super Runnable>) jobComparator);
|
||||
priorityQueue = new PriorityBlockingQueue<Job>(queueSize,
|
||||
Comparator.comparing(Job::getJobPriority));
|
||||
|
||||
priorityJobScheduler = Executors.newSingleThreadExecutor();
|
||||
priorityJobScheduler.execute(()->{
|
||||
while (true) {
|
||||
try {
|
||||
priorityJobPoolExecutor.execute(priorityQueue.take());
|
||||
} catch (InterruptedException e) {
|
||||
// exception needs special handling
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
package com.baeldung.concurrent.threadlifecycle;
|
||||
|
||||
public class BlockedState {
|
||||
public static void main(String[] args) throws InterruptedException {
|
||||
Thread t1 = new Thread(new DemoThreadB());
|
||||
Thread t2 = new Thread(new DemoThreadB());
|
||||
|
||||
t1.start();
|
||||
t2.start();
|
||||
|
||||
Thread.sleep(1000);
|
||||
|
||||
System.out.println(t2.getState());
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
class DemoThreadB implements Runnable {
|
||||
@Override
|
||||
public void run() {
|
||||
commonResource();
|
||||
}
|
||||
|
||||
public static synchronized void commonResource() {
|
||||
while(true) {
|
||||
// Infinite loop to mimic heavy processing
|
||||
// Thread 't1' won't leave this method
|
||||
// when Thread 't2' enters this
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package com.baeldung.concurrent.threadlifecycle;
|
||||
|
||||
public class NewState implements Runnable {
|
||||
public static void main(String[] args) {
|
||||
Runnable runnable = new NewState();
|
||||
Thread t = new Thread(runnable);
|
||||
System.out.println(t.getState());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package com.baeldung.concurrent.threadlifecycle;
|
||||
|
||||
public class RunnableState implements Runnable {
|
||||
public static void main(String[] args) {
|
||||
Runnable runnable = new NewState();
|
||||
Thread t = new Thread(runnable);
|
||||
t.start();
|
||||
System.out.println(t.getState());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package com.baeldung.concurrent.threadlifecycle;
|
||||
|
||||
public class TerminatedState implements Runnable {
|
||||
public static void main(String[] args) throws InterruptedException {
|
||||
Thread t1 = new Thread(new TerminatedState());
|
||||
t1.start();
|
||||
Thread.sleep(1000);
|
||||
System.out.println(t1.getState());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
// No processing in this block
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package com.baeldung.concurrent.threadlifecycle;
|
||||
|
||||
public class TimedWaitingState {
|
||||
public static void main(String[] args) throws InterruptedException {
|
||||
DemoThread obj1 = new DemoThread();
|
||||
Thread t1 = new Thread(obj1);
|
||||
t1.start();
|
||||
// The following sleep will give enough time for ThreadScheduler
|
||||
// to start processing of thread t1
|
||||
Thread.sleep(1000);
|
||||
System.out.println(t1.getState());
|
||||
}
|
||||
}
|
||||
|
||||
class DemoThread implements Runnable {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Thread.sleep(5000);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package com.baeldung.concurrent.threadlifecycle;
|
||||
|
||||
public class WaitingState implements Runnable {
|
||||
public static Thread t1;
|
||||
|
||||
public static void main(String[] args) {
|
||||
t1 = new Thread(new WaitingState());
|
||||
t1.start();
|
||||
}
|
||||
|
||||
public void run() {
|
||||
Thread t2 = new Thread(new DemoThreadWS());
|
||||
t2.start();
|
||||
|
||||
try {
|
||||
t2.join();
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class DemoThreadWS implements Runnable {
|
||||
public void run() {
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
System.out.println(WaitingState.t1.getState());
|
||||
}
|
||||
}
|
|
@ -30,7 +30,9 @@ public class PriorityJobSchedulerUnitTest {
|
|||
// delay to avoid job sleep (added for demo) being interrupted
|
||||
try {
|
||||
Thread.sleep(2000);
|
||||
} catch (InterruptedException ignored) {
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
pjs.closeScheduler();
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
package com.baeldung.methodoverloadingoverriding.application;
|
||||
|
||||
import com.baeldung.methodoverloadingoverriding.model.Car;
|
||||
import com.baeldung.methodoverloadingoverriding.model.Vehicle;
|
||||
import com.baeldung.methodoverloadingoverriding.util.Multiplier;
|
||||
|
||||
public class Application {
|
||||
|
||||
public static void main(String[] args) {
|
||||
Multiplier multiplier = new Multiplier();
|
||||
System.out.println(multiplier.multiply(10, 10));
|
||||
System.out.println(multiplier.multiply(10, 10, 10));
|
||||
System.out.println(multiplier.multiply(10, 10.5));
|
||||
System.out.println(multiplier.multiply(10.5, 10.5));
|
||||
|
||||
Vehicle vehicle = new Vehicle();
|
||||
System.out.println(vehicle.accelerate(100));
|
||||
System.out.println(vehicle.run());
|
||||
System.out.println(vehicle.stop());
|
||||
|
||||
Vehicle car = new Car();
|
||||
System.out.println(car.accelerate(80));
|
||||
System.out.println(car.run());
|
||||
System.out.println(car.stop());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package com.baeldung.methodoverloadingoverriding.model;
|
||||
|
||||
public class Car extends Vehicle {
|
||||
|
||||
@Override
|
||||
public String accelerate(long mph) {
|
||||
return "The car accelerates at : " + mph + " MPH.";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package com.baeldung.methodoverloadingoverriding.model;
|
||||
|
||||
public class Vehicle {
|
||||
|
||||
public String accelerate(long mph) {
|
||||
return "The vehicle accelerates at : " + mph + " MPH.";
|
||||
}
|
||||
|
||||
public String stop() {
|
||||
return "The vehicle has stopped.";
|
||||
}
|
||||
|
||||
public String run() {
|
||||
return "The vehicle is running.";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package com.baeldung.methodoverloadingoverriding.util;
|
||||
|
||||
public class Multiplier {
|
||||
|
||||
public int multiply(int a, int b) {
|
||||
return a * b;
|
||||
}
|
||||
|
||||
public int multiply(int a, int b, int c) {
|
||||
return a * b * c;
|
||||
}
|
||||
|
||||
public double multiply(double a, double b) {
|
||||
return a * b;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
package com.baeldung.string;
|
||||
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
public class Palindrome {
|
||||
|
||||
public boolean isPalindrome(String text) {
|
||||
String clean = text.replaceAll("\\s+", "").toLowerCase();
|
||||
int length = clean.length();
|
||||
int forward = 0;
|
||||
int backward = length - 1;
|
||||
while (backward > forward) {
|
||||
char forwardChar = clean.charAt(forward++);
|
||||
char backwardChar = clean.charAt(backward--);
|
||||
if (forwardChar != backwardChar)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isPalindromeReverseTheString(String text) {
|
||||
StringBuilder reverse = new StringBuilder();
|
||||
String clean = text.replaceAll("\\s+", "").toLowerCase();
|
||||
char[] plain = clean.toCharArray();
|
||||
for (int i = plain.length - 1; i >= 0; i--)
|
||||
reverse.append(plain[i]);
|
||||
return (reverse.toString()).equals(clean);
|
||||
}
|
||||
|
||||
public boolean isPalindromeUsingStringBuilder(String text) {
|
||||
String clean = text.replaceAll("\\s+", "").toLowerCase();
|
||||
StringBuilder plain = new StringBuilder(clean);
|
||||
StringBuilder reverse = plain.reverse();
|
||||
return (reverse.toString()).equals(clean);
|
||||
}
|
||||
|
||||
public boolean isPalindromeUsingStringBuffer(String text) {
|
||||
String clean = text.replaceAll("\\s+", "").toLowerCase();
|
||||
StringBuffer plain = new StringBuffer(clean);
|
||||
StringBuffer reverse = plain.reverse();
|
||||
return (reverse.toString()).equals(clean);
|
||||
}
|
||||
|
||||
public boolean isPalindromeRecursive(String text) {
|
||||
String clean = text.replaceAll("\\s+", "").toLowerCase();
|
||||
return recursivePalindrome(clean, 0, clean.length() - 1);
|
||||
}
|
||||
|
||||
private boolean recursivePalindrome(String text, int forward, int backward) {
|
||||
if (forward == backward)
|
||||
return true;
|
||||
if ((text.charAt(forward)) != (text.charAt(backward)))
|
||||
return false;
|
||||
if (forward < backward + 1) {
|
||||
return recursivePalindrome(text, forward + 1, backward - 1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isPalindromeUsingIntStream(String text) {
|
||||
String temp = text.replaceAll("\\s+", "").toLowerCase();
|
||||
return IntStream.range(0, temp.length() / 2)
|
||||
.noneMatch(i -> temp.charAt(i) != temp.charAt(temp.length() - i - 1));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,116 @@
|
|||
package com.baeldung.decimalformat;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.DecimalFormatSymbols;
|
||||
import java.text.NumberFormat;
|
||||
import java.text.ParseException;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class DecimalFormatExamplesTest {
|
||||
|
||||
double d = 1234567.89;
|
||||
|
||||
@Test
|
||||
public void givenSimpleDecimal_WhenFormatting_ThenCorrectOutput() {
|
||||
|
||||
assertThat(new DecimalFormat("#.##", new DecimalFormatSymbols(Locale.ENGLISH)).format(d))
|
||||
.isEqualTo("1234567.89");
|
||||
|
||||
assertThat(new DecimalFormat("0.00", new DecimalFormatSymbols(Locale.ENGLISH)).format(d))
|
||||
.isEqualTo("1234567.89");
|
||||
|
||||
assertThat(new DecimalFormat("#########.###", new DecimalFormatSymbols(Locale.ENGLISH)).format(d))
|
||||
.isEqualTo("1234567.89");
|
||||
|
||||
assertThat(new DecimalFormat("000000000.000", new DecimalFormatSymbols(Locale.ENGLISH)).format(d))
|
||||
.isEqualTo("001234567.890");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenSmallerDecimalPattern_WhenFormatting_ThenRounding() {
|
||||
|
||||
assertThat(new DecimalFormat("#.#", new DecimalFormatSymbols(Locale.ENGLISH)).format(d)).isEqualTo("1234567.9");
|
||||
|
||||
assertThat(new DecimalFormat("#", new DecimalFormatSymbols(Locale.ENGLISH)).format(d)).isEqualTo("1234568");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenGroupingSeparator_WhenFormatting_ThenGroupedOutput() {
|
||||
|
||||
assertThat(new DecimalFormat("#,###.#", new DecimalFormatSymbols(Locale.ENGLISH)).format(d))
|
||||
.isEqualTo("1,234,567.9");
|
||||
|
||||
assertThat(new DecimalFormat("#,###", new DecimalFormatSymbols(Locale.ENGLISH)).format(d))
|
||||
.isEqualTo("1,234,568");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenMixedPattern_WhenFormatting_ThenCorrectOutput() {
|
||||
|
||||
assertThat(new DecimalFormat("The # number", new DecimalFormatSymbols(Locale.ENGLISH)).format(d))
|
||||
.isEqualTo("The 1234568 number");
|
||||
|
||||
assertThat(new DecimalFormat("The '#' # number", new DecimalFormatSymbols(Locale.ENGLISH)).format(d))
|
||||
.isEqualTo("The # 1234568 number");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenLocales_WhenFormatting_ThenCorrectOutput() {
|
||||
|
||||
assertThat(new DecimalFormat("#,###.##", new DecimalFormatSymbols(Locale.ENGLISH)).format(d))
|
||||
.isEqualTo("1,234,567.89");
|
||||
|
||||
assertThat(new DecimalFormat("#,###.##", new DecimalFormatSymbols(Locale.ITALIAN)).format(d))
|
||||
.isEqualTo("1.234.567,89");
|
||||
|
||||
assertThat(new DecimalFormat("#,###.##", DecimalFormatSymbols.getInstance(new Locale("it", "IT"))).format(d))
|
||||
.isEqualTo("1.234.567,89");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenE_WhenFormatting_ThenScientificNotation() {
|
||||
|
||||
assertThat(new DecimalFormat("00.#######E0", new DecimalFormatSymbols(Locale.ENGLISH)).format(d))
|
||||
.isEqualTo("12.3456789E5");
|
||||
|
||||
assertThat(new DecimalFormat("000.000000E0", new DecimalFormatSymbols(Locale.ENGLISH)).format(d))
|
||||
.isEqualTo("123.456789E4");
|
||||
|
||||
assertThat(new DecimalFormat("##0.######E0", new DecimalFormatSymbols(Locale.ENGLISH)).format(d))
|
||||
.isEqualTo("1.23456789E6");
|
||||
|
||||
assertThat(new DecimalFormat("###.000000E0", new DecimalFormatSymbols(Locale.ENGLISH)).format(d))
|
||||
.isEqualTo("1.23456789E6");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenString_WhenParsing_ThenCorrectOutput() throws ParseException {
|
||||
|
||||
assertThat(new DecimalFormat("", new DecimalFormatSymbols(Locale.ENGLISH)).parse("1234567.89"))
|
||||
.isEqualTo(1234567.89);
|
||||
|
||||
assertThat(new DecimalFormat("", new DecimalFormatSymbols(Locale.ITALIAN)).parse("1.234.567,89"))
|
||||
.isEqualTo(1234567.89);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenStringAndBigDecimalFlag_WhenParsing_ThenCorrectOutput() throws ParseException {
|
||||
|
||||
NumberFormat nf = new DecimalFormat("", new DecimalFormatSymbols(Locale.ENGLISH));
|
||||
((DecimalFormat) nf).setParseBigDecimal(true);
|
||||
assertThat(nf.parse("1234567.89")).isEqualTo(BigDecimal.valueOf(1234567.89));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package com.baeldung.methodoverloadingoverriding.test;
|
||||
|
||||
import com.baeldung.methodoverloadingoverriding.util.Multiplier;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
public class MethodOverloadingUnitTest {
|
||||
|
||||
private static Multiplier multiplier;
|
||||
|
||||
@BeforeClass
|
||||
public static void setUpMultiplierInstance() {
|
||||
multiplier = new Multiplier();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenMultiplierInstance_whenCalledMultiplyWithTwoIntegers_thenOneAssertion() {
|
||||
assertThat(multiplier.multiply(10, 10)).isEqualTo(100);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenMultiplierInstance_whenCalledMultiplyWithTreeIntegers_thenOneAssertion() {
|
||||
assertThat(multiplier.multiply(10, 10, 10)).isEqualTo(1000);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenMultiplierInstance_whenCalledMultiplyWithIntDouble_thenOneAssertion() {
|
||||
assertThat(multiplier.multiply(10, 10.5)).isEqualTo(105.0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenMultiplierInstance_whenCalledMultiplyWithDoubleDouble_thenOneAssertion() {
|
||||
assertThat(multiplier.multiply(10.5, 10.5)).isEqualTo(110.25);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenMultiplierInstance_whenCalledMultiplyWithIntIntAndMatching_thenNoTypePromotion() {
|
||||
assertThat(multiplier.multiply(10, 10)).isEqualTo(100);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
package com.baeldung.methodoverloadingoverriding.test;
|
||||
|
||||
import com.baeldung.methodoverloadingoverriding.model.Car;
|
||||
import com.baeldung.methodoverloadingoverriding.model.Vehicle;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
public class MethodOverridingUnitTest {
|
||||
|
||||
private static Vehicle vehicle;
|
||||
private static Car car;
|
||||
|
||||
@BeforeClass
|
||||
public static void setUpVehicleInstance() {
|
||||
vehicle = new Vehicle();
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void setUpCarInstance() {
|
||||
car = new Car();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenVehicleInstance_whenCalledAccelerate_thenOneAssertion() {
|
||||
assertThat(vehicle.accelerate(100)).isEqualTo("The vehicle accelerates at : 100 MPH.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenVehicleInstance_whenCalledRun_thenOneAssertion() {
|
||||
assertThat(vehicle.run()).isEqualTo("The vehicle is running.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenVehicleInstance_whenCalledStop_thenOneAssertion() {
|
||||
assertThat(vehicle.stop()).isEqualTo("The vehicle has stopped.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenCarInstance_whenCalledAccelerate_thenOneAssertion() {
|
||||
assertThat(car.accelerate(80)).isEqualTo("The car accelerates at : 80 MPH.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenCarInstance_whenCalledRun_thenOneAssertion() {
|
||||
assertThat(car.run()).isEqualTo("The vehicle is running.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenCarInstance_whenCalledStop_thenOneAssertion() {
|
||||
assertThat(car.stop()).isEqualTo("The vehicle has stopped.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenVehicleCarInstances_whenCalledAccelerateWithSameArgument_thenNotEqual() {
|
||||
assertThat(vehicle.accelerate(100)).isNotEqualTo(car.accelerate(100));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenVehicleCarInstances_whenCalledRun_thenEqual() {
|
||||
assertThat(vehicle.run()).isEqualTo(car.run());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenVehicleCarInstances_whenCalledStop_thenEqual() {
|
||||
assertThat(vehicle.stop()).isEqualTo(car.stop());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
package com.baeldung.string;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import org.junit.Test;
|
||||
|
||||
public class PalindromeTest {
|
||||
|
||||
private String[] words = {
|
||||
"Anna",
|
||||
"Civic",
|
||||
"Kayak",
|
||||
"Level",
|
||||
"Madam",
|
||||
};
|
||||
|
||||
private String[] sentences = {
|
||||
"Sore was I ere I saw Eros",
|
||||
"Euston saw I was not Sue",
|
||||
"Too hot to hoot",
|
||||
"No mists or frost Simon",
|
||||
"Stella won no wallets"
|
||||
};
|
||||
|
||||
private Palindrome palindrome = new Palindrome();
|
||||
|
||||
@Test
|
||||
public void whenWord_shouldBePalindrome() {
|
||||
for (String word : words)
|
||||
assertTrue(palindrome.isPalindrome(word));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenSentence_shouldBePalindrome() {
|
||||
for (String sentence : sentences)
|
||||
assertTrue(palindrome.isPalindrome(sentence));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenReverseWord_shouldBePalindrome() {
|
||||
for (String word : words)
|
||||
assertTrue(palindrome.isPalindromeReverseTheString(word));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenReverseSentence_shouldBePalindrome() {
|
||||
for (String sentence : sentences)
|
||||
assertTrue(palindrome.isPalindromeReverseTheString(sentence));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenStringBuilderWord_shouldBePalindrome() {
|
||||
for (String word : words)
|
||||
assertTrue(palindrome.isPalindromeUsingStringBuilder(word));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenStringBuilderSentence_shouldBePalindrome() {
|
||||
for (String sentence : sentences)
|
||||
assertTrue(palindrome.isPalindromeUsingStringBuilder(sentence));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenStringBufferWord_shouldBePalindrome() {
|
||||
for (String word : words)
|
||||
assertTrue(palindrome.isPalindromeUsingStringBuffer(word));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenStringBufferSentence_shouldBePalindrome() {
|
||||
for (String sentence : sentences)
|
||||
assertTrue(palindrome.isPalindromeUsingStringBuffer(sentence));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenPalindromeRecursive_wordShouldBePalindrome() {
|
||||
for (String word : words)
|
||||
assertTrue(palindrome.isPalindromeRecursive(word));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenPalindromeRecursive_sentenceShouldBePalindrome() {
|
||||
for (String sentence : sentences)
|
||||
assertTrue(palindrome.isPalindromeRecursive(sentence));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenPalindromeStreams_wordShouldBePalindrome() {
|
||||
for (String word : words)
|
||||
assertTrue(palindrome.isPalindromeUsingIntStream(word));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenPalindromeStreams_sentenceShouldBePalindrome() {
|
||||
for (String sentence : sentences)
|
||||
assertTrue(palindrome.isPalindromeUsingIntStream(sentence));
|
||||
}
|
||||
}
|
|
@ -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))
|
||||
}
|
||||
|
||||
}
|
|
@ -129,7 +129,7 @@
|
|||
|
||||
<properties>
|
||||
<!-- marshalling -->
|
||||
<jackson.version>2.9.2</jackson.version>
|
||||
<jackson.version>2.9.4</jackson.version>
|
||||
|
||||
<!-- util -->
|
||||
<guava.version>19.0</guava.version>
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
package com.baeldung.controller;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.RequestDispatcher;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.annotation.WebServlet;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import com.baeldung.service.StudentService;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author haseeb
|
||||
*
|
||||
*/
|
||||
@WebServlet(name = "StudentServlet", urlPatterns = "/student-record")
|
||||
public class StudentServlet extends HttpServlet {
|
||||
|
||||
protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||
StudentService studentService = new StudentService();
|
||||
String studentID = request.getParameter("id");
|
||||
if (studentID != null) {
|
||||
int id = Integer.parseInt(studentID);
|
||||
request.setAttribute("studentRecord", studentService.getStudent(id));
|
||||
}
|
||||
|
||||
RequestDispatcher dispatcher = request.getRequestDispatcher("/WEB-INF/jsp/student-record.jsp");
|
||||
dispatcher.forward(request, response);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||
processRequest(request, response);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||
processRequest(request, response);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
package com.baeldung.model;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author haseeb
|
||||
*
|
||||
*/
|
||||
public class Student {
|
||||
|
||||
private int id;
|
||||
private String firstName;
|
||||
private String lastName;
|
||||
|
||||
public Student(int id, String firstName, String lastName) {
|
||||
super();
|
||||
this.id = id;
|
||||
this.firstName = firstName;
|
||||
this.lastName = lastName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the id
|
||||
*/
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param id the id to set
|
||||
*/
|
||||
public void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the firstName
|
||||
*/
|
||||
public String getFirstName() {
|
||||
return firstName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param firstName the firstName to set
|
||||
*/
|
||||
public void setFirstName(String firstName) {
|
||||
this.firstName = firstName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the lastName
|
||||
*/
|
||||
public String getLastName() {
|
||||
return lastName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param lastName the lastName to set
|
||||
*/
|
||||
public void setLastName(String lastName) {
|
||||
this.lastName = lastName;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package com.baeldung.service;
|
||||
|
||||
import com.baeldung.model.Student;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author haseeb
|
||||
*
|
||||
*/
|
||||
public class StudentService {
|
||||
|
||||
/**
|
||||
*
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
public Student getStudent(int id) {
|
||||
|
||||
Student student = null;
|
||||
|
||||
switch (id) {
|
||||
case 1:
|
||||
student = new Student(1, "John", "Doe");
|
||||
break;
|
||||
case 2:
|
||||
student = new Student(2, "Jane", "Goodall");
|
||||
break;
|
||||
case 3:
|
||||
student = new Student(3, "Max", "Born");
|
||||
break;
|
||||
}
|
||||
return student;
|
||||
}
|
||||
}
|
|
@ -25,7 +25,7 @@ public class FormServlet extends HttpServlet {
|
|||
response.setHeader("Test", "Success");
|
||||
response.setHeader("BMI", String.valueOf(bmi));
|
||||
|
||||
RequestDispatcher dispatcher = request.getRequestDispatcher("index.jsp");
|
||||
RequestDispatcher dispatcher = request.getRequestDispatcher("/WEB-INF/jsp/index.jsp");
|
||||
dispatcher.forward(request, response);
|
||||
} catch (Exception e) {
|
||||
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
|
||||
pageEncoding="ISO-8859-1"%>
|
||||
|
||||
<%@ page import="com.baeldung.model.Student"%>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>Student Record</title>
|
||||
</head>
|
||||
<body>
|
||||
<%
|
||||
if (request.getAttribute("studentRecord") != null) {
|
||||
Student student = (Student) request.getAttribute("studentRecord");
|
||||
%>
|
||||
|
||||
<h1>Student Record</h1>
|
||||
<div>
|
||||
ID:
|
||||
<%=student.getId()%></div>
|
||||
<div>
|
||||
First Name:
|
||||
<%=student.getFirstName()%></div>
|
||||
<div>
|
||||
Last Name:
|
||||
<%=student.getLastName()%></div>
|
||||
|
||||
<%
|
||||
} else {
|
||||
%>
|
||||
<h1>No student record found.</h1>
|
||||
<%
|
||||
}
|
||||
%>
|
||||
</body>
|
||||
</html>
|
|
@ -6,10 +6,11 @@
|
|||
<version>0.1-SNAPSHOT</version>
|
||||
|
||||
<properties>
|
||||
<validation-api.version>2.0.0.Final</validation-api.version>
|
||||
<hibernate-validator.version>6.0.2.Final</hibernate-validator.version>
|
||||
<validation-api.version>2.0.1.Final</validation-api.version>
|
||||
<hibernate-validator.version>6.0.7.Final</hibernate-validator.version>
|
||||
<javax.el-api.version>3.0.0</javax.el-api.version>
|
||||
<javax.el.version>2.2.6</javax.el.version>
|
||||
<org.springframework.version>5.0.2.RELEASE</org.springframework.version>
|
||||
</properties>
|
||||
|
||||
|
||||
|
@ -21,12 +22,6 @@
|
|||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.validation</groupId>
|
||||
<artifactId>validation-api</artifactId>
|
||||
<version>${validation-api.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-validator</artifactId>
|
||||
|
@ -50,6 +45,16 @@
|
|||
<artifactId>javax.el</artifactId>
|
||||
<version>${javax.el.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<version>${org.springframework.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<version>${org.springframework.version}</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
package org.baeldung.javaxval.methodvalidation;
|
||||
|
||||
import org.baeldung.javaxval.methodvalidation.model.Customer;
|
||||
import org.baeldung.javaxval.methodvalidation.model.Reservation;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
@Configuration
|
||||
@ComponentScan({ "org.baeldung.javaxval.methodvalidation.model" })
|
||||
public class MethodValidationConfig {
|
||||
|
||||
@Bean
|
||||
public MethodValidationPostProcessor methodValidationPostProcessor() {
|
||||
return new MethodValidationPostProcessor();
|
||||
}
|
||||
|
||||
@Bean("customer")
|
||||
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
|
||||
public Customer customer(String firstName, String lastName) {
|
||||
|
||||
Customer customer = new Customer(firstName, lastName);
|
||||
return customer;
|
||||
}
|
||||
|
||||
@Bean("reservation")
|
||||
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
|
||||
public Reservation reservation(LocalDate begin, LocalDate end, Customer customer, int room) {
|
||||
|
||||
Reservation reservation = new Reservation(begin, end, customer, room);
|
||||
return reservation;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package org.baeldung.javaxval.methodvalidation.constraints;
|
||||
|
||||
import javax.validation.ConstraintValidator;
|
||||
import javax.validation.ConstraintValidatorContext;
|
||||
import javax.validation.constraintvalidation.SupportedValidationTarget;
|
||||
import javax.validation.constraintvalidation.ValidationTarget;
|
||||
import java.time.LocalDate;
|
||||
|
||||
@SupportedValidationTarget(ValidationTarget.PARAMETERS)
|
||||
public class ConsistentDateParameterValidator implements ConstraintValidator<ConsistentDateParameters, Object[]> {
|
||||
|
||||
@Override
|
||||
public boolean isValid(Object[] value, ConstraintValidatorContext context) {
|
||||
|
||||
if (value[0] == null || value[1] == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(value[0] instanceof LocalDate) || !(value[1] instanceof LocalDate)) {
|
||||
throw new IllegalArgumentException("Illegal method signature, expected two parameters of type LocalDate.");
|
||||
}
|
||||
|
||||
return ((LocalDate) value[0]).isAfter(LocalDate.now()) && ((LocalDate) value[0]).isBefore((LocalDate) value[1]);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package org.baeldung.javaxval.methodvalidation.constraints;
|
||||
|
||||
import javax.validation.Constraint;
|
||||
import javax.validation.Payload;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import static java.lang.annotation.ElementType.*;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
@Constraint(validatedBy = ConsistentDateParameterValidator.class)
|
||||
@Target({ METHOD, CONSTRUCTOR })
|
||||
@Retention(RUNTIME)
|
||||
@Documented
|
||||
public @interface ConsistentDateParameters {
|
||||
|
||||
String message() default "End date must be after begin date and both must be in the future";
|
||||
|
||||
Class<?>[] groups() default {};
|
||||
|
||||
Class<? extends Payload>[] payload() default {};
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package org.baeldung.javaxval.methodvalidation.constraints;
|
||||
|
||||
import javax.validation.Constraint;
|
||||
import javax.validation.Payload;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import static java.lang.annotation.ElementType.CONSTRUCTOR;
|
||||
import static java.lang.annotation.ElementType.METHOD;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
@Constraint(validatedBy = ValidReservationValidator.class)
|
||||
@Target({ METHOD, CONSTRUCTOR })
|
||||
@Retention(RUNTIME)
|
||||
@Documented
|
||||
public @interface ValidReservation {
|
||||
|
||||
String message() default "End date must be after begin date and both must be in the future, room number must be bigger than 0";
|
||||
|
||||
Class<?>[] groups() default {};
|
||||
|
||||
Class<? extends Payload>[] payload() default {};
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package org.baeldung.javaxval.methodvalidation.constraints;
|
||||
|
||||
import org.baeldung.javaxval.methodvalidation.model.Reservation;
|
||||
|
||||
import javax.validation.ConstraintValidator;
|
||||
import javax.validation.ConstraintValidatorContext;
|
||||
import java.time.LocalDate;
|
||||
|
||||
public class ValidReservationValidator implements ConstraintValidator<ValidReservation, Reservation> {
|
||||
|
||||
@Override
|
||||
public boolean isValid(Reservation reservation, ConstraintValidatorContext context) {
|
||||
|
||||
if (reservation == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(reservation instanceof Reservation)) {
|
||||
throw new IllegalArgumentException("Illegal method signature, expected parameter of type Reservation.");
|
||||
}
|
||||
|
||||
if (reservation.getBegin() == null || reservation.getEnd() == null || reservation.getCustomer() == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (reservation.getBegin()
|
||||
.isAfter(LocalDate.now())
|
||||
&& reservation.getBegin()
|
||||
.isBefore(reservation.getEnd())
|
||||
&& reservation.getRoom() > 0);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package org.baeldung.javaxval.methodvalidation.model;
|
||||
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
@Validated
|
||||
public class Customer {
|
||||
|
||||
@Size(min = 5, max = 200)
|
||||
private String firstName;
|
||||
|
||||
@Size(min = 5, max = 200)
|
||||
private String lastName;
|
||||
|
||||
public Customer(@Size(min = 5, max = 200) @NotNull String firstName, @Size(min = 5, max = 200) @NotNull String lastName) {
|
||||
this.firstName = firstName;
|
||||
this.lastName = lastName;
|
||||
}
|
||||
|
||||
public Customer() {
|
||||
|
||||
}
|
||||
|
||||
public String getFirstName() {
|
||||
return firstName;
|
||||
}
|
||||
|
||||
public void setFirstName(String firstName) {
|
||||
this.firstName = firstName;
|
||||
}
|
||||
|
||||
public String getLastName() {
|
||||
return lastName;
|
||||
}
|
||||
|
||||
public void setLastName(String lastName) {
|
||||
this.lastName = lastName;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
package org.baeldung.javaxval.methodvalidation.model;
|
||||
|
||||
import org.baeldung.javaxval.methodvalidation.constraints.ConsistentDateParameters;
|
||||
import org.baeldung.javaxval.methodvalidation.constraints.ValidReservation;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.Positive;
|
||||
import java.time.LocalDate;
|
||||
|
||||
@Validated
|
||||
public class Reservation {
|
||||
|
||||
private LocalDate begin;
|
||||
|
||||
private LocalDate end;
|
||||
|
||||
@Valid
|
||||
private Customer customer;
|
||||
|
||||
@Positive
|
||||
private int room;
|
||||
|
||||
@ConsistentDateParameters
|
||||
@ValidReservation
|
||||
public Reservation(LocalDate begin, LocalDate end, Customer customer, int room) {
|
||||
this.begin = begin;
|
||||
this.end = end;
|
||||
this.customer = customer;
|
||||
this.room = room;
|
||||
}
|
||||
|
||||
public LocalDate getBegin() {
|
||||
return begin;
|
||||
}
|
||||
|
||||
public void setBegin(LocalDate begin) {
|
||||
this.begin = begin;
|
||||
}
|
||||
|
||||
public LocalDate getEnd() {
|
||||
return end;
|
||||
}
|
||||
|
||||
public void setEnd(LocalDate end) {
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
public Customer getCustomer() {
|
||||
return customer;
|
||||
}
|
||||
|
||||
public void setCustomer(Customer customer) {
|
||||
this.customer = customer;
|
||||
}
|
||||
|
||||
public int getRoom() {
|
||||
return room;
|
||||
}
|
||||
|
||||
public void setRoom(int room) {
|
||||
this.room = room;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
package org.baeldung.javaxval.methodvalidation.model;
|
||||
|
||||
import org.baeldung.javaxval.methodvalidation.constraints.ConsistentDateParameters;
|
||||
import org.baeldung.javaxval.methodvalidation.constraints.ValidReservation;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.*;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
@Controller
|
||||
@Validated
|
||||
public class ReservationManagement {
|
||||
|
||||
@Autowired
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
@ConsistentDateParameters
|
||||
public void createReservation(LocalDate begin, LocalDate end, @NotNull Customer customer) {
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
public void createReservation(@NotNull @Future LocalDate begin, @Min(1) int duration, @NotNull Customer customer) {
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
public void createReservation(@Valid Reservation reservation) {
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Size(min = 1)
|
||||
public List<@NotNull Customer> getAllCustomers() {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Valid
|
||||
public Reservation getReservationById(int id) {
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
package org.baeldung.javaxval.methodvalidation;
|
||||
|
||||
import org.baeldung.javaxval.methodvalidation.model.Customer;
|
||||
import org.baeldung.javaxval.methodvalidation.model.Reservation;
|
||||
import org.baeldung.javaxval.methodvalidation.model.ReservationManagement;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.support.AnnotationConfigContextLoader;
|
||||
|
||||
import javax.validation.ConstraintViolationException;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(classes = { MethodValidationConfig.class }, loader = AnnotationConfigContextLoader.class)
|
||||
public class ContainerValidationIntegrationTest {
|
||||
|
||||
@Autowired
|
||||
ReservationManagement reservationManagement;
|
||||
|
||||
@Rule
|
||||
public final ExpectedException exception = ExpectedException.none();
|
||||
|
||||
@Test
|
||||
public void whenValidationWithInvalidMethodParameters_thenConstraintViolationException() {
|
||||
|
||||
exception.expect(ConstraintViolationException.class);
|
||||
reservationManagement.createReservation(LocalDate.now(), 0, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenValidationWithValidMethodParameters_thenNoException() {
|
||||
|
||||
reservationManagement.createReservation(LocalDate.now()
|
||||
.plusDays(1), 1, new Customer("William", "Smith"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenCrossParameterValidationWithInvalidParameters_thenConstraintViolationException() {
|
||||
|
||||
exception.expect(ConstraintViolationException.class);
|
||||
reservationManagement.createReservation(LocalDate.now(), LocalDate.now(), null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenCrossParameterValidationWithValidParameters_thenNoException() {
|
||||
|
||||
reservationManagement.createReservation(LocalDate.now()
|
||||
.plusDays(1),
|
||||
LocalDate.now()
|
||||
.plusDays(2),
|
||||
new Customer("William", "Smith"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenValidationWithInvalidReturnValue_thenConstraintViolationException() {
|
||||
|
||||
exception.expect(ConstraintViolationException.class);
|
||||
List<Customer> list = reservationManagement.getAllCustomers();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenValidationWithInvalidCascadedValue_thenConstraintViolationException() {
|
||||
|
||||
Customer customer = new Customer();
|
||||
customer.setFirstName("John");
|
||||
customer.setLastName("Doe");
|
||||
Reservation reservation = new Reservation(LocalDate.now()
|
||||
.plusDays(1),
|
||||
LocalDate.now()
|
||||
.plusDays(2),
|
||||
customer, 1);
|
||||
|
||||
exception.expect(ConstraintViolationException.class);
|
||||
reservationManagement.createReservation(reservation);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenValidationWithValidCascadedValue_thenCNoException() {
|
||||
|
||||
Customer customer = new Customer();
|
||||
customer.setFirstName("William");
|
||||
customer.setLastName("Smith");
|
||||
Reservation reservation = new Reservation(LocalDate.now()
|
||||
.plusDays(1),
|
||||
LocalDate.now()
|
||||
.plusDays(2),
|
||||
customer, 1);
|
||||
|
||||
reservationManagement.createReservation(reservation);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,209 @@
|
|||
package org.baeldung.javaxval.methodvalidation;
|
||||
|
||||
import org.baeldung.javaxval.methodvalidation.model.Customer;
|
||||
import org.baeldung.javaxval.methodvalidation.model.Reservation;
|
||||
import org.baeldung.javaxval.methodvalidation.model.ReservationManagement;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import javax.validation.ConstraintViolation;
|
||||
import javax.validation.Validation;
|
||||
import javax.validation.ValidatorFactory;
|
||||
import javax.validation.executable.ExecutableValidator;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.time.LocalDate;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
public class ValidationIntegrationTest {
|
||||
|
||||
private ExecutableValidator executableValidator;
|
||||
|
||||
@Before
|
||||
public void getExecutableValidator() {
|
||||
|
||||
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
|
||||
this.executableValidator = factory.getValidator()
|
||||
.forExecutables();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenValidationWithInvalidMethodParameters_thenCorrectNumberOfVoilations() throws NoSuchMethodException {
|
||||
|
||||
ReservationManagement object = new ReservationManagement();
|
||||
Method method = ReservationManagement.class.getMethod("createReservation", LocalDate.class, int.class, Customer.class);
|
||||
Object[] parameterValues = { LocalDate.now(), 0, null };
|
||||
Set<ConstraintViolation<ReservationManagement>> violations = executableValidator.validateParameters(object, method, parameterValues);
|
||||
|
||||
assertEquals(3, violations.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenValidationWithValidMethodParameters_thenZeroVoilations() throws NoSuchMethodException {
|
||||
|
||||
ReservationManagement object = new ReservationManagement();
|
||||
Method method = ReservationManagement.class.getMethod("createReservation", LocalDate.class, int.class, Customer.class);
|
||||
Object[] parameterValues = { LocalDate.now()
|
||||
.plusDays(1), 1, new Customer("John", "Doe") };
|
||||
Set<ConstraintViolation<ReservationManagement>> violations = executableValidator.validateParameters(object, method, parameterValues);
|
||||
|
||||
assertEquals(0, violations.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenCrossParameterValidationWithInvalidParameters_thenCorrectNumberOfVoilations() throws NoSuchMethodException {
|
||||
|
||||
ReservationManagement object = new ReservationManagement();
|
||||
Method method = ReservationManagement.class.getMethod("createReservation", LocalDate.class, LocalDate.class, Customer.class);
|
||||
Object[] parameterValues = { LocalDate.now(), LocalDate.now(), new Customer("John", "Doe") };
|
||||
Set<ConstraintViolation<ReservationManagement>> violations = executableValidator.validateParameters(object, method, parameterValues);
|
||||
|
||||
assertEquals(1, violations.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenCrossParameterValidationWithValidParameters_thenZeroVoilations() throws NoSuchMethodException {
|
||||
|
||||
ReservationManagement object = new ReservationManagement();
|
||||
Method method = ReservationManagement.class.getMethod("createReservation", LocalDate.class, LocalDate.class, Customer.class);
|
||||
Object[] parameterValues = { LocalDate.now()
|
||||
.plusDays(1),
|
||||
LocalDate.now()
|
||||
.plusDays(2),
|
||||
new Customer("John", "Doe") };
|
||||
Set<ConstraintViolation<ReservationManagement>> violations = executableValidator.validateParameters(object, method, parameterValues);
|
||||
|
||||
assertEquals(0, violations.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenValidationWithInvalidConstructorParameters_thenCorrectNumberOfVoilations() throws NoSuchMethodException {
|
||||
|
||||
Constructor<Customer> constructor = Customer.class.getConstructor(String.class, String.class);
|
||||
Object[] parameterValues = { "John", "Doe" };
|
||||
Set<ConstraintViolation<Customer>> violations = executableValidator.validateConstructorParameters(constructor, parameterValues);
|
||||
|
||||
assertEquals(2, violations.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenValidationWithValidConstructorParameters_thenZeroVoilations() throws NoSuchMethodException {
|
||||
|
||||
Constructor<Customer> constructor = Customer.class.getConstructor(String.class, String.class);
|
||||
Object[] parameterValues = { "William", "Smith" };
|
||||
Set<ConstraintViolation<Customer>> violations = executableValidator.validateConstructorParameters(constructor, parameterValues);
|
||||
|
||||
assertEquals(0, violations.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenCrossParameterValidationWithInvalidConstructorParameters_thenCorrectNumberOfVoilations() throws NoSuchMethodException {
|
||||
|
||||
Constructor<Reservation> constructor = Reservation.class.getConstructor(LocalDate.class, LocalDate.class, Customer.class, int.class);
|
||||
Object[] parameterValues = { LocalDate.now(), LocalDate.now(), new Customer("William", "Smith"), 1 };
|
||||
Set<ConstraintViolation<Reservation>> violations = executableValidator.validateConstructorParameters(constructor, parameterValues);
|
||||
|
||||
assertEquals(1, violations.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenCrossParameterValidationWithValidConstructorParameters_thenZeroVoilations() throws NoSuchMethodException {
|
||||
|
||||
Constructor<Reservation> constructor = Reservation.class.getConstructor(LocalDate.class, LocalDate.class, Customer.class, int.class);
|
||||
Object[] parameterValues = { LocalDate.now()
|
||||
.plusDays(1),
|
||||
LocalDate.now()
|
||||
.plusDays(2),
|
||||
new Customer("William", "Smith"), 1 };
|
||||
Set<ConstraintViolation<Reservation>> violations = executableValidator.validateConstructorParameters(constructor, parameterValues);
|
||||
|
||||
assertEquals(0, violations.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenValidationWithInvalidReturnValue_thenCorrectNumberOfVoilations() throws NoSuchMethodException {
|
||||
|
||||
ReservationManagement object = new ReservationManagement();
|
||||
Method method = ReservationManagement.class.getMethod("getAllCustomers");
|
||||
Object returnValue = Collections.<Customer> emptyList();
|
||||
Set<ConstraintViolation<ReservationManagement>> violations = executableValidator.validateReturnValue(object, method, returnValue);
|
||||
|
||||
assertEquals(1, violations.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenValidationWithValidReturnValue_thenZeroVoilations() throws NoSuchMethodException {
|
||||
|
||||
ReservationManagement object = new ReservationManagement();
|
||||
Method method = ReservationManagement.class.getMethod("getAllCustomers");
|
||||
Object returnValue = Collections.singletonList(new Customer("William", "Smith"));
|
||||
Set<ConstraintViolation<ReservationManagement>> violations = executableValidator.validateReturnValue(object, method, returnValue);
|
||||
|
||||
assertEquals(0, violations.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenValidationWithInvalidConstructorReturnValue_thenCorrectNumberOfVoilations() throws NoSuchMethodException {
|
||||
|
||||
Constructor<Reservation> constructor = Reservation.class.getConstructor(LocalDate.class, LocalDate.class, Customer.class, int.class);
|
||||
Reservation createdObject = new Reservation(LocalDate.now(), LocalDate.now(), new Customer("William", "Smith"), 0);
|
||||
Set<ConstraintViolation<Reservation>> violations = executableValidator.validateConstructorReturnValue(constructor, createdObject);
|
||||
|
||||
assertEquals(1, violations.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenValidationWithValidConstructorReturnValue_thenZeroVoilations() throws NoSuchMethodException {
|
||||
|
||||
Constructor<Reservation> constructor = Reservation.class.getConstructor(LocalDate.class, LocalDate.class, Customer.class, int.class);
|
||||
Reservation createdObject = new Reservation(LocalDate.now()
|
||||
.plusDays(1),
|
||||
LocalDate.now()
|
||||
.plusDays(2),
|
||||
new Customer("William", "Smith"), 1);
|
||||
Set<ConstraintViolation<Reservation>> violations = executableValidator.validateConstructorReturnValue(constructor, createdObject);
|
||||
|
||||
assertEquals(0, violations.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenValidationWithInvalidCascadedValue_thenCorrectNumberOfVoilations() throws NoSuchMethodException {
|
||||
|
||||
ReservationManagement object = new ReservationManagement();
|
||||
Method method = ReservationManagement.class.getMethod("createReservation", Reservation.class);
|
||||
Customer customer = new Customer();
|
||||
customer.setFirstName("John");
|
||||
customer.setLastName("Doe");
|
||||
Reservation reservation = new Reservation(LocalDate.now()
|
||||
.plusDays(1),
|
||||
LocalDate.now()
|
||||
.plusDays(2),
|
||||
customer, 1);
|
||||
Object[] parameterValues = { reservation };
|
||||
Set<ConstraintViolation<ReservationManagement>> violations = executableValidator.validateParameters(object, method, parameterValues);
|
||||
|
||||
assertEquals(2, violations.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenValidationWithValidCascadedValue_thenCorrectNumberOfVoilations() throws NoSuchMethodException {
|
||||
|
||||
ReservationManagement object = new ReservationManagement();
|
||||
Method method = ReservationManagement.class.getMethod("createReservation", Reservation.class);
|
||||
Customer customer = new Customer();
|
||||
customer.setFirstName("William");
|
||||
customer.setLastName("Smith");
|
||||
Reservation reservation = new Reservation(LocalDate.now()
|
||||
.plusDays(1),
|
||||
LocalDate.now()
|
||||
.plusDays(2),
|
||||
customer, 1);
|
||||
Object[] parameterValues = { reservation };
|
||||
Set<ConstraintViolation<ReservationManagement>> violations = executableValidator.validateParameters(object, method, parameterValues);
|
||||
|
||||
assertEquals(0, violations.size());
|
||||
}
|
||||
|
||||
}
|
|
@ -649,6 +649,11 @@
|
|||
<artifactId>google-http-client-gson</artifactId>
|
||||
<version>${googleclient.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.infinispan</groupId>
|
||||
<artifactId>infinispan-core</artifactId>
|
||||
<version>${infinispan.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!--Java Docker API Client-->
|
||||
<dependency>
|
||||
|
@ -811,5 +816,6 @@
|
|||
<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>
|
||||
<infinispan.version>9.1.5.Final</infinispan.version>
|
||||
</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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
pragma solidity ^0.4.0;
|
||||
|
||||
contract Greeting {
|
||||
address creator;
|
||||
string message;
|
||||
|
||||
function Greeting(string _message) {
|
||||
message = _message;
|
||||
creator = msg.sender;
|
||||
}
|
||||
|
||||
function greet() constant returns (string) {
|
||||
return message;
|
||||
}
|
||||
|
||||
function setGreeting(string _message) {
|
||||
message = _message;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
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;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
protected long timeThis(Callable callable) {
|
||||
try {
|
||||
long milis = System.currentTimeMillis();
|
||||
callable.call();
|
||||
return System.currentTimeMillis() - milis;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return 0l;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
package com.baeldung.infinispan.service;
|
||||
|
||||
import com.baeldung.infinispan.ConfigurationTest;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static org.assertj.core.api.Java6Assertions.assertThat;
|
||||
|
||||
public class HelloWorldServiceUnitTest extends ConfigurationTest {
|
||||
|
||||
@Test
|
||||
public void whenGetIsCalledTwoTimes_thenTheSecondShouldHitTheCache() {
|
||||
assertThat(timeThis(() -> helloWorldService.findSimpleHelloWorld()))
|
||||
.isGreaterThanOrEqualTo(1000);
|
||||
|
||||
assertThat(timeThis(() -> helloWorldService.findSimpleHelloWorld()))
|
||||
.isLessThan(100);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenGetIsCalledTwoTimesQuickly_thenTheSecondShouldHitTheCache() {
|
||||
assertThat(timeThis(() -> helloWorldService.findExpiringHelloWorld()))
|
||||
.isGreaterThanOrEqualTo(1000);
|
||||
|
||||
assertThat(timeThis(() -> helloWorldService.findExpiringHelloWorld()))
|
||||
.isLessThan(100);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenGetIsCalledTwoTimesSparsely_thenNeitherShouldHitTheCache()
|
||||
throws InterruptedException {
|
||||
|
||||
assertThat(timeThis(() -> helloWorldService.findExpiringHelloWorld()))
|
||||
.isGreaterThanOrEqualTo(1000);
|
||||
|
||||
Thread.sleep(1100);
|
||||
|
||||
assertThat(timeThis(() -> helloWorldService.findExpiringHelloWorld()))
|
||||
.isGreaterThanOrEqualTo(1000);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenOneEntryIsConfigured_whenTwoAreAdded_thenFirstShouldntBeAvailable() {
|
||||
|
||||
assertThat(timeThis(() -> helloWorldService.findEvictingHelloWorld("key 1")))
|
||||
.isGreaterThanOrEqualTo(1000);
|
||||
|
||||
assertThat(timeThis(() -> helloWorldService.findEvictingHelloWorld("key 2")))
|
||||
.isGreaterThanOrEqualTo(1000);
|
||||
|
||||
assertThat(timeThis(() -> helloWorldService.findEvictingHelloWorld("key 1")))
|
||||
.isGreaterThanOrEqualTo(1000);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenOneEntryIsConfigured_whenTwoAreAdded_thenTheFirstShouldBeAvailable() {
|
||||
|
||||
assertThat(timeThis(() -> helloWorldService.findPassivatingHelloWorld("key 1")))
|
||||
.isGreaterThanOrEqualTo(1000);
|
||||
|
||||
assertThat(timeThis(() -> helloWorldService.findPassivatingHelloWorld("key 2")))
|
||||
.isGreaterThanOrEqualTo(1000);
|
||||
|
||||
assertThat(timeThis(() -> helloWorldService.findPassivatingHelloWorld("key 1")))
|
||||
.isLessThan(100);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
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
|
||||
|
||||
assertThat(timeThis(() -> transactionalService.getQuickHowManyVisits()))
|
||||
.isGreaterThan(500).isLessThan(1000);
|
||||
}
|
||||
|
||||
}
|
|
@ -23,6 +23,10 @@
|
|||
<spring-data-dynamodb.version>4.4.1</spring-data-dynamodb.version>
|
||||
<aws-java-sdk-dynamodb.version>1.11.64</aws-java-sdk-dynamodb.version>
|
||||
<bootstrap.version>3.3.7-1</bootstrap.version>
|
||||
<sqlite4java.version>1.0.392</sqlite4java.version>
|
||||
<dynamodb.version>1.11.106</dynamodb.version>
|
||||
<dynamodblocal.version>1.11.86</dynamodblocal.version>
|
||||
<dynamodblocal.repository.url>https://s3.eu-central-1.amazonaws.com/dynamodb-local-frankfurt/release</dynamodblocal.repository.url>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
|
@ -103,6 +107,57 @@
|
|||
<artifactId>httpclient</artifactId>
|
||||
<version>${httpclient.version}</version>
|
||||
</dependency>
|
||||
<!-- ================================================== -->
|
||||
<!-- DynamoDBLocal dependencies -->
|
||||
<!-- ================================================== -->
|
||||
<dependency>
|
||||
<groupId>com.amazonaws</groupId>
|
||||
<artifactId>DynamoDBLocal</artifactId>
|
||||
<version>${dynamodblocal.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.almworks.sqlite4java</groupId>
|
||||
<artifactId>sqlite4java</artifactId>
|
||||
<version>${sqlite4java.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.almworks.sqlite4java</groupId>
|
||||
<artifactId>sqlite4java-win32-x86</artifactId>
|
||||
<version>${sqlite4java.version}</version>
|
||||
<type>dll</type>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.almworks.sqlite4java</groupId>
|
||||
<artifactId>sqlite4java-win32-x64</artifactId>
|
||||
<version>${sqlite4java.version}</version>
|
||||
<type>dll</type>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.almworks.sqlite4java</groupId>
|
||||
<artifactId>libsqlite4java-osx</artifactId>
|
||||
<version>${sqlite4java.version}</version>
|
||||
<type>dylib</type>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.almworks.sqlite4java</groupId>
|
||||
<artifactId>libsqlite4java-linux-i386</artifactId>
|
||||
<version>${sqlite4java.version}</version>
|
||||
<type>so</type>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.almworks.sqlite4java</groupId>
|
||||
<artifactId>libsqlite4java-linux-amd64</artifactId>
|
||||
<version>${sqlite4java.version}</version>
|
||||
<type>so</type>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
@ -120,6 +175,25 @@
|
|||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-war-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<version>2.10</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy-dependencies</id>
|
||||
<phase>test-compile</phase>
|
||||
<goals>
|
||||
<goal>copy-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<includeScope>test</includeScope>
|
||||
<includeTypes>so,dll,dylib</includeTypes>
|
||||
<outputDirectory>${project.basedir}/native-libs</outputDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
</plugins>
|
||||
|
||||
|
@ -142,6 +216,11 @@
|
|||
<enabled>false</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>dynamodb-local</id>
|
||||
<name>DynamoDB Local Release Repository</name>
|
||||
<url>${dynamodblocal.repository.url}</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
|
|
|
@ -8,8 +8,9 @@ import com.amazonaws.services.dynamodbv2.model.ResourceInUseException;
|
|||
import com.baeldung.Application;
|
||||
import com.baeldung.spring.data.dynamodb.model.ProductInfo;
|
||||
import com.baeldung.spring.data.dynamodb.repositories.ProductInfoRepository;
|
||||
import com.baeldung.spring.data.dynamodb.repository.rule.LocalDynamoDBCreationRule;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
@ -21,7 +22,10 @@ import org.springframework.test.context.web.WebAppConfiguration;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.hamcrest.Matchers.greaterThan;
|
||||
import static org.hamcrest.core.Is.is;
|
||||
import static org.hamcrest.core.IsEqual.equalTo;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@SpringBootTest(classes = Application.class)
|
||||
|
@ -30,6 +34,9 @@ import static org.junit.Assert.assertTrue;
|
|||
@TestPropertySource(properties = { "amazon.dynamodb.endpoint=http://localhost:8000/", "amazon.aws.accesskey=test1", "amazon.aws.secretkey=test231" })
|
||||
public class ProductInfoRepositoryIntegrationTest {
|
||||
|
||||
@ClassRule
|
||||
public static LocalDynamoDBCreationRule dynamoDB = new LocalDynamoDBCreationRule();
|
||||
|
||||
private DynamoDBMapper dynamoDBMapper;
|
||||
|
||||
@Autowired
|
||||
|
@ -42,7 +49,6 @@ public class ProductInfoRepositoryIntegrationTest {
|
|||
private static final String EXPECTED_PRICE = "50";
|
||||
|
||||
@Before
|
||||
@Ignore // TODO Remove Ignore annotations when running locally with Local DynamoDB instance
|
||||
public void setup() throws Exception {
|
||||
|
||||
try {
|
||||
|
@ -57,19 +63,18 @@ public class ProductInfoRepositoryIntegrationTest {
|
|||
// Do nothing, table already created
|
||||
}
|
||||
|
||||
// TODO How to handle different environments. i.e. AVOID deleting all entries in ProductInfoion table
|
||||
// TODO How to handle different environments. i.e. AVOID deleting all entries in ProductInfo on table
|
||||
dynamoDBMapper.batchDelete((List<ProductInfo>) repository.findAll());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore // TODO Remove Ignore annotations when running locally with Local DynamoDB instance
|
||||
public void givenItemWithExpectedCost_whenRunFindAll_thenItemIsFound() {
|
||||
|
||||
ProductInfo productInfo = new ProductInfo(EXPECTED_COST, EXPECTED_PRICE);
|
||||
repository.save(productInfo);
|
||||
|
||||
List<ProductInfo> result = (List<ProductInfo>) repository.findAll();
|
||||
assertTrue("Not empty", result.size() > 0);
|
||||
assertTrue("Contains item with expected cost", result.get(0).getCost().equals(EXPECTED_COST));
|
||||
assertThat(result.size(), is(greaterThan(0)));
|
||||
assertThat(result.get(0).getCost(), is(equalTo(EXPECTED_COST)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
package com.baeldung.spring.data.dynamodb.repository.rule;
|
||||
|
||||
import com.amazonaws.services.dynamodbv2.local.main.ServerRunner;
|
||||
import com.amazonaws.services.dynamodbv2.local.server.DynamoDBProxyServer;
|
||||
import org.junit.rules.ExternalResource;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class LocalDynamoDBCreationRule extends ExternalResource {
|
||||
|
||||
protected DynamoDBProxyServer server;
|
||||
|
||||
public LocalDynamoDBCreationRule() {
|
||||
System.setProperty("sqlite4java.library.path", "native-libs");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void before() throws Exception {
|
||||
String port = "8000";
|
||||
this.server = ServerRunner.createServerFromCommandLineArgs(new String[]{"-inMemory", "-port", port});
|
||||
server.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void after() {
|
||||
Optional.ofNullable(server).ifPresent(this::stopUnchecked);
|
||||
}
|
||||
|
||||
protected void stopUnchecked(DynamoDBProxyServer dynamoDbServer) {
|
||||
try {
|
||||
dynamoDbServer.stop();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -16,11 +16,13 @@
|
|||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<spring.version>4.3.7.RELEASE</spring.version>
|
||||
<spring-data-redis>1.8.1.RELEASE</spring-data-redis>
|
||||
<spring.version>5.0.3.RELEASE</spring.version>
|
||||
<spring-data-redis>2.0.3.RELEASE</spring-data-redis>
|
||||
<cglib.version>3.2.4</cglib.version>
|
||||
<jedis.version>2.9.0</jedis.version>
|
||||
<nosqlunit.version>0.10.0</nosqlunit.version>
|
||||
<spring-data-commons.version>2.0.3.RELEASE</spring-data-commons.version>
|
||||
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
@ -73,6 +75,12 @@
|
|||
<artifactId>nosqlunit-redis</artifactId>
|
||||
<version>${nosqlunit.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-commons</artifactId>
|
||||
<version>${spring-data-commons.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
package com.baeldung.spring.data.redis.config;
|
||||
|
||||
import com.baeldung.spring.data.redis.queue.MessagePublisher;
|
||||
import com.baeldung.spring.data.redis.queue.RedisMessagePublisher;
|
||||
import com.baeldung.spring.data.redis.queue.RedisMessageSubscriber;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
@ -11,10 +8,16 @@ import org.springframework.data.redis.core.RedisTemplate;
|
|||
import org.springframework.data.redis.listener.ChannelTopic;
|
||||
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
|
||||
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;
|
||||
import org.springframework.data.redis.repository.configuration.EnableRedisRepositories;
|
||||
import org.springframework.data.redis.serializer.GenericToStringSerializer;
|
||||
|
||||
import com.baeldung.spring.data.redis.queue.MessagePublisher;
|
||||
import com.baeldung.spring.data.redis.queue.RedisMessagePublisher;
|
||||
import com.baeldung.spring.data.redis.queue.RedisMessageSubscriber;
|
||||
|
||||
@Configuration
|
||||
@ComponentScan("com.baeldung.spring.data.redis")
|
||||
@EnableRedisRepositories(basePackages = "com.baeldung.spring.data.redis.repo")
|
||||
public class RedisConfig {
|
||||
|
||||
@Bean
|
||||
|
|
|
@ -2,6 +2,9 @@ package com.baeldung.spring.data.redis.model;
|
|||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.springframework.data.redis.core.RedisHash;
|
||||
|
||||
@RedisHash("Student")
|
||||
public class Student implements Serializable {
|
||||
|
||||
public enum Gender {
|
||||
|
|
|
@ -1,18 +1,9 @@
|
|||
package com.baeldung.spring.data.redis.repo;
|
||||
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import com.baeldung.spring.data.redis.model.Student;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public interface StudentRepository {
|
||||
|
||||
void saveStudent(Student person);
|
||||
|
||||
void updateStudent(Student student);
|
||||
|
||||
Student findStudent(String id);
|
||||
|
||||
Map<Object, Object> findAllStudents();
|
||||
|
||||
void deleteStudent(String id);
|
||||
}
|
||||
@Repository
|
||||
public interface StudentRepository extends CrudRepository<Student, String> {}
|
||||
|
|
|
@ -1,49 +0,0 @@
|
|||
package com.baeldung.spring.data.redis.repo;
|
||||
|
||||
import com.baeldung.spring.data.redis.model.Student;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.redis.core.HashOperations;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.util.Map;
|
||||
|
||||
@Repository
|
||||
public class StudentRepositoryImpl implements StudentRepository {
|
||||
|
||||
private static final String KEY = "Student";
|
||||
|
||||
private RedisTemplate<String, Object> redisTemplate;
|
||||
private HashOperations hashOperations;
|
||||
|
||||
@Autowired
|
||||
public StudentRepositoryImpl(RedisTemplate<String, Object> redisTemplate) {
|
||||
this.redisTemplate = redisTemplate;
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
private void init() {
|
||||
hashOperations = redisTemplate.opsForHash();
|
||||
}
|
||||
|
||||
public void saveStudent(final Student student) {
|
||||
hashOperations.put(KEY, student.getId(), student);
|
||||
}
|
||||
|
||||
public void updateStudent(final Student student) {
|
||||
hashOperations.put(KEY, student.getId(), student);
|
||||
}
|
||||
|
||||
public Student findStudent(final String id) {
|
||||
return (Student) hashOperations.get(KEY, id);
|
||||
}
|
||||
|
||||
public Map<Object, Object> findAllStudents() {
|
||||
return hashOperations.entries(KEY);
|
||||
}
|
||||
|
||||
public void deleteStudent(final String id) {
|
||||
hashOperations.delete(KEY, id);
|
||||
}
|
||||
}
|
|
@ -1,17 +1,20 @@
|
|||
package com.baeldung.spring.data.redis.repo;
|
||||
|
||||
import com.baeldung.spring.data.redis.config.RedisConfig;
|
||||
import com.baeldung.spring.data.redis.model.Student;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import com.baeldung.spring.data.redis.config.RedisConfig;
|
||||
import com.baeldung.spring.data.redis.model.Student;
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(classes = RedisConfig.class)
|
||||
|
@ -23,18 +26,18 @@ public class StudentRepositoryIntegrationTest {
|
|||
@Test
|
||||
public void whenSavingStudent_thenAvailableOnRetrieval() throws Exception {
|
||||
final Student student = new Student("Eng2015001", "John Doe", Student.Gender.MALE, 1);
|
||||
studentRepository.saveStudent(student);
|
||||
final Student retrievedStudent = studentRepository.findStudent(student.getId());
|
||||
studentRepository.save(student);
|
||||
final Student retrievedStudent = studentRepository.findById(student.getId()).get();
|
||||
assertEquals(student.getId(), retrievedStudent.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenUpdatingStudent_thenAvailableOnRetrieval() throws Exception {
|
||||
final Student student = new Student("Eng2015001", "John Doe", Student.Gender.MALE, 1);
|
||||
studentRepository.saveStudent(student);
|
||||
studentRepository.save(student);
|
||||
student.setName("Richard Watson");
|
||||
studentRepository.saveStudent(student);
|
||||
final Student retrievedStudent = studentRepository.findStudent(student.getId());
|
||||
studentRepository.save(student);
|
||||
final Student retrievedStudent = studentRepository.findById(student.getId()).get();
|
||||
assertEquals(student.getName(), retrievedStudent.getName());
|
||||
}
|
||||
|
||||
|
@ -42,18 +45,19 @@ public class StudentRepositoryIntegrationTest {
|
|||
public void whenSavingStudents_thenAllShouldAvailableOnRetrieval() throws Exception {
|
||||
final Student engStudent = new Student("Eng2015001", "John Doe", Student.Gender.MALE, 1);
|
||||
final Student medStudent = new Student("Med2015001", "Gareth Houston", Student.Gender.MALE, 2);
|
||||
studentRepository.saveStudent(engStudent);
|
||||
studentRepository.saveStudent(medStudent);
|
||||
final Map<Object, Object> retrievedStudent = studentRepository.findAllStudents();
|
||||
assertEquals(retrievedStudent.size(), 2);
|
||||
studentRepository.save(engStudent);
|
||||
studentRepository.save(medStudent);
|
||||
List<Student> students = new ArrayList<>();
|
||||
studentRepository.findAll().forEach(students::add);
|
||||
assertEquals(students.size(), 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenDeletingStudent_thenNotAvailableOnRetrieval() throws Exception {
|
||||
final Student student = new Student("Eng2015001", "John Doe", Student.Gender.MALE, 1);
|
||||
studentRepository.saveStudent(student);
|
||||
studentRepository.deleteStudent(student.getId());
|
||||
final Student retrievedStudent = studentRepository.findStudent(student.getId());
|
||||
studentRepository.save(student);
|
||||
studentRepository.deleteById(student.getId());
|
||||
final Student retrievedStudent = studentRepository.findById(student.getId()).orElse(null);
|
||||
assertNull(retrievedStudent);
|
||||
}
|
||||
}
|
|
@ -13,7 +13,7 @@
|
|||
<groupId>com.baeldung</groupId>
|
||||
<artifactId>parent-modules</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<relativePath>../</relativePath>
|
||||
<relativePath>../../</relativePath>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
|
|
|
@ -2,6 +2,17 @@ package org.baeldung.inmemory.persistence.dao;
|
|||
|
||||
import org.baeldung.inmemory.persistence.model.Student;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface StudentRepository extends JpaRepository<Student, Long> {
|
||||
|
||||
@Query("SELECT s FROM Student s JOIN s.tags t WHERE t = LOWER(:tag)")
|
||||
List<Student> retrieveByTag(@Param("tag") String tag);
|
||||
|
||||
@Query("SELECT s FROM Student s JOIN s.tags t WHERE s.name = LOWER(:name) AND t = LOWER(:tag)")
|
||||
List<Student> retrieveByNameFilterByTag(@Param("name") String name, @Param("tag") String tag);
|
||||
|
||||
}
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
package org.baeldung.inmemory.persistence.model;
|
||||
|
||||
import javax.persistence.ElementCollection;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Entity
|
||||
public class Student {
|
||||
|
@ -10,6 +13,9 @@ public class Student {
|
|||
private long id;
|
||||
private String name;
|
||||
|
||||
@ElementCollection
|
||||
private List<String> tags = new ArrayList<>();
|
||||
|
||||
public Student() {
|
||||
}
|
||||
|
||||
|
@ -35,4 +41,11 @@ public class Student {
|
|||
this.name = name;
|
||||
}
|
||||
|
||||
public List<String> getTags() {
|
||||
return tags;
|
||||
}
|
||||
|
||||
public void setTags(List<String> tags) {
|
||||
this.tags.addAll(tags);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,9 @@ import org.springframework.transaction.annotation.Transactional;
|
|||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
|
@ -34,4 +37,46 @@ public class InMemoryDBIntegrationTest {
|
|||
assertEquals("name incorrect", NAME, student2.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenStudentWithTags_whenSave_thenGetByTagOk(){
|
||||
Student student = new Student(ID, NAME);
|
||||
student.setTags(Arrays.asList("full time", "computer science"));
|
||||
studentRepository.save(student);
|
||||
|
||||
Student student2 = studentRepository.retrieveByTag("full time").get(0);
|
||||
assertEquals("name incorrect", NAME, student2.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenMultipleStudentsWithTags_whenSave_thenGetByTagReturnsCorrectCount(){
|
||||
Student student = new Student(0, "Larry");
|
||||
student.setTags(Arrays.asList("full time", "computer science"));
|
||||
studentRepository.save(student);
|
||||
|
||||
Student student2 = new Student(1, "Curly");
|
||||
student2.setTags(Arrays.asList("part time", "rocket science"));
|
||||
studentRepository.save(student2);
|
||||
|
||||
Student student3 = new Student(2, "Moe");
|
||||
student3.setTags(Arrays.asList("full time", "philosophy"));
|
||||
studentRepository.save(student3);
|
||||
|
||||
Student student4 = new Student(3, "Shemp");
|
||||
student4.setTags(Arrays.asList("part time", "mathematics"));
|
||||
studentRepository.save(student4);
|
||||
|
||||
List<Student> students = studentRepository.retrieveByTag("full time");
|
||||
assertEquals("size incorrect", 2, students.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenStudentWithTags_whenSave_thenGetByNameAndTagOk(){
|
||||
Student student = new Student(ID, NAME);
|
||||
student.setTags(Arrays.asList("full time", "computer science"));
|
||||
studentRepository.save(student);
|
||||
|
||||
Student student2 = studentRepository.retrieveByNameFilterByTag("John", "full time").get(0);
|
||||
assertEquals("name incorrect", NAME, student2.getName());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
2
pom.xml
2
pom.xml
|
@ -49,7 +49,9 @@
|
|||
<module>core-java</module>
|
||||
<module>core-java-io</module>
|
||||
<module>core-java-8</module>
|
||||
<!--
|
||||
<module>core-java-concurrency</module>
|
||||
-->
|
||||
<module>couchbase</module>
|
||||
|
||||
<module>deltaspike</module>
|
||||
|
|
|
@ -26,11 +26,17 @@
|
|||
<version>${assertj.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>io.projectreactor</groupId>
|
||||
<artifactId>reactor-test</artifactId>
|
||||
<version>${reactor-core.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<reactor-core.version>3.0.5.RELEASE</reactor-core.version>
|
||||
<reactor-core.version>3.1.3.RELEASE</reactor-core.version>
|
||||
<assertj.version>3.6.1</assertj.version>
|
||||
</properties>
|
||||
|
||||
|
|
|
@ -0,0 +1,182 @@
|
|||
package com.baeldung.reactor.core;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
public class CombiningPublishersTest {
|
||||
|
||||
private static Integer min = 1;
|
||||
private static Integer max = 5;
|
||||
|
||||
private static Flux<Integer> evenNumbers = Flux.range(min, max).filter(x -> x % 2 == 0);
|
||||
private static Flux<Integer> oddNumbers = Flux.range(min, max).filter(x -> x % 2 > 0);
|
||||
|
||||
|
||||
@Test
|
||||
public void testMerge() {
|
||||
Flux<Integer> fluxOfIntegers = Flux.merge(
|
||||
evenNumbers,
|
||||
oddNumbers);
|
||||
|
||||
StepVerifier.create(fluxOfIntegers)
|
||||
.expectNext(2)
|
||||
.expectNext(4)
|
||||
.expectNext(1)
|
||||
.expectNext(3)
|
||||
.expectNext(5)
|
||||
.expectComplete()
|
||||
.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMergeWithDelayedElements() {
|
||||
Flux<Integer> fluxOfIntegers = Flux.merge(
|
||||
evenNumbers.delayElements(Duration.ofMillis(500L)),
|
||||
oddNumbers.delayElements(Duration.ofMillis(300L)));
|
||||
|
||||
StepVerifier.create(fluxOfIntegers)
|
||||
.expectNext(1)
|
||||
.expectNext(2)
|
||||
.expectNext(3)
|
||||
.expectNext(5)
|
||||
.expectNext(4)
|
||||
.expectComplete()
|
||||
.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConcat() {
|
||||
Flux<Integer> fluxOfIntegers = Flux.concat(
|
||||
evenNumbers.delayElements(Duration.ofMillis(500L)),
|
||||
oddNumbers.delayElements(Duration.ofMillis(300L)));
|
||||
|
||||
StepVerifier.create(fluxOfIntegers)
|
||||
.expectNext(2)
|
||||
.expectNext(4)
|
||||
.expectNext(1)
|
||||
.expectNext(3)
|
||||
.expectNext(5)
|
||||
.expectComplete()
|
||||
.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConcatWith() {
|
||||
Flux<Integer> fluxOfIntegers = evenNumbers
|
||||
.concatWith(oddNumbers);
|
||||
|
||||
StepVerifier.create(fluxOfIntegers)
|
||||
.expectNext(2)
|
||||
.expectNext(4)
|
||||
.expectNext(1)
|
||||
.expectNext(3)
|
||||
.expectNext(5)
|
||||
.expectComplete()
|
||||
.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCombineLatest() {
|
||||
Flux<Integer> fluxOfIntegers = Flux.combineLatest(
|
||||
evenNumbers,
|
||||
oddNumbers,
|
||||
(a, b) -> a + b);
|
||||
|
||||
StepVerifier.create(fluxOfIntegers)
|
||||
.expectNext(5)
|
||||
.expectNext(7)
|
||||
.expectNext(9)
|
||||
.expectComplete()
|
||||
.verify();
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCombineLatest1() {
|
||||
StepVerifier.create(Flux.combineLatest(obj -> (int) obj[1], evenNumbers, oddNumbers))
|
||||
.expectNext(1)
|
||||
.expectNext(3)
|
||||
.expectNext(5)
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMergeSequential() {
|
||||
Flux<Integer> fluxOfIntegers = Flux.mergeSequential(
|
||||
evenNumbers,
|
||||
oddNumbers);
|
||||
|
||||
StepVerifier.create(fluxOfIntegers)
|
||||
.expectNext(2)
|
||||
.expectNext(4)
|
||||
.expectNext(1)
|
||||
.expectNext(3)
|
||||
.expectNext(5)
|
||||
.expectComplete()
|
||||
.verify();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testMergeDelayError() {
|
||||
Flux<Integer> fluxOfIntegers = Flux.mergeDelayError(1,
|
||||
evenNumbers.delayElements(Duration.ofMillis(500L)),
|
||||
oddNumbers.delayElements(Duration.ofMillis(300L)));
|
||||
|
||||
StepVerifier.create(fluxOfIntegers)
|
||||
.expectNext(1)
|
||||
.expectNext(2)
|
||||
.expectNext(3)
|
||||
.expectNext(5)
|
||||
.expectNext(4)
|
||||
.expectComplete()
|
||||
.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMergeWith() {
|
||||
Flux<Integer> fluxOfIntegers = evenNumbers.mergeWith(oddNumbers);
|
||||
|
||||
StepVerifier.create(fluxOfIntegers)
|
||||
.expectNext(2)
|
||||
.expectNext(4)
|
||||
.expectNext(1)
|
||||
.expectNext(3)
|
||||
.expectNext(5)
|
||||
.expectComplete()
|
||||
.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testZip() {
|
||||
Flux<Integer> fluxOfIntegers = Flux.zip(
|
||||
evenNumbers,
|
||||
oddNumbers,
|
||||
(a, b) -> a + b);
|
||||
|
||||
StepVerifier.create(fluxOfIntegers)
|
||||
.expectNext(3)
|
||||
.expectNext(7)
|
||||
.expectComplete()
|
||||
.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testZipWith() {
|
||||
Flux<Integer> fluxOfIntegers = evenNumbers
|
||||
.zipWith(oddNumbers,
|
||||
(a, b) -> a * b);
|
||||
|
||||
StepVerifier.create(fluxOfIntegers)
|
||||
.expectNext(2)
|
||||
.expectNext(12)
|
||||
.expectComplete()
|
||||
.verify();
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package com.baeldung.dsl;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
||||
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
|
||||
|
||||
public class ClientErrorLoggingConfigurer extends AbstractHttpConfigurer<ClientErrorLoggingConfigurer, HttpSecurity> {
|
||||
|
||||
private List<HttpStatus> errorCodes;
|
||||
|
||||
public ClientErrorLoggingConfigurer(List<HttpStatus> errorCodes) {
|
||||
this.errorCodes = errorCodes;
|
||||
}
|
||||
|
||||
public ClientErrorLoggingConfigurer() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(HttpSecurity http) throws Exception {
|
||||
// initialization code
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(HttpSecurity http) throws Exception {
|
||||
http.addFilterAfter(new ClientErrorLoggingFilter(errorCodes), FilterSecurityInterceptor.class);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
package com.baeldung.dsl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.web.filter.GenericFilterBean;
|
||||
|
||||
public class ClientErrorLoggingFilter extends GenericFilterBean {
|
||||
|
||||
private static final Logger logger = LogManager.getLogger(ClientErrorLoggingFilter.class);
|
||||
|
||||
private List<HttpStatus> errorCodes;
|
||||
|
||||
public ClientErrorLoggingFilter(List<HttpStatus> errorCodes) {
|
||||
this.errorCodes = errorCodes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
|
||||
|
||||
Authentication auth = SecurityContextHolder.getContext()
|
||||
.getAuthentication();
|
||||
|
||||
if (auth != null) {
|
||||
int status = ((HttpServletResponse) response).getStatus();
|
||||
if (status >= 400 && status < 500) {
|
||||
if (errorCodes == null) {
|
||||
logger.debug("User " + auth.getName() + " encountered error " + status);
|
||||
} else {
|
||||
if (errorCodes.stream()
|
||||
.filter(s -> s.value() == status)
|
||||
.findFirst()
|
||||
.isPresent()) {
|
||||
logger.debug("User " + auth.getName() + " encountered error " + status);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package com.baeldung.dsl;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class CustomConfigurerApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(CustomConfigurerApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package com.baeldung.dsl;
|
||||
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
public class MyController {
|
||||
|
||||
@GetMapping("/admin")
|
||||
public String getAdminPage() {
|
||||
return "Hello Admin";
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
package com.baeldung.dsl;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
|
||||
@Configuration
|
||||
public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http.authorizeRequests()
|
||||
.antMatchers("/admin*")
|
||||
.hasAnyRole("ADMIN")
|
||||
.anyRequest()
|
||||
.authenticated()
|
||||
.and()
|
||||
.formLogin()
|
||||
.and()
|
||||
.apply(clientErrorLogging());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ClientErrorLoggingConfigurer clientErrorLogging() {
|
||||
return new ClientErrorLoggingConfigurer();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth.inMemoryAuthentication()
|
||||
.passwordEncoder(passwordEncoder())
|
||||
.withUser("user1")
|
||||
.password(passwordEncoder().encode("user"))
|
||||
.roles("USER")
|
||||
.and()
|
||||
.withUser("admin")
|
||||
.password(passwordEncoder().encode("admin"))
|
||||
.roles("ADMIN");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PasswordEncoder passwordEncoder() {
|
||||
return new BCryptPasswordEncoder();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
server.port=8081
|
||||
|
||||
logging.level.root=INFO
|
||||
logging.level.root=INFO
|
||||
|
||||
logging.level.com.baeldung.dsl.ClientErrorLoggingFilter=DEBUG
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
package com.baeldung.execption;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
@RestController
|
||||
public class ActorController {
|
||||
|
||||
@Autowired
|
||||
ActorService actorService;
|
||||
|
||||
@GetMapping("/actor/{id}")
|
||||
public String getActorName(@PathVariable("id") int id) {
|
||||
try {
|
||||
return actorService.getActor(id);
|
||||
} catch (ActorNotFoundException ex) {
|
||||
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Actor Not Found", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@DeleteMapping("/actor/{id}")
|
||||
public String getActor(@PathVariable("id") int id) {
|
||||
return actorService.removeActor(id);
|
||||
}
|
||||
|
||||
@PutMapping("/actor/{id}/{name}")
|
||||
public String updateActorName(@PathVariable("id") int id, @PathVariable("name") String name) {
|
||||
try {
|
||||
return actorService.updateActor(id, name);
|
||||
} catch (ActorNotFoundException ex) {
|
||||
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Provide correct Actor Id", ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package com.baeldung.execption;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
@ResponseStatus(code = HttpStatus.NOT_FOUND, reason = "Actor Not Found")
|
||||
public class ActorNotFoundException extends Exception {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public ActorNotFoundException(String errorMessage) {
|
||||
super(errorMessage);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package com.baeldung.execption;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
@Service
|
||||
public class ActorService {
|
||||
List<String> actors = Arrays.asList("Jack Nicholson", "Marlon Brando", "Robert De Niro", "Al Pacino", "Tom Hanks");
|
||||
|
||||
public String getActor(int index) throws ActorNotFoundException {
|
||||
if (index >= actors.size()) {
|
||||
throw new ActorNotFoundException("Actor Not Found in Repsoitory");
|
||||
}
|
||||
return actors.get(index);
|
||||
}
|
||||
|
||||
public String updateActor(int index, String actorName) throws ActorNotFoundException {
|
||||
if (index >= actors.size()) {
|
||||
throw new ActorNotFoundException("Actor Not Found in Repsoitory");
|
||||
}
|
||||
actors.set(index, actorName);
|
||||
return actorName;
|
||||
}
|
||||
|
||||
public String removeActor(int index) {
|
||||
if (index >= actors.size()) {
|
||||
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Actor Not Found in Repsoitory");
|
||||
}
|
||||
return actors.remove(index);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package com.baeldung.execption;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
|
||||
@SpringBootApplication(exclude = SecurityAutoConfiguration.class)
|
||||
@ComponentScan(basePackages = { "com.baeldung.execption" })
|
||||
public class SpringExceptionApplication {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SpringExceptionApplication.class, args);
|
||||
}
|
||||
}
|
|
@ -18,9 +18,10 @@
|
|||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<spring.version>4.3.4.RELEASE</spring.version>
|
||||
<spring.batch.version>3.0.7.RELEASE</spring.batch.version>
|
||||
<spring.version>5.0.3.RELEASE</spring.version>
|
||||
<spring.batch.version>4.0.0.RELEASE</spring.batch.version>
|
||||
<sqlite.version>3.15.1</sqlite.version>
|
||||
<opencsv.version>4.1</opencsv.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
@ -51,6 +52,16 @@
|
|||
<artifactId>spring-batch-core</artifactId>
|
||||
<version>${spring.batch.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.batch</groupId>
|
||||
<artifactId>spring-batch-test</artifactId>
|
||||
<version>${spring.batch.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.opencsv</groupId>
|
||||
<artifactId>opencsv</artifactId>
|
||||
<version>${opencsv.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
package org.baeldung.taskletsvschunks.chunks;
|
||||
|
||||
import org.baeldung.taskletsvschunks.model.Line;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.batch.core.ExitStatus;
|
||||
import org.springframework.batch.core.StepExecution;
|
||||
import org.springframework.batch.core.StepExecutionListener;
|
||||
import org.springframework.batch.item.ItemProcessor;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
|
||||
public class LineProcessor implements ItemProcessor<Line, Line>, StepExecutionListener {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(LineProcessor.class);
|
||||
|
||||
@Override
|
||||
public void beforeStep(StepExecution stepExecution) {
|
||||
logger.debug("Line Processor initialized.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Line process(Line line) throws Exception {
|
||||
long age = ChronoUnit.YEARS.between(line.getDob(), LocalDate.now());
|
||||
logger.debug("Calculated age " + age + " for line " + line.toString());
|
||||
line.setAge(age);
|
||||
return line;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExitStatus afterStep(StepExecution stepExecution) {
|
||||
logger.debug("Line Processor ended.");
|
||||
return ExitStatus.COMPLETED;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package org.baeldung.taskletsvschunks.chunks;
|
||||
|
||||
import org.baeldung.taskletsvschunks.model.Line;
|
||||
import org.baeldung.taskletsvschunks.utils.FileUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.batch.core.ExitStatus;
|
||||
import org.springframework.batch.core.StepExecution;
|
||||
import org.springframework.batch.core.StepExecutionListener;
|
||||
import org.springframework.batch.item.ItemReader;
|
||||
|
||||
public class LineReader implements ItemReader<Line>, StepExecutionListener {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(LineReader.class);
|
||||
private FileUtils fu;
|
||||
|
||||
@Override
|
||||
public void beforeStep(StepExecution stepExecution) {
|
||||
fu = new FileUtils("taskletsvschunks/input/tasklets-vs-chunks.csv");
|
||||
logger.debug("Line Reader initialized.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Line read() throws Exception {
|
||||
Line line = fu.readLine();
|
||||
if (line != null) logger.debug("Read line: " + line.toString());
|
||||
return line;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExitStatus afterStep(StepExecution stepExecution) {
|
||||
fu.closeReader();
|
||||
logger.debug("Line Reader ended.");
|
||||
return ExitStatus.COMPLETED;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package org.baeldung.taskletsvschunks.chunks;
|
||||
|
||||
import org.baeldung.taskletsvschunks.model.Line;
|
||||
import org.baeldung.taskletsvschunks.utils.FileUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.batch.core.ExitStatus;
|
||||
import org.springframework.batch.core.StepExecution;
|
||||
import org.springframework.batch.core.StepExecutionListener;
|
||||
import org.springframework.batch.item.ItemWriter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class LinesWriter implements ItemWriter<Line>, StepExecutionListener {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(LinesWriter.class);
|
||||
private FileUtils fu;
|
||||
|
||||
@Override
|
||||
public void beforeStep(StepExecution stepExecution) {
|
||||
fu = new FileUtils("output.csv");
|
||||
logger.debug("Line Writer initialized.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExitStatus afterStep(StepExecution stepExecution) {
|
||||
fu.closeWriter();
|
||||
logger.debug("Line Writer ended.");
|
||||
return ExitStatus.COMPLETED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(List<? extends Line> lines) throws Exception {
|
||||
for (Line line : lines) {
|
||||
fu.writeLine(line);
|
||||
logger.debug("Wrote line " + line.toString());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
package org.baeldung.taskletsvschunks.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
public class Line implements Serializable {
|
||||
|
||||
private String name;
|
||||
private LocalDate dob;
|
||||
private Long age;
|
||||
|
||||
public Line(String name, LocalDate dob) {
|
||||
this.name = name;
|
||||
this.dob = dob;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public LocalDate getDob() {
|
||||
return dob;
|
||||
}
|
||||
|
||||
public void setDob(LocalDate dob) {
|
||||
this.dob = dob;
|
||||
}
|
||||
|
||||
public Long getAge() {
|
||||
return age;
|
||||
}
|
||||
|
||||
public void setAge(Long age) {
|
||||
this.age = age;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("[");
|
||||
sb.append(this.name);
|
||||
sb.append(",");
|
||||
sb.append(this.dob.format(DateTimeFormatter.ofPattern("MM/dd/yyyy")));
|
||||
if (this.age != null) {
|
||||
sb.append(",");
|
||||
sb.append(this.age);
|
||||
}
|
||||
sb.append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package org.baeldung.taskletsvschunks.tasklets;
|
||||
|
||||
import org.baeldung.taskletsvschunks.model.Line;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.batch.core.ExitStatus;
|
||||
import org.springframework.batch.core.StepContribution;
|
||||
import org.springframework.batch.core.StepExecution;
|
||||
import org.springframework.batch.core.StepExecutionListener;
|
||||
import org.springframework.batch.core.scope.context.ChunkContext;
|
||||
import org.springframework.batch.core.step.tasklet.Tasklet;
|
||||
import org.springframework.batch.item.ExecutionContext;
|
||||
import org.springframework.batch.repeat.RepeatStatus;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.List;
|
||||
|
||||
public class LinesProcessor implements Tasklet, StepExecutionListener {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(LinesProcessor.class);
|
||||
|
||||
private List<Line> lines;
|
||||
|
||||
@Override
|
||||
public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
|
||||
for (Line line : lines) {
|
||||
long age = ChronoUnit.YEARS.between(line.getDob(), LocalDate.now());
|
||||
logger.debug("Calculated age " + age + " for line " + line.toString());
|
||||
line.setAge(age);
|
||||
}
|
||||
return RepeatStatus.FINISHED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeStep(StepExecution stepExecution) {
|
||||
ExecutionContext executionContext = stepExecution
|
||||
.getJobExecution()
|
||||
.getExecutionContext();
|
||||
this.lines = (List<Line>) executionContext.get("lines");
|
||||
logger.debug("Lines Processor initialized.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExitStatus afterStep(StepExecution stepExecution) {
|
||||
logger.debug("Lines Processor ended.");
|
||||
return ExitStatus.COMPLETED;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
package org.baeldung.taskletsvschunks.tasklets;
|
||||
|
||||
import org.baeldung.taskletsvschunks.model.Line;
|
||||
import org.baeldung.taskletsvschunks.utils.FileUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.batch.core.ExitStatus;
|
||||
import org.springframework.batch.core.StepContribution;
|
||||
import org.springframework.batch.core.StepExecution;
|
||||
import org.springframework.batch.core.StepExecutionListener;
|
||||
import org.springframework.batch.core.scope.context.ChunkContext;
|
||||
import org.springframework.batch.core.step.tasklet.Tasklet;
|
||||
import org.springframework.batch.repeat.RepeatStatus;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class LinesReader implements Tasklet, StepExecutionListener {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(LinesReader.class);
|
||||
|
||||
private List<Line> lines;
|
||||
private FileUtils fu;
|
||||
|
||||
@Override
|
||||
public void beforeStep(StepExecution stepExecution) {
|
||||
lines = new ArrayList<Line>();
|
||||
fu = new FileUtils("taskletsvschunks/input/tasklets-vs-chunks.csv");
|
||||
logger.debug("Lines Reader initialized.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
|
||||
Line line = fu.readLine();
|
||||
while (line != null) {
|
||||
lines.add(line);
|
||||
logger.debug("Read line: " + line.toString());
|
||||
line = fu.readLine();
|
||||
}
|
||||
return RepeatStatus.FINISHED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExitStatus afterStep(StepExecution stepExecution) {
|
||||
fu.closeReader();
|
||||
stepExecution
|
||||
.getJobExecution()
|
||||
.getExecutionContext()
|
||||
.put("lines", this.lines);
|
||||
logger.debug("Lines Reader ended.");
|
||||
return ExitStatus.COMPLETED;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
package org.baeldung.taskletsvschunks.tasklets;
|
||||
|
||||
import org.baeldung.taskletsvschunks.model.Line;
|
||||
import org.baeldung.taskletsvschunks.utils.FileUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.batch.core.ExitStatus;
|
||||
import org.springframework.batch.core.StepContribution;
|
||||
import org.springframework.batch.core.StepExecution;
|
||||
import org.springframework.batch.core.StepExecutionListener;
|
||||
import org.springframework.batch.core.scope.context.ChunkContext;
|
||||
import org.springframework.batch.core.step.tasklet.Tasklet;
|
||||
import org.springframework.batch.item.ExecutionContext;
|
||||
import org.springframework.batch.repeat.RepeatStatus;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class LinesWriter implements Tasklet, StepExecutionListener {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(LinesWriter.class);
|
||||
|
||||
private List<Line> lines;
|
||||
private FileUtils fu;
|
||||
|
||||
@Override
|
||||
public void beforeStep(StepExecution stepExecution) {
|
||||
ExecutionContext executionContext = stepExecution
|
||||
.getJobExecution()
|
||||
.getExecutionContext();
|
||||
this.lines = (List<Line>) executionContext.get("lines");
|
||||
fu = new FileUtils("output.csv");
|
||||
logger.debug("Lines Writer initialized.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
|
||||
for (Line line : lines) {
|
||||
fu.writeLine(line);
|
||||
logger.debug("Wrote line " + line.toString());
|
||||
}
|
||||
return RepeatStatus.FINISHED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExitStatus afterStep(StepExecution stepExecution) {
|
||||
fu.closeWriter();
|
||||
logger.debug("Lines Writer ended.");
|
||||
return ExitStatus.COMPLETED;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
package org.baeldung.taskletsvschunks.utils;
|
||||
|
||||
import com.opencsv.CSVReader;
|
||||
import com.opencsv.CSVWriter;
|
||||
import org.baeldung.taskletsvschunks.model.Line;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
public class FileUtils {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(FileUtils.class);
|
||||
|
||||
private String fileName;
|
||||
private CSVReader CSVReader;
|
||||
private CSVWriter CSVWriter;
|
||||
private FileReader fileReader;
|
||||
private FileWriter fileWriter;
|
||||
private File file;
|
||||
|
||||
public FileUtils(String fileName) {
|
||||
this.fileName = fileName;
|
||||
}
|
||||
|
||||
public Line readLine() {
|
||||
try {
|
||||
if (CSVReader == null) initReader();
|
||||
String[] line = CSVReader.readNext();
|
||||
if (line == null) return null;
|
||||
return new Line(line[0], LocalDate.parse(line[1], DateTimeFormatter.ofPattern("MM/dd/yyyy")));
|
||||
} catch (Exception e) {
|
||||
logger.error("Error while reading line in file: " + this.fileName);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void writeLine(Line line) {
|
||||
try {
|
||||
if (CSVWriter == null) initWriter();
|
||||
String[] lineStr = new String[2];
|
||||
lineStr[0] = line.getName();
|
||||
lineStr[1] = line
|
||||
.getAge()
|
||||
.toString();
|
||||
CSVWriter.writeNext(lineStr);
|
||||
} catch (Exception e) {
|
||||
logger.error("Error while writing line in file: " + this.fileName);
|
||||
}
|
||||
}
|
||||
|
||||
private void initReader() throws Exception {
|
||||
ClassLoader classLoader = this
|
||||
.getClass()
|
||||
.getClassLoader();
|
||||
if (file == null) file = new File(classLoader
|
||||
.getResource(fileName)
|
||||
.getFile());
|
||||
if (fileReader == null) fileReader = new FileReader(file);
|
||||
if (CSVReader == null) CSVReader = new CSVReader(fileReader);
|
||||
}
|
||||
|
||||
private void initWriter() throws Exception {
|
||||
if (file == null) {
|
||||
file = new File(fileName);
|
||||
file.createNewFile();
|
||||
}
|
||||
if (fileWriter == null) fileWriter = new FileWriter(file, true);
|
||||
if (CSVWriter == null) CSVWriter = new CSVWriter(fileWriter);
|
||||
}
|
||||
|
||||
public void closeWriter() {
|
||||
try {
|
||||
CSVWriter.close();
|
||||
fileWriter.close();
|
||||
} catch (IOException e) {
|
||||
logger.error("Error while closing writer.");
|
||||
}
|
||||
}
|
||||
|
||||
public void closeReader() {
|
||||
try {
|
||||
CSVReader.close();
|
||||
fileReader.close();
|
||||
} catch (IOException e) {
|
||||
logger.error("Error while closing reader.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
<configuration>
|
||||
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<layout class="ch.qos.logback.classic.PatternLayout">
|
||||
<Pattern>
|
||||
%d{yyyy-MM-dd HH:mm:ss} [%thread] %level %logger{35} - %msg%n
|
||||
</Pattern>
|
||||
</layout>
|
||||
</appender>
|
||||
|
||||
<logger name="org.baeldung.taskletsvschunks" level="debug"
|
||||
additivity="false">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</logger>
|
||||
|
||||
<root level="error">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</root>
|
||||
|
||||
</configuration>
|
|
@ -0,0 +1,39 @@
|
|||
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:batch="http://www.springframework.org/schema/batch"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/batch
|
||||
http://www.springframework.org/schema/batch/spring-batch-3.0.xsd
|
||||
http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd">
|
||||
|
||||
<bean class="org.springframework.batch.test.JobLauncherTestUtils"/>
|
||||
|
||||
<bean id="jobRepository"
|
||||
class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean">
|
||||
<property name="transactionManager" ref="transactionManager"/>
|
||||
</bean>
|
||||
|
||||
<bean id="transactionManager"
|
||||
class="org.springframework.batch.support.transaction.ResourcelessTransactionManager"/>
|
||||
|
||||
<bean id="jobLauncher"
|
||||
class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
|
||||
<property name="jobRepository" ref="jobRepository"/>
|
||||
</bean>
|
||||
|
||||
<bean id="lineReader" class="org.baeldung.taskletsvschunks.chunks.LineReader"/>
|
||||
|
||||
<bean id="lineProcessor" class="org.baeldung.taskletsvschunks.chunks.LineProcessor"/>
|
||||
|
||||
<bean id="linesWriter" class="org.baeldung.taskletsvschunks.chunks.LinesWriter"/>
|
||||
|
||||
<batch:job id="chunksJob">
|
||||
<batch:step id="processLines">
|
||||
<batch:tasklet>
|
||||
<batch:chunk reader="lineReader" writer="linesWriter" processor="lineProcessor" commit-interval="2"/>
|
||||
</batch:tasklet>
|
||||
<batch:end on="FAILED"/>
|
||||
<batch:end on="COMPLETED"/>
|
||||
</batch:step>
|
||||
</batch:job>
|
||||
|
||||
</beans>
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue