diff --git a/.gitignore b/.gitignore index 08f570ad06..693a35c176 100644 --- a/.gitignore +++ b/.gitignore @@ -43,3 +43,4 @@ spring-call-getters-using-reflection/.mvn/wrapper/maven-wrapper.properties spring-check-if-a-property-is-null/.mvn/wrapper/maven-wrapper.properties *.springBeans +20171220-JMeter.csv diff --git a/algorithms/src/main/java/com/baeldung/algorithms/maze/solver/BFSMazeSolver.java b/algorithms/src/main/java/com/baeldung/algorithms/maze/solver/BFSMazeSolver.java new file mode 100644 index 0000000000..08972251b8 --- /dev/null +++ b/algorithms/src/main/java/com/baeldung/algorithms/maze/solver/BFSMazeSolver.java @@ -0,0 +1,52 @@ +package com.baeldung.algorithms.maze.solver; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +public class BFSMazeSolver { + private static final int[][] DIRECTIONS = { { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, 0 } }; + + public List solve(Maze maze) { + LinkedList nextToVisit = new LinkedList<>(); + Coordinate start = maze.getEntry(); + nextToVisit.add(start); + + while (!nextToVisit.isEmpty()) { + Coordinate cur = nextToVisit.remove(); + + if (!maze.isValidLocation(cur.getX(), cur.getY()) || maze.isExplored(cur.getX(), cur.getY())) { + continue; + } + + if (maze.isWall(cur.getX(), cur.getY())) { + maze.setVisited(cur.getX(), cur.getY(), true); + continue; + } + + if (maze.isExit(cur.getX(), cur.getY())) { + return backtrackPath(cur); + } + + for (int[] direction : DIRECTIONS) { + Coordinate coordinate = new Coordinate(cur.getX() + direction[0], cur.getY() + direction[1], cur); + nextToVisit.add(coordinate); + maze.setVisited(cur.getX(), cur.getY(), true); + } + } + return Collections.emptyList(); + } + + private List backtrackPath(Coordinate cur) { + List path = new ArrayList<>(); + Coordinate iter = cur; + + while (iter != null) { + path.add(iter); + iter = iter.parent; + } + + return path; + } +} diff --git a/algorithms/src/main/java/com/baeldung/algorithms/maze/solver/Coordinate.java b/algorithms/src/main/java/com/baeldung/algorithms/maze/solver/Coordinate.java new file mode 100644 index 0000000000..09b2ced5e6 --- /dev/null +++ b/algorithms/src/main/java/com/baeldung/algorithms/maze/solver/Coordinate.java @@ -0,0 +1,31 @@ +package com.baeldung.algorithms.maze.solver; + +public class Coordinate { + int x; + int y; + Coordinate parent; + + public Coordinate(int x, int y) { + this.x = x; + this.y = y; + this.parent = null; + } + + public Coordinate(int x, int y, Coordinate parent) { + this.x = x; + this.y = y; + this.parent = parent; + } + + int getX() { + return x; + } + + int getY() { + return y; + } + + Coordinate getParent() { + return parent; + } +} diff --git a/algorithms/src/main/java/com/baeldung/algorithms/maze/solver/DFSMazeSolver.java b/algorithms/src/main/java/com/baeldung/algorithms/maze/solver/DFSMazeSolver.java new file mode 100644 index 0000000000..f9640066b9 --- /dev/null +++ b/algorithms/src/main/java/com/baeldung/algorithms/maze/solver/DFSMazeSolver.java @@ -0,0 +1,48 @@ +package com.baeldung.algorithms.maze.solver; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class DFSMazeSolver { + private static final int[][] DIRECTIONS = { { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, 0 } }; + + public List solve(Maze maze) { + List path = new ArrayList<>(); + if (explore(maze, maze.getEntry() + .getX(), + maze.getEntry() + .getY(), + path)) { + return path; + } + return Collections.emptyList(); + } + + private boolean explore(Maze maze, int row, int col, List path) { + if (!maze.isValidLocation(row, col) || maze.isWall(row, col) || maze.isExplored(row, col)) { + return false; + } + + path.add(new Coordinate(row, col)); + maze.setVisited(row, col, true); + + if (maze.isExit(row, col)) { + return true; + } + + for (int[] direction : DIRECTIONS) { + Coordinate coordinate = getNextCoordinate(row, col, direction[0], direction[1]); + if (explore(maze, coordinate.getX(), coordinate.getY(), path)) { + return true; + } + } + + path.remove(path.size() - 1); + return false; + } + + private Coordinate getNextCoordinate(int row, int col, int i, int j) { + return new Coordinate(row + i, col + j); + } +} diff --git a/algorithms/src/main/java/com/baeldung/algorithms/maze/solver/Maze.java b/algorithms/src/main/java/com/baeldung/algorithms/maze/solver/Maze.java new file mode 100644 index 0000000000..8aaa44d9b1 --- /dev/null +++ b/algorithms/src/main/java/com/baeldung/algorithms/maze/solver/Maze.java @@ -0,0 +1,141 @@ +package com.baeldung.algorithms.maze.solver; + +import java.io.File; +import java.io.FileNotFoundException; +import java.util.Arrays; +import java.util.List; +import java.util.Scanner; + +public class Maze { + private static final int ROAD = 0; + private static final int WALL = 1; + private static final int START = 2; + private static final int EXIT = 3; + private static final int PATH = 4; + + private int[][] maze; + private boolean[][] visited; + private Coordinate start; + private Coordinate end; + + public Maze(File maze) throws FileNotFoundException { + String fileText = ""; + try (Scanner input = new Scanner(maze)) { + while (input.hasNextLine()) { + fileText += input.nextLine() + "\n"; + } + } + initializeMaze(fileText); + } + + private void initializeMaze(String text) { + if (text == null || (text = text.trim()).length() == 0) { + throw new IllegalArgumentException("empty lines data"); + } + + String[] lines = text.split("[\r]?\n"); + maze = new int[lines.length][lines[0].length()]; + visited = new boolean[lines.length][lines[0].length()]; + + for (int row = 0; row < getHeight(); row++) { + if (lines[row].length() != getWidth()) { + throw new IllegalArgumentException("line " + (row + 1) + " wrong length (was " + lines[row].length() + " but should be " + getWidth() + ")"); + } + + for (int col = 0; col < getWidth(); col++) { + if (lines[row].charAt(col) == '#') + maze[row][col] = WALL; + else if (lines[row].charAt(col) == 'S') { + maze[row][col] = START; + start = new Coordinate(row, col); + } else if (lines[row].charAt(col) == 'E') { + maze[row][col] = EXIT; + end = new Coordinate(row, col); + } else + maze[row][col] = ROAD; + } + } + } + + public int getHeight() { + return maze.length; + } + + public int getWidth() { + return maze[0].length; + } + + public Coordinate getEntry() { + return start; + } + + public Coordinate getExit() { + return end; + } + + public boolean isExit(int x, int y) { + return x == end.getX() && y == end.getY(); + } + + public boolean isStart(int x, int y) { + return x == start.getX() && y == start.getY(); + } + + public boolean isExplored(int row, int col) { + return visited[row][col]; + } + + public boolean isWall(int row, int col) { + return maze[row][col] == WALL; + } + + public void setVisited(int row, int col, boolean value) { + visited[row][col] = value; + } + + public boolean isValidLocation(int row, int col) { + if (row < 0 || row >= getHeight() || col < 0 || col >= getWidth()) { + return false; + } + return true; + } + + public void printPath(List path) { + int[][] tempMaze = Arrays.stream(maze) + .map(int[]::clone) + .toArray(int[][]::new); + for (Coordinate coordinate : path) { + if (isStart(coordinate.getX(), coordinate.getY()) || isExit(coordinate.getX(), coordinate.getY())) { + continue; + } + tempMaze[coordinate.getX()][coordinate.getY()] = PATH; + } + System.out.println(toString(tempMaze)); + } + + public String toString(int[][] maze) { + StringBuilder result = new StringBuilder(getWidth() * (getHeight() + 1)); + for (int row = 0; row < getHeight(); row++) { + for (int col = 0; col < getWidth(); col++) { + if (maze[row][col] == ROAD) { + result.append(' '); + } else if (maze[row][col] == WALL) { + result.append('#'); + } else if (maze[row][col] == START) { + result.append('S'); + } else if (maze[row][col] == EXIT) { + result.append('E'); + } else { + result.append('.'); + } + } + result.append('\n'); + } + return result.toString(); + } + + public void reset() { + for (int i = 0; i < visited.length; i++) + Arrays.fill(visited[i], false); + } +} diff --git a/algorithms/src/main/java/com/baeldung/algorithms/maze/solver/MazeDriver.java b/algorithms/src/main/java/com/baeldung/algorithms/maze/solver/MazeDriver.java new file mode 100644 index 0000000000..60263deba3 --- /dev/null +++ b/algorithms/src/main/java/com/baeldung/algorithms/maze/solver/MazeDriver.java @@ -0,0 +1,34 @@ +package com.baeldung.algorithms.maze.solver; + +import java.io.File; +import java.util.List; + +public class MazeDriver { + public static void main(String[] args) throws Exception { + File maze1 = new File("src/main/resources/maze/maze1.txt"); + File maze2 = new File("src/main/resources/maze/maze2.txt"); + + execute(maze1); + execute(maze2); + } + + private static void execute(File file) throws Exception { + Maze maze = new Maze(file); + dfs(maze); + bfs(maze); + } + + private static void bfs(Maze maze) { + BFSMazeSolver bfs = new BFSMazeSolver(); + List path = bfs.solve(maze); + maze.printPath(path); + maze.reset(); + } + + private static void dfs(Maze maze) { + DFSMazeSolver dfs = new DFSMazeSolver(); + List path = dfs.solve(maze); + maze.printPath(path); + maze.reset(); + } +} diff --git a/algorithms/src/main/java/com/baeldung/algorithms/multiswarm/Constants.java b/algorithms/src/main/java/com/baeldung/algorithms/multiswarm/Constants.java new file mode 100644 index 0000000000..b646c686b2 --- /dev/null +++ b/algorithms/src/main/java/com/baeldung/algorithms/multiswarm/Constants.java @@ -0,0 +1,47 @@ +package com.baeldung.algorithms.multiswarm; + +/** + * Constants used by the Multi-swarm optimization algorithms. + * + * @author Donato Rimenti + * + */ +public class Constants { + + /** + * The inertia factor encourages a particle to continue moving in its + * current direction. + */ + public static final double INERTIA_FACTOR = 0.729; + + /** + * The cognitive weight encourages a particle to move toward its historical + * best-known position. + */ + public static final double COGNITIVE_WEIGHT = 1.49445; + + /** + * The social weight encourages a particle to move toward the best-known + * position found by any of the particle’s swarm-mates. + */ + public static final double SOCIAL_WEIGHT = 1.49445; + + /** + * The global weight encourages a particle to move toward the best-known + * position found by any particle in any swarm. + */ + public static final double GLOBAL_WEIGHT = 0.3645; + + /** + * Upper bound for the random generation. We use it to reduce the + * computation time since we can rawly estimate it. + */ + public static final int PARTICLE_UPPER_BOUND = 10000000; + + /** + * Private constructor for utility class. + */ + private Constants() { + } + +} diff --git a/algorithms/src/main/java/com/baeldung/algorithms/multiswarm/FitnessFunction.java b/algorithms/src/main/java/com/baeldung/algorithms/multiswarm/FitnessFunction.java new file mode 100644 index 0000000000..2d86ec8d94 --- /dev/null +++ b/algorithms/src/main/java/com/baeldung/algorithms/multiswarm/FitnessFunction.java @@ -0,0 +1,21 @@ +package com.baeldung.algorithms.multiswarm; + +/** + * Interface for a fitness function, used to decouple the main algorithm logic + * from the specific problem solution. + * + * @author Donato Rimenti + * + */ +public interface FitnessFunction { + + /** + * Returns the fitness of a particle given its position. + * + * @param particlePosition + * the position of the particle + * @return the fitness of the particle + */ + public double getFitness(long[] particlePosition); + +} diff --git a/algorithms/src/main/java/com/baeldung/algorithms/multiswarm/Multiswarm.java b/algorithms/src/main/java/com/baeldung/algorithms/multiswarm/Multiswarm.java new file mode 100644 index 0000000000..ef60726278 --- /dev/null +++ b/algorithms/src/main/java/com/baeldung/algorithms/multiswarm/Multiswarm.java @@ -0,0 +1,227 @@ +package com.baeldung.algorithms.multiswarm; + +import java.util.Arrays; +import java.util.Random; + +/** + * Represents a collection of {@link Swarm}. + * + * @author Donato Rimenti + * + */ +public class Multiswarm { + + /** + * The swarms managed by this multiswarm. + */ + private Swarm[] swarms; + + /** + * The best position found within all the {@link #swarms}. + */ + private long[] bestPosition; + + /** + * The best fitness score found within all the {@link #swarms}. + */ + private double bestFitness = Double.NEGATIVE_INFINITY; + + /** + * A random generator. + */ + private Random random = new Random(); + + /** + * The fitness function used to determine how good is a particle. + */ + private FitnessFunction fitnessFunction; + + /** + * Instantiates a new Multiswarm. + * + * @param numSwarms + * the number of {@link #swarms} + * @param particlesPerSwarm + * the number of particle for each {@link #swarms} + * @param fitnessFunction + * the {@link #fitnessFunction} + */ + public Multiswarm(int numSwarms, int particlesPerSwarm, FitnessFunction fitnessFunction) { + this.fitnessFunction = fitnessFunction; + this.swarms = new Swarm[numSwarms]; + for (int i = 0; i < numSwarms; i++) { + swarms[i] = new Swarm(particlesPerSwarm); + } + } + + /** + * Main loop of the algorithm. Iterates all particles of all + * {@link #swarms}. For each particle, computes the new fitness and checks + * if a new best position has been found among itself, the swarm and all the + * swarms and finally updates the particle position and speed. + */ + public void mainLoop() { + for (Swarm swarm : swarms) { + for (Particle particle : swarm.getParticles()) { + + long[] particleOldPosition = particle.getPosition().clone(); + + // Calculate the particle fitness. + particle.setFitness(fitnessFunction.getFitness(particleOldPosition)); + + // Check if a new best position has been found for the particle + // itself, within the swarm and the multiswarm. + if (particle.getFitness() > particle.getBestFitness()) { + particle.setBestFitness(particle.getFitness()); + particle.setBestPosition(particleOldPosition); + + if (particle.getFitness() > swarm.getBestFitness()) { + swarm.setBestFitness(particle.getFitness()); + swarm.setBestPosition(particleOldPosition); + + if (swarm.getBestFitness() > bestFitness) { + bestFitness = swarm.getBestFitness(); + bestPosition = swarm.getBestPosition().clone(); + } + + } + } + + // Updates the particle position by adding the speed to the + // actual position. + long[] position = particle.getPosition(); + long[] speed = particle.getSpeed(); + + position[0] += speed[0]; + position[1] += speed[1]; + + // Updates the particle speed. + speed[0] = getNewParticleSpeedForIndex(particle, swarm, 0); + speed[1] = getNewParticleSpeedForIndex(particle, swarm, 1); + } + } + } + + /** + * Computes a new speed for a given particle of a given swarm on a given + * axis. The new speed is computed using the formula: + * + *
+	 * ({@link Constants#INERTIA_FACTOR} * {@link Particle#getSpeed()}) + 
+	 * (({@link Constants#COGNITIVE_WEIGHT} * random(0,1)) * ({@link Particle#getBestPosition()} - {@link Particle#getPosition()})) +
+	 * (({@link Constants#SOCIAL_WEIGHT} * random(0,1)) * ({@link Swarm#getBestPosition()} - {@link Particle#getPosition()})) + 
+	 * (({@link Constants#GLOBAL_WEIGHT} * random(0,1)) * ({@link #bestPosition} - {@link Particle#getPosition()}))
+	 * 
+ * + * @param particle + * the particle whose new speed needs to be computed + * @param swarm + * the swarm which contains the particle + * @param index + * the index of the particle axis whose speeds needs to be + * computed + * @return the new speed of the particle passed on the given axis + */ + private int getNewParticleSpeedForIndex(Particle particle, Swarm swarm, int index) { + return (int) ((Constants.INERTIA_FACTOR * particle.getSpeed()[index]) + + (randomizePercentage(Constants.COGNITIVE_WEIGHT) + * (particle.getBestPosition()[index] - particle.getPosition()[index])) + + (randomizePercentage(Constants.SOCIAL_WEIGHT) + * (swarm.getBestPosition()[index] - particle.getPosition()[index])) + + (randomizePercentage(Constants.GLOBAL_WEIGHT) + * (bestPosition[index] - particle.getPosition()[index]))); + } + + /** + * Returns a random number between 0 and the value passed as argument. + * + * @param value + * the value to randomize + * @return a random value between 0 and the one passed as argument + */ + private double randomizePercentage(double value) { + return random.nextDouble() * value; + } + + /** + * Gets the {@link #bestPosition}. + * + * @return the {@link #bestPosition} + */ + public long[] getBestPosition() { + return bestPosition; + } + + /** + * Gets the {@link #bestFitness}. + * + * @return the {@link #bestFitness} + */ + public double getBestFitness() { + return bestFitness; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + long temp; + temp = Double.doubleToLongBits(bestFitness); + result = prime * result + (int) (temp ^ (temp >>> 32)); + result = prime * result + Arrays.hashCode(bestPosition); + result = prime * result + ((fitnessFunction == null) ? 0 : fitnessFunction.hashCode()); + result = prime * result + ((random == null) ? 0 : random.hashCode()); + result = prime * result + Arrays.hashCode(swarms); + return result; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Multiswarm other = (Multiswarm) obj; + if (Double.doubleToLongBits(bestFitness) != Double.doubleToLongBits(other.bestFitness)) + return false; + if (!Arrays.equals(bestPosition, other.bestPosition)) + return false; + if (fitnessFunction == null) { + if (other.fitnessFunction != null) + return false; + } else if (!fitnessFunction.equals(other.fitnessFunction)) + return false; + if (random == null) { + if (other.random != null) + return false; + } else if (!random.equals(other.random)) + return false; + if (!Arrays.equals(swarms, other.swarms)) + return false; + return true; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return "Multiswarm [swarms=" + Arrays.toString(swarms) + ", bestPosition=" + Arrays.toString(bestPosition) + + ", bestFitness=" + bestFitness + ", random=" + random + ", fitnessFunction=" + fitnessFunction + "]"; + } + +} diff --git a/algorithms/src/main/java/com/baeldung/algorithms/multiswarm/Particle.java b/algorithms/src/main/java/com/baeldung/algorithms/multiswarm/Particle.java new file mode 100644 index 0000000000..5930a94267 --- /dev/null +++ b/algorithms/src/main/java/com/baeldung/algorithms/multiswarm/Particle.java @@ -0,0 +1,204 @@ +package com.baeldung.algorithms.multiswarm; + +import java.util.Arrays; + +/** + * Represents a particle, the basic component of a {@link Swarm}. + * + * @author Donato Rimenti + * + */ +public class Particle { + + /** + * The current position of this particle. + */ + private long[] position; + + /** + * The speed of this particle. + */ + private long[] speed; + + /** + * The fitness of this particle for the current position. + */ + private double fitness; + + /** + * The best position found by this particle. + */ + private long[] bestPosition; + + /** + * The best fitness found by this particle. + */ + private double bestFitness = Double.NEGATIVE_INFINITY; + + /** + * Instantiates a new Particle. + * + * @param initialPosition + * the initial {@link #position} + * @param initialSpeed + * the initial {@link #speed} + */ + public Particle(long[] initialPosition, long[] initialSpeed) { + this.position = initialPosition; + this.speed = initialSpeed; + } + + /** + * Gets the {@link #position}. + * + * @return the {@link #position} + */ + public long[] getPosition() { + return position; + } + + /** + * Gets the {@link #speed}. + * + * @return the {@link #speed} + */ + public long[] getSpeed() { + return speed; + } + + /** + * Gets the {@link #fitness}. + * + * @return the {@link #fitness} + */ + public double getFitness() { + return fitness; + } + + /** + * Gets the {@link #bestPosition}. + * + * @return the {@link #bestPosition} + */ + public long[] getBestPosition() { + return bestPosition; + } + + /** + * Gets the {@link #bestFitness}. + * + * @return the {@link #bestFitness} + */ + public double getBestFitness() { + return bestFitness; + } + + /** + * Sets the {@link #position}. + * + * @param position + * the new {@link #position} + */ + public void setPosition(long[] position) { + this.position = position; + } + + /** + * Sets the {@link #speed}. + * + * @param speed + * the new {@link #speed} + */ + public void setSpeed(long[] speed) { + this.speed = speed; + } + + /** + * Sets the {@link #fitness}. + * + * @param fitness + * the new {@link #fitness} + */ + public void setFitness(double fitness) { + this.fitness = fitness; + } + + /** + * Sets the {@link #bestPosition}. + * + * @param bestPosition + * the new {@link #bestPosition} + */ + public void setBestPosition(long[] bestPosition) { + this.bestPosition = bestPosition; + } + + /** + * Sets the {@link #bestFitness}. + * + * @param bestFitness + * the new {@link #bestFitness} + */ + public void setBestFitness(double bestFitness) { + this.bestFitness = bestFitness; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + long temp; + temp = Double.doubleToLongBits(bestFitness); + result = prime * result + (int) (temp ^ (temp >>> 32)); + result = prime * result + Arrays.hashCode(bestPosition); + temp = Double.doubleToLongBits(fitness); + result = prime * result + (int) (temp ^ (temp >>> 32)); + result = prime * result + Arrays.hashCode(position); + result = prime * result + Arrays.hashCode(speed); + return result; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Particle other = (Particle) obj; + if (Double.doubleToLongBits(bestFitness) != Double.doubleToLongBits(other.bestFitness)) + return false; + if (!Arrays.equals(bestPosition, other.bestPosition)) + return false; + if (Double.doubleToLongBits(fitness) != Double.doubleToLongBits(other.fitness)) + return false; + if (!Arrays.equals(position, other.position)) + return false; + if (!Arrays.equals(speed, other.speed)) + return false; + return true; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return "Particle [position=" + Arrays.toString(position) + ", speed=" + Arrays.toString(speed) + ", fitness=" + + fitness + ", bestPosition=" + Arrays.toString(bestPosition) + ", bestFitness=" + bestFitness + "]"; + } + +} diff --git a/algorithms/src/main/java/com/baeldung/algorithms/multiswarm/Swarm.java b/algorithms/src/main/java/com/baeldung/algorithms/multiswarm/Swarm.java new file mode 100644 index 0000000000..e6d37bb7e6 --- /dev/null +++ b/algorithms/src/main/java/com/baeldung/algorithms/multiswarm/Swarm.java @@ -0,0 +1,155 @@ +package com.baeldung.algorithms.multiswarm; + +import java.util.Arrays; +import java.util.Random; + +/** + * Represents a collection of {@link Particle}. + * + * @author Donato Rimenti + * + */ +public class Swarm { + + /** + * The particles of this swarm. + */ + private Particle[] particles; + + /** + * The best position found within the particles of this swarm. + */ + private long[] bestPosition; + + /** + * The best fitness score found within the particles of this swarm. + */ + private double bestFitness = Double.NEGATIVE_INFINITY; + + /** + * A random generator. + */ + private Random random = new Random(); + + /** + * Instantiates a new Swarm. + * + * @param numParticles + * the number of particles of the swarm + */ + public Swarm(int numParticles) { + particles = new Particle[numParticles]; + for (int i = 0; i < numParticles; i++) { + long[] initialParticlePosition = { random.nextInt(Constants.PARTICLE_UPPER_BOUND), + random.nextInt(Constants.PARTICLE_UPPER_BOUND) }; + long[] initialParticleSpeed = { random.nextInt(Constants.PARTICLE_UPPER_BOUND), + random.nextInt(Constants.PARTICLE_UPPER_BOUND) }; + particles[i] = new Particle(initialParticlePosition, initialParticleSpeed); + } + } + + /** + * Gets the {@link #particles}. + * + * @return the {@link #particles} + */ + public Particle[] getParticles() { + return particles; + } + + /** + * Gets the {@link #bestPosition}. + * + * @return the {@link #bestPosition} + */ + public long[] getBestPosition() { + return bestPosition; + } + + /** + * Gets the {@link #bestFitness}. + * + * @return the {@link #bestFitness} + */ + public double getBestFitness() { + return bestFitness; + } + + /** + * Sets the {@link #bestPosition}. + * + * @param bestPosition + * the new {@link #bestPosition} + */ + public void setBestPosition(long[] bestPosition) { + this.bestPosition = bestPosition; + } + + /** + * Sets the {@link #bestFitness}. + * + * @param bestFitness + * the new {@link #bestFitness} + */ + public void setBestFitness(double bestFitness) { + this.bestFitness = bestFitness; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + long temp; + temp = Double.doubleToLongBits(bestFitness); + result = prime * result + (int) (temp ^ (temp >>> 32)); + result = prime * result + Arrays.hashCode(bestPosition); + result = prime * result + Arrays.hashCode(particles); + result = prime * result + ((random == null) ? 0 : random.hashCode()); + return result; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Swarm other = (Swarm) obj; + if (Double.doubleToLongBits(bestFitness) != Double.doubleToLongBits(other.bestFitness)) + return false; + if (!Arrays.equals(bestPosition, other.bestPosition)) + return false; + if (!Arrays.equals(particles, other.particles)) + return false; + if (random == null) { + if (other.random != null) + return false; + } else if (!random.equals(other.random)) + return false; + return true; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return "Swarm [particles=" + Arrays.toString(particles) + ", bestPosition=" + Arrays.toString(bestPosition) + + ", bestFitness=" + bestFitness + ", random=" + random + "]"; + } + +} diff --git a/algorithms/src/main/java/com/baeldung/algorithms/sudoku/BacktrackingAlgorithm.java b/algorithms/src/main/java/com/baeldung/algorithms/sudoku/BacktrackingAlgorithm.java new file mode 100644 index 0000000000..4b37558aab --- /dev/null +++ b/algorithms/src/main/java/com/baeldung/algorithms/sudoku/BacktrackingAlgorithm.java @@ -0,0 +1,104 @@ +package com.baeldung.algorithms.sudoku; + +import java.util.stream.IntStream; + +public class BacktrackingAlgorithm { + + private static final int BOARD_SIZE = 9; + private static final int SUBSECTION_SIZE = 3; + private static final int BOARD_START_INDEX = 0; + + private static final int NO_VALUE = 0; + private static final int MIN_VALUE = 1; + private static final int MAX_VALUE = 9; + + private static int[][] board = { + {8, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 3, 6, 0, 0, 0, 0, 0}, + {0, 7, 0, 0, 9, 0, 2, 0, 0}, + {0, 5, 0, 0, 0, 7, 0, 0, 0}, + {0, 0, 0, 0, 4, 5, 7, 0, 0}, + {0, 0, 0, 1, 0, 0, 0, 3, 0}, + {0, 0, 1, 0, 0, 0, 0, 6, 8}, + {0, 0, 8, 5, 0, 0, 0, 1, 0}, + {0, 9, 0, 0, 0, 0, 4, 0, 0} + }; + + public static void main(String[] args) { + BacktrackingAlgorithm solver = new BacktrackingAlgorithm(); + solver.solve(board); + solver.printBoard(); + } + + private void printBoard() { + for (int row = BOARD_START_INDEX; row < BOARD_SIZE; row++) { + for (int column = BOARD_START_INDEX; column < BOARD_SIZE; column++) { + System.out.print(board[row][column] + " "); + } + System.out.println(); + } + } + + private boolean solve(int[][] board) { + 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[row][column] = k; + if (isValid(board, row, column) && solve(board)) { + return true; + } + board[row][column] = NO_VALUE; + } + return false; + } + } + } + return true; + } + + 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 row, int column) { + boolean[] constraint = new boolean[BOARD_SIZE]; + int subsectionRowStart = (row / SUBSECTION_SIZE) * SUBSECTION_SIZE; + int subsectionRowEnd = subsectionRowStart + SUBSECTION_SIZE; + + int subsectionColumnStart = (column / SUBSECTION_SIZE) * SUBSECTION_SIZE; + int subsectionColumnEnd = subsectionColumnStart + SUBSECTION_SIZE; + + 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 column) { + boolean[] constraint = new boolean[BOARD_SIZE]; + return IntStream.range(BOARD_START_INDEX, BOARD_SIZE) + .allMatch(row -> checkConstraint(board, row, constraint, column)); + } + + private boolean rowConstraint(int[][] board, int row) { + boolean[] constraint = new boolean[BOARD_SIZE]; + return IntStream.range(BOARD_START_INDEX, BOARD_SIZE) + .allMatch(column -> checkConstraint(board, row, constraint, column)); + } + + 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; + } +} diff --git a/algorithms/src/main/java/com/baeldung/algorithms/sudoku/ColumnNode.java b/algorithms/src/main/java/com/baeldung/algorithms/sudoku/ColumnNode.java new file mode 100644 index 0000000000..46995ca42f --- /dev/null +++ b/algorithms/src/main/java/com/baeldung/algorithms/sudoku/ColumnNode.java @@ -0,0 +1,33 @@ +package com.baeldung.algorithms.sudoku; + +class ColumnNode extends DancingNode { + int size; + String name; + + ColumnNode(String n) { + super(); + size = 0; + name = n; + C = this; + } + + void cover() { + unlinkLR(); + for (DancingNode i = this.D; i != this; i = i.D) { + for (DancingNode j = i.R; j != i; j = j.R) { + j.unlinkUD(); + j.C.size--; + } + } + } + + void uncover() { + for (DancingNode i = this.U; i != this; i = i.U) { + for (DancingNode j = i.L; j != i; j = j.L) { + j.C.size++; + j.relinkUD(); + } + } + relinkLR(); + } +} \ No newline at end of file diff --git a/algorithms/src/main/java/com/baeldung/algorithms/sudoku/DancingLinks.java b/algorithms/src/main/java/com/baeldung/algorithms/sudoku/DancingLinks.java new file mode 100644 index 0000000000..d3cbb2bd02 --- /dev/null +++ b/algorithms/src/main/java/com/baeldung/algorithms/sudoku/DancingLinks.java @@ -0,0 +1,133 @@ +package com.baeldung.algorithms.sudoku; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +public class DancingLinks { + + private ColumnNode header; + private List answer; + + private void search(int k) { + if (header.R == header) { + handleSolution(answer); + } else { + ColumnNode c = selectColumnNodeHeuristic(); + c.cover(); + + for (DancingNode r = c.D; r != c; r = r.D) { + answer.add(r); + + for (DancingNode j = r.R; j != r; j = j.R) { + j.C.cover(); + } + + search(k + 1); + + r = answer.remove(answer.size() - 1); + c = r.C; + + for (DancingNode j = r.L; j != r; j = j.L) { + j.C.uncover(); + } + } + c.uncover(); + } + } + + private ColumnNode selectColumnNodeHeuristic() { + int min = Integer.MAX_VALUE; + ColumnNode ret = null; + for (ColumnNode c = (ColumnNode) header.R; c != header; c = (ColumnNode) c.R) { + if (c.size < min) { + min = c.size; + ret = c; + } + } + return ret; + } + + private ColumnNode makeDLXBoard(boolean[][] grid) { + final int COLS = grid[0].length; + + ColumnNode headerNode = new ColumnNode("header"); + List columnNodes = new ArrayList<>(); + + for (int i = 0; i < COLS; i++) { + ColumnNode n = new ColumnNode(Integer.toString(i)); + columnNodes.add(n); + headerNode = (ColumnNode) headerNode.hookRight(n); + } + headerNode = headerNode.R.C; + + for (boolean[] aGrid : grid) { + DancingNode prev = null; + for (int j = 0; j < COLS; j++) { + if (aGrid[j]) { + ColumnNode col = columnNodes.get(j); + DancingNode newNode = new DancingNode(col); + if (prev == null) + prev = newNode; + col.U.hookDown(newNode); + prev = prev.hookRight(newNode); + col.size++; + } + } + } + + headerNode.size = COLS; + + return headerNode; + } + + DancingLinks(boolean[][] cover) { + header = makeDLXBoard(cover); + } + + public void runSolver() { + answer = new LinkedList<>(); + search(0); + } + + private void handleSolution(List answer) { + int[][] result = parseBoard(answer); + printSolution(result); + } + + private int size = 9; + + private int[][] parseBoard(List answer) { + int[][] result = new int[size][size]; + for (DancingNode n : answer) { + DancingNode rcNode = n; + int min = Integer.parseInt(rcNode.C.name); + for (DancingNode tmp = n.R; tmp != n; tmp = tmp.R) { + int val = Integer.parseInt(tmp.C.name); + if (val < min) { + min = val; + rcNode = tmp; + } + } + int ans1 = Integer.parseInt(rcNode.C.name); + int ans2 = Integer.parseInt(rcNode.R.C.name); + int r = ans1 / size; + int c = ans1 % size; + int num = (ans2 % size) + 1; + result[r][c] = num; + } + return result; + } + + private static void printSolution(int[][] result) { + int size = result.length; + for (int[] aResult : result) { + StringBuilder ret = new StringBuilder(); + for (int j = 0; j < size; j++) { + ret.append(aResult[j]).append(" "); + } + System.out.println(ret); + } + System.out.println(); + } +} diff --git a/algorithms/src/main/java/com/baeldung/algorithms/sudoku/DancingLinksAlgorithm.java b/algorithms/src/main/java/com/baeldung/algorithms/sudoku/DancingLinksAlgorithm.java new file mode 100644 index 0000000000..df02ff3d11 --- /dev/null +++ b/algorithms/src/main/java/com/baeldung/algorithms/sudoku/DancingLinksAlgorithm.java @@ -0,0 +1,121 @@ +package com.baeldung.algorithms.sudoku; + +import java.util.Arrays; + +public class DancingLinksAlgorithm { + private static final int BOARD_SIZE = 9; + private static final int SUBSECTION_SIZE = 3; + private static final int NO_VALUE = 0; + private static final int CONSTRAINTS = 4; + private static final int MIN_VALUE = 1; + private static final int MAX_VALUE = 9; + private static final int COVER_START_INDEX = 1; + + private static int[][] board = { + {8, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 3, 6, 0, 0, 0, 0, 0}, + {0, 7, 0, 0, 9, 0, 2, 0, 0}, + {0, 5, 0, 0, 0, 7, 0, 0, 0}, + {0, 0, 0, 0, 4, 5, 7, 0, 0}, + {0, 0, 0, 1, 0, 0, 0, 3, 0}, + {0, 0, 1, 0, 0, 0, 0, 6, 8}, + {0, 0, 8, 5, 0, 0, 0, 1, 0}, + {0, 9, 0, 0, 0, 0, 4, 0, 0} + }; + + public static void main(String[] args) { + DancingLinksAlgorithm solver = new DancingLinksAlgorithm(); + solver.solve(board); + } + + private void solve(int[][] board) { + boolean[][] cover = initializeExactCoverBoard(board); + DancingLinks dlx = new DancingLinks(cover); + dlx.runSolver(); + } + + 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[][] 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; + } + + 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 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 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[][] 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(coverBoard[getIndex(row, column, num)], false); + } + } + } + } + } + return coverBoard; + } +} \ No newline at end of file diff --git a/algorithms/src/main/java/com/baeldung/algorithms/sudoku/DancingNode.java b/algorithms/src/main/java/com/baeldung/algorithms/sudoku/DancingNode.java new file mode 100644 index 0000000000..2422ff0dff --- /dev/null +++ b/algorithms/src/main/java/com/baeldung/algorithms/sudoku/DancingNode.java @@ -0,0 +1,50 @@ +package com.baeldung.algorithms.sudoku; + +class DancingNode { + DancingNode L, R, U, D; + ColumnNode C; + + 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 node) { + node.R = this.R; + node.R.L = node; + node.L = this; + this.R = node; + return node; + } + + void unlinkLR() { + this.L.R = this.R; + this.R.L = this.L; + } + + void relinkLR() { + this.L.R = this.R.L = this; + } + + void unlinkUD() { + this.U.D = this.D; + this.D.U = this.U; + } + + void relinkUD() { + this.U.D = this.D.U = this; + } + + DancingNode() { + L = R = U = D = this; + } + + DancingNode(ColumnNode c) { + this(); + C = c; + } +} \ No newline at end of file diff --git a/algorithms/src/main/resources/maze/maze1.txt b/algorithms/src/main/resources/maze/maze1.txt new file mode 100644 index 0000000000..0a6309d25b --- /dev/null +++ b/algorithms/src/main/resources/maze/maze1.txt @@ -0,0 +1,12 @@ +S ######## +# # +# ### ## # +# # # # +# # # # # +# ## ##### +# # # +# # # # # +##### #### +# # E +# # # # +########## \ No newline at end of file diff --git a/algorithms/src/main/resources/maze/maze2.txt b/algorithms/src/main/resources/maze/maze2.txt new file mode 100644 index 0000000000..22e6d0382a --- /dev/null +++ b/algorithms/src/main/resources/maze/maze2.txt @@ -0,0 +1,22 @@ +S ########################## +# # # # +# # #### ############### # +# # # # # # +# # #### # # ############### +# # # # # # # +# # # #### ### ########### # +# # # # # # +# ################## # +######### # # # # # +# # #### # ####### # # +# # ### ### # # # # # +# # ## # ##### # # +##### ####### # # # # # +# # ## ## #### # # +# ##### ####### # # +# # ############ +####### ######### # # +# # ######## # +# ####### ###### ## # E +# # # ## # +############################ \ No newline at end of file diff --git a/algorithms/src/test/java/com/baeldung/algorithms/multiswarm/LolFitnessFunction.java b/algorithms/src/test/java/com/baeldung/algorithms/multiswarm/LolFitnessFunction.java new file mode 100644 index 0000000000..726d4c135d --- /dev/null +++ b/algorithms/src/test/java/com/baeldung/algorithms/multiswarm/LolFitnessFunction.java @@ -0,0 +1,52 @@ +package com.baeldung.algorithms.multiswarm; + +/** + * Specific fitness function implementation to solve the League of Legends + * problem. This is the problem statement:
+ *
+ * In League of Legends, a player's Effective Health when defending against + * physical damage is given by E=H(100+A)/100, where H is health and A is armor. + * Health costs 2.5 gold per unit, and Armor costs 18 gold per unit. You have + * 3600 gold, and you need to optimize the effectiveness E of your health and + * armor to survive as long as possible against the enemy team's attacks. How + * much of each should you buy?
+ *
+ * + * @author Donato Rimenti + * + */ +public class LolFitnessFunction implements FitnessFunction { + + /* + * (non-Javadoc) + * + * @see + * com.baeldung.algorithms.multiswarm.FitnessFunction#getFitness(long[]) + */ + @Override + public double getFitness(long[] particlePosition) { + + long health = particlePosition[0]; + long armor = particlePosition[1]; + + // No negatives values accepted. + if (health < 0 && armor < 0) { + return -(health * armor); + } else if (health < 0) { + return health; + } else if (armor < 0) { + return armor; + } + + // Checks if the solution is actually feasible provided our gold. + double cost = (health * 2.5) + (armor * 18); + if (cost > 3600) { + return 3600 - cost; + } else { + // Check how good is the solution. + long fitness = (health * (100 + armor)) / 100; + return fitness; + } + } + +} diff --git a/algorithms/src/test/java/com/baeldung/algorithms/multiswarm/MultiswarmUnitTest.java b/algorithms/src/test/java/com/baeldung/algorithms/multiswarm/MultiswarmUnitTest.java new file mode 100644 index 0000000000..3455cd3932 --- /dev/null +++ b/algorithms/src/test/java/com/baeldung/algorithms/multiswarm/MultiswarmUnitTest.java @@ -0,0 +1,54 @@ +package com.baeldung.algorithms.multiswarm; + +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +import com.baeldung.algorithms.support.MayFailRule; + +/** + * Test for {@link Multiswarm}. + * + * @author Donato Rimenti + * + */ +public class MultiswarmUnitTest { + + /** + * Rule for handling expected failures. We use this since this test may + * actually fail due to bad luck in the random generation. + */ + @Rule + public MayFailRule mayFailRule = new MayFailRule(); + + /** + * Tests the multiswarm algorithm with a generic problem. The problem is the + * following:
+ *
+ * In League of Legends, a player's Effective Health when defending against + * physical damage is given by E=H(100+A)/100, where H is health and A is + * armor. Health costs 2.5 gold per unit, and Armor costs 18 gold per unit. + * You have 3600 gold, and you need to optimize the effectiveness E of your + * health and armor to survive as long as possible against the enemy team's + * attacks. How much of each should you buy?
+ *
+ * The solution is H = 1080, A = 50 for a total fitness of 1620. Tested with + * 50 swarms each with 1000 particles. + */ + @Test + public void givenMultiswarm_whenThousandIteration_thenSolutionFound() { + Multiswarm multiswarm = new Multiswarm(50, 1000, new LolFitnessFunction()); + + // Iterates 1000 times through the main loop and prints the result. + for (int i = 0; i < 1000; i++) { + multiswarm.mainLoop(); + } + + System.out.println("Best fitness found: " + multiswarm.getBestFitness() + "[" + multiswarm.getBestPosition()[0] + + "," + multiswarm.getBestPosition()[1] + "]"); + Assert.assertEquals(1080, multiswarm.getBestPosition()[0]); + Assert.assertEquals(50, multiswarm.getBestPosition()[1]); + Assert.assertEquals(1620, (int) multiswarm.getBestFitness()); + } + +} diff --git a/algorithms/src/test/java/com/baeldung/algorithms/support/MayFailRule.java b/algorithms/src/test/java/com/baeldung/algorithms/support/MayFailRule.java new file mode 100644 index 0000000000..91df78ce4a --- /dev/null +++ b/algorithms/src/test/java/com/baeldung/algorithms/support/MayFailRule.java @@ -0,0 +1,38 @@ +package com.baeldung.algorithms.support; + +import org.junit.Rule; +import org.junit.rules.TestRule; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +/** + * JUnit custom rule for managing tests that may fail due to heuristics or + * randomness. In order to use this, just instantiate this object as a public + * field inside the test class and annotate it with {@link Rule}. + * + * @author Donato Rimenti + * + */ +public class MayFailRule implements TestRule { + + /* + * (non-Javadoc) + * + * @see org.junit.rules.TestRule#apply(org.junit.runners.model.Statement, + * org.junit.runner.Description) + */ + @Override + public Statement apply(Statement base, Description description) { + return new Statement() { + @Override + public void evaluate() throws Throwable { + try { + base.evaluate(); + } catch (Throwable e) { + // Ignore the exception since we expect this. + } + } + }; + } + +} diff --git a/apache-zookeeper/pom.xml b/apache-zookeeper/pom.xml new file mode 100644 index 0000000000..6d49d74ade --- /dev/null +++ b/apache-zookeeper/pom.xml @@ -0,0 +1,30 @@ + + 4.0.0 + com.baeldung + apache-zookeeper + 0.0.1-SNAPSHOT + jar + + + + org.apache.zookeeper + zookeeper + 3.3.2 + + + com.sun.jmx + jmxri + + + com.sun.jdmk + jmxtools + + + javax.jms + jms + + + + + diff --git a/apache-zookeeper/src/main/java/com/baeldung/zookeeper/connection/ZKConnection.java b/apache-zookeeper/src/main/java/com/baeldung/zookeeper/connection/ZKConnection.java new file mode 100644 index 0000000000..0678250d57 --- /dev/null +++ b/apache-zookeeper/src/main/java/com/baeldung/zookeeper/connection/ZKConnection.java @@ -0,0 +1,33 @@ +package com.baeldung.zookeeper.connection; + +import java.io.IOException; +import java.util.concurrent.CountDownLatch; + +import org.apache.zookeeper.WatchedEvent; +import org.apache.zookeeper.Watcher; +import org.apache.zookeeper.Watcher.Event.KeeperState; +import org.apache.zookeeper.ZooKeeper; + +public class ZKConnection { + private ZooKeeper zoo; + final CountDownLatch connectionLatch = new CountDownLatch(1); + + public ZKConnection() { + } + + public ZooKeeper connect(String host) throws IOException, InterruptedException { + zoo = new ZooKeeper(host, 2000, new Watcher() { + public void process(WatchedEvent we) { + if (we.getState() == KeeperState.SyncConnected) { + connectionLatch.countDown(); + } + } + }); + connectionLatch.await(); + return zoo; + } + + public void close() throws InterruptedException { + zoo.close(); + } +} diff --git a/apache-zookeeper/src/main/java/com/baeldung/zookeeper/manager/ZKManager.java b/apache-zookeeper/src/main/java/com/baeldung/zookeeper/manager/ZKManager.java new file mode 100644 index 0000000000..0c0ad52123 --- /dev/null +++ b/apache-zookeeper/src/main/java/com/baeldung/zookeeper/manager/ZKManager.java @@ -0,0 +1,35 @@ +package com.baeldung.zookeeper.manager; + +import org.apache.zookeeper.KeeperException; + +public interface ZKManager { + /** + * Create a Znode and save some data + * + * @param path + * @param data + * @throws KeeperException + * @throws InterruptedException + */ + public void create(String path, byte[] data) throws KeeperException, InterruptedException; + + /** + * Get ZNode Data + * + * @param path + * @param boolean watchFlag + * @throws KeeperException + * @throws InterruptedException + */ + public Object getZNodeData(String path, boolean watchFlag); + + /** + * Update the ZNode Data + * + * @param path + * @param data + * @throws KeeperException + * @throws InterruptedException + */ + public void update(String path, byte[] data) throws KeeperException, InterruptedException, KeeperException; +} diff --git a/apache-zookeeper/src/main/java/com/baeldung/zookeeper/manager/ZKManagerImpl.java b/apache-zookeeper/src/main/java/com/baeldung/zookeeper/manager/ZKManagerImpl.java new file mode 100644 index 0000000000..adf76bc0f2 --- /dev/null +++ b/apache-zookeeper/src/main/java/com/baeldung/zookeeper/manager/ZKManagerImpl.java @@ -0,0 +1,58 @@ +package com.baeldung.zookeeper.manager; + +import org.apache.zookeeper.CreateMode; +import org.apache.zookeeper.KeeperException; +import org.apache.zookeeper.ZooDefs; +import org.apache.zookeeper.ZooKeeper; + +import com.baeldung.zookeeper.connection.ZKConnection; + +public class ZKManagerImpl implements ZKManager { + private static ZooKeeper zkeeper; + private static ZKConnection zkConnection; + + public ZKManagerImpl() { + initialize(); + } + + /** * Initialize connection */ + private void initialize() { + try { + zkConnection = new ZKConnection(); + zkeeper = zkConnection.connect("localhost"); + } catch (Exception e) { + System.out.println(e.getMessage()); + } + } + + public void closeConnection() { + try { + zkConnection.close(); + } catch (InterruptedException e) { + System.out.println(e.getMessage()); + } + } + + public void create(String path, byte[] data) throws KeeperException, InterruptedException { + zkeeper.create(path, data, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); + } + + public Object getZNodeData(String path, boolean watchFlag) { + try { + byte[] b = null; + b = zkeeper.getData(path, null, null); + String data = new String(b, "UTF-8"); + System.out.println(data); + return data; + } catch (Exception e) { + System.out.println(e.getMessage()); + } + return null; + } + + public void update(String path, byte[] data) throws KeeperException, InterruptedException { + int version = zkeeper.exists(path, true) + .getVersion(); + zkeeper.setData(path, data, version); + } +} diff --git a/checker-plugin/pom.xml b/checker-plugin/pom.xml new file mode 100644 index 0000000000..bc7a669d4f --- /dev/null +++ b/checker-plugin/pom.xml @@ -0,0 +1,114 @@ + + 4.0.0 + com.baeldung + checker-plugin + jar + 1.0-SNAPSHOT + checker-plugin + http://maven.apache.org + + + + + + ${org.checkerframework:jdk8:jar} + + + + + + + + + + org.checkerframework + checker-qual + 2.3.1 + + + org.checkerframework + checker + 2.3.1 + + + org.checkerframework + jdk8 + 2.3.1 + + + + org.checkerframework + compiler + 2.3.1 + + + + + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + + + properties + + + + + + + maven-compiler-plugin + 3.6.1 + + 1.8 + 1.8 + + + + 10000 + 10000 + + + + org.checkerframework.checker.nullness.NullnessChecker + org.checkerframework.checker.interning.InterningChecker + org.checkerframework.checker.fenum.FenumChecker + org.checkerframework.checker.formatter.FormatterChecker + org.checkerframework.checker.regex.RegexChecker + + + -AprintErrorStack + + + -Xbootclasspath/p:${annotatedJdk} + + + + + + -Awarns + + + + + + + diff --git a/checker-plugin/src/main/java/com/baeldung/typechecker/FakeNumExample.java b/checker-plugin/src/main/java/com/baeldung/typechecker/FakeNumExample.java new file mode 100644 index 0000000000..f1769cfdea --- /dev/null +++ b/checker-plugin/src/main/java/com/baeldung/typechecker/FakeNumExample.java @@ -0,0 +1,42 @@ +package com.baeldung.typechecker; + +import org.checkerframework.checker.fenum.qual.Fenum; + +//@SuppressWarnings("fenum:assignment.type.incompatible") +public class FakeNumExample { + + // Here we use some String constants to represents countries. + static final @Fenum("country") String ITALY = "IT"; + static final @Fenum("country") String US = "US"; + static final @Fenum("country") String UNITED_KINGDOM = "UK"; + + // Here we use other String constants to represent planets instead. + static final @Fenum("planet") String MARS = "Mars"; + static final @Fenum("planet") String EARTH = "Earth"; + static final @Fenum("planet") String VENUS = "Venus"; + + // Now we write this method and we want to be sure that + // the String parameter has a value of a country, not that is just a String. + void greetCountries(@Fenum("country") String country) { + System.out.println("Hello " + country); + } + + // Similarly we're enforcing here that the provided + // parameter is a String that represent a planet. + void greetPlanets(@Fenum("planet") String planet) { + System.out.println("Hello " + planet); + } + + public static void main(String[] args) { + + FakeNumExample obj = new FakeNumExample(); + + // This will fail because we pass a planet-String to a method that + // accept a country-String. + obj.greetCountries(MARS); + + // Here the opposite happens. + obj.greetPlanets(US); + } + +} diff --git a/checker-plugin/src/main/java/com/baeldung/typechecker/FormatExample.java b/checker-plugin/src/main/java/com/baeldung/typechecker/FormatExample.java new file mode 100644 index 0000000000..2fa53ff2c2 --- /dev/null +++ b/checker-plugin/src/main/java/com/baeldung/typechecker/FormatExample.java @@ -0,0 +1,23 @@ +package com.baeldung.typechecker; + +public class FormatExample { + + public static void main(String[] args) { + + // Just enabling org.checkerframework.checker.formatter.FormatterChecker + // we can be sure at compile time that the format strings we pass to format() + // are correct. Normally we would have those errors raised just at runtime. + // All those formats are in fact wrong. + + String.format("%y", 7); // error: invalid format string + + String.format("%d", "a string"); // error: invalid argument type for %d + + String.format("%d %s", 7); // error: missing argument for %s + + String.format("%d", 7, 3); // warning: unused argument 3 + + String.format("{0}", 7); // warning: unused argument 7, because {0} is wrong syntax + } + +} diff --git a/checker-plugin/src/main/java/com/baeldung/typechecker/KeyForExample.java b/checker-plugin/src/main/java/com/baeldung/typechecker/KeyForExample.java new file mode 100644 index 0000000000..b3072b72ee --- /dev/null +++ b/checker-plugin/src/main/java/com/baeldung/typechecker/KeyForExample.java @@ -0,0 +1,31 @@ +package com.baeldung.typechecker; + +import org.checkerframework.checker.nullness.qual.KeyFor; + +import java.util.HashMap; +import java.util.Map; + +public class KeyForExample { + + private final Map config = new HashMap<>(); + + KeyForExample() { + + // Here we initialize a map to store + // some config data. + config.put("url", "http://1.2.3.4"); + config.put("name", "foobaz"); + } + + public void dumpPort() { + + // Here, we want to dump the port value stored in the + // config, so we declare that this key has to be + // present in the config map. + // Obviously that will fail because such key is not present + // in the map. + @KeyFor("config") String key = "port"; + System.out.println( config.get(key) ); + } + +} diff --git a/checker-plugin/src/main/java/com/baeldung/typechecker/MonotonicNotNullExample.java b/checker-plugin/src/main/java/com/baeldung/typechecker/MonotonicNotNullExample.java new file mode 100644 index 0000000000..c4b9c6afe1 --- /dev/null +++ b/checker-plugin/src/main/java/com/baeldung/typechecker/MonotonicNotNullExample.java @@ -0,0 +1,28 @@ +package com.baeldung.typechecker; + +import org.checkerframework.checker.nullness.qual.MonotonicNonNull; + +import java.util.Date; + +public class MonotonicNotNullExample { + + // The idea is we need this field to be to lazily initialized, + // so it starts as null but once it becomes not null + // it cannot return null. + // In these cases, we can use @MonotonicNonNull + @MonotonicNonNull private Date firstCall; + + public Date getFirstCall() { + if (firstCall == null) { + firstCall = new Date(); + } + return firstCall; + } + + public void reset() { + // This is reported as error because + // we wrongly set the field back to null. + firstCall = null; + } + +} diff --git a/checker-plugin/src/main/java/com/baeldung/typechecker/NonNullExample.java b/checker-plugin/src/main/java/com/baeldung/typechecker/NonNullExample.java new file mode 100644 index 0000000000..c929eea23f --- /dev/null +++ b/checker-plugin/src/main/java/com/baeldung/typechecker/NonNullExample.java @@ -0,0 +1,27 @@ +package com.baeldung.typechecker; + +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; + +public class NonNullExample { + + // This method's parameter is annotated in order + // to tell the pluggable type system that it can never be null. + private static int countArgs(@NonNull String[] args) { + return args.length; + } + + // This method's parameter is annotated in order + // to tell the pluggable type system that it may be null. + public static void main(@Nullable String[] args) { + + // Here lies a potential error, + // because we pass a potential null reference to a method + // that does not accept nulls. + // The Checker Framework will spot this problem at compile time + // instead of runtime. + System.out.println(countArgs(args)); + + } + +} diff --git a/checker-plugin/src/main/java/com/baeldung/typechecker/RegexExample.java b/checker-plugin/src/main/java/com/baeldung/typechecker/RegexExample.java new file mode 100644 index 0000000000..9503865214 --- /dev/null +++ b/checker-plugin/src/main/java/com/baeldung/typechecker/RegexExample.java @@ -0,0 +1,18 @@ +package com.baeldung.typechecker; + +import org.checkerframework.checker.regex.qual.Regex; + +public class RegexExample { + + // For some reason we want to be sure that this regex + // contains at least one capturing group. + // However, we do an error and we forgot to define such + // capturing group in it. + @Regex(1) private static String findNumbers = "\\d*"; + + public static void main(String[] args) { + String message = "My phone number is +3911223344."; + message.matches(findNumbers); + } + +} diff --git a/core-groovy/README.md b/core-groovy/README.md new file mode 100644 index 0000000000..5954a8ab7e --- /dev/null +++ b/core-groovy/README.md @@ -0,0 +1,4 @@ +# Groovy + +## Relevant articles: + diff --git a/core-groovy/pom.xml b/core-groovy/pom.xml index 7ab91c7af2..eb9932e0cf 100644 --- a/core-groovy/pom.xml +++ b/core-groovy/pom.xml @@ -54,7 +54,6 @@ 2.4.0 test - org.spockframework spock-core @@ -126,5 +125,5 @@ 4.12.0 4.12 + - \ No newline at end of file diff --git a/core-groovy/src/test/groovy/com/baeldung/groovy/sql/SqlTest.groovy b/core-groovy/src/test/groovy/com/baeldung/groovy/sql/SqlTest.groovy new file mode 100644 index 0000000000..ac96a55773 --- /dev/null +++ b/core-groovy/src/test/groovy/com/baeldung/groovy/sql/SqlTest.groovy @@ -0,0 +1,229 @@ +package com.baeldung.groovy.sql + +import groovy.sql.GroovyResultSet +import groovy.sql.GroovyRowResult +import groovy.sql.Sql +import groovy.transform.CompileStatic +import static org.junit.Assert.* +import org.junit.Test + +class SqlTest { + + final Map dbConnParams = [url: 'jdbc:hsqldb:mem:testDB', user: 'sa', password: '', driver: 'org.hsqldb.jdbc.JDBCDriver'] + + @Test + void whenNewSqlInstance_thenDbIsAccessed() { + def sql = Sql.newInstance(dbConnParams) + sql.close() + sql.close() + } + + @Test + void whenTableDoesNotExist_thenSelectFails() { + try { + Sql.withInstance(dbConnParams) { Sql sql -> + sql.eachRow('select * from PROJECT') {} + } + + fail("An exception should have been thrown") + } catch (ignored) { + //Ok + } + } + + @Test + void whenTableCreated_thenSelectIsPossible() { + Sql.withInstance(dbConnParams) { Sql sql -> + def result = sql.execute 'create table PROJECT_1 (id integer not null, name varchar(50), url varchar(100))' + + assertEquals(0, sql.updateCount) + assertFalse(result) + + result = sql.execute('select * from PROJECT_1') + + assertTrue(result) + } + } + + @Test + void whenIdentityColumn_thenInsertReturnsNewId() { + Sql.withInstance(dbConnParams) { Sql sql -> + sql.execute 'create table PROJECT_2 (ID IDENTITY, NAME VARCHAR (50), URL VARCHAR (100))' + def ids = sql.executeInsert("INSERT INTO PROJECT_2 (NAME, URL) VALUES ('tutorials', 'github.com/eugenp/tutorials')") + + assertEquals(0, ids[0][0]) + + ids = sql.executeInsert("INSERT INTO PROJECT_2 (NAME, URL) VALUES ('REST with Spring', 'github.com/eugenp/REST-With-Spring')") + + assertEquals(1, ids[0][0]) + } + } + + @Test + void whenUpdate_thenNumberOfAffectedRows() { + Sql.withInstance(dbConnParams) { Sql sql -> + sql.execute 'create table PROJECT_3 (ID IDENTITY, NAME VARCHAR (50), URL VARCHAR (100))' + sql.executeInsert("INSERT INTO PROJECT_3 (NAME, URL) VALUES ('tutorials', 'github.com/eugenp/tutorials')") + sql.executeInsert("INSERT INTO PROJECT_3 (NAME, URL) VALUES ('REST with Spring', 'github.com/eugenp/REST-With-Spring')") + def count = sql.executeUpdate("UPDATE PROJECT_3 SET URL = 'https://' + URL") + + assertEquals(2, count) + } + } + + @Test + void whenEachRow_thenResultSetHasProperties() { + Sql.withInstance(dbConnParams) { Sql sql -> + sql.execute 'create table PROJECT_4 (ID IDENTITY, NAME VARCHAR (50), URL VARCHAR (100))' + sql.executeInsert("INSERT INTO PROJECT_4 (NAME, URL) VALUES ('tutorials', 'https://github.com/eugenp/tutorials')") + sql.executeInsert("INSERT INTO PROJECT_4 (NAME, URL) VALUES ('REST with Spring', 'https://github.com/eugenp/REST-With-Spring')") + + sql.eachRow("SELECT * FROM PROJECT_4") { GroovyResultSet rs -> + assertNotNull(rs.name) + assertNotNull(rs.url) + assertNotNull(rs[0]) + assertNotNull(rs[1]) + assertNotNull(rs[2]) + assertEquals(rs.name, rs['name']) + assertEquals(rs.url, rs['url']) + } + } + } + + @Test + void whenPagination_thenSubsetIsReturned() { + Sql.withInstance(dbConnParams) { Sql sql -> + sql.execute 'create table PROJECT_5 (ID IDENTITY, NAME VARCHAR (50), URL VARCHAR (100))' + sql.executeInsert("INSERT INTO PROJECT_5 (NAME, URL) VALUES ('tutorials', 'github.com/eugenp/tutorials')") + sql.executeInsert("INSERT INTO PROJECT_5 (NAME, URL) VALUES ('REST with Spring', 'github.com/eugenp/REST-With-Spring')") + def rows = sql.rows('SELECT * FROM PROJECT_5 ORDER BY NAME', 1, 1) + + assertEquals(1, rows.size()) + assertEquals('REST with Spring', rows[0].name) + } + } + + @Test + void whenParameters_thenReplacement() { + Sql.withInstance(dbConnParams) { Sql sql -> + sql.execute 'create table PROJECT_6 (ID IDENTITY, NAME VARCHAR (50), URL VARCHAR (100))' + sql.execute('INSERT INTO PROJECT_6 (NAME, URL) VALUES (?, ?)', 'tutorials', 'github.com/eugenp/tutorials') + sql.execute("INSERT INTO PROJECT_6 (NAME, URL) VALUES (:name, :url)", [name: 'REST with Spring', url: 'github.com/eugenp/REST-With-Spring']) + + def rows = sql.rows("SELECT * FROM PROJECT_6 WHERE NAME = 'tutorials'") + + assertEquals(1, rows.size()) + + rows = sql.rows("SELECT * FROM PROJECT_6 WHERE NAME = 'REST with Spring'") + + assertEquals(1, rows.size()) + } + } + + @Test + void whenParametersInGString_thenReplacement() { + Sql.withInstance(dbConnParams) { Sql sql -> + sql.execute 'create table PROJECT_7 (ID IDENTITY, NAME VARCHAR (50), URL VARCHAR (100))' + sql.execute "INSERT INTO PROJECT_7 (NAME, URL) VALUES (${'tutorials'}, ${'github.com/eugenp/tutorials'})" + def name = 'REST with Spring' + def url = 'github.com/eugenp/REST-With-Spring' + sql.execute "INSERT INTO PROJECT_7 (NAME, URL) VALUES (${name}, ${url})" + + def rows = sql.rows("SELECT * FROM PROJECT_7 WHERE NAME = 'tutorials'") + + assertEquals(1, rows.size()) + + rows = sql.rows("SELECT * FROM PROJECT_7 WHERE NAME = 'REST with Spring'") + + assertEquals(1, rows.size()) + } + } + + @Test + void whenTransactionRollback_thenNoDataInserted() { + Sql.withInstance(dbConnParams) { Sql sql -> + sql.withTransaction { + sql.execute 'create table PROJECT_8 (ID IDENTITY, NAME VARCHAR (50), URL VARCHAR (100))' + sql.executeInsert("INSERT INTO PROJECT_8 (NAME, URL) VALUES ('tutorials', 'https://github.com/eugenp/tutorials')") + sql.executeInsert("INSERT INTO PROJECT_8 (NAME, URL) VALUES ('REST with Spring', 'https://github.com/eugenp/REST-With-Spring')") + sql.rollback() + + def rows = sql.rows("SELECT * FROM PROJECT_8") + + assertEquals(0, rows.size()) + } + } + } + + @Test + void whenTransactionRollbackThenCommit_thenOnlyLastInserted() { + Sql.withInstance(dbConnParams) { Sql sql -> + sql.withTransaction { + sql.execute 'create table PROJECT_9 (ID IDENTITY, NAME VARCHAR (50), URL VARCHAR (100))' + sql.executeInsert("INSERT INTO PROJECT_9 (NAME, URL) VALUES ('tutorials', 'https://github.com/eugenp/tutorials')") + sql.rollback() + sql.executeInsert("INSERT INTO PROJECT_9 (NAME, URL) VALUES ('REST with Spring', 'https://github.com/eugenp/REST-With-Spring')") + sql.rollback() + sql.executeInsert("INSERT INTO PROJECT_9 (NAME, URL) VALUES ('tutorials', 'https://github.com/eugenp/tutorials')") + sql.executeInsert("INSERT INTO PROJECT_9 (NAME, URL) VALUES ('REST with Spring', 'https://github.com/eugenp/REST-With-Spring')") + } + + def rows = sql.rows("SELECT * FROM PROJECT_9") + + assertEquals(2, rows.size()) + } + } + + @Test + void whenException_thenTransactionIsRolledBack() { + Sql.withInstance(dbConnParams) { Sql sql -> + try { + sql.withTransaction { + sql.execute 'create table PROJECT_10 (ID IDENTITY, NAME VARCHAR (50), URL VARCHAR (100))' + sql.executeInsert("INSERT INTO PROJECT_10 (NAME, URL) VALUES ('tutorials', 'https://github.com/eugenp/tutorials')") + throw new Exception('rollback') + } + } catch (ignored) {} + + def rows = sql.rows("SELECT * FROM PROJECT_10") + + assertEquals(0, rows.size()) + } + } + + @Test + void givenCachedConnection_whenException_thenDataIsPersisted() { + Sql.withInstance(dbConnParams) { Sql sql -> + try { + sql.cacheConnection { + sql.execute 'create table PROJECT_11 (ID IDENTITY, NAME VARCHAR (50), URL VARCHAR (100))' + sql.executeInsert("INSERT INTO PROJECT_11 (NAME, URL) VALUES ('tutorials', 'https://github.com/eugenp/tutorials')") + throw new Exception('This does not rollback') + } + } catch (ignored) {} + + def rows = sql.rows("SELECT * FROM PROJECT_11") + + assertEquals(1, rows.size()) + } + } + + /*@Test + void whenModifyResultSet_thenDataIsChanged() { + Sql.withInstance(dbConnParams) { Sql sql -> + sql.execute 'create table PROJECT_5 (ID IDENTITY, NAME VARCHAR (50), URL VARCHAR (100))' + sql.executeInsert("INSERT INTO PROJECT_5 (NAME, URL) VALUES ('tutorials', 'github.com/eugenp/tutorials')") + sql.executeInsert("INSERT INTO PROJECT_5 (NAME, URL) VALUES ('REST with Spring', 'github.com/eugenp/REST-With-Spring')") + + sql.eachRow("SELECT * FROM PROJECT_5 FOR UPDATE ") { GroovyResultSet rs -> + rs['name'] = "The great ${rs.name}!" as String + rs.updateRow() + } + + sql.eachRow("SELECT * FROM PROJECT_5") { GroovyResultSet rs -> + assertTrue(rs.name.startsWith('The great ')) + } + } + }*/ + +} diff --git a/core-java-8/README.md b/core-java-8/README.md index 9260e3d447..1b5208961d 100644 --- a/core-java-8/README.md +++ b/core-java-8/README.md @@ -40,3 +40,4 @@ - [Efficient Word Frequency Calculator in Java](http://www.baeldung.com/java-word-frequency) - [Primitive Type Streams in Java 8](http://www.baeldung.com/java-8-primitive-streams) - [Fail-Safe Iterator vs Fail-Fast Iterator](http://www.baeldung.com/java-fail-safe-vs-fail-fast-iterator) +- [Shuffling Collections In Java](http://www.baeldung.com/java-shuffle-collection) diff --git a/core-java-8/src/test/java/com/baeldung/shufflingcollections/ShufflingCollectionsUnitTest.java b/core-java-8/src/test/java/com/baeldung/shufflingcollections/ShufflingCollectionsUnitTest.java new file mode 100644 index 0000000000..d013907c9a --- /dev/null +++ b/core-java-8/src/test/java/com/baeldung/shufflingcollections/ShufflingCollectionsUnitTest.java @@ -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 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 whenShufflingMapEntries_thenValuesAreShuffled() { + Map 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> shuffledStudentEntries = new ArrayList<>(studentsById.entrySet()); + Collections.shuffle(shuffledStudentEntries); + + List shuffledStudents = shuffledStudentEntries.stream() + .map(Map.Entry::getValue) + .collect(Collectors.toList()); + + System.out.println("Students after shuffling"); + System.out.println(shuffledStudents); + } + + @Test + public void whenShufflingSet_thenElementsAreShuffled() { + Set students = new HashSet<>(Arrays.asList("Foo", "Bar", "Baz", "Qux")); + + System.out.println("Set before shuffling:"); + System.out.println(students); + + List studentList = new ArrayList<>(students); + + Collections.shuffle(studentList); + System.out.println("Shuffled set elements:"); + System.out.println(studentList); + } + + @Test + public void whenShufflingWithSameRandomness_thenElementsAreShuffledDeterministically() { + List students_1 = Arrays.asList("Foo", "Bar", "Baz", "Qux"); + List 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); + } +} diff --git a/core-java-9/src/test/java/com/baeldung/java9/httpclient/HttpClientTest.java b/core-java-9/src/test/java/com/baeldung/java9/httpclient/HttpClientTest.java index a4c6ac0d7d..5cf3b9098f 100644 --- a/core-java-9/src/test/java/com/baeldung/java9/httpclient/HttpClientTest.java +++ b/core-java-9/src/test/java/com/baeldung/java9/httpclient/HttpClientTest.java @@ -11,6 +11,7 @@ import java.util.Arrays; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.stream.Collectors; @@ -116,18 +117,20 @@ public class HttpClientTest { .GET() .build(); + ExecutorService executorService = Executors.newFixedThreadPool(2); + CompletableFuture> response1 = HttpClient.newBuilder() - .executor(Executors.newFixedThreadPool(2)) + .executor(executorService) .build() .sendAsync(request, HttpResponse.BodyHandler.asString()); CompletableFuture> response2 = HttpClient.newBuilder() - .executor(Executors.newFixedThreadPool(2)) + .executor(executorService) .build() .sendAsync(request, HttpResponse.BodyHandler.asString()); CompletableFuture> response3 = HttpClient.newBuilder() - .executor(Executors.newFixedThreadPool(2)) + .executor(executorService) .build() .sendAsync(request, HttpResponse.BodyHandler.asString()); diff --git a/core-java-9/src/test/java/com/baeldung/java9/httpclient/SimpleHttpRequestsUnitTest.java b/core-java-9/src/test/java/com/baeldung/java9/httpclient/SimpleHttpRequestsUnitTest.java deleted file mode 100644 index 4a704139a1..0000000000 --- a/core-java-9/src/test/java/com/baeldung/java9/httpclient/SimpleHttpRequestsUnitTest.java +++ /dev/null @@ -1,126 +0,0 @@ -package com.baeldung.java9.httpclient; - -import static java.net.HttpURLConnection.HTTP_OK; -import static org.junit.Assert.assertTrue; - -import java.io.IOException; -import java.net.CookieManager; -import java.net.CookiePolicy; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.http.HttpClient; -import java.net.http.HttpHeaders; -import java.net.http.HttpRequest; -import java.net.http.HttpResponse; -import java.security.NoSuchAlgorithmException; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; - -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLParameters; - -import org.junit.Before; -import org.junit.Test; - -public class SimpleHttpRequestsUnitTest { - - private URI httpURI; - - @Before - public void init() throws URISyntaxException { - httpURI = new URI("http://www.baeldung.com/"); - } - - @Test - public void quickGet() throws IOException, InterruptedException, URISyntaxException { - HttpRequest request = HttpRequest.create(httpURI).GET(); - HttpResponse response = request.response(); - int responseStatusCode = response.statusCode(); - String responseBody = response.body(HttpResponse.asString()); - assertTrue("Get response status code is bigger then 400", responseStatusCode < 400); - } - - @Test - public void asynchronousGet() throws URISyntaxException, IOException, InterruptedException, ExecutionException { - HttpRequest request = HttpRequest.create(httpURI).GET(); - long before = System.currentTimeMillis(); - CompletableFuture futureResponse = request.responseAsync(); - futureResponse.thenAccept(response -> { - String responseBody = response.body(HttpResponse.asString()); - }); - HttpResponse resp = futureResponse.get(); - HttpHeaders hs = resp.headers(); - assertTrue("There should be more then 1 header.", hs.map().size() > 1); - } - - @Test - public void postMehtod() throws URISyntaxException, IOException, InterruptedException { - HttpRequest.Builder requestBuilder = HttpRequest.create(httpURI); - requestBuilder.body(HttpRequest.fromString("param1=foo,param2=bar")).followRedirects(HttpClient.Redirect.SECURE); - HttpRequest request = requestBuilder.POST(); - HttpResponse response = request.response(); - int statusCode = response.statusCode(); - assertTrue("HTTP return code", statusCode == HTTP_OK); - } - - @Test - public void configureHttpClient() throws NoSuchAlgorithmException, URISyntaxException, IOException, InterruptedException { - CookieManager cManager = new CookieManager(); - cManager.setCookiePolicy(CookiePolicy.ACCEPT_ORIGINAL_SERVER); - - SSLParameters sslParam = new SSLParameters(new String[] { "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256" }, new String[] { "TLSv1.2" }); - - HttpClient.Builder hcBuilder = HttpClient.create(); - hcBuilder.cookieManager(cManager).sslContext(SSLContext.getDefault()).sslParameters(sslParam); - HttpClient httpClient = hcBuilder.build(); - HttpRequest.Builder reqBuilder = httpClient.request(new URI("https://www.facebook.com")); - - HttpRequest request = reqBuilder.followRedirects(HttpClient.Redirect.ALWAYS).GET(); - HttpResponse response = request.response(); - int statusCode = response.statusCode(); - assertTrue("HTTP return code", statusCode == HTTP_OK); - } - - SSLParameters getDefaultSSLParameters() throws NoSuchAlgorithmException { - SSLParameters sslP1 = SSLContext.getDefault().getSupportedSSLParameters(); - String[] proto = sslP1.getApplicationProtocols(); - String[] cifers = sslP1.getCipherSuites(); - System.out.println(printStringArr(proto)); - System.out.println(printStringArr(cifers)); - return sslP1; - } - - String printStringArr(String... args) { - if (args == null) { - return null; - } - StringBuilder sb = new StringBuilder(); - for (String s : args) { - sb.append(s); - sb.append("\n"); - } - return sb.toString(); - } - - String printHeaders(HttpHeaders h) { - if (h == null) { - return null; - } - - StringBuilder sb = new StringBuilder(); - Map> hMap = h.map(); - for (String k : hMap.keySet()) { - sb.append(k).append(":"); - List l = hMap.get(k); - if (l != null) { - l.forEach(s -> { - sb.append(s).append(","); - }); - } - sb.append("\n"); - } - return sb.toString(); - } -} diff --git a/core-java-concurrency/src/main/java/com/baeldung/concurrent/prioritytaskexecution/Job.java b/core-java-concurrency/src/main/java/com/baeldung/concurrent/prioritytaskexecution/Job.java new file mode 100644 index 0000000000..9900d1c63d --- /dev/null +++ b/core-java-concurrency/src/main/java/com/baeldung/concurrent/prioritytaskexecution/Job.java @@ -0,0 +1,25 @@ +package com.baeldung.concurrent.prioritytaskexecution; + +public class Job implements Runnable { + private String jobName; + private JobPriority jobPriority; + + public Job(String jobName, JobPriority jobPriority) { + this.jobName = jobName; + this.jobPriority = jobPriority != null ? jobPriority : JobPriority.MEDIUM; + } + + public JobPriority getJobPriority() { + return jobPriority; + } + + @Override + public void run() { + try { + System.out.println("Job:" + jobName + + " Priority:" + jobPriority); + Thread.sleep(1000); + } catch (InterruptedException ignored) { + } + } +} \ No newline at end of file diff --git a/core-java-concurrency/src/main/java/com/baeldung/concurrent/prioritytaskexecution/JobPriority.java b/core-java-concurrency/src/main/java/com/baeldung/concurrent/prioritytaskexecution/JobPriority.java new file mode 100644 index 0000000000..d8092a9ce7 --- /dev/null +++ b/core-java-concurrency/src/main/java/com/baeldung/concurrent/prioritytaskexecution/JobPriority.java @@ -0,0 +1,7 @@ +package com.baeldung.concurrent.prioritytaskexecution; + +public enum JobPriority { + HIGH, + MEDIUM, + LOW +} diff --git a/core-java-concurrency/src/main/java/com/baeldung/concurrent/prioritytaskexecution/PriorityJobScheduler.java b/core-java-concurrency/src/main/java/com/baeldung/concurrent/prioritytaskexecution/PriorityJobScheduler.java new file mode 100644 index 0000000000..ba55696d5a --- /dev/null +++ b/core-java-concurrency/src/main/java/com/baeldung/concurrent/prioritytaskexecution/PriorityJobScheduler.java @@ -0,0 +1,56 @@ +package com.baeldung.concurrent.prioritytaskexecution; + +import java.util.Comparator; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.PriorityBlockingQueue; +import java.util.concurrent.TimeUnit; + +public class PriorityJobScheduler { + + private ExecutorService priorityJobPoolExecutor; + private ExecutorService priorityJobScheduler = + Executors.newSingleThreadExecutor(); + private PriorityBlockingQueue priorityQueue; + + public PriorityJobScheduler(Integer poolSize, Integer queueSize) { + priorityJobPoolExecutor = Executors.newFixedThreadPool(poolSize); + priorityQueue = new PriorityBlockingQueue(queueSize, + Comparator.comparing(Job::getJobPriority)); + + priorityJobScheduler.execute(()->{ + while (true) { + try { + priorityJobPoolExecutor.execute(priorityQueue.take()); + } catch (InterruptedException e) { + // exception needs special handling + break; + } + } + }); + } + + public void scheduleJob(Job job) { + priorityQueue.add(job); + } + + public int getQueuedTaskCount() { + return priorityQueue.size(); + } + + protected void close(ExecutorService scheduler) { + scheduler.shutdown(); + try { + if (!scheduler.awaitTermination(5, TimeUnit.SECONDS)) { + scheduler.shutdownNow(); + } + } catch (InterruptedException e) { + scheduler.shutdownNow(); + } + } + + public void closeScheduler() { + close(priorityJobPoolExecutor); + close(priorityJobScheduler); + } +} diff --git a/core-java-concurrency/src/main/java/com/baeldung/concurrent/threadlifecycle/BlockedState.java b/core-java-concurrency/src/main/java/com/baeldung/concurrent/threadlifecycle/BlockedState.java new file mode 100644 index 0000000000..19c6d08c2d --- /dev/null +++ b/core-java-concurrency/src/main/java/com/baeldung/concurrent/threadlifecycle/BlockedState.java @@ -0,0 +1,31 @@ +package com.baeldung.concurrent.threadlifecycle; + +public class BlockedState { + public static void main(String[] args) throws InterruptedException { + Thread t1 = new Thread(new DemoThreadB()); + Thread t2 = new Thread(new DemoThreadB()); + + t1.start(); + t2.start(); + + Thread.sleep(1000); + + System.out.println(t2.getState()); + System.exit(0); + } +} + +class DemoThreadB implements Runnable { + @Override + public void run() { + commonResource(); + } + + public static synchronized void commonResource() { + while(true) { + // Infinite loop to mimic heavy processing + // Thread 't1' won't leave this method + // when Thread 't2' enters this + } + } +} \ No newline at end of file diff --git a/core-java-concurrency/src/main/java/com/baeldung/concurrent/threadlifecycle/NewState.java b/core-java-concurrency/src/main/java/com/baeldung/concurrent/threadlifecycle/NewState.java new file mode 100644 index 0000000000..b524cc5ec7 --- /dev/null +++ b/core-java-concurrency/src/main/java/com/baeldung/concurrent/threadlifecycle/NewState.java @@ -0,0 +1,14 @@ +package com.baeldung.concurrent.threadlifecycle; + +public class NewState implements Runnable { + public static void main(String[] args) { + Runnable runnable = new NewState(); + Thread t = new Thread(runnable); + System.out.println(t.getState()); + } + + @Override + public void run() { + + } +} \ No newline at end of file diff --git a/core-java-concurrency/src/main/java/com/baeldung/concurrent/threadlifecycle/RunnableState.java b/core-java-concurrency/src/main/java/com/baeldung/concurrent/threadlifecycle/RunnableState.java new file mode 100644 index 0000000000..4aa8b36a76 --- /dev/null +++ b/core-java-concurrency/src/main/java/com/baeldung/concurrent/threadlifecycle/RunnableState.java @@ -0,0 +1,15 @@ +package com.baeldung.concurrent.threadlifecycle; + +public class RunnableState implements Runnable { + public static void main(String[] args) { + Runnable runnable = new NewState(); + Thread t = new Thread(runnable); + t.start(); + System.out.println(t.getState()); + } + + @Override + public void run() { + + } +} \ No newline at end of file diff --git a/core-java-concurrency/src/main/java/com/baeldung/concurrent/threadlifecycle/TerminatedState.java b/core-java-concurrency/src/main/java/com/baeldung/concurrent/threadlifecycle/TerminatedState.java new file mode 100644 index 0000000000..7c8884dc22 --- /dev/null +++ b/core-java-concurrency/src/main/java/com/baeldung/concurrent/threadlifecycle/TerminatedState.java @@ -0,0 +1,15 @@ +package com.baeldung.concurrent.threadlifecycle; + +public class TerminatedState implements Runnable { + public static void main(String[] args) throws InterruptedException { + Thread t1 = new Thread(new TerminatedState()); + t1.start(); + Thread.sleep(1000); + System.out.println(t1.getState()); + } + + @Override + public void run() { + // No processing in this block + } +} \ No newline at end of file diff --git a/core-java-concurrency/src/main/java/com/baeldung/concurrent/threadlifecycle/TimedWaitingState.java b/core-java-concurrency/src/main/java/com/baeldung/concurrent/threadlifecycle/TimedWaitingState.java new file mode 100644 index 0000000000..8d005352eb --- /dev/null +++ b/core-java-concurrency/src/main/java/com/baeldung/concurrent/threadlifecycle/TimedWaitingState.java @@ -0,0 +1,25 @@ +package com.baeldung.concurrent.threadlifecycle; + +public class TimedWaitingState { + public static void main(String[] args) throws InterruptedException { + DemoThread obj1 = new DemoThread(); + Thread t1 = new Thread(obj1); + t1.start(); + // The following sleep will give enough time for ThreadScheduler + // to start processing of thread t1 + Thread.sleep(1000); + System.out.println(t1.getState()); + } +} + +class DemoThread implements Runnable { + @Override + public void run() { + try { + Thread.sleep(5000); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + e.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/core-java-concurrency/src/main/java/com/baeldung/concurrent/threadlifecycle/WaitingState.java b/core-java-concurrency/src/main/java/com/baeldung/concurrent/threadlifecycle/WaitingState.java new file mode 100644 index 0000000000..98a6844309 --- /dev/null +++ b/core-java-concurrency/src/main/java/com/baeldung/concurrent/threadlifecycle/WaitingState.java @@ -0,0 +1,35 @@ +package com.baeldung.concurrent.threadlifecycle; + +public class WaitingState implements Runnable { + public static Thread t1; + + public static void main(String[] args) { + t1 = new Thread(new WaitingState()); + t1.start(); + } + + public void run() { + Thread t2 = new Thread(new DemoThreadWS()); + t2.start(); + + try { + t2.join(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + e.printStackTrace(); + } + } +} + +class DemoThreadWS implements Runnable { + public void run() { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + e.printStackTrace(); + } + + System.out.println(WaitingState.t1.getState()); + } +} \ No newline at end of file diff --git a/core-java-concurrency/src/main/java/com/baeldung/concurrent/waitandnotify/Data.java b/core-java-concurrency/src/main/java/com/baeldung/concurrent/waitandnotify/Data.java index d9e7434e0c..9d76c1fcd1 100644 --- a/core-java-concurrency/src/main/java/com/baeldung/concurrent/waitandnotify/Data.java +++ b/core-java-concurrency/src/main/java/com/baeldung/concurrent/waitandnotify/Data.java @@ -1,7 +1,5 @@ package com.baeldung.concurrent.waitandnotify; -import org.slf4j.Logger; - public class Data { private String packet; @@ -14,6 +12,7 @@ public class Data { try { wait(); } catch (InterruptedException e) { + Thread.currentThread().interrupt(); System.out.println("Thread Interrupted"); } } @@ -28,6 +27,7 @@ public class Data { try { wait(); } catch (InterruptedException e) { + Thread.currentThread().interrupt(); System.out.println("Thread Interrupted"); } } diff --git a/core-java-concurrency/src/main/java/com/baeldung/concurrent/waitandnotify/Receiver.java b/core-java-concurrency/src/main/java/com/baeldung/concurrent/waitandnotify/Receiver.java index 724e908a99..21ba822bfd 100644 --- a/core-java-concurrency/src/main/java/com/baeldung/concurrent/waitandnotify/Receiver.java +++ b/core-java-concurrency/src/main/java/com/baeldung/concurrent/waitandnotify/Receiver.java @@ -20,6 +20,7 @@ public class Receiver implements Runnable { try { Thread.sleep(ThreadLocalRandom.current().nextInt(1000, 5000)); } catch (InterruptedException e) { + Thread.currentThread().interrupt(); System.out.println("Thread Interrupted"); } } diff --git a/core-java-concurrency/src/main/java/com/baeldung/concurrent/waitandnotify/Sender.java b/core-java-concurrency/src/main/java/com/baeldung/concurrent/waitandnotify/Sender.java index b4945b7b73..c365294cdd 100644 --- a/core-java-concurrency/src/main/java/com/baeldung/concurrent/waitandnotify/Sender.java +++ b/core-java-concurrency/src/main/java/com/baeldung/concurrent/waitandnotify/Sender.java @@ -25,6 +25,7 @@ public class Sender implements Runnable { try { Thread.sleep(ThreadLocalRandom.current().nextInt(1000, 5000)); } catch (InterruptedException e) { + Thread.currentThread().interrupt(); System.out.println("Thread Interrupted"); } } diff --git a/core-java-concurrency/src/test/java/com/baeldung/concurrent/prioritytaskexecution/PriorityJobSchedulerUnitTest.java b/core-java-concurrency/src/test/java/com/baeldung/concurrent/prioritytaskexecution/PriorityJobSchedulerUnitTest.java new file mode 100644 index 0000000000..1e67fe45c1 --- /dev/null +++ b/core-java-concurrency/src/test/java/com/baeldung/concurrent/prioritytaskexecution/PriorityJobSchedulerUnitTest.java @@ -0,0 +1,40 @@ +package com.baeldung.concurrent.prioritytaskexecution; + +import org.junit.Test; + +public class PriorityJobSchedulerUnitTest { + private static int POOL_SIZE = 1; + private static int QUEUE_SIZE = 10; + + @Test + public void whenMultiplePriorityJobsQueued_thenHighestPriorityJobIsPicked() { + Job job1 = new Job("Job1", JobPriority.LOW); + Job job2 = new Job("Job2", JobPriority.MEDIUM); + Job job3 = new Job("Job3", JobPriority.HIGH); + Job job4 = new Job("Job4", JobPriority.MEDIUM); + Job job5 = new Job("Job5", JobPriority.LOW); + Job job6 = new Job("Job6", JobPriority.HIGH); + + PriorityJobScheduler pjs = new PriorityJobScheduler(POOL_SIZE, QUEUE_SIZE); + + pjs.scheduleJob(job1); + pjs.scheduleJob(job2); + pjs.scheduleJob(job3); + pjs.scheduleJob(job4); + pjs.scheduleJob(job5); + pjs.scheduleJob(job6); + + // ensure no tasks is pending before closing the scheduler + while (pjs.getQueuedTaskCount() != 0); + + // delay to avoid job sleep (added for demo) being interrupted + try { + Thread.sleep(2000); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RuntimeException(e); + } + + pjs.closeScheduler(); + } +} diff --git a/core-java-concurrency/src/test/java/com/baeldung/concurrent/stopping/StopThreadTest.java b/core-java-concurrency/src/test/java/com/baeldung/concurrent/stopping/StopThreadManualTest.java similarity index 97% rename from core-java-concurrency/src/test/java/com/baeldung/concurrent/stopping/StopThreadTest.java rename to core-java-concurrency/src/test/java/com/baeldung/concurrent/stopping/StopThreadManualTest.java index af54d6932e..9ea40824ca 100644 --- a/core-java-concurrency/src/test/java/com/baeldung/concurrent/stopping/StopThreadTest.java +++ b/core-java-concurrency/src/test/java/com/baeldung/concurrent/stopping/StopThreadManualTest.java @@ -10,7 +10,7 @@ import org.junit.Test; import com.jayway.awaitility.Awaitility; -public class StopThreadTest { +public class StopThreadManualTest { @Test public void whenStoppedThreadIsStopped() throws InterruptedException { diff --git a/core-java-concurrency/src/test/java/com/baeldung/concurrent/waitandnotify/NetworkIntegrationTest.java b/core-java-concurrency/src/test/java/com/baeldung/concurrent/waitandnotify/NetworkIntegrationTest.java index 8ecc92236e..e2bc328df3 100644 --- a/core-java-concurrency/src/test/java/com/baeldung/concurrent/waitandnotify/NetworkIntegrationTest.java +++ b/core-java-concurrency/src/test/java/com/baeldung/concurrent/waitandnotify/NetworkIntegrationTest.java @@ -57,7 +57,8 @@ public class NetworkIntegrationTest { sender.join(); receiver.join(); } catch (InterruptedException e) { - e.printStackTrace(); + Thread.currentThread().interrupt(); + System.out.println("Thread Interrupted"); } assertEquals(expected, outContent.toString()); diff --git a/core-java/README.md b/core-java/README.md index ed60db855c..b160d2271e 100644 --- a/core-java/README.md +++ b/core-java/README.md @@ -127,3 +127,4 @@ - [Polymorphism in Java](http://www.baeldung.com/java-polymorphism) - [Recursion In Java](http://www.baeldung.com/java-recursion) - [A Guide to the finalize Method in Java](http://www.baeldung.com/java-finalize) +- [Compiling Java *.class Files with javac](http://www.baeldung.com/javac) diff --git a/core-java/pom.xml b/core-java/pom.xml index 5c1e9fcad0..e2983de9dd 100644 --- a/core-java/pom.xml +++ b/core-java/pom.xml @@ -78,6 +78,11 @@ jackson-databind ${jackson.version} + + com.google.code.gson + gson + ${gson.version} + @@ -468,6 +473,7 @@ 2.8.5 + 2.8.2 1.7.21 diff --git a/core-java/src/main/java/com/baeldung/casting/Animal.java b/core-java/src/main/java/com/baeldung/casting/Animal.java new file mode 100644 index 0000000000..9f31c1dda3 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/casting/Animal.java @@ -0,0 +1,13 @@ +package com.baeldung.casting; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class Animal { + private static final Logger LOGGER = LoggerFactory.getLogger(Animal.class); + + public void eat() { + LOGGER.info("animal is eating"); + } + +} diff --git a/core-java/src/main/java/com/baeldung/casting/AnimalFeeder.java b/core-java/src/main/java/com/baeldung/casting/AnimalFeeder.java new file mode 100644 index 0000000000..89b972e5c2 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/casting/AnimalFeeder.java @@ -0,0 +1,23 @@ +package com.baeldung.casting; + +import java.util.List; + +public class AnimalFeeder { + + public void feed(List animals) { + animals.forEach(animal -> { + animal.eat(); + if (animal instanceof Cat) { + ((Cat) animal).meow(); + } + }); + } + + public void uncheckedFeed(List animals) { + animals.forEach(animal -> { + animal.eat(); + ((Cat) animal).meow(); + }); + } + +} diff --git a/core-java/src/main/java/com/baeldung/casting/Cat.java b/core-java/src/main/java/com/baeldung/casting/Cat.java new file mode 100644 index 0000000000..aa9a9a881a --- /dev/null +++ b/core-java/src/main/java/com/baeldung/casting/Cat.java @@ -0,0 +1,16 @@ +package com.baeldung.casting; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class Cat extends Animal implements Mew { + private static final Logger LOGGER = LoggerFactory.getLogger(Cat.class); + + public void eat() { + LOGGER.info("cat is eating"); + } + + public void meow() { + LOGGER.info("meow"); + } +} diff --git a/core-java/src/main/java/com/baeldung/casting/Dog.java b/core-java/src/main/java/com/baeldung/casting/Dog.java new file mode 100644 index 0000000000..763c6b4785 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/casting/Dog.java @@ -0,0 +1,12 @@ +package com.baeldung.casting; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class Dog extends Animal { + private static final Logger LOGGER = LoggerFactory.getLogger(Dog.class); + + public void eat() { + LOGGER.info("dog is eating"); + } +} diff --git a/core-java/src/main/java/com/baeldung/casting/Mew.java b/core-java/src/main/java/com/baeldung/casting/Mew.java new file mode 100644 index 0000000000..f3c7324551 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/casting/Mew.java @@ -0,0 +1,5 @@ +package com.baeldung.casting; + +public interface Mew { + public void meow(); +} diff --git a/core-java/src/main/java/com/baeldung/classloader/CustomClassLoader.java b/core-java/src/main/java/com/baeldung/classloader/CustomClassLoader.java new file mode 100644 index 0000000000..c44e863776 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/classloader/CustomClassLoader.java @@ -0,0 +1,29 @@ +package com.baeldung.classloader; + +import java.io.*; + +public class CustomClassLoader extends ClassLoader { + + + public Class getClass(String name) throws ClassNotFoundException { + byte[] b = loadClassFromFile(name); + return defineClass(name, b, 0, b.length); + } + + private byte[] loadClassFromFile(String fileName) { + InputStream inputStream = getClass().getClassLoader().getResourceAsStream( + fileName.replace('.', File.separatorChar) + ".class"); + byte[] buffer; + ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); + int nextValue = 0; + try { + while ( (nextValue = inputStream.read()) != -1 ) { + byteStream.write(nextValue); + } + } catch (IOException e) { + e.printStackTrace(); + } + buffer = byteStream.toByteArray(); + return buffer; + } +} diff --git a/core-java/src/main/java/com/baeldung/classloader/PrintClassLoader.java b/core-java/src/main/java/com/baeldung/classloader/PrintClassLoader.java new file mode 100644 index 0000000000..09ee68bf6e --- /dev/null +++ b/core-java/src/main/java/com/baeldung/classloader/PrintClassLoader.java @@ -0,0 +1,22 @@ +package com.baeldung.classloader; + +import com.sun.javafx.util.Logging; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; +import java.util.ArrayList; + +public class PrintClassLoader { + + public void printClassLoaders() throws ClassNotFoundException { + + System.out.println("Classloader of this class:" + PrintClassLoader.class.getClassLoader()); + System.out.println("Classloader of Logging:" + Logging.class.getClassLoader()); + System.out.println("Classloader of ArrayList:" + ArrayList.class.getClassLoader()); + + } +} diff --git a/core-java/src/main/java/com/baeldung/deepcopy/Address.java b/core-java/src/main/java/com/baeldung/deepcopy/Address.java new file mode 100644 index 0000000000..4e010ea92b --- /dev/null +++ b/core-java/src/main/java/com/baeldung/deepcopy/Address.java @@ -0,0 +1,59 @@ +package com.baeldung.deepcopy; + +import java.io.Serializable; + +public class Address implements Serializable, Cloneable { + + @Override + public Object clone() { + try { + return (Address) super.clone(); + } catch (CloneNotSupportedException e) { + return new Address(this.street, this.getCity(), this.getCountry()); + } + } + + private static final long serialVersionUID = 1740913841244949416L; + private String street; + private String city; + + private String country; + + public Address(Address that) { + this(that.getStreet(), that.getCity(), that.getCountry()); + } + + public Address(String street, String city, String country) { + this.street = street; + this.city = city; + this.country = country; + } + + public Address() { + } + + public String getStreet() { + return street; + } + + public String getCity() { + return city; + } + + public String getCountry() { + return country; + } + + public void setStreet(String street) { + this.street = street; + } + + public void setCity(String city) { + this.city = city; + } + + public void setCountry(String country) { + this.country = country; + } +} + diff --git a/core-java/src/main/java/com/baeldung/deepcopy/User.java b/core-java/src/main/java/com/baeldung/deepcopy/User.java new file mode 100644 index 0000000000..329cfc6b27 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/deepcopy/User.java @@ -0,0 +1,48 @@ +package com.baeldung.deepcopy; + +import java.io.Serializable; + +public class User implements Serializable, Cloneable { + + private static final long serialVersionUID = -3427002229954777557L; + private String firstName; + private String lastName; + private Address address; + + public User(String firstName, String lastName, Address address) { + this.firstName = firstName; + this.lastName = lastName; + this.address = address; + } + + public User(User that) { + this(that.getFirstName(), that.getLastName(), new Address(that.getAddress())); + } + + public User() { + } + + @Override + public Object clone() { + User user; + try { + user = (User) super.clone(); + } catch (CloneNotSupportedException e) { + user = new User(this.getFirstName(), this.getLastName(), this.getAddress()); + } + user.address = (Address) this.address.clone(); + return user; + } + + public String getFirstName() { + return firstName; + } + + public String getLastName() { + return lastName; + } + + public Address getAddress() { + return address; + } +} diff --git a/core-java/src/main/java/com/baeldung/designpatterns/chainofresponsibility/AuthenticationProcessor.java b/core-java/src/main/java/com/baeldung/designpatterns/chainofresponsibility/AuthenticationProcessor.java new file mode 100644 index 0000000000..b86a572393 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/designpatterns/chainofresponsibility/AuthenticationProcessor.java @@ -0,0 +1,13 @@ +package com.baeldung.designpatterns.chainofresponsibility; + +public abstract class AuthenticationProcessor { + + // next element in chain or responsibility + public AuthenticationProcessor nextProcessor; + + public AuthenticationProcessor(AuthenticationProcessor nextProcessor) { + this.nextProcessor = nextProcessor; + } + + public abstract boolean isAuthorized(AuthenticationProvider authProvider); +} diff --git a/core-java/src/main/java/com/baeldung/designpatterns/chainofresponsibility/AuthenticationProvider.java b/core-java/src/main/java/com/baeldung/designpatterns/chainofresponsibility/AuthenticationProvider.java new file mode 100644 index 0000000000..552a7ff6d9 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/designpatterns/chainofresponsibility/AuthenticationProvider.java @@ -0,0 +1,5 @@ +package com.baeldung.designpatterns.chainofresponsibility; + +public interface AuthenticationProvider { + +} diff --git a/core-java/src/main/java/com/baeldung/designpatterns/chainofresponsibility/OAuthAuthenticationProcessor.java b/core-java/src/main/java/com/baeldung/designpatterns/chainofresponsibility/OAuthAuthenticationProcessor.java new file mode 100644 index 0000000000..2e2e51fed2 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/designpatterns/chainofresponsibility/OAuthAuthenticationProcessor.java @@ -0,0 +1,21 @@ +package com.baeldung.designpatterns.chainofresponsibility; + +public class OAuthAuthenticationProcessor extends AuthenticationProcessor { + + public OAuthAuthenticationProcessor(AuthenticationProcessor nextProcessor) { + super(nextProcessor); + } + + @Override + public boolean isAuthorized(AuthenticationProvider authProvider) { + + if (authProvider instanceof OAuthTokenProvider) { + return Boolean.TRUE; + } else if (nextProcessor != null) { + return nextProcessor.isAuthorized(authProvider); + } else { + return Boolean.FALSE; + } + } + +} diff --git a/core-java/src/main/java/com/baeldung/designpatterns/chainofresponsibility/OAuthTokenProvider.java b/core-java/src/main/java/com/baeldung/designpatterns/chainofresponsibility/OAuthTokenProvider.java new file mode 100644 index 0000000000..d4e516053b --- /dev/null +++ b/core-java/src/main/java/com/baeldung/designpatterns/chainofresponsibility/OAuthTokenProvider.java @@ -0,0 +1,5 @@ +package com.baeldung.designpatterns.chainofresponsibility; + +public class OAuthTokenProvider implements AuthenticationProvider { + +} diff --git a/core-java/src/main/java/com/baeldung/designpatterns/chainofresponsibility/SamlAuthenticationProvider.java b/core-java/src/main/java/com/baeldung/designpatterns/chainofresponsibility/SamlAuthenticationProvider.java new file mode 100644 index 0000000000..533b2b4a2d --- /dev/null +++ b/core-java/src/main/java/com/baeldung/designpatterns/chainofresponsibility/SamlAuthenticationProvider.java @@ -0,0 +1,5 @@ +package com.baeldung.designpatterns.chainofresponsibility; + +public class SamlAuthenticationProvider implements AuthenticationProvider { + +} diff --git a/core-java/src/main/java/com/baeldung/designpatterns/chainofresponsibility/UsernamePasswordAuthenticationProcessor.java b/core-java/src/main/java/com/baeldung/designpatterns/chainofresponsibility/UsernamePasswordAuthenticationProcessor.java new file mode 100644 index 0000000000..df600c35db --- /dev/null +++ b/core-java/src/main/java/com/baeldung/designpatterns/chainofresponsibility/UsernamePasswordAuthenticationProcessor.java @@ -0,0 +1,20 @@ +package com.baeldung.designpatterns.chainofresponsibility; + +public class UsernamePasswordAuthenticationProcessor extends AuthenticationProcessor { + + public UsernamePasswordAuthenticationProcessor(AuthenticationProcessor nextProcessor) { + super(nextProcessor); + } + + @Override + public boolean isAuthorized(AuthenticationProvider authProvider) { + if (authProvider instanceof UsernamePasswordProvider) { + return Boolean.TRUE; + } else if (nextProcessor != null) { + return nextProcessor.isAuthorized(authProvider); + } else { + return Boolean.FALSE; + } + } + +} diff --git a/core-java/src/main/java/com/baeldung/designpatterns/chainofresponsibility/UsernamePasswordProvider.java b/core-java/src/main/java/com/baeldung/designpatterns/chainofresponsibility/UsernamePasswordProvider.java new file mode 100644 index 0000000000..9fbfa7554d --- /dev/null +++ b/core-java/src/main/java/com/baeldung/designpatterns/chainofresponsibility/UsernamePasswordProvider.java @@ -0,0 +1,5 @@ +package com.baeldung.designpatterns.chainofresponsibility; + +public class UsernamePasswordProvider implements AuthenticationProvider { + +} diff --git a/core-java/src/main/java/com/baeldung/designpatterns/flyweight/Car.java b/core-java/src/main/java/com/baeldung/designpatterns/flyweight/Car.java new file mode 100644 index 0000000000..50f62cafaa --- /dev/null +++ b/core-java/src/main/java/com/baeldung/designpatterns/flyweight/Car.java @@ -0,0 +1,85 @@ +package com.baeldung.designpatterns.flyweight; + +import java.awt.Color; + +import javax.annotation.concurrent.Immutable; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Represents a car. This class is immutable. + * + * @author Donato Rimenti + */ +@Immutable +public class Car implements Vehicle { + + /** + * Logger. + */ + private final static Logger LOG = LoggerFactory.getLogger(Car.class); + + /** + * The car's engine. + */ + private Engine engine; + + /** + * The car's color. + */ + private Color color; + + /** + * Instantiates a new Car. + * + * @param engine + * the {@link #engine} + * @param color + * the {@link #color} + */ + public Car(Engine engine, Color color) { + this.engine = engine; + this.color = color; + + // Building a new car is a very expensive operation! + try { + Thread.sleep(2000); + } catch (InterruptedException e) { + LOG.error("Error while creating a new car", e); + } + } + + /* + * (non-Javadoc) + * + * @see com.baeldung.designpatterns.flyweight.Vehicle#start() + */ + @Override + public void start() { + LOG.info("Car is starting!"); + engine.start(); + } + + /* + * (non-Javadoc) + * + * @see com.baeldung.designpatterns.flyweight.Vehicle#stop() + */ + @Override + public void stop() { + LOG.info("Car is stopping!"); + engine.stop(); + } + + /* + * (non-Javadoc) + * + * @see com.baeldung.designpatterns.flyweight.Vehicle#getColor() + */ + @Override + public Color getColor() { + return this.color; + } + +} diff --git a/core-java/src/main/java/com/baeldung/designpatterns/flyweight/Engine.java b/core-java/src/main/java/com/baeldung/designpatterns/flyweight/Engine.java new file mode 100644 index 0000000000..05d9ca98b8 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/designpatterns/flyweight/Engine.java @@ -0,0 +1,31 @@ +package com.baeldung.designpatterns.flyweight; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Engine for a vehicle. + * + * @author Donato Rimenti + */ +public class Engine { + + /** + * Logger. + */ + private final static Logger LOG = LoggerFactory.getLogger(Engine.class); + + /** + * Starts the engine. + */ + public void start() { + LOG.info("Engine is starting!"); + } + + /** + * Stops the engine. + */ + public void stop() { + LOG.info("Engine is stopping!"); + } +} diff --git a/core-java/src/main/java/com/baeldung/designpatterns/flyweight/Vehicle.java b/core-java/src/main/java/com/baeldung/designpatterns/flyweight/Vehicle.java new file mode 100644 index 0000000000..c285f9fcff --- /dev/null +++ b/core-java/src/main/java/com/baeldung/designpatterns/flyweight/Vehicle.java @@ -0,0 +1,29 @@ +package com.baeldung.designpatterns.flyweight; + +import java.awt.Color; + +/** + * Interface for a vehicle. + * + * @author Donato Rimenti + */ +public interface Vehicle { + + /** + * Starts the vehicle. + */ + public void start(); + + /** + * Stops the vehicle. + */ + public void stop(); + + /** + * Gets the color of the vehicle. + * + * @return the color of the vehicle + */ + public Color getColor(); + +} \ No newline at end of file diff --git a/core-java/src/main/java/com/baeldung/designpatterns/flyweight/VehicleFactory.java b/core-java/src/main/java/com/baeldung/designpatterns/flyweight/VehicleFactory.java new file mode 100644 index 0000000000..2854b7dab1 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/designpatterns/flyweight/VehicleFactory.java @@ -0,0 +1,45 @@ +package com.baeldung.designpatterns.flyweight; + +import java.awt.Color; +import java.util.HashMap; +import java.util.Map; + +/** + * Factory which implements the Flyweight pattern to return an existing vehicle + * if present or a new one otherwise. + * + * @author Donato Rimenti + */ +public class VehicleFactory { + + /** + * Stores the already created vehicles. + */ + private static Map vehiclesCache = new HashMap(); + + /** + * Private constructor to prevent this class instantiation. + */ + private VehicleFactory() { + } + + /** + * Returns a vehicle of the same color passed as argument. If that vehicle + * was already created by this factory, that vehicle is returned, otherwise + * a new one is created and returned. + * + * @param color + * the color of the vehicle to return + * @return a vehicle of the specified color + */ + public static Vehicle createVehicle(Color color) { + // Looks for the requested vehicle into the cache. + // If the vehicle doesn't exist, a new one is created. + Vehicle newVehicle = vehiclesCache.computeIfAbsent(color, newColor -> { + // Creates the new car. + Engine newEngine = new Engine(); + return new Car(newEngine, newColor); + }); + return newVehicle; + } +} diff --git a/core-java/src/main/java/com/baeldung/designpatterns/observer/Channel.java b/core-java/src/main/java/com/baeldung/designpatterns/observer/Channel.java new file mode 100644 index 0000000000..9ca2edac38 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/designpatterns/observer/Channel.java @@ -0,0 +1,5 @@ +package com.baeldung.designpatterns.observer; + +public interface Channel { + public void update(Object o); +} diff --git a/core-java/src/main/java/com/baeldung/designpatterns/observer/NewsAgency.java b/core-java/src/main/java/com/baeldung/designpatterns/observer/NewsAgency.java new file mode 100644 index 0000000000..0330fbdcdc --- /dev/null +++ b/core-java/src/main/java/com/baeldung/designpatterns/observer/NewsAgency.java @@ -0,0 +1,24 @@ +package com.baeldung.designpatterns.observer; + +import java.util.ArrayList; +import java.util.List; + +public class NewsAgency { + private String news; + private List channels = new ArrayList<>(); + + public void addObserver(Channel channel) { + this.channels.add(channel); + } + + public void removeObserver(Channel channel) { + this.channels.remove(channel); + } + + public void setNews(String news) { + this.news = news; + for (Channel channel : this.channels) { + channel.update(this.news); + } + } +} diff --git a/core-java/src/main/java/com/baeldung/designpatterns/observer/NewsChannel.java b/core-java/src/main/java/com/baeldung/designpatterns/observer/NewsChannel.java new file mode 100644 index 0000000000..09c22e0ad8 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/designpatterns/observer/NewsChannel.java @@ -0,0 +1,20 @@ +package com.baeldung.designpatterns.observer; + +public class NewsChannel implements Channel { + + private String news; + + @Override + public void update(Object news) { + this.setNews((String) news); + } + + public String getNews() { + return news; + } + + public void setNews(String news) { + this.news = news; + } + +} diff --git a/core-java/src/main/java/com/baeldung/designpatterns/observer/ONewsAgency.java b/core-java/src/main/java/com/baeldung/designpatterns/observer/ONewsAgency.java new file mode 100644 index 0000000000..2849820663 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/designpatterns/observer/ONewsAgency.java @@ -0,0 +1,13 @@ +package com.baeldung.designpatterns.observer; + +import java.util.Observable; + +public class ONewsAgency extends Observable { + private String news; + + public void setNews(String news) { + this.news = news; + setChanged(); + notifyObservers(news); + } +} diff --git a/core-java/src/main/java/com/baeldung/designpatterns/observer/ONewsChannel.java b/core-java/src/main/java/com/baeldung/designpatterns/observer/ONewsChannel.java new file mode 100644 index 0000000000..3989fe0286 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/designpatterns/observer/ONewsChannel.java @@ -0,0 +1,22 @@ +package com.baeldung.designpatterns.observer; + +import java.util.Observable; +import java.util.Observer; + +public class ONewsChannel implements Observer { + + private String news; + + @Override + public void update(Observable o, Object news) { + this.setNews((String) news); + } + + public String getNews() { + return news; + } + + public void setNews(String news) { + this.news = news; + } +} diff --git a/core-java/src/main/java/com/baeldung/designpatterns/observer/PCLNewsAgency.java b/core-java/src/main/java/com/baeldung/designpatterns/observer/PCLNewsAgency.java new file mode 100644 index 0000000000..b05b97ab0b --- /dev/null +++ b/core-java/src/main/java/com/baeldung/designpatterns/observer/PCLNewsAgency.java @@ -0,0 +1,28 @@ +package com.baeldung.designpatterns.observer; + +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; + +public class PCLNewsAgency { + private String news; + + private PropertyChangeSupport support; + + public PCLNewsAgency() { + support = new PropertyChangeSupport(this); + } + + public void addPropertyChangeListener(PropertyChangeListener pcl) { + support.addPropertyChangeListener(pcl); + } + + public void removePropertyChangeListener(PropertyChangeListener pcl) { + support.removePropertyChangeListener(pcl); + } + + public void setNews(String value) { + support.firePropertyChange("news", this.news, value); + this.news = value; + + } +} diff --git a/core-java/src/main/java/com/baeldung/designpatterns/observer/PCLNewsChannel.java b/core-java/src/main/java/com/baeldung/designpatterns/observer/PCLNewsChannel.java new file mode 100644 index 0000000000..ff8d35463c --- /dev/null +++ b/core-java/src/main/java/com/baeldung/designpatterns/observer/PCLNewsChannel.java @@ -0,0 +1,21 @@ +package com.baeldung.designpatterns.observer; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +public class PCLNewsChannel implements PropertyChangeListener { + + private String news; + + public void propertyChange(PropertyChangeEvent evt) { + this.setNews((String) evt.getNewValue()); + } + + public String getNews() { + return news; + } + + public void setNews(String news) { + this.news = news; + } +} diff --git a/core-java/src/main/java/com/baeldung/inheritance/ArmoredCar.java b/core-java/src/main/java/com/baeldung/inheritance/ArmoredCar.java new file mode 100644 index 0000000000..b6bb5181b8 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/inheritance/ArmoredCar.java @@ -0,0 +1,43 @@ +package com.baeldung.inheritance; + +public class ArmoredCar extends Car implements Floatable, Flyable{ + private int bulletProofWindows; + private String model; + + public void remoteStartCar() { + // this vehicle can be started by using a remote control + } + + public String registerModel() { + return model; + } + + public String getAValue() { + return super.model; // returns value of model defined in base class Car + // return this.model; // will return value of model defined in ArmoredCar + // return model; // will return value of model defined in ArmoredCar + } + + public static String msg() { + // return super.msg(); // this won't compile. + return "ArmoredCar"; + } + + @Override + public void floatOnWater() { + System.out.println("I can float!"); + } + + @Override + public void fly() { + System.out.println("I can fly!"); + } + + public void aMethod() { + // System.out.println(duration); // Won't compile + System.out.println(Floatable.duration); // outputs 10 + System.out.println(Flyable.duration); // outputs 20 + } + + +} diff --git a/core-java/src/main/java/com/baeldung/inheritance/BMW.java b/core-java/src/main/java/com/baeldung/inheritance/BMW.java new file mode 100644 index 0000000000..8ad3bb683f --- /dev/null +++ b/core-java/src/main/java/com/baeldung/inheritance/BMW.java @@ -0,0 +1,12 @@ +package com.baeldung.inheritance; + +public class BMW extends Car { + public BMW() { + super(5, "BMW"); + } + + @Override + public String toString() { + return model; + } +} diff --git a/core-java/src/main/java/com/baeldung/inheritance/Car.java b/core-java/src/main/java/com/baeldung/inheritance/Car.java new file mode 100644 index 0000000000..21ea9ea569 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/inheritance/Car.java @@ -0,0 +1,32 @@ +package com.baeldung.inheritance; + +public class Car { + private final int DEFAULT_WHEEL_COUNT = 5; + private final String DEFAULT_MODEL = "Basic"; + + protected int wheels; + protected String model; + + public Car() { + this.wheels = DEFAULT_WHEEL_COUNT; + this.model = DEFAULT_MODEL; + } + + public Car(int wheels, String model) { + this.wheels = wheels; + this.model = model; + } + + public void start() { + // Check essential parts + // If okay, start. + } + public static int count = 10; + public static String msg() { + return "Car"; + } + + public String toString() { + return model; + } +} \ No newline at end of file diff --git a/core-java/src/main/java/com/baeldung/inheritance/Employee.java b/core-java/src/main/java/com/baeldung/inheritance/Employee.java new file mode 100644 index 0000000000..599a1d7331 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/inheritance/Employee.java @@ -0,0 +1,15 @@ +package com.baeldung.inheritance; + +public class Employee { + private String name; + private Car car; + + public Employee(String name, Car car) { + this.name = name; + this.car = car; + } + + public Car getCar() { + return car; + } +} \ No newline at end of file diff --git a/core-java/src/main/java/com/baeldung/inheritance/Floatable.java b/core-java/src/main/java/com/baeldung/inheritance/Floatable.java new file mode 100644 index 0000000000..c0b456dffb --- /dev/null +++ b/core-java/src/main/java/com/baeldung/inheritance/Floatable.java @@ -0,0 +1,10 @@ +package com.baeldung.inheritance; + +public interface Floatable { + int duration = 10; + void floatOnWater(); + + default void repair() { + System.out.println("Repairing Floatable object"); + } +} diff --git a/core-java/src/main/java/com/baeldung/inheritance/Flyable.java b/core-java/src/main/java/com/baeldung/inheritance/Flyable.java new file mode 100644 index 0000000000..cb8244cf5b --- /dev/null +++ b/core-java/src/main/java/com/baeldung/inheritance/Flyable.java @@ -0,0 +1,13 @@ +package com.baeldung.inheritance; + +public interface Flyable { + int duration = 10; + void fly(); + + /* + * Commented + */ + //default void repair() { + // System.out.println("Repairing Flyable object"); + //} +} diff --git a/core-java/src/main/java/com/baeldung/inheritance/SpaceCar.java b/core-java/src/main/java/com/baeldung/inheritance/SpaceCar.java new file mode 100644 index 0000000000..8c23b26da9 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/inheritance/SpaceCar.java @@ -0,0 +1,18 @@ +package com.baeldung.inheritance; + +public class SpaceCar extends Car implements SpaceTraveller { + @Override + public void floatOnWater() { + System.out.println("SpaceCar floating!"); + } + + @Override + public void fly() { + System.out.println("SpaceCar flying!"); + } + + @Override + public void remoteControl() { + System.out.println("SpaceCar being controlled remotely!"); + } +} diff --git a/core-java/src/main/java/com/baeldung/inheritance/SpaceTraveller.java b/core-java/src/main/java/com/baeldung/inheritance/SpaceTraveller.java new file mode 100644 index 0000000000..9b66441791 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/inheritance/SpaceTraveller.java @@ -0,0 +1,6 @@ +package com.baeldung.inheritance; + +public interface SpaceTraveller extends Floatable, Flyable { + int duration = 10; + void remoteControl(); +} \ No newline at end of file diff --git a/core-java/src/main/java/com/baeldung/java/list/CustomList.java b/core-java/src/main/java/com/baeldung/java/list/CustomList.java new file mode 100644 index 0000000000..bc1321b1a3 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/java/list/CustomList.java @@ -0,0 +1,229 @@ +package com.baeldung.java.list; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; + +public class CustomList implements List { + private Object[] internal = {}; + + @Override + public void add(int index, E element) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean addAll(Collection collection) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean addAll(int index, Collection collection) { + throw new UnsupportedOperationException(); + } + + @Override + public E remove(int index) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean remove(Object object) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean removeAll(Collection collection) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean retainAll(Collection collection) { + throw new UnsupportedOperationException(); + } + + @Override + public int size() { + return internal.length; + } + + @Override + public boolean isEmpty() { + return internal.length == 0; + } + + @Override + public boolean add(E element) { + // the first cycle + // internal = new Object[1]; + // internal[0] = element; + // return true; + + Object[] temp = new Object[internal.length + 1]; + System.arraycopy(internal, 0, temp, 0, internal.length); + temp[internal.length] = element; + internal = temp; + return true; + } + + @SuppressWarnings("unchecked") + @Override + public E get(int index) { + return (E) internal[index]; + } + + @Override + public boolean contains(Object object) { + // return false + + for (Object element : internal) { + if (object.equals(element)) { + return true; + } + } + return false; + } + + @Override + public boolean containsAll(Collection collection) { + // the first cycle + // for (Object element : collection) { + // if (element.equals(internal[0])) { + // return true; + // } + // } + // return false; + + for (Object element : collection) + if (!contains(element)) { + return false; + } + return true; + } + + @SuppressWarnings("unchecked") + @Override + public E set(int index, E element) { + E oldElement = (E) internal[index]; + internal[index] = element; + return oldElement; + } + + @Override + public void clear() { + internal = new Object[0]; + } + + @Override + public int indexOf(Object object) { + // the first cycle + // if (object.equals(internal[0])) { + // return 0; + // } + // return -1; + + for (int i = 0; i < internal.length; i++) { + if (object.equals(internal[i])) { + return i; + } + } + return -1; + } + + @Override + public int lastIndexOf(Object object) { + // the first cycle + // if (object.equals(internal[0])) { + // return 0; + // } + // return -1; + + for (int i = internal.length - 1; i >= 0; i--) { + if (object.equals(internal[i])) { + return i; + } + } + return -1; + } + + @SuppressWarnings("unchecked") + @Override + public List subList(int fromIndex, int toIndex) { + // the first cycle + // return (List) Arrays.asList(internal); + + Object[] temp = new Object[toIndex - fromIndex]; + System.arraycopy(internal, fromIndex, temp, 0, temp.length); + return (List) Arrays.asList(temp); + } + + @Override + public Object[] toArray() { + return Arrays.copyOf(internal, internal.length); + } + + @SuppressWarnings("unchecked") + @Override + public T[] toArray(T[] array) { + // the first cycle + // array[0] = (T) internal[0]; + // return array; + + // the second cycle + // if (array.length < internal.length) { + // return (T[]) Arrays.copyOf(internal, internal.length, array.getClass()); + // } + // return (T[]) Arrays.copyOf(internal, internal.length, array.getClass()); + + if (array.length < internal.length) { + return (T[]) Arrays.copyOf(internal, internal.length, array.getClass()); + } + + System.arraycopy(internal, 0, array, 0, internal.length); + if (array.length > internal.length) { + array[internal.length] = null; + } + return array; + } + + @Override + public Iterator iterator() { + return new CustomIterator(); + } + + @Override + public ListIterator listIterator() { + return null; + } + + @Override + public ListIterator listIterator(int index) { + // ignored for brevity + return null; + } + + private class CustomIterator implements Iterator { + int index; + + @Override + public boolean hasNext() { + // the first cycle + // return true; + + return index != internal.length; + } + + @SuppressWarnings("unchecked") + @Override + public E next() { + // the first cycle + // return (E) CustomList.this.internal[0]; + + E element = (E) CustomList.this.internal[index]; + index++; + return element; + } + } +} diff --git a/core-java/src/main/java/com/baeldung/javac/Data.java b/core-java/src/main/java/com/baeldung/javac/Data.java index f6912fbd14..feef0c4f1e 100644 --- a/core-java/src/main/java/com/baeldung/javac/Data.java +++ b/core-java/src/main/java/com/baeldung/javac/Data.java @@ -1,28 +1,16 @@ package com.baeldung.javac; -import java.io.Serializable; import java.util.ArrayList; import java.util.List; -public class Data implements Serializable { - static List textList = new ArrayList(); +public class Data { + List textList = new ArrayList(); - private static void addText() { - textList.add("baeldung"); - textList.add("."); - textList.add("com"); + public void addText(String text) { + textList.add(text); } public List getTextList() { - this.addText(); - List result = new ArrayList(); - String firstElement = (String) textList.get(0); - switch (firstElement) { - case "baeldung": - result.add("baeldung"); - case "com": - result.add("com"); - } - return result; + return this.textList; } -} +} \ No newline at end of file diff --git a/core-java/src/main/java/com/baeldung/methodoverloadingoverriding/application/Application.java b/core-java/src/main/java/com/baeldung/methodoverloadingoverriding/application/Application.java new file mode 100644 index 0000000000..6e023e9fa8 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/methodoverloadingoverriding/application/Application.java @@ -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()); + } +} diff --git a/core-java/src/main/java/com/baeldung/methodoverloadingoverriding/model/Car.java b/core-java/src/main/java/com/baeldung/methodoverloadingoverriding/model/Car.java new file mode 100644 index 0000000000..aa5bdcaec9 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/methodoverloadingoverriding/model/Car.java @@ -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."; + } +} diff --git a/core-java/src/main/java/com/baeldung/methodoverloadingoverriding/model/Vehicle.java b/core-java/src/main/java/com/baeldung/methodoverloadingoverriding/model/Vehicle.java new file mode 100644 index 0000000000..eb59e8ca23 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/methodoverloadingoverriding/model/Vehicle.java @@ -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."; + } +} diff --git a/core-java/src/main/java/com/baeldung/methodoverloadingoverriding/util/Multiplier.java b/core-java/src/main/java/com/baeldung/methodoverloadingoverriding/util/Multiplier.java new file mode 100644 index 0000000000..c43e61c78f --- /dev/null +++ b/core-java/src/main/java/com/baeldung/methodoverloadingoverriding/util/Multiplier.java @@ -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; + } +} diff --git a/core-java/src/main/java/com/baeldung/recursion/BinaryNode.java b/core-java/src/main/java/com/baeldung/recursion/BinaryNode.java new file mode 100644 index 0000000000..0c3f0ecc40 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/recursion/BinaryNode.java @@ -0,0 +1,31 @@ +package com.baeldung.recursion; + +public class BinaryNode { + int value; + BinaryNode left; + BinaryNode right; + + public BinaryNode(int value){ + this.value = value; + } + + public int getValue() { + return value; + } + public void setValue(int value) { + this.value = value; + } + public BinaryNode getLeft() { + return left; + } + public void setLeft(BinaryNode left) { + this.left = left; + } + public BinaryNode getRight() { + return right; + } + public void setRight(BinaryNode right) { + this.right = right; + } + +} diff --git a/core-java/src/main/java/com/baeldung/recursion/RecursionExample.java b/core-java/src/main/java/com/baeldung/recursion/RecursionExample.java new file mode 100644 index 0000000000..649c0e0587 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/recursion/RecursionExample.java @@ -0,0 +1,64 @@ +package com.baeldung.recursion; + +public class RecursionExample { + + public int sum(int n){ + if (n >= 1){ + return sum(n - 1) + n; + } + return n; + } + + public int tailSum(int currentSum, int n){ + if (n <= 1) { + return currentSum + n; + } + return tailSum(currentSum + n, n - 1); + } + + public int iterativeSum(int n){ + int sum = 0; + if(n < 0){ + return -1; + } + for(int i=0; i<=n; i++){ + sum += i; + } + return sum; + } + + public int powerOf10(int n){ + if (n == 0){ + return 1; + } + return powerOf10(n-1)*10; + } + + public int fibonacci(int n){ + if (n <=1 ){ + return n; + } + return fibonacci(n-1) + fibonacci(n-2); + } + + public String toBinary(int n){ + if (n <= 1 ){ + return String.valueOf(n); + } + return toBinary(n / 2) + String.valueOf(n % 2); + } + + public int calculateTreeHeight(BinaryNode root){ + if (root!= null){ + if (root.getLeft() != null || root.getRight() != null){ + return 1 + max(calculateTreeHeight(root.left) , calculateTreeHeight(root.right)); + } + } + return 0; + } + + public int max(int a,int b){ + return a>b ? a:b; + } + +} diff --git a/core-java/src/main/java/com/baeldung/resourcebundle/ExampleControl.java b/core-java/src/main/java/com/baeldung/resourcebundle/ExampleControl.java new file mode 100644 index 0000000000..88ce36c27f --- /dev/null +++ b/core-java/src/main/java/com/baeldung/resourcebundle/ExampleControl.java @@ -0,0 +1,15 @@ +package com.baeldung.resourcebundle; + +import java.util.Arrays; +import java.util.List; +import java.util.Locale; +import java.util.ResourceBundle; + +public class ExampleControl extends ResourceBundle.Control { + + @Override + public List getCandidateLocales(String s, Locale locale) { + return Arrays.asList(new Locale("pl", "PL")); + } + +} diff --git a/core-java/src/main/java/com/baeldung/resourcebundle/ExampleResource.java b/core-java/src/main/java/com/baeldung/resourcebundle/ExampleResource.java new file mode 100644 index 0000000000..52ccc80f52 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/resourcebundle/ExampleResource.java @@ -0,0 +1,14 @@ +package com.baeldung.resourcebundle; + +import java.util.ListResourceBundle; + +public class ExampleResource extends ListResourceBundle { + + @Override + protected Object[][] getContents() { + return new Object[][] { + { "greeting", "hello" } + }; + } + +} diff --git a/core-java/src/main/java/com/baeldung/resourcebundle/ExampleResource_pl.java b/core-java/src/main/java/com/baeldung/resourcebundle/ExampleResource_pl.java new file mode 100644 index 0000000000..7d4f11a5d3 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/resourcebundle/ExampleResource_pl.java @@ -0,0 +1,15 @@ +package com.baeldung.resourcebundle; + +import java.util.ListResourceBundle; + +public class ExampleResource_pl extends ListResourceBundle { + + @Override + protected Object[][] getContents() { + return new Object[][] { + { "greeting", "cześć" }, + { "language", "polish" }, + }; + } + +} diff --git a/core-java/src/main/java/com/baeldung/resourcebundle/ExampleResource_pl_PL.java b/core-java/src/main/java/com/baeldung/resourcebundle/ExampleResource_pl_PL.java new file mode 100644 index 0000000000..252bfcb9cf --- /dev/null +++ b/core-java/src/main/java/com/baeldung/resourcebundle/ExampleResource_pl_PL.java @@ -0,0 +1,17 @@ +package com.baeldung.resourcebundle; + +import java.math.BigDecimal; +import java.util.ListResourceBundle; + +public class ExampleResource_pl_PL extends ListResourceBundle { + + @Override + protected Object[][] getContents() { + return new Object[][] { + { "currency", "polish zloty" }, + { "toUsdRate", new BigDecimal("3.401") }, + { "cities", new String[] { "Warsaw", "Cracow" } } + }; + } + +} diff --git a/core-java/src/main/java/com/baeldung/string/Palindrome.java b/core-java/src/main/java/com/baeldung/string/Palindrome.java new file mode 100644 index 0000000000..97d4d36d07 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/string/Palindrome.java @@ -0,0 +1,66 @@ +package com.baeldung.string; + +import java.util.stream.IntStream; + +public class Palindrome { + + public boolean isPalindrome(String text) { + String clean = text.replaceAll("\\s+", "").toLowerCase(); + int length = clean.length(); + int forward = 0; + int backward = length - 1; + while (backward > forward) { + char forwardChar = clean.charAt(forward++); + char backwardChar = clean.charAt(backward--); + if (forwardChar != backwardChar) + return false; + } + return true; + } + + public boolean isPalindromeReverseTheString(String text) { + StringBuilder reverse = new StringBuilder(); + String clean = text.replaceAll("\\s+", "").toLowerCase(); + char[] plain = clean.toCharArray(); + for (int i = plain.length - 1; i >= 0; i--) + reverse.append(plain[i]); + return (reverse.toString()).equals(clean); + } + + public boolean isPalindromeUsingStringBuilder(String text) { + String clean = text.replaceAll("\\s+", "").toLowerCase(); + StringBuilder plain = new StringBuilder(clean); + StringBuilder reverse = plain.reverse(); + return (reverse.toString()).equals(clean); + } + + public boolean isPalindromeUsingStringBuffer(String text) { + String clean = text.replaceAll("\\s+", "").toLowerCase(); + StringBuffer plain = new StringBuffer(clean); + StringBuffer reverse = plain.reverse(); + return (reverse.toString()).equals(clean); + } + + public boolean isPalindromeRecursive(String text) { + String clean = text.replaceAll("\\s+", "").toLowerCase(); + return recursivePalindrome(clean, 0, clean.length() - 1); + } + + private boolean recursivePalindrome(String text, int forward, int backward) { + if (forward == backward) + return true; + if ((text.charAt(forward)) != (text.charAt(backward))) + return false; + if (forward < backward + 1) { + return recursivePalindrome(text, forward + 1, backward - 1); + } + + return true; + } + + public boolean isPalindromeUsingIntStream(String text) { + String temp = text.replaceAll("\\s+", "").toLowerCase(); + return IntStream.range(0, temp.length() / 2) + .noneMatch(i -> temp.charAt(i) != temp.charAt(temp.length() - i - 1)); + } +} diff --git a/core-java/src/main/resources/resourcebundle/resource.properties b/core-java/src/main/resources/resourcebundle/resource.properties new file mode 100644 index 0000000000..edeae3ef4b --- /dev/null +++ b/core-java/src/main/resources/resourcebundle/resource.properties @@ -0,0 +1,6 @@ +# Buttons +cancelButton=cancel +continueButton continue + +! Labels +helloLabel:hello diff --git a/core-java/src/main/resources/resourcebundle/resource_en.properties b/core-java/src/main/resources/resourcebundle/resource_en.properties new file mode 100644 index 0000000000..5d72b65e2f --- /dev/null +++ b/core-java/src/main/resources/resourcebundle/resource_en.properties @@ -0,0 +1 @@ +deleteButton=delete \ No newline at end of file diff --git a/core-java/src/main/resources/resourcebundle/resource_pl_PL.properties b/core-java/src/main/resources/resourcebundle/resource_pl_PL.properties new file mode 100644 index 0000000000..37dea822ad --- /dev/null +++ b/core-java/src/main/resources/resourcebundle/resource_pl_PL.properties @@ -0,0 +1,3 @@ +backButton=cofnij +helloLabel=cze\u015b\u0107 +helloLabelNoEncoding=cześć \ No newline at end of file diff --git a/core-java/src/test/java/com/baeldung/casting/CastingTest.java b/core-java/src/test/java/com/baeldung/casting/CastingTest.java new file mode 100644 index 0000000000..0ca1ce88dc --- /dev/null +++ b/core-java/src/test/java/com/baeldung/casting/CastingTest.java @@ -0,0 +1,58 @@ +package com.baeldung.casting; + +import org.junit.Test; +import static org.junit.Assert.*; +import java.util.ArrayList; +import java.util.List; + +public class CastingTest { + + @Test + public void whenPrimitiveConverted_thenValueChanged() { + double myDouble = 1.1; + int myInt = (int) myDouble; + assertNotEquals(myDouble, myInt); + } + + @Test + public void whenUpcast_thenInstanceUnchanged() { + Cat cat = new Cat(); + Animal animal = cat; + animal = (Animal) cat; + assertTrue(animal instanceof Cat); + } + + @Test + public void whenUpcastToObject_thenInstanceUnchanged() { + Object object = new Animal(); + assertTrue(object instanceof Animal); + } + + @Test + public void whenUpcastToInterface_thenInstanceUnchanged() { + Mew mew = new Cat(); + assertTrue(mew instanceof Cat); + } + + @Test + public void whenUpcastToAnimal_thenOverridenMethodsCalled() { + List animals = new ArrayList<>(); + animals.add(new Cat()); + animals.add(new Dog()); + new AnimalFeeder().feed(animals); + } + + @Test + public void whenDowncastToCat_thenMeowIsCalled() { + Animal animal = new Cat(); + ((Cat) animal).meow(); + } + + @Test(expected = ClassCastException.class) + public void whenDownCastWithoutCheck_thenExceptionThrown() { + List animals = new ArrayList<>(); + animals.add(new Cat()); + animals.add(new Dog()); + new AnimalFeeder().uncheckedFeed(animals); + } +} diff --git a/core-java/src/test/java/com/baeldung/classloader/CustomClassLoaderTest.java b/core-java/src/test/java/com/baeldung/classloader/CustomClassLoaderTest.java new file mode 100644 index 0000000000..9f3c751805 --- /dev/null +++ b/core-java/src/test/java/com/baeldung/classloader/CustomClassLoaderTest.java @@ -0,0 +1,23 @@ +package com.baeldung.classloader; + +import org.junit.Test; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +public class CustomClassLoaderTest { + + @Test + public void customLoader() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException { + + CustomClassLoader customClassLoader = new CustomClassLoader(); + Class c = customClassLoader.getClass(PrintClassLoader.class.getName()); + + Object ob = c.newInstance(); + + Method md = c.getMethod("printClassLoaders"); + md.invoke(ob); + + } + +} diff --git a/core-java/src/test/java/com/baeldung/classloader/PrintClassLoaderTest.java b/core-java/src/test/java/com/baeldung/classloader/PrintClassLoaderTest.java new file mode 100644 index 0000000000..f44a5cef09 --- /dev/null +++ b/core-java/src/test/java/com/baeldung/classloader/PrintClassLoaderTest.java @@ -0,0 +1,14 @@ +package com.baeldung.classloader; + +import org.junit.Test; + +import static org.junit.Assert.*; + +public class PrintClassLoaderTest { + @Test(expected = ClassNotFoundException.class) + public void givenAppClassLoader_whenParentClassLoader_thenClassNotFoundException() throws Exception { + PrintClassLoader sampleClassLoader = (PrintClassLoader) Class.forName(PrintClassLoader.class.getName()).newInstance(); + sampleClassLoader.printClassLoaders(); + Class.forName(PrintClassLoader.class.getName(), true, PrintClassLoader.class.getClassLoader().getParent()); + } +} \ No newline at end of file diff --git a/core-java/src/test/java/com/baeldung/decimalformat/DecimalFormatExamplesTest.java b/core-java/src/test/java/com/baeldung/decimalformat/DecimalFormatExamplesTest.java new file mode 100644 index 0000000000..8acd4e023e --- /dev/null +++ b/core-java/src/test/java/com/baeldung/decimalformat/DecimalFormatExamplesTest.java @@ -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)); + } + +} diff --git a/core-java/src/test/java/com/baeldung/deepcopy/DeepCopyUnitTest.java b/core-java/src/test/java/com/baeldung/deepcopy/DeepCopyUnitTest.java new file mode 100644 index 0000000000..196b69fbf7 --- /dev/null +++ b/core-java/src/test/java/com/baeldung/deepcopy/DeepCopyUnitTest.java @@ -0,0 +1,128 @@ +package com.baeldung.deepcopy; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.IOException; + +import org.apache.commons.lang.SerializationUtils; +import org.junit.Ignore; +import org.junit.Test; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.gson.Gson; + +public class DeepCopyUnitTest { + + @Test + public void whenCreatingDeepCopyWithCopyConstructor_thenObjectsShouldNotBeSame() { + + Address address = new Address("Downing St 10", "London", "England"); + User pm = new User("Prime", "Minister", address); + + User deepCopy = new User(pm); + + assertThat(deepCopy).isNotSameAs(pm); + } + + @Test + public void whenModifyingOriginalObject_thenConstructorCopyShouldNotChange() { + Address address = new Address("Downing St 10", "London", "England"); + User pm = new User("Prime", "Minister", address); + User deepCopy = new User(pm); + + address.setCountry("Great Britain"); + + assertThat(deepCopy.getAddress().getCountry()).isNotEqualTo(pm.getAddress().getCountry()); + } + + @Test + public void whenModifyingOriginalObject_thenCloneCopyShouldNotChange() { + Address address = new Address("Downing St 10", "London", "England"); + User pm = new User("Prime", "Minister", address); + User deepCopy = (User) pm.clone(); + + address.setCountry("Great Britain"); + + assertThat(deepCopy.getAddress().getCountry()).isNotEqualTo(pm.getAddress().getCountry()); + } + + @Test + public void whenModifyingOriginalObject_thenCommonsCloneShouldNotChange() { + Address address = new Address("Downing St 10", "London", "England"); + User pm = new User("Prime", "Minister", address); + User deepCopy = (User) SerializationUtils.clone(pm); + + address.setCountry("Great Britain"); + + assertThat(deepCopy.getAddress().getCountry()).isNotEqualTo(pm.getAddress().getCountry()); + } + + @Test + public void whenModifyingOriginalObject_thenGsonCloneShouldNotChange() { + Address address = new Address("Downing St 10", "London", "England"); + User pm = new User("Prime", "Minister", address); + Gson gson = new Gson(); + User deepCopy = gson.fromJson(gson.toJson(pm), User.class); + + address.setCountry("Great Britain"); + + assertThat(deepCopy.getAddress().getCountry()).isNotEqualTo(pm.getAddress().getCountry()); + } + + @Test + public void whenModifyingOriginalObject_thenJacksonCopyShouldNotChange() throws IOException { + Address address = new Address("Downing St 10", "London", "England"); + User pm = new User("Prime", "Minister", address); + ObjectMapper objectMapper = new ObjectMapper(); + User deepCopy = objectMapper.readValue(objectMapper.writeValueAsString(pm), User.class); + + address.setCountry("Great Britain"); + + assertThat(deepCopy.getAddress().getCountry()).isNotEqualTo(pm.getAddress().getCountry()); + } + + @Test + @Ignore + public void whenMakingCopies_thenShowHowLongEachMethodTakes() throws CloneNotSupportedException, IOException { + int times = 1000000; + Address address = new Address("Downing St 10", "London", "England"); + User pm = new User("Prime", "Minister", address); + + long start = System.currentTimeMillis(); + for (int i = 0; i < times; i++) { + User primeMinisterClone = (User) SerializationUtils.clone(pm); + } + long end = System.currentTimeMillis(); + System.out.println("Cloning with Apache Commons Lang took " + (end - start) + " milliseconds."); + + start = System.currentTimeMillis(); + Gson gson = new Gson(); + for (int i = 0; i < times; i++) { + User primeMinisterClone = gson.fromJson(gson.toJson(pm), User.class); + } + end = System.currentTimeMillis(); + System.out.println("Cloning with Gson took " + (end - start) + " milliseconds."); + + start = System.currentTimeMillis(); + for (int i = 0; i < times; i++) { + User primeMinisterClone = new User(pm); + } + end = System.currentTimeMillis(); + System.out.println("Cloning with the copy constructor took " + (end - start) + " milliseconds."); + + start = System.currentTimeMillis(); + for (int i = 0; i < times; i++) { + User primeMinisterClone = (User) pm.clone(); + } + end = System.currentTimeMillis(); + System.out.println("Cloning with Cloneable interface took " + (end - start) + " milliseconds."); + + start = System.currentTimeMillis(); + ObjectMapper objectMapper = new ObjectMapper(); + for (int i = 0; i < times; i++) { + User primeMinisterClone = objectMapper.readValue(objectMapper.writeValueAsString(pm), User.class); + } + end = System.currentTimeMillis(); + System.out.println("Cloning with Jackson took " + (end - start) + " milliseconds."); + } +} diff --git a/core-java/src/test/java/com/baeldung/deepcopy/ShallowCopyUnitTest.java b/core-java/src/test/java/com/baeldung/deepcopy/ShallowCopyUnitTest.java new file mode 100644 index 0000000000..57660fadf1 --- /dev/null +++ b/core-java/src/test/java/com/baeldung/deepcopy/ShallowCopyUnitTest.java @@ -0,0 +1,33 @@ +package com.baeldung.deepcopy; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.Test; + +public class ShallowCopyUnitTest { + + + @Test + public void whenShallowCopying_thenObjectsShouldNotBeSame() { + + Address address = new Address("Downing St 10", "London", "England"); + User pm = new User("Prime", "Minister", address); + + User shallowCopy = new User(pm.getFirstName(), pm.getLastName(), pm.getAddress()); + + assertThat(shallowCopy) + .isNotSameAs(pm); + } + + @Test + public void whenModifyingOriginalObject_thenCopyShouldChange() { + Address address = new Address("Downing St 10", "London", "England"); + User pm = new User("Prime", "Minister", address); + User shallowCopy = new User(pm.getFirstName(), pm.getLastName(), pm.getAddress()); + + address.setCountry("Great Britain"); + + assertThat(shallowCopy.getAddress().getCountry()) + .isEqualTo(pm.getAddress().getCountry()); + } +} diff --git a/core-java/src/test/java/com/baeldung/designpatterns/chainofresponsibility/ChainOfResponsibilityTest.java b/core-java/src/test/java/com/baeldung/designpatterns/chainofresponsibility/ChainOfResponsibilityTest.java new file mode 100644 index 0000000000..a28577efb1 --- /dev/null +++ b/core-java/src/test/java/com/baeldung/designpatterns/chainofresponsibility/ChainOfResponsibilityTest.java @@ -0,0 +1,37 @@ +package com.baeldung.designpatterns.chainofresponsibility; + +import org.junit.Test; + +import static org.junit.Assert.assertTrue; + +public class ChainOfResponsibilityTest { + + private static AuthenticationProcessor getChainOfAuthProcessor() { + + AuthenticationProcessor oAuthProcessor = new OAuthAuthenticationProcessor(null); + AuthenticationProcessor unamePasswordProcessor = new UsernamePasswordAuthenticationProcessor(oAuthProcessor); + return unamePasswordProcessor; + } + + @Test + public void givenOAuthProvider_whenCheckingAuthorized_thenSuccess() { + AuthenticationProcessor authProcessorChain = getChainOfAuthProcessor(); + boolean isAuthorized = authProcessorChain.isAuthorized(new OAuthTokenProvider()); + assertTrue(isAuthorized); + } + + @Test + public void givenUsernamePasswordProvider_whenCheckingAuthorized_thenSuccess() { + AuthenticationProcessor authProcessorChain = getChainOfAuthProcessor(); + boolean isAuthorized = authProcessorChain.isAuthorized(new UsernamePasswordProvider()); + assertTrue(isAuthorized); + } + + @Test + public void givenSamlAuthProvider_whenCheckingAuthorized_thenFailure() { + AuthenticationProcessor authProcessorChain = getChainOfAuthProcessor(); + boolean isAuthorized = authProcessorChain.isAuthorized(new SamlAuthenticationProvider()); + assertTrue(!isAuthorized); + } + +} diff --git a/core-java/src/test/java/com/baeldung/designpatterns/flyweight/FlyweightUnitTest.java b/core-java/src/test/java/com/baeldung/designpatterns/flyweight/FlyweightUnitTest.java new file mode 100644 index 0000000000..645e2fd459 --- /dev/null +++ b/core-java/src/test/java/com/baeldung/designpatterns/flyweight/FlyweightUnitTest.java @@ -0,0 +1,42 @@ +package com.baeldung.designpatterns.flyweight; + +import java.awt.Color; + +import org.junit.Assert; +import org.junit.Test; + +/** + * Unit test for {@link VehicleFactory}. + * + * @author Donato Rimenti + */ +public class FlyweightUnitTest { + + /** + * Checks that when the {@link VehicleFactory} is asked to provide two + * vehicles of different colors, the objects returned are different. + */ + @Test + public void givenDifferentFlyweightObjects_whenEquals_thenFalse() { + Vehicle blackVehicle = VehicleFactory.createVehicle(Color.BLACK); + Vehicle blueVehicle = VehicleFactory.createVehicle(Color.BLUE); + + Assert.assertNotNull("Object returned by the factory is null!", blackVehicle); + Assert.assertNotNull("Object returned by the factory is null!", blueVehicle); + Assert.assertNotEquals("Objects returned by the factory are equals!", blackVehicle, blueVehicle); + } + + /** + * Checks that when the {@link VehicleFactory} is asked to provide two + * vehicles of the same colors, the same object is returned twice. + */ + @Test + public void givenSameFlyweightObjects_whenEquals_thenTrue() { + Vehicle blackVehicle = VehicleFactory.createVehicle(Color.BLACK); + Vehicle anotherBlackVehicle = VehicleFactory.createVehicle(Color.BLACK); + + Assert.assertNotNull("Object returned by the factory is null!", blackVehicle); + Assert.assertNotNull("Object returned by the factory is null!", anotherBlackVehicle); + Assert.assertEquals("Objects returned by the factory are not equals!", blackVehicle, anotherBlackVehicle); + } +} diff --git a/core-java/src/test/java/com/baeldung/designpatterns/observer/ObserverIntegrationTest.java b/core-java/src/test/java/com/baeldung/designpatterns/observer/ObserverIntegrationTest.java new file mode 100644 index 0000000000..a8a0e29990 --- /dev/null +++ b/core-java/src/test/java/com/baeldung/designpatterns/observer/ObserverIntegrationTest.java @@ -0,0 +1,47 @@ +package com.baeldung.designpatterns.observer; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import com.baeldung.designpatterns.observer.NewsAgency; +import com.baeldung.designpatterns.observer.NewsChannel; + +public class ObserverIntegrationTest { + + @Test + public void whenChangingNewsAgencyState_thenNewsChannelNotified() { + + NewsAgency observable = new NewsAgency(); + NewsChannel observer = new NewsChannel(); + + observable.addObserver(observer); + + observable.setNews("news"); + assertEquals(observer.getNews(), "news"); + } + + @Test + public void whenChangingONewsAgencyState_thenONewsChannelNotified() { + + ONewsAgency observable = new ONewsAgency(); + ONewsChannel observer = new ONewsChannel(); + + observable.addObserver(observer); + + observable.setNews("news"); + assertEquals(observer.getNews(), "news"); + } + + @Test + public void whenChangingPCLNewsAgencyState_thenONewsChannelNotified() { + + PCLNewsAgency observable = new PCLNewsAgency(); + PCLNewsChannel observer = new PCLNewsChannel(); + + observable.addPropertyChangeListener(observer); + + observable.setNews("news"); + assertEquals(observer.getNews(), "news"); + } +} diff --git a/core-java/src/test/java/com/baeldung/inheritance/AppTest.java b/core-java/src/test/java/com/baeldung/inheritance/AppTest.java new file mode 100644 index 0000000000..1235761aba --- /dev/null +++ b/core-java/src/test/java/com/baeldung/inheritance/AppTest.java @@ -0,0 +1,46 @@ +package com.baeldung.inheritance; + +import com.baeldung.inheritance.*; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +public class AppTest extends TestCase { + + public AppTest(String testName) { + super( testName ); + } + + public static Test suite() { + return new TestSuite(AppTest.class); + } + + @SuppressWarnings("static-access") + public void testStaticMethodUsingBaseClassVariable() { + Car first = new ArmoredCar(); + assertEquals("Car", first.msg()); + } + + @SuppressWarnings("static-access") + public void testStaticMethodUsingDerivedClassVariable() { + ArmoredCar second = new ArmoredCar(); + assertEquals("ArmoredCar", second.msg()); + } + + public void testAssignArmoredCarToCar() { + Employee e1 = new Employee("Shreya", new ArmoredCar()); + assertNotNull(e1.getCar()); + } + + public void testAssignSpaceCarToCar() { + Employee e2 = new Employee("Paul", new SpaceCar()); + assertNotNull(e2.getCar()); + } + + public void testBMWToCar() { + Employee e3 = new Employee("Pavni", new BMW()); + assertNotNull(e3.getCar()); + } + +} diff --git a/core-java/src/test/java/com/baeldung/java/list/CustomListUnitTest.java b/core-java/src/test/java/com/baeldung/java/list/CustomListUnitTest.java new file mode 100644 index 0000000000..3ee3195e80 --- /dev/null +++ b/core-java/src/test/java/com/baeldung/java/list/CustomListUnitTest.java @@ -0,0 +1,282 @@ +package com.baeldung.java.list; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +import org.junit.Test; + +public class CustomListUnitTest { + @Test(expected = UnsupportedOperationException.class) + public void whenAddToSpecifiedIndex_thenExceptionIsThrown() { + new CustomList<>().add(0, null); + } + + @Test(expected = UnsupportedOperationException.class) + public void whenAddAllToTheEnd_thenExceptionIsThrown() { + Collection collection = new ArrayList<>(); + List list = new CustomList<>(); + list.addAll(collection); + } + + @Test(expected = UnsupportedOperationException.class) + public void whenAddAllToSpecifiedIndex_thenExceptionIsThrown() { + Collection collection = new ArrayList<>(); + List list = new CustomList<>(); + list.addAll(0, collection); + } + + @Test(expected = UnsupportedOperationException.class) + public void whenRemoveAtSpecifiedIndex_thenExceptionIsThrown() { + List list = new CustomList<>(); + list.add("baeldung"); + list.remove(0); + } + + @Test(expected = UnsupportedOperationException.class) + public void whenRemoveSpecifiedElement_thenExceptionIsThrown() { + List list = new CustomList<>(); + list.add("baeldung"); + list.remove("baeldung"); + } + + @Test(expected = UnsupportedOperationException.class) + public void whenRemoveAll_thenExceptionIsThrown() { + Collection collection = new ArrayList<>(); + collection.add("baeldung"); + List list = new CustomList<>(); + list.removeAll(collection); + } + + @Test(expected = UnsupportedOperationException.class) + public void whenRetainAll_thenExceptionIsThrown() { + Collection collection = new ArrayList<>(); + collection.add("baeldung"); + List list = new CustomList<>(); + list.add("baeldung"); + list.retainAll(collection); + } + + @Test + public void givenEmptyList_whenSize_thenZeroIsReturned() { + List list = new CustomList<>(); + + assertEquals(0, list.size()); + } + + @Test + public void givenEmptyList_whenIsEmpty_thenTrueIsReturned() { + List list = new CustomList<>(); + + assertTrue(list.isEmpty()); + } + + @Test + public void givenEmptyList_whenElementIsAdded_thenGetReturnsThatElement() { + List list = new CustomList<>(); + boolean succeeded = list.add("baeldung"); + Object element = list.get(0); + + assertTrue(succeeded); + assertEquals("baeldung", element); + } + + @Test + public void givenListWithAnElement_whenAnotherIsAdded_thenGetReturnsBoth() { + List list = new CustomList<>(); + boolean succeeded1 = list.add("baeldung"); + boolean succeeded2 = list.add(".com"); + Object element1 = list.get(0); + Object element2 = list.get(1); + + assertTrue(succeeded1); + assertTrue(succeeded2); + assertEquals("baeldung", element1); + assertEquals(".com", element2); + } + + @Test + public void givenEmptyList_whenContains_thenFalseIsReturned() { + List list = new CustomList<>(); + + assertFalse(list.contains(null)); + } + + @Test + public void givenListWithAnElement_whenContains_thenTrueIsReturned() { + List list = new CustomList<>(); + list.add("baeldung"); + + assertTrue(list.contains("baeldung")); + } + + @Test + public void givenListWithAnElement_whenContainsAll_thenTrueIsReturned() { + Collection collection = new ArrayList<>(); + collection.add("baeldung"); + List list = new CustomList<>(); + list.add("baeldung"); + + assertTrue(list.containsAll(collection)); + } + + @Test + public void givenList_whenContainsAll_thenEitherTrueOrFalseIsReturned() { + Collection collection1 = new ArrayList<>(); + collection1.add("baeldung"); + collection1.add(".com"); + Collection collection2 = new ArrayList<>(); + collection2.add("baeldung"); + + List list = new CustomList<>(); + list.add("baeldung"); + + assertFalse(list.containsAll(collection1)); + assertTrue(list.containsAll(collection2)); + } + + @Test + public void givenList_whenSet_thenOldElementIsReturned() { + List list = new CustomList<>(); + list.add("baeldung"); + Object element = list.set(0, null); + + assertEquals("baeldung", element); + assertNull(list.get(0)); + } + + @Test + public void givenList_whenClear_thenAllElementsAreRemoved() { + List list = new CustomList<>(); + list.add("baeldung"); + list.clear(); + + assertTrue(list.isEmpty()); + } + + @Test + public void givenList_whenIndexOf_thenIndexZeroIsReturned() { + List list = new CustomList<>(); + list.add("baeldung"); + + assertEquals(0, list.indexOf("baeldung")); + } + + @Test + public void givenList_whenIndexOf_thenPositiveIndexOrMinusOneIsReturned() { + List list = new CustomList<>(); + list.add("baeldung"); + list.add(".com"); + list.add(".com"); + + assertEquals(1, list.indexOf(".com")); + assertEquals(-1, list.indexOf("com")); + } + + @Test + public void whenLastIndexOf_thenIndexZeroIsReturned() { + List list = new CustomList<>(); + list.add("baeldung"); + + assertEquals(0, list.lastIndexOf("baeldung")); + } + + @Test + public void whenLastIndexOf_thenPositiveIndexOrMinusOneIsReturned() { + List list = new CustomList<>(); + list.add("baeldung"); + list.add("baeldung"); + list.add(".com"); + + assertEquals(1, list.lastIndexOf("baeldung")); + assertEquals(-1, list.indexOf("com")); + } + + @Test + public void whenSubListZeroToOne_thenListContainingFirstElementIsReturned() { + List list = new CustomList<>(); + list.add("baeldung"); + List subList = list.subList(0, 1); + + assertEquals("baeldung", subList.get(0)); + } + + @Test + public void whenSubListOneToTwo_thenListContainingSecondElementIsReturned() { + List list = new CustomList<>(); + list.add("baeldung"); + list.add("."); + list.add("com"); + List subList = list.subList(1, 2); + + assertEquals(1, subList.size()); + assertEquals(".", subList.get(0)); + } + + @Test + public void givenListWithElements_whenToArray_thenArrayContainsThose() { + List list = new CustomList<>(); + list.add("baeldung"); + list.add(".com"); + Object[] array = list.toArray(); + + assertArrayEquals(new Object[] { "baeldung", ".com" }, array); + } + + @Test + public void givenListWithAnElement_whenToArray_thenInputArrayIsReturned() { + List list = new CustomList<>(); + list.add("baeldung"); + String[] input = new String[1]; + String[] output = list.toArray(input); + + assertArrayEquals(new String[] { "baeldung" }, input); + } + + @Test + public void whenToArrayIsCalledWithEmptyInputArray_thenNewArrayIsReturned() { + List list = new CustomList<>(); + list.add("baeldung"); + String[] input = {}; + String[] output = list.toArray(input); + + assertArrayEquals(new String[] { "baeldung" }, output); + } + + @Test + public void whenToArrayIsCalledWithLargerInput_thenOutputHasTrailingNull() { + List list = new CustomList<>(); + list.add("baeldung"); + String[] input = new String[2]; + String[] output = list.toArray(input); + + assertArrayEquals(new String[] { "baeldung", null }, output); + } + + @Test + public void givenListWithOneElement_whenIterator_thenThisElementIsNext() { + List list = new CustomList<>(); + list.add("baeldung"); + Iterator iterator = list.iterator(); + + assertTrue(iterator.hasNext()); + assertEquals("baeldung", iterator.next()); + } + + @Test + public void whenIteratorNextIsCalledTwice_thenTheSecondReturnsFalse() { + List list = new CustomList<>(); + list.add("baeldung"); + Iterator iterator = list.iterator(); + + iterator.next(); + assertFalse(iterator.hasNext()); + } +} diff --git a/core-java/src/test/java/com/baeldung/methodoverloadingoverriding/test/MethodOverloadingUnitTest.java b/core-java/src/test/java/com/baeldung/methodoverloadingoverriding/test/MethodOverloadingUnitTest.java new file mode 100644 index 0000000000..081a30c34a --- /dev/null +++ b/core-java/src/test/java/com/baeldung/methodoverloadingoverriding/test/MethodOverloadingUnitTest.java @@ -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); + } +} diff --git a/core-java/src/test/java/com/baeldung/methodoverloadingoverriding/test/MethodOverridingUnitTest.java b/core-java/src/test/java/com/baeldung/methodoverloadingoverriding/test/MethodOverridingUnitTest.java new file mode 100644 index 0000000000..554ac121bc --- /dev/null +++ b/core-java/src/test/java/com/baeldung/methodoverloadingoverriding/test/MethodOverridingUnitTest.java @@ -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()); + } +} diff --git a/core-java/src/test/java/com/baeldung/recursion/RecursionExampleTest.java b/core-java/src/test/java/com/baeldung/recursion/RecursionExampleTest.java new file mode 100644 index 0000000000..c65be24240 --- /dev/null +++ b/core-java/src/test/java/com/baeldung/recursion/RecursionExampleTest.java @@ -0,0 +1,61 @@ +package com.baeldung.recursion; + +import org.junit.Assert; +import org.junit.Test; + +public class RecursionExampleTest { + + RecursionExample recursion = new RecursionExample(); + + @Test + public void testPowerOf10() { + int p0 = recursion.powerOf10(0); + int p1 = recursion.powerOf10(1); + int p4 = recursion.powerOf10(4); + + Assert.assertEquals(1, p0); + Assert.assertEquals(10, p1); + Assert.assertEquals(10000, p4); + } + + @Test + public void testFibonacci() { + int n0 = recursion.fibonacci(0); + int n1 = recursion.fibonacci(1); + int n7 = recursion.fibonacci(7); + + Assert.assertEquals(0, n0); + Assert.assertEquals(1, n1); + Assert.assertEquals(13, n7); + } + + @Test + public void testToBinary() { + String b0 = recursion.toBinary(0); + String b1 = recursion.toBinary(1); + String b10 = recursion.toBinary(10); + + Assert.assertEquals("0", b0); + Assert.assertEquals("1", b1); + Assert.assertEquals("1010", b10); + } + + @Test + public void testCalculateTreeHeight() { + BinaryNode root = new BinaryNode(1); + root.setLeft(new BinaryNode(1)); + root.setRight(new BinaryNode(1)); + + root.getLeft().setLeft(new BinaryNode(1)); + root.getLeft().getLeft().setRight(new BinaryNode(1)); + root.getLeft().getLeft().getRight().setLeft(new BinaryNode(1)); + + root.getRight().setLeft(new BinaryNode(1)); + root.getRight().getLeft().setRight(new BinaryNode(1)); + + int height = recursion.calculateTreeHeight(root); + + Assert.assertEquals(4, height); + } + +} diff --git a/core-java/src/test/java/com/baeldung/resourcebundle/ExampleResourceUnitTest.java b/core-java/src/test/java/com/baeldung/resourcebundle/ExampleResourceUnitTest.java new file mode 100644 index 0000000000..1ce4f1bb8f --- /dev/null +++ b/core-java/src/test/java/com/baeldung/resourcebundle/ExampleResourceUnitTest.java @@ -0,0 +1,39 @@ +package com.baeldung.resourcebundle; + +import org.junit.Test; + +import java.math.BigDecimal; +import java.util.Arrays; +import java.util.Locale; +import java.util.ResourceBundle; + +import static org.junit.Assert.*; + +public class ExampleResourceUnitTest { + + @Test + public void whenGetBundleExampleResourceForLocalePlPl_thenItShouldInheritPropertiesGreetingAndLanguage() { + Locale plLocale = new Locale("pl", "PL"); + + ResourceBundle exampleBundle = ResourceBundle.getBundle("com.baeldung.resourcebundle.ExampleResource", plLocale); + + assertTrue(exampleBundle.keySet() + .containsAll(Arrays.asList("toUsdRate", "cities", "greeting", "currency", "language"))); + assertEquals(exampleBundle.getString("greeting"), "cześć"); + assertEquals(exampleBundle.getObject("toUsdRate"), new BigDecimal("3.401")); + assertArrayEquals(exampleBundle.getStringArray("cities"), new String[] { "Warsaw", "Cracow" }); + } + + @Test + public void whenGetBundleExampleResourceForLocaleUs_thenItShouldContainOnlyGreeting() { + Locale usLocale = Locale.US; + + ResourceBundle exampleBundle = ResourceBundle.getBundle("com.baeldung.resourcebundle.ExampleResource", usLocale); + + assertFalse(exampleBundle.keySet() + .containsAll(Arrays.asList("toUsdRate", "cities", "currency", "language"))); + assertTrue(exampleBundle.keySet() + .containsAll(Arrays.asList("greeting"))); + } + +} diff --git a/core-java/src/test/java/com/baeldung/resourcebundle/PropertyResourceUnitTest.java b/core-java/src/test/java/com/baeldung/resourcebundle/PropertyResourceUnitTest.java new file mode 100644 index 0000000000..4da71567e1 --- /dev/null +++ b/core-java/src/test/java/com/baeldung/resourcebundle/PropertyResourceUnitTest.java @@ -0,0 +1,62 @@ +package com.baeldung.resourcebundle; + +import org.junit.Test; + +import java.util.Arrays; +import java.util.Locale; +import java.util.ResourceBundle; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class PropertyResourceUnitTest { + + @Test + public void givenLocaleUsAsDefualt_whenGetBundleForLocalePlPl_thenItShouldContain3ButtonsAnd1Label() { + Locale.setDefault(Locale.US); + + ResourceBundle bundle = ResourceBundle.getBundle("resourcebundle.resource", new Locale("pl", "PL")); + + assertTrue(bundle.keySet() + .containsAll(Arrays.asList("backButton", "helloLabel", "cancelButton", "continueButton", "helloLabelNoEncoding"))); + } + + @Test + public void givenLocaleUsAsDefualt_whenGetBundleForLocaleFrFr_thenItShouldContainKeys1To3AndKey4() { + Locale.setDefault(Locale.US); + + ResourceBundle bundle = ResourceBundle.getBundle("resourcebundle.resource", new Locale("fr", "FR")); + + assertTrue(bundle.keySet() + .containsAll(Arrays.asList("deleteButton", "helloLabel", "cancelButton", "continueButton"))); + } + + @Test + public void givenLocaleChinaAsDefualt_whenGetBundleForLocaleFrFr_thenItShouldOnlyContainKeys1To3() { + Locale.setDefault(Locale.CHINA); + + ResourceBundle bundle = ResourceBundle.getBundle("resourcebundle.resource", new Locale("fr", "FR")); + + assertTrue(bundle.keySet() + .containsAll(Arrays.asList("continueButton", "helloLabel", "cancelButton"))); + } + + @Test + public void givenLocaleChinaAsDefualt_whenGetBundleForLocaleFrFrAndExampleControl_thenItShouldOnlyContainKey5() { + Locale.setDefault(Locale.CHINA); + + ResourceBundle bundle = ResourceBundle.getBundle("resourcebundle.resource", new Locale("fr", "FR"), new ExampleControl()); + + assertTrue(bundle.keySet() + .containsAll(Arrays.asList("backButton", "helloLabel"))); + } + + @Test + public void givenValuesDifferentlyEncoded_whenGetBundleForLocalePlPl_thenItShouldContain3ButtonsAnd1Label() { + ResourceBundle bundle = ResourceBundle.getBundle("resourcebundle.resource", new Locale("pl", "PL")); + + assertEquals(bundle.getString("helloLabel"), "cześć"); + assertEquals(bundle.getString("helloLabelNoEncoding"), "czeÅ\u009BÄ\u0087"); + } + +} diff --git a/core-java/src/test/java/com/baeldung/string/PalindromeTest.java b/core-java/src/test/java/com/baeldung/string/PalindromeTest.java new file mode 100644 index 0000000000..bc6fee2cd9 --- /dev/null +++ b/core-java/src/test/java/com/baeldung/string/PalindromeTest.java @@ -0,0 +1,97 @@ +package com.baeldung.string; + +import static org.junit.Assert.*; +import org.junit.Test; + +public class PalindromeTest { + + private String[] words = { + "Anna", + "Civic", + "Kayak", + "Level", + "Madam", + }; + + private String[] sentences = { + "Sore was I ere I saw Eros", + "Euston saw I was not Sue", + "Too hot to hoot", + "No mists or frost Simon", + "Stella won no wallets" + }; + + private Palindrome palindrome = new Palindrome(); + + @Test + public void whenWord_shouldBePalindrome() { + for (String word : words) + assertTrue(palindrome.isPalindrome(word)); + } + + @Test + public void whenSentence_shouldBePalindrome() { + for (String sentence : sentences) + assertTrue(palindrome.isPalindrome(sentence)); + } + + @Test + public void whenReverseWord_shouldBePalindrome() { + for (String word : words) + assertTrue(palindrome.isPalindromeReverseTheString(word)); + } + + @Test + public void whenReverseSentence_shouldBePalindrome() { + for (String sentence : sentences) + assertTrue(palindrome.isPalindromeReverseTheString(sentence)); + } + + @Test + public void whenStringBuilderWord_shouldBePalindrome() { + for (String word : words) + assertTrue(palindrome.isPalindromeUsingStringBuilder(word)); + } + + @Test + public void whenStringBuilderSentence_shouldBePalindrome() { + for (String sentence : sentences) + assertTrue(palindrome.isPalindromeUsingStringBuilder(sentence)); + } + + @Test + public void whenStringBufferWord_shouldBePalindrome() { + for (String word : words) + assertTrue(palindrome.isPalindromeUsingStringBuffer(word)); + } + + @Test + public void whenStringBufferSentence_shouldBePalindrome() { + for (String sentence : sentences) + assertTrue(palindrome.isPalindromeUsingStringBuffer(sentence)); + } + + @Test + public void whenPalindromeRecursive_wordShouldBePalindrome() { + for (String word : words) + assertTrue(palindrome.isPalindromeRecursive(word)); + } + + @Test + public void whenPalindromeRecursive_sentenceShouldBePalindrome() { + for (String sentence : sentences) + assertTrue(palindrome.isPalindromeRecursive(sentence)); + } + + @Test + public void whenPalindromeStreams_wordShouldBePalindrome() { + for (String word : words) + assertTrue(palindrome.isPalindromeUsingIntStream(word)); + } + + @Test + public void whenPalindromeStreams_sentenceShouldBePalindrome() { + for (String sentence : sentences) + assertTrue(palindrome.isPalindromeUsingIntStream(sentence)); + } +} diff --git a/core-java/src/test/java/com/baeldung/string/StringComparisonTest.java b/core-java/src/test/java/com/baeldung/string/StringComparisonTest.java new file mode 100644 index 0000000000..5869676004 --- /dev/null +++ b/core-java/src/test/java/com/baeldung/string/StringComparisonTest.java @@ -0,0 +1,154 @@ +package com.baeldung.string; + +import org.apache.commons.lang3.StringUtils; +import org.junit.Test; + +import java.util.Objects; + +import static org.assertj.core.api.Assertions.assertThat; + +public class StringComparisonTest { + + @Test + public void whenUsingComparisonOperator_ThenComparingStrings(){ + + String string1 = "using comparison operator"; + String string2 = "using comparison operator"; + String string3 = new String("using comparison operator"); + + assertThat(string1 == string2).isTrue(); + assertThat(string1 == string3).isFalse(); + } + + @Test + public void whenUsingEqualsMethod_ThenComparingStrings(){ + + String string1 = "using equals method"; + String string2 = "using equals method"; + + String string3 = "using EQUALS method"; + String string4 = new String("using equals method"); + + assertThat(string1.equals(string2)).isTrue(); + assertThat(string1.equals(string4)).isTrue(); + + assertThat(string1.equals(null)).isFalse(); + assertThat(string1.equals(string3)).isFalse(); + } + + @Test + public void whenUsingEqualsIgnoreCase_ThenComparingStrings(){ + + String string1 = "using equals ignore case"; + String string2 = "USING EQUALS IGNORE CASE"; + + assertThat(string1.equalsIgnoreCase(string2)).isTrue(); + } + + @Test + public void whenUsingCompareTo_ThenComparingStrings(){ + + String author = "author"; + String book = "book"; + String duplicateBook = "book"; + + assertThat(author.compareTo(book)).isEqualTo(-1); + assertThat(book.compareTo(author)).isEqualTo(1); + assertThat(duplicateBook.compareTo(book)).isEqualTo(0); + } + + @Test + public void whenUsingCompareToIgnoreCase_ThenComparingStrings(){ + + String author = "Author"; + String book = "book"; + String duplicateBook = "BOOK"; + + assertThat(author.compareToIgnoreCase(book)).isEqualTo(-1); + assertThat(book.compareToIgnoreCase(author)).isEqualTo(1); + assertThat(duplicateBook.compareToIgnoreCase(book)).isEqualTo(0); + } + + @Test + public void whenUsingObjectsEqualsMethod_ThenComparingStrings(){ + + String string1 = "using objects equals"; + String string2 = "using objects equals"; + String string3 = new String("using objects equals"); + + assertThat(Objects.equals(string1, string2)).isTrue(); + assertThat(Objects.equals(string1, string3)).isTrue(); + + assertThat(Objects.equals(null, null)).isTrue(); + assertThat(Objects.equals(null, string1)).isFalse(); + } + + @Test + public void whenUsingEqualsOfApacheCommons_ThenComparingStrings(){ + + assertThat(StringUtils.equals(null, null)).isTrue(); + assertThat(StringUtils.equals(null, "equals method")).isFalse(); + assertThat(StringUtils.equals("equals method", "equals method")).isTrue(); + assertThat(StringUtils.equals("equals method", "EQUALS METHOD")).isFalse(); + } + + @Test + public void whenUsingEqualsIgnoreCaseOfApacheCommons_ThenComparingStrings(){ + + assertThat(StringUtils.equalsIgnoreCase(null, null)).isTrue(); + assertThat(StringUtils.equalsIgnoreCase(null, "equals method")).isFalse(); + assertThat(StringUtils.equalsIgnoreCase("equals method", "equals method")).isTrue(); + assertThat(StringUtils.equalsIgnoreCase("equals method", "EQUALS METHOD")).isTrue(); + } + + @Test + public void whenUsingEqualsAnyOf_ThenComparingStrings(){ + + assertThat(StringUtils.equalsAny(null, null, null)).isTrue(); + assertThat(StringUtils.equalsAny("equals any", "equals any", "any")).isTrue(); + assertThat(StringUtils.equalsAny("equals any", null, "equals any")).isTrue(); + assertThat(StringUtils.equalsAny(null, "equals", "any")).isFalse(); + assertThat(StringUtils.equalsAny("equals any", "EQUALS ANY", "ANY")).isFalse(); + } + + @Test + public void whenUsingEqualsAnyIgnoreCase_ThenComparingStrings(){ + + assertThat(StringUtils.equalsAnyIgnoreCase(null, null, null)).isTrue(); + assertThat(StringUtils.equalsAnyIgnoreCase("equals any", "equals any", "any")).isTrue(); + assertThat(StringUtils.equalsAnyIgnoreCase("equals any", null, "equals any")).isTrue(); + assertThat(StringUtils.equalsAnyIgnoreCase(null, "equals", "any")).isFalse(); + assertThat(StringUtils.equalsAnyIgnoreCase( + "equals any ignore case", "EQUALS ANY IGNORE CASE", "any")).isTrue(); + } + + @Test + public void whenUsingCompare_thenComparingStringsWithNulls(){ + + assertThat(StringUtils.compare(null, null)).isEqualTo(0); + assertThat(StringUtils.compare(null, "abc")).isEqualTo(-1); + + assertThat(StringUtils.compare("abc", "bbc")).isEqualTo(-1); + assertThat(StringUtils.compare("bbc", "abc")).isEqualTo(1); + assertThat(StringUtils.compare("abc", "abc")).isEqualTo(0); + } + + @Test + public void whenUsingCompareIgnoreCase_ThenComparingStringsWithNulls(){ + + assertThat(StringUtils.compareIgnoreCase(null, null)).isEqualTo(0); + assertThat(StringUtils.compareIgnoreCase(null, "abc")).isEqualTo(-1); + + assertThat(StringUtils.compareIgnoreCase("Abc", "bbc")).isEqualTo(-1); + assertThat(StringUtils.compareIgnoreCase("bbc", "ABC")).isEqualTo(1); + assertThat(StringUtils.compareIgnoreCase("abc", "ABC")).isEqualTo(0); + } + + @Test + public void whenUsingCompareWithNullIsLessOption_ThenComparingStrings(){ + + assertThat(StringUtils.compare(null, "abc", true)).isEqualTo(-1); + assertThat(StringUtils.compare(null, "abc", false)).isEqualTo(1); + } + +} diff --git a/core-kotlin/README.md b/core-kotlin/README.md index 5908d480b7..1c64817815 100644 --- a/core-kotlin/README.md +++ b/core-kotlin/README.md @@ -17,4 +17,4 @@ - [Sealed Classes in Kotlin](http://www.baeldung.com/kotlin-sealed-classes) - [JUnit 5 for Kotlin Developers](http://www.baeldung.com/junit-5-kotlin) - [Extension Methods in Kotlin](http://www.baeldung.com/kotlin-extension-methods) - +- [Infix Functions in Kotlin](http://www.baeldung.com/kotlin-infix-functions) diff --git a/core-kotlin/src/test/kotlin/com/baeldung/kotlin/InfixFunctionsTest.kt b/core-kotlin/src/test/kotlin/com/baeldung/kotlin/InfixFunctionsTest.kt new file mode 100644 index 0000000000..fc4286460a --- /dev/null +++ b/core-kotlin/src/test/kotlin/com/baeldung/kotlin/InfixFunctionsTest.kt @@ -0,0 +1,51 @@ +package com.baeldung.kotlin + +import org.junit.Assert +import org.junit.Test + +class InfixFunctionsTest { + @Test + fun testColours() { + val color = 0x123456 + val red = (color and 0xff0000) shr 16 + val green = (color and 0x00ff00) shr 8 + val blue = (color and 0x0000ff) shr 0 + + Assert.assertEquals(0x12, red) + Assert.assertEquals(0x34, green) + Assert.assertEquals(0x56, blue) + } + + @Test + fun testNewAssertions() { + class Assertion(private val target: T) { + infix fun isEqualTo(other: T) { + Assert.assertEquals(other, target) + } + + infix fun isDifferentFrom(other: T) { + Assert.assertNotEquals(other, target) + } + } + + val result = Assertion(5) + + result isEqualTo 5 + + // The following two lines are expected to fail + // result isEqualTo 6 + // result isDifferentFrom 5 + } + + @Test + fun testNewStringMethod() { + infix fun String.substringMatches(r: Regex) : List { + return r.findAll(this) + .map { it.value } + .toList() + } + + val matches = "a bc def" substringMatches ".*? ".toRegex() + Assert.assertEquals(listOf("a ", "bc "), matches) + } +} diff --git a/core-kotlin/src/test/kotlin/com/baeldung/kotlin/stdlib/RegexTest.kt b/core-kotlin/src/test/kotlin/com/baeldung/kotlin/stdlib/RegexTest.kt new file mode 100644 index 0000000000..eeb587ee22 --- /dev/null +++ b/core-kotlin/src/test/kotlin/com/baeldung/kotlin/stdlib/RegexTest.kt @@ -0,0 +1,128 @@ +package com.baeldung.kotlin.stdlib + +import org.junit.Test +import java.beans.ExceptionListener +import java.beans.XMLEncoder +import java.io.* +import java.lang.Exception +import kotlin.test.* +import kotlin.text.RegexOption.* + +class RegexTest { + + @Test + fun whenRegexIsInstantiated_thenIsEqualToToRegexMethod() { + val pattern = """a([bc]+)d?\\""" + + assertEquals(Regex.fromLiteral(pattern).pattern, pattern) + assertEquals(pattern, Regex(pattern).pattern) + assertEquals(pattern, pattern.toRegex().pattern) + } + + @Test + fun whenRegexMatches_thenResultIsTrue() { + val regex = """a([bc]+)d?""".toRegex() + + assertTrue(regex.containsMatchIn("xabcdy")) + assertTrue(regex.matches("abcd")) + assertFalse(regex matches "xabcdy") + } + + @Test + fun givenCompletelyMatchingRegex_whenMatchResult_thenDestructuring() { + val regex = """a([bc]+)d?""".toRegex() + + assertNull(regex.matchEntire("xabcdy")) + + val matchResult = regex.matchEntire("abbccbbd") + + assertNotNull(matchResult) + assertEquals(matchResult!!.value, matchResult.groupValues[0]) + assertEquals(matchResult.destructured.toList(), matchResult.groupValues.drop(1)) + assertEquals("bbccbb", matchResult.destructured.component1()) + assertNull(matchResult.next()) + } + + @Test + fun givenPartiallyMatchingRegex_whenMatchResult_thenGroups() { + val regex = """a([bc]+)d?""".toRegex() + var matchResult = regex.find("abcb abbd") + + assertNotNull(matchResult) + assertEquals(matchResult!!.value, matchResult.groupValues[0]) + assertEquals("abcb", matchResult.value) + assertEquals(IntRange(0, 3), matchResult.range) + assertEquals(listOf("abcb", "bcb"), matchResult.groupValues) + assertEquals(matchResult.destructured.toList(), matchResult.groupValues.drop(1)) + + matchResult = matchResult.next() + + assertNotNull(matchResult) + assertEquals("abbd", matchResult!!.value) + assertEquals("bb", matchResult.groupValues[1]) + + matchResult = matchResult.next() + + assertNull(matchResult) + } + + @Test + fun givenPartiallyMatchingRegex_whenMatchResult_thenDestructuring() { + val regex = """([\w\s]+) is (\d+) years old""".toRegex() + val matchResult = regex.find("Mickey Mouse is 95 years old") + val (name, age) = matchResult!!.destructured + + assertEquals("Mickey Mouse", name) + assertEquals("95", age) + } + + @Test + fun givenNonMatchingRegex_whenFindCalled_thenNull() { + val regex = """a([bc]+)d?""".toRegex() + val matchResult = regex.find("foo") + + assertNull(matchResult) + } + + @Test + fun givenNonMatchingRegex_whenFindAllCalled_thenEmptySet() { + val regex = """a([bc]+)d?""".toRegex() + val matchResults = regex.findAll("foo") + + assertNotNull(matchResults) + assertTrue(matchResults.none()) + } + + @Test + fun whenReplace_thenReplacement() { + val regex = """(red|green|blue)""".toRegex() + val beautiful = "Roses are red, Violets are blue" + val grim = regex.replace(beautiful, "dark") + val shiny = regex.replaceFirst(beautiful, "rainbow") + + assertEquals("Roses are dark, Violets are dark", grim) + assertEquals("Roses are rainbow, Violets are blue", shiny) + } + + @Test + fun whenComplexReplace_thenReplacement() { + val regex = """(red|green|blue)""".toRegex() + val beautiful = "Roses are red, Violets are blue" + val reallyBeautiful = regex.replace(beautiful) { + matchResult -> matchResult.value.toUpperCase() + "!" + } + + assertEquals("Roses are RED!, Violets are BLUE!", reallyBeautiful) + } + + @Test + fun whenSplit_thenList() { + val regex = """\W+""".toRegex() + val beautiful = "Roses are red, Violets are blue" + + assertEquals(listOf("Roses", "are", "red", "Violets", "are", "blue"), regex.split(beautiful)) + assertEquals(listOf("Roses", "are", "red", "Violets are blue"), regex.split(beautiful, 4)) + assertEquals(regex.toPattern().split(beautiful).asList(), regex.split(beautiful)) + } + +} \ No newline at end of file diff --git a/google-cloud/README.md b/google-cloud/README.md new file mode 100644 index 0000000000..6022796a0e --- /dev/null +++ b/google-cloud/README.md @@ -0,0 +1,16 @@ +## Google Cloud Tutorial Project + +### Relevant Article: +- [Intro to Google Cloud Storage With Java](http://www.baeldung.com/intro-to-google-cloud-storage-with-java/) + +### Overview +This Maven project contains the Java code for the article linked above. + +### Package Organization +Java classes for the intro tutorial are in the org.baeldung.google.cloud package. Please note that Google Cloud requires +a user account and credentials, as explained in the tutorial. + + +### Running the tests + +``` diff --git a/google-cloud/pom.xml b/google-cloud/pom.xml new file mode 100644 index 0000000000..0f1eff36f8 --- /dev/null +++ b/google-cloud/pom.xml @@ -0,0 +1,38 @@ + + + 4.0.0 + google-cloud + 0.1-SNAPSHOT + jar + google-cloud + Google Cloud Tutorials + + + com.baeldung + parent-modules + 1.0.0-SNAPSHOT + + + + + com.google.cloud + google-cloud-storage + 1.16.0 + + + org.projectlombok + lombok + + ${lombok.version} + provided + + + + + 1.16.18 + 1.8 + UTF-8 + + + diff --git a/google-cloud/src/main/java/com/baeldung/google/cloud/storage/GoogleCloudStorage.java b/google-cloud/src/main/java/com/baeldung/google/cloud/storage/GoogleCloudStorage.java new file mode 100644 index 0000000000..a69171f1db --- /dev/null +++ b/google-cloud/src/main/java/com/baeldung/google/cloud/storage/GoogleCloudStorage.java @@ -0,0 +1,105 @@ +package com.baeldung.google.cloud.storage; + +import com.google.api.gax.paging.Page; +import com.google.auth.Credentials; +import com.google.auth.oauth2.GoogleCredentials; +import com.google.cloud.storage.*; +import lombok.extern.slf4j.Slf4j; + +import java.io.FileInputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.WritableByteChannel; + +import static java.nio.charset.StandardCharsets.UTF_8; + +/** + * Simple class for creating, reading and modifying text blobs on Google Cloud + */ +@Slf4j +public class GoogleCloudStorage { + + private Storage storage; + private Bucket bucket; + + public static void main(String[] args) throws Exception { + + // Use this variation to read the Google authorization JSON from the resources directory with a path + // and a project name. + GoogleCloudStorage googleCloudStorage = + new GoogleCloudStorage("google-cloud/src/main/resources/google_auth.json", "baeldung-cloud-tutorial"); + + // Bucket require globally unique names, so you'll probably need to change this + Bucket bucket = googleCloudStorage.getBucket("baeldung-1-bucket"); + + // Save a simple string + BlobId blobId = googleCloudStorage.saveString("my-first-blob", "Hi there!", bucket); + + // Get it by blob id this time + String value = googleCloudStorage.getString(blobId); + + log.info("Read data: {}", value); + + googleCloudStorage.updateString(blobId, "Bye now!"); + + // Get the string by blob name + value = googleCloudStorage.getString("my-first-blob"); + + log.info("Read modified data: {}", value); + + + } + + + // Use path and project name + private GoogleCloudStorage(String pathToConfig, String projectId) throws IOException { + Credentials credentials = GoogleCredentials.fromStream(new FileInputStream(pathToConfig)); + storage = StorageOptions.newBuilder().setCredentials(credentials).setProjectId(projectId).build().getService(); + } + + // Check for bucket existence and create if needed. + private Bucket getBucket(String bucketName) { + bucket = storage.get(bucketName); + if (bucket == null) { + System.out.println("Creating new bucket."); + bucket = storage.create(BucketInfo.of(bucketName)); + } + return bucket; + } + + // Save a string to a blob + private BlobId saveString(String blobName, String value, Bucket bucket) { + byte[] bytes = value.getBytes(UTF_8); + Blob blob = bucket.create(blobName, bytes); + return blob.getBlobId(); + } + + + // get a blob by id + private String getString(BlobId blobId) { + Blob blob = storage.get(blobId); + return new String(blob.getContent()); + } + + + // get a blob by name + private String getString(String name) { + Page blobs = bucket.list(); + for (Blob blob: blobs.getValues()) { + if (name.equals(blob.getName())) { + return new String(blob.getContent()); + } + } + return "Blob not found"; + } + + // Update a blob + private void updateString(BlobId blobId, String newString) throws IOException { + Blob blob = storage.get(blobId); + if (blob != null) { + WritableByteChannel channel = blob.writer(); + channel.write(ByteBuffer.wrap(newString.getBytes(UTF_8))); + channel.close(); + } + } +} \ No newline at end of file diff --git a/guava/README.md b/guava/README.md index 7ab70cb01f..924187867e 100644 --- a/guava/README.md +++ b/guava/README.md @@ -19,6 +19,7 @@ - [Guide to Guava’s Ordering](http://www.baeldung.com/guava-ordering) - [Guide to Guava’s PreConditions](http://www.baeldung.com/guava-preconditions) - [Introduction to Guava CacheLoader](http://www.baeldung.com/guava-cacheloader) +- [Introduction to Guava Memoizer](http://www.baeldung.com/guava-memoizer) - [Guide to Guava’s EventBus](http://www.baeldung.com/guava-eventbus) - [Guide to Guava Multimap](http://www.baeldung.com/guava-multimap) - [Guide to Guava RangeSet](http://www.baeldung.com/guava-rangeset) diff --git a/guava/src/test/java/org/baeldung/guava/GuavaMemoizerUnitTest.java b/guava/src/test/java/org/baeldung/guava/GuavaMemoizerUnitTest.java index 0ae1f438e3..1f934347b4 100644 --- a/guava/src/test/java/org/baeldung/guava/GuavaMemoizerUnitTest.java +++ b/guava/src/test/java/org/baeldung/guava/GuavaMemoizerUnitTest.java @@ -38,7 +38,7 @@ public class GuavaMemoizerUnitTest { int n = 95; // when - BigInteger factorial = new Factorial().getFactorial(n); + BigInteger factorial = Factorial.getFactorial(n); // then BigInteger expectedFactorial = new BigInteger("10329978488239059262599702099394727095397746340117372869212250571234293987594703124871765375385424468563282236864226607350415360000000000000000000000"); @@ -47,52 +47,46 @@ public class GuavaMemoizerUnitTest { @Test public void givenMemoizedSupplier_whenGet_thenSubsequentGetsAreFast() { + // given Supplier memoizedSupplier; memoizedSupplier = Suppliers.memoize(CostlySupplier::generateBigNumber); - Instant start = Instant.now(); - BigInteger bigNumber = memoizedSupplier.get(); - Long durationInMs = Duration.between(start, Instant.now()).toMillis(); - assertThat(bigNumber, is(equalTo(new BigInteger("12345")))); - assertThat(durationInMs.doubleValue(), is(closeTo(2000D, 100D))); + // when + BigInteger expectedValue = new BigInteger("12345"); + assertSupplierGetExecutionResultAndDuration(memoizedSupplier, expectedValue, 2000D); - start = Instant.now(); - bigNumber = memoizedSupplier.get().add(BigInteger.ONE); - durationInMs = Duration.between(start, Instant.now()).toMillis(); - assertThat(bigNumber, is(equalTo(new BigInteger("12346")))); - assertThat(durationInMs.doubleValue(), is(closeTo(0D, 100D))); - - start = Instant.now(); - bigNumber = memoizedSupplier.get().add(BigInteger.TEN); - durationInMs = Duration.between(start, Instant.now()).toMillis(); - assertThat(bigNumber, is(equalTo(new BigInteger("12355")))); - assertThat(durationInMs.doubleValue(), is(closeTo(0D, 100D))); + // then + assertSupplierGetExecutionResultAndDuration(memoizedSupplier, expectedValue, 0D); + assertSupplierGetExecutionResultAndDuration(memoizedSupplier, expectedValue, 0D); } @Test public void givenMemoizedSupplierWithExpiration_whenGet_thenSubsequentGetsBeforeExpiredAreFast() throws InterruptedException { + // given Supplier memoizedSupplier; memoizedSupplier = Suppliers.memoizeWithExpiration(CostlySupplier::generateBigNumber, 3, TimeUnit.SECONDS); - Instant start = Instant.now(); - BigInteger bigNumber = memoizedSupplier.get(); - Long durationInMs = Duration.between(start, Instant.now()).toMillis(); - assertThat(bigNumber, is(equalTo(new BigInteger("12345")))); - assertThat(durationInMs.doubleValue(), is(closeTo(2000D, 100D))); - - start = Instant.now(); - bigNumber = memoizedSupplier.get().add(BigInteger.ONE); - durationInMs = Duration.between(start, Instant.now()).toMillis(); - assertThat(bigNumber, is(equalTo(new BigInteger("12346")))); - assertThat(durationInMs.doubleValue(), is(closeTo(0D, 100D))); + // when + BigInteger expectedValue = new BigInteger("12345"); + assertSupplierGetExecutionResultAndDuration(memoizedSupplier, expectedValue, 2000D); + // then + assertSupplierGetExecutionResultAndDuration(memoizedSupplier, expectedValue, 0D); + // add one more second until memoized Supplier is evicted from memory TimeUnit.SECONDS.sleep(1); + assertSupplierGetExecutionResultAndDuration(memoizedSupplier, expectedValue, 2000D); + } - start = Instant.now(); - bigNumber = memoizedSupplier.get().add(BigInteger.TEN); - durationInMs = Duration.between(start, Instant.now()).toMillis(); - assertThat(bigNumber, is(equalTo(new BigInteger("12355")))); - assertThat(durationInMs.doubleValue(), is(closeTo(2000D, 100D))); + private void assertSupplierGetExecutionResultAndDuration(Supplier supplier, + T expectedValue, + double expectedDurationInMs) { + Instant start = Instant.now(); + T value = supplier.get(); + Long durationInMs = Duration.between(start, Instant.now()).toMillis(); + double marginOfErrorInMs = 100D; + + assertThat(value, is(equalTo(expectedValue))); + assertThat(durationInMs.doubleValue(), is(closeTo(expectedDurationInMs, marginOfErrorInMs))); } } diff --git a/guest/core-java/pom.xml b/guest/core-java/pom.xml index 222716386b..eda3846c1f 100644 --- a/guest/core-java/pom.xml +++ b/guest/core-java/pom.xml @@ -16,6 +16,24 @@ log4j-core ${log4j2.version} + + org.hamcrest + hamcrest-core + ${org.hamcrest.version} + test + + + org.hamcrest + hamcrest-library + ${org.hamcrest.version} + test + + + org.hamcrest + hamcrest-all + ${org.hamcrest.version} + test + @@ -32,5 +50,6 @@ 2.8.2 + 1.3 \ No newline at end of file diff --git a/guest/core-java/src/main/java/com/stackify/stream/Employee.java b/guest/core-java/src/main/java/com/stackify/stream/Employee.java new file mode 100644 index 0000000000..005990c863 --- /dev/null +++ b/guest/core-java/src/main/java/com/stackify/stream/Employee.java @@ -0,0 +1,46 @@ +package com.stackify.stream; + +public class Employee { + private Integer id; + private String name; + private Double salary; + + public Employee(Integer id, String name, Double salary) { + this.id = id; + this.name = name; + this.salary = salary; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Double getSalary() { + return salary; + } + + public void setSalary(Double salary) { + this.salary = salary; + } + + public void salaryIncrement(Double percentage) { + Double newSalary = salary + percentage * salary / 100; + setSalary(newSalary); + } + + public String toString() { + return "Id: " + id + " Name:" + name + " Price:" + salary; + } +} diff --git a/guest/core-java/src/main/java/com/stackify/stream/EmployeeRepository.java b/guest/core-java/src/main/java/com/stackify/stream/EmployeeRepository.java new file mode 100644 index 0000000000..223fee5e26 --- /dev/null +++ b/guest/core-java/src/main/java/com/stackify/stream/EmployeeRepository.java @@ -0,0 +1,21 @@ +package com.stackify.stream; + +import java.util.List; + +public class EmployeeRepository { + private List empList; + + public EmployeeRepository(List empList) { + this.empList = empList; + + } + public Employee findById(Integer id) { + for (Employee emp : empList) { + if (emp.getId() == id) { + return emp; + } + } + + return null; + } +} diff --git a/guest/core-java/src/test/java/com/stackify/stream/EmployeeTest.java b/guest/core-java/src/test/java/com/stackify/stream/EmployeeTest.java new file mode 100644 index 0000000000..cf988d035a --- /dev/null +++ b/guest/core-java/src/test/java/com/stackify/stream/EmployeeTest.java @@ -0,0 +1,455 @@ +package com.stackify.stream; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.beans.HasPropertyWithValue.hasProperty; +import static org.junit.Assert.assertEquals; + +import java.io.IOException; +import java.io.PrintWriter; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.Collection; +import java.util.Comparator; +import java.util.DoubleSummaryStatistics; +import java.util.List; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Optional; +import java.util.Set; +import java.util.Vector; +import java.util.function.BinaryOperator; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.junit.After; +import org.junit.Test; + +public class EmployeeTest { + private String fileName = "src/test/resources/test.txt"; + + private static Employee[] arrayOfEmps = { + new Employee(1, "Jeff Bezos", 100000.0), + new Employee(2, "Bill Gates", 200000.0), + new Employee(3, "Mark Zuckerberg", 300000.0) + }; + + private static List empList = Arrays.asList(arrayOfEmps); + private static EmployeeRepository employeeRepository = new EmployeeRepository(empList); + + @After + public void cleanup() throws IOException { + Files.deleteIfExists(Paths.get(fileName)); + } + + @Test + public void whenGetStreamFromList_ObtainStream() { + assert(empList.stream() instanceof Stream); + } + + @Test + public void whenGetStreamFromArray_ObtainStream() { + assert(Stream.of(arrayOfEmps) instanceof Stream); + } + + @Test + public void whenGetStreamFromElements_ObtainStream() { + assert(Stream.of(arrayOfEmps[0], arrayOfEmps[1], arrayOfEmps[2]) instanceof Stream); + } + + @Test + public void whenBuildStreamFromElements_ObtainStream() { + Stream.Builder empStreamBuilder = Stream.builder(); + + empStreamBuilder.accept(arrayOfEmps[0]); + empStreamBuilder.accept(arrayOfEmps[1]); + empStreamBuilder.accept(arrayOfEmps[2]); + + Stream empStream = empStreamBuilder.build(); + + assert(empStream instanceof Stream); + } + + @Test + public void whenIncrementSalaryForEachEmployee_thenApplyNewSalary() { + Employee[] arrayOfEmps = { + new Employee(1, "Jeff Bezos", 100000.0), + new Employee(2, "Bill Gates", 200000.0), + new Employee(3, "Mark Zuckerberg", 300000.0) + }; + + List empList = Arrays.asList(arrayOfEmps); + + empList.stream().forEach(e -> e.salaryIncrement(10.0)); + + assertThat(empList, contains( + hasProperty("salary", equalTo(110000.0)), + hasProperty("salary", equalTo(220000.0)), + hasProperty("salary", equalTo(330000.0)) + )); + } + + @Test + public void whenIncrementSalaryUsingPeek_thenApplyNewSalary() { + Employee[] arrayOfEmps = { + new Employee(1, "Jeff Bezos", 100000.0), + new Employee(2, "Bill Gates", 200000.0), + new Employee(3, "Mark Zuckerberg", 300000.0) + }; + + List empList = Arrays.asList(arrayOfEmps); + + empList.stream() + .peek(e -> e.salaryIncrement(10.0)) + .peek(System.out::println) + .collect(Collectors.toList()); + + assertThat(empList, contains( + hasProperty("salary", equalTo(110000.0)), + hasProperty("salary", equalTo(220000.0)), + hasProperty("salary", equalTo(330000.0)) + )); + } + + @Test + public void whenMapIdToEmployees_thenGetEmployeeStream() { + Integer[] empIds = { 1, 2, 3 }; + + List employees = Stream.of(empIds) + .map(employeeRepository::findById) + .collect(Collectors.toList()); + + assertEquals(employees.size(), empIds.length); + } + + @Test + public void whenFlatMapEmployeeNames_thenGetNameStream() { + List> namesNested = Arrays.asList( + Arrays.asList("Jeff", "Bezos"), + Arrays.asList("Bill", "Gates"), + Arrays.asList("Mark", "Zuckerberg")); + + List namesFlatStream = namesNested.stream() + .flatMap(Collection::stream) + .collect(Collectors.toList()); + + assertEquals(namesFlatStream.size(), namesNested.size() * 2); + } + + @Test + public void whenFilterEmployees_thenGetFilteredStream() { + Integer[] empIds = { 1, 2, 3, 4 }; + + List employees = Stream.of(empIds) + .map(employeeRepository::findById) + .filter(e -> e != null) + .filter(e -> e.getSalary() > 200000) + .collect(Collectors.toList()); + + assertEquals(Arrays.asList(arrayOfEmps[2]), employees); + } + + @Test + public void whenFindFirst_thenGetFirstEmployeeInStream() { + Integer[] empIds = { 1, 2, 3, 4 }; + + Employee employee = Stream.of(empIds) + .map(employeeRepository::findById) + .filter(e -> e != null) + .filter(e -> e.getSalary() > 100000) + .findFirst() + .orElse(null); + + assertEquals(employee.getSalary(), new Double(200000)); + } + + @Test + public void whenCollectStreamToList_thenGetList() { + List employees = empList.stream().collect(Collectors.toList()); + + assertEquals(empList, employees); + } + + @Test + public void whenStreamToArray_thenGetArray() { + Employee[] employees = empList.stream().toArray(Employee[]::new); + + assertThat(empList.toArray(), equalTo(employees)); + } + + @Test + public void whenStreamCount_thenGetElementCount() { + Long empCount = empList.stream() + .filter(e -> e.getSalary() > 200000) + .count(); + + assertEquals(empCount, new Long(1)); + } + + @Test + public void whenLimitInfiniteStream_thenGetFiniteElements() { + Stream infiniteStream = Stream.iterate(2, i -> i * 2); + + List collect = infiniteStream + .skip(3) + .limit(5) + .collect(Collectors.toList()); + + assertEquals(collect, Arrays.asList(16, 32, 64, 128, 256)); + } + + @Test + public void whenSortStream_thenGetSortedStream() { + List employees = empList.stream() + .sorted((e1, e2) -> e1.getName().compareTo(e2.getName())) + .collect(Collectors.toList()); + + assertEquals(employees.get(0).getName(), "Bill Gates"); + assertEquals(employees.get(1).getName(), "Jeff Bezos"); + assertEquals(employees.get(2).getName(), "Mark Zuckerberg"); + } + + + @Test + public void whenFindMin_thenGetMinElementFromStream() { + Employee firstEmp = empList.stream() + .min((e1, e2) -> e1.getId() - e2.getId()) + .orElseThrow(NoSuchElementException::new); + + assertEquals(firstEmp.getId(), new Integer(1)); + } + + @Test + public void whenFindMax_thenGetMaxElementFromStream() { + Employee maxSalEmp = empList.stream() + .max(Comparator.comparing(Employee::getSalary)) + .orElseThrow(NoSuchElementException::new); + + assertEquals(maxSalEmp.getSalary(), new Double(300000.0)); + } + + @Test + public void whenApplyDistinct_thenRemoveDuplicatesFromStream() { + List intList = Arrays.asList(2, 5, 3, 2, 4, 3); + List distinctIntList = intList.stream().distinct().collect(Collectors.toList()); + + assertEquals(distinctIntList, Arrays.asList(2, 5, 3, 4)); + } + + @Test + public void whenApplyMatch_thenReturnBoolean() { + List intList = Arrays.asList(2, 4, 5, 6, 8); + + boolean allEven = intList.stream().allMatch(i -> i % 2 == 0); + boolean oneEven = intList.stream().anyMatch(i -> i % 2 == 0); + boolean noneMultipleOfThree = intList.stream().noneMatch(i -> i % 3 == 0); + + assertEquals(allEven, false); + assertEquals(oneEven, true); + assertEquals(noneMultipleOfThree, false); + } + + @Test + public void whenFindMaxOnIntStream_thenGetMaxInteger() { + Integer latestEmpId = empList.stream() + .mapToInt(Employee::getId) + .max() + .orElseThrow(NoSuchElementException::new); + + assertEquals(latestEmpId, new Integer(3)); + } + + @Test + public void whenApplySumOnIntStream_thenGetSum() { + Double avgSal = empList.stream() + .mapToDouble(Employee::getSalary) + .average() + .orElseThrow(NoSuchElementException::new); + + assertEquals(avgSal, new Double(200000)); + } + + @Test + public void whenApplyReduceOnStream_thenGetValue() { + Double sumSal = empList.stream() + .map(Employee::getSalary) + .reduce(0.0, Double::sum); + + assertEquals(sumSal, new Double(600000)); + } + + @Test + public void whenCollectByJoining_thenGetJoinedString() { + String empNames = empList.stream() + .map(Employee::getName) + .collect(Collectors.joining(", ")) + .toString(); + + assertEquals(empNames, "Jeff Bezos, Bill Gates, Mark Zuckerberg"); + } + + @Test + public void whenCollectBySet_thenGetSet() { + Set empNames = empList.stream() + .map(Employee::getName) + .collect(Collectors.toSet()); + + assertEquals(empNames.size(), 3); + } + + @Test + public void whenToVectorCollection_thenGetVector() { + Vector empNames = empList.stream() + .map(Employee::getName) + .collect(Collectors.toCollection(Vector::new)); + + assertEquals(empNames.size(), 3); + } + + @Test + public void whenApplySummarizing_thenGetBasicStats() { + DoubleSummaryStatistics stats = empList.stream() + .collect(Collectors.summarizingDouble(Employee::getSalary)); + + assertEquals(stats.getCount(), 3); + assertEquals(stats.getSum(), 600000.0, 0); + assertEquals(stats.getMin(), 100000.0, 0); + assertEquals(stats.getMax(), 300000.0, 0); + assertEquals(stats.getAverage(), 200000.0, 0); + } + + @Test + public void whenApplySummaryStatistics_thenGetBasicStats() { + DoubleSummaryStatistics stats = empList.stream() + .mapToDouble(Employee::getSalary) + .summaryStatistics(); + + assertEquals(stats.getCount(), 3); + assertEquals(stats.getSum(), 600000.0, 0); + assertEquals(stats.getMin(), 100000.0, 0); + assertEquals(stats.getMax(), 300000.0, 0); + assertEquals(stats.getAverage(), 200000.0, 0); + } + + @Test + public void whenStreamPartition_thenGetMap() { + List intList = Arrays.asList(2, 4, 5, 6, 8); + Map> isEven = intList.stream().collect( + Collectors.partitioningBy(i -> i % 2 == 0)); + + assertEquals(isEven.get(true).size(), 4); + assertEquals(isEven.get(false).size(), 1); + } + + @Test + public void whenStreamGroupingBy_thenGetMap() { + Map> groupByAlphabet = empList.stream().collect( + Collectors.groupingBy(e -> new Character(e.getName().charAt(0)))); + + assertEquals(groupByAlphabet.get('B').get(0).getName(), "Bill Gates"); + assertEquals(groupByAlphabet.get('J').get(0).getName(), "Jeff Bezos"); + assertEquals(groupByAlphabet.get('M').get(0).getName(), "Mark Zuckerberg"); + } + + @Test + public void whenStreamMapping_thenGetMap() { + Map> idGroupedByAlphabet = empList.stream().collect( + Collectors.groupingBy(e -> new Character(e.getName().charAt(0)), + Collectors.mapping(Employee::getId, Collectors.toList()))); + + assertEquals(idGroupedByAlphabet.get('B').get(0), new Integer(2)); + assertEquals(idGroupedByAlphabet.get('J').get(0), new Integer(1)); + assertEquals(idGroupedByAlphabet.get('M').get(0), new Integer(3)); + } + + @Test + public void whenStreamReducing_thenGetValue() { + Double percentage = 10.0; + Double salIncrOverhead = empList.stream().collect(Collectors.reducing( + 0.0, e -> e.getSalary() * percentage / 100, (s1, s2) -> s1 + s2)); + + assertEquals(salIncrOverhead, 60000.0, 0); + } + + @Test + public void whenStreamGroupingAndReducing_thenGetMap() { + Comparator byNameLength = Comparator.comparing(Employee::getName); + + Map> longestNameByAlphabet = empList.stream().collect( + Collectors.groupingBy(e -> new Character(e.getName().charAt(0)), + Collectors.reducing(BinaryOperator.maxBy(byNameLength)))); + + assertEquals(longestNameByAlphabet.get('B').get().getName(), "Bill Gates"); + assertEquals(longestNameByAlphabet.get('J').get().getName(), "Jeff Bezos"); + assertEquals(longestNameByAlphabet.get('M').get().getName(), "Mark Zuckerberg"); + } + + @Test + public void whenParallelStream_thenPerformOperationsInParallel() { + Employee[] arrayOfEmps = { + new Employee(1, "Jeff Bezos", 100000.0), + new Employee(2, "Bill Gates", 200000.0), + new Employee(3, "Mark Zuckerberg", 300000.0) + }; + + List empList = Arrays.asList(arrayOfEmps); + + empList.stream().parallel().forEach(e -> e.salaryIncrement(10.0)); + + assertThat(empList, contains( + hasProperty("salary", equalTo(110000.0)), + hasProperty("salary", equalTo(220000.0)), + hasProperty("salary", equalTo(330000.0)) + )); + } + + @Test + public void whenGenerateStream_thenGetInfiniteStream() { + Stream.generate(Math::random) + .limit(5) + .forEach(System.out::println); + } + + @Test + public void whenIterateStream_thenGetInfiniteStream() { + Stream evenNumStream = Stream.iterate(2, i -> i * 2); + + List collect = evenNumStream + .limit(5) + .collect(Collectors.toList()); + + assertEquals(collect, Arrays.asList(2, 4, 8, 16, 32)); + } + + @Test + public void whenStreamToFile_thenGetFile() throws IOException { + String[] words = { + "hello", + "refer", + "world", + "level" + }; + + try (PrintWriter pw = new PrintWriter( + Files.newBufferedWriter(Paths.get(fileName)))) { + Stream.of(words).forEach(pw::println); + } + } + + private List getPalindrome(Stream stream, int length) { + return stream.filter(s -> s.length() == length) + .filter(s -> s.compareToIgnoreCase( + new StringBuilder(s).reverse().toString()) == 0) + .collect(Collectors.toList()); + } + + @Test + public void whenFileToStream_thenGetStream() throws IOException { + whenStreamToFile_thenGetFile(); + + List str = getPalindrome(Files.lines(Paths.get(fileName)), 5); + assertThat(str, contains("refer", "level")); + } +} diff --git a/spring-cloud/spring-cloud-security/oauth2client/src/main/resources/application.properties b/guest/core-java/src/test/resources/.keep similarity index 100% rename from spring-cloud/spring-cloud-security/oauth2client/src/main/resources/application.properties rename to guest/core-java/src/test/resources/.keep diff --git a/hibernate5/src/main/java/com/baeldung/hibernate/HibernateUtil.java b/hibernate5/src/main/java/com/baeldung/hibernate/HibernateUtil.java index 25fc0d7b02..130edec8cc 100644 --- a/hibernate5/src/main/java/com/baeldung/hibernate/HibernateUtil.java +++ b/hibernate5/src/main/java/com/baeldung/hibernate/HibernateUtil.java @@ -81,6 +81,7 @@ public class HibernateUtil { metadataSources.addAnnotatedClass(Bag.class); metadataSources.addAnnotatedClass(PointEntity.class); metadataSources.addAnnotatedClass(PolygonEntity.class); + metadataSources.addAnnotatedClass(com.baeldung.hibernate.pojo.Person.class); Metadata metadata = metadataSources.buildMetadata(); return metadata.getSessionFactoryBuilder() diff --git a/hibernate5/src/main/java/com/baeldung/hibernate/converters/PersonNameConverter.java b/hibernate5/src/main/java/com/baeldung/hibernate/converters/PersonNameConverter.java new file mode 100644 index 0000000000..506e674984 --- /dev/null +++ b/hibernate5/src/main/java/com/baeldung/hibernate/converters/PersonNameConverter.java @@ -0,0 +1,61 @@ +package com.baeldung.hibernate.converters; + +import javax.persistence.AttributeConverter; +import javax.persistence.Converter; + +import com.baeldung.hibernate.pojo.PersonName; + +@Converter +public class PersonNameConverter implements AttributeConverter { + + private static final String SEPARATOR = ", "; + + @Override + public String convertToDatabaseColumn(PersonName personName) { + if (personName == null) { + return null; + } + + StringBuilder sb = new StringBuilder(); + if (personName.getSurname() != null && !personName.getSurname() + .isEmpty()) { + sb.append(personName.getSurname()); + sb.append(SEPARATOR); + } + + if (personName.getName() != null && !personName.getName() + .isEmpty()) { + sb.append(personName.getName()); + } + + return sb.toString(); + } + + @Override + public PersonName convertToEntityAttribute(String dbPersonName) { + if (dbPersonName == null || dbPersonName.isEmpty()) { + return null; + } + + String[] pieces = dbPersonName.split(SEPARATOR); + + if (pieces == null || pieces.length == 0) { + return null; + } + + PersonName personName = new PersonName(); + String firstPiece = !pieces[0].isEmpty() ? pieces[0] : null; + if (dbPersonName.contains(SEPARATOR)) { + personName.setSurname(firstPiece); + + if (pieces.length >= 2 && pieces[1] != null && !pieces[1].isEmpty()) { + personName.setName(pieces[1]); + } + } else { + personName.setName(firstPiece); + } + + return personName; + } + +} diff --git a/hibernate5/src/main/java/com/baeldung/hibernate/interceptors/CustomInterceptorImpl.java b/hibernate5/src/main/java/com/baeldung/hibernate/interceptors/CustomInterceptorImpl.java index a84a981f7f..6736b39b64 100644 --- a/hibernate5/src/main/java/com/baeldung/hibernate/interceptors/CustomInterceptorImpl.java +++ b/hibernate5/src/main/java/com/baeldung/hibernate/interceptors/CustomInterceptorImpl.java @@ -9,7 +9,7 @@ import org.hibernate.Interceptor; import org.hibernate.Transaction; import org.hibernate.type.Type; -public class CustomInterceptorImpl implements Interceptor { +public class CustomInterceptorImpl implements Interceptor, Serializable { @Override public boolean onLoad(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) throws CallbackException { diff --git a/hibernate5/src/main/java/com/baeldung/hibernate/pojo/Person.java b/hibernate5/src/main/java/com/baeldung/hibernate/pojo/Person.java new file mode 100644 index 0000000000..390a5954ed --- /dev/null +++ b/hibernate5/src/main/java/com/baeldung/hibernate/pojo/Person.java @@ -0,0 +1,32 @@ +package com.baeldung.hibernate.pojo; + +import javax.persistence.Convert; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +import com.baeldung.hibernate.converters.PersonNameConverter; + +@Entity(name = "PersonTable") +public class Person { + + @Id + @GeneratedValue + private Long id; + + @Convert(converter = PersonNameConverter.class) + private PersonName personName; + + public PersonName getPersonName() { + return personName; + } + + public void setPersonName(PersonName personName) { + this.personName = personName; + } + + public Long getId() { + return id; + } + +} diff --git a/hibernate5/src/main/java/com/baeldung/hibernate/pojo/PersonName.java b/hibernate5/src/main/java/com/baeldung/hibernate/pojo/PersonName.java new file mode 100644 index 0000000000..335fe73f75 --- /dev/null +++ b/hibernate5/src/main/java/com/baeldung/hibernate/pojo/PersonName.java @@ -0,0 +1,29 @@ +package com.baeldung.hibernate.pojo; + +import java.io.Serializable; + +public class PersonName implements Serializable { + + private static final long serialVersionUID = 7883094644631050150L; + + private String name; + + private String surname; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getSurname() { + return surname; + } + + public void setSurname(String surname) { + this.surname = surname; + } + +} diff --git a/hibernate5/src/test/java/com/baeldung/hibernate/converter/PersonNameConverterTest.java b/hibernate5/src/test/java/com/baeldung/hibernate/converter/PersonNameConverterTest.java new file mode 100644 index 0000000000..204d8775ff --- /dev/null +++ b/hibernate5/src/test/java/com/baeldung/hibernate/converter/PersonNameConverterTest.java @@ -0,0 +1,200 @@ +package com.baeldung.hibernate.converter; + +import java.io.IOException; + +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import com.baeldung.hibernate.HibernateUtil; +import com.baeldung.hibernate.pojo.Person; +import com.baeldung.hibernate.pojo.PersonName; + +import static org.junit.Assert.assertEquals; + +public class PersonNameConverterTest { + + private Session session; + private Transaction transaction; + + @Before + public void setUp() throws IOException { + session = HibernateUtil.getSessionFactory() + .openSession(); + transaction = session.beginTransaction(); + + session.createNativeQuery("delete from personTable") + .executeUpdate(); + + transaction.commit(); + transaction = session.beginTransaction(); + } + + @After + public void tearDown() { + transaction.rollback(); + session.close(); + } + + @Test + public void givenPersonName_WhenSaving_ThenNameAndSurnameConcat() { + final String name = "name"; + final String surname = "surname"; + + PersonName personName = new PersonName(); + personName.setName(name); + personName.setSurname(surname); + + Person person = new Person(); + person.setPersonName(personName); + + Long id = (Long) session.save(person); + + session.flush(); + session.clear(); + + String dbPersonName = (String) session.createNativeQuery("select p.personName from PersonTable p where p.id = :id") + .setParameter("id", id) + .getSingleResult(); + + assertEquals(surname + ", " + name, dbPersonName); + + Person dbPerson = session.createNativeQuery("select * from PersonTable p where p.id = :id", Person.class) + .setParameter("id", id) + .getSingleResult(); + + assertEquals(dbPerson.getPersonName() + .getName(), name); + assertEquals(dbPerson.getPersonName() + .getSurname(), surname); + } + + @Test + public void givenPersonNameNull_WhenSaving_ThenNullStored() { + final String name = null; + final String surname = null; + + PersonName personName = new PersonName(); + personName.setName(name); + personName.setSurname(surname); + + Person person = new Person(); + person.setPersonName(personName); + + Long id = (Long) session.save(person); + + session.flush(); + session.clear(); + + String dbPersonName = (String) session.createNativeQuery("select p.personName from PersonTable p where p.id = :id") + .setParameter("id", id) + .getSingleResult(); + + assertEquals("", dbPersonName); + + Person dbPerson = session.createNativeQuery("select * from PersonTable p where p.id = :id", Person.class) + .setParameter("id", id) + .getSingleResult(); + + assertEquals(dbPerson.getPersonName(), null); + } + + @Test + public void givenPersonNameWithoutName_WhenSaving_ThenNotNameStored() { + final String name = null; + final String surname = "surname"; + + PersonName personName = new PersonName(); + personName.setName(name); + personName.setSurname(surname); + + Person person = new Person(); + person.setPersonName(personName); + + Long id = (Long) session.save(person); + + session.flush(); + session.clear(); + + String dbPersonName = (String) session.createNativeQuery("select p.personName from PersonTable p where p.id = :id") + .setParameter("id", id) + .getSingleResult(); + + assertEquals("surname, ", dbPersonName); + + Person dbPerson = session.createNativeQuery("select * from PersonTable p where p.id = :id", Person.class) + .setParameter("id", id) + .getSingleResult(); + + assertEquals(dbPerson.getPersonName() + .getName(), name); + assertEquals(dbPerson.getPersonName() + .getSurname(), surname); + } + + @Test + public void givenPersonNameWithoutSurName_WhenSaving_ThenNotSurNameStored() { + final String name = "name"; + final String surname = null; + + PersonName personName = new PersonName(); + personName.setName(name); + personName.setSurname(surname); + + Person person = new Person(); + person.setPersonName(personName); + + Long id = (Long) session.save(person); + + session.flush(); + session.clear(); + + String dbPersonName = (String) session.createNativeQuery("select p.personName from PersonTable p where p.id = :id") + .setParameter("id", id) + .getSingleResult(); + + assertEquals("name", dbPersonName); + + Person dbPerson = session.createNativeQuery("select * from PersonTable p where p.id = :id", Person.class) + .setParameter("id", id) + .getSingleResult(); + + assertEquals(dbPerson.getPersonName() + .getName(), name); + assertEquals(dbPerson.getPersonName() + .getSurname(), surname); + } + + @Test + public void givenPersonNameEmptyFields_WhenSaving_ThenFielsNotStored() { + final String name = ""; + final String surname = ""; + + PersonName personName = new PersonName(); + personName.setName(name); + personName.setSurname(surname); + + Person person = new Person(); + person.setPersonName(personName); + + Long id = (Long) session.save(person); + + session.flush(); + session.clear(); + + String dbPersonName = (String) session.createNativeQuery("select p.personName from PersonTable p where p.id = :id") + .setParameter("id", id) + .getSingleResult(); + + assertEquals("", dbPersonName); + + Person dbPerson = session.createNativeQuery("select * from PersonTable p where p.id = :id", Person.class) + .setParameter("id", id) + .getSingleResult(); + + assertEquals(dbPerson.getPersonName(), null); + } + +} diff --git a/influxdb/README.md b/influxdb/README.md index 7d1684688d..f2c421580e 100644 --- a/influxdb/README.md +++ b/influxdb/README.md @@ -2,7 +2,6 @@ ### Relevant Article: - [Introduction to using InfluxDB with Java](http://www.baeldung.com/using-influxdb-with-java/) -- [Using InfluxDB with Java](http://www.baeldung.com/java-influxdb) ### Overview This Maven project contains the Java code for the article linked above. diff --git a/influxdb/src/test/java/com/baeldung/influxdb/InfluxDBConnectionLiveTest.java b/influxdb/src/test/java/com/baeldung/influxdb/InfluxDBConnectionLiveTest.java index 6c7a03cb70..858903a676 100644 --- a/influxdb/src/test/java/com/baeldung/influxdb/InfluxDBConnectionLiveTest.java +++ b/influxdb/src/test/java/com/baeldung/influxdb/InfluxDBConnectionLiveTest.java @@ -8,7 +8,6 @@ import org.influxdb.dto.*; import org.influxdb.impl.InfluxDBResultMapper; import org.junit.Test; -import java.io.IOException; import java.util.List; import java.util.concurrent.TimeUnit; @@ -103,7 +102,7 @@ public class InfluxDBConnectionLiveTest { // another brief pause. Thread.sleep(10); - List memoryPointList = getPoints(connection, "Select * from memory", "baeldung"); + List memoryPointList = getPoints(connection, "Select * from memory", "baeldung"); assertEquals(10, memoryPointList.size()); diff --git a/jackson/pom.xml b/jackson/pom.xml index 001fde5021..2587e61ac1 100644 --- a/jackson/pom.xml +++ b/jackson/pom.xml @@ -129,7 +129,7 @@ - 2.9.2 + 2.9.4 19.0 diff --git a/java-lite/pom.xml b/java-lite/pom.xml index eb18bc40a5..d7950487ca 100644 --- a/java-lite/pom.xml +++ b/java-lite/pom.xml @@ -1,7 +1,6 @@ - + 4.0.0 org.baeldung @@ -22,10 +21,15 @@ 5.1.45 1.7.0 1.8.2 - 4.11 + 4.12 + + + src/main/webapp/WEB-INF + + org.eclipse.jetty @@ -85,7 +89,14 @@ system ${java.home}/../lib/tools.jar - + + + org.javalite + activeweb-testing + 1.15 + test + + junit junit diff --git a/java-lite/src/main/java/app/config/AppBootstrap.java b/java-lite/src/main/java/app/config/AppBootstrap.java index 7a87c2d0a7..02c8360986 100644 --- a/java-lite/src/main/java/app/config/AppBootstrap.java +++ b/java-lite/src/main/java/app/config/AppBootstrap.java @@ -3,7 +3,15 @@ package app.config; import org.javalite.activeweb.AppContext; import org.javalite.activeweb.Bootstrap; +import com.google.inject.Guice; +import com.google.inject.Injector; + +import app.services.ArticleServiceModule; + public class AppBootstrap extends Bootstrap { public void init(AppContext context) { } + public Injector getInjector() { + return Guice.createInjector(new ArticleServiceModule()); + } } diff --git a/java-lite/src/main/java/app/controllers/ArticleController.java b/java-lite/src/main/java/app/controllers/ArticleController.java new file mode 100755 index 0000000000..2b8dc452bd --- /dev/null +++ b/java-lite/src/main/java/app/controllers/ArticleController.java @@ -0,0 +1,28 @@ +package app.controllers; + +import javax.inject.Inject; + +import org.javalite.activeweb.AppController; + +import app.services.ArticleService; + +public class ArticleController extends AppController { + + @Inject + private ArticleService articleService; + + public void index() { + view("articles", articleService.getArticles()); + } + + public void search() { + + String keyword = param("key"); + if (null != keyword) { + assign("article", articleService.search(keyword)); + } else { + render("/common/error"); + } + + } +} diff --git a/java-lite/src/main/java/app/controllers/HomeController.java b/java-lite/src/main/java/app/controllers/HomeController.java new file mode 100755 index 0000000000..0e284af0ad --- /dev/null +++ b/java-lite/src/main/java/app/controllers/HomeController.java @@ -0,0 +1,11 @@ +package app.controllers; + +import org.javalite.activeweb.AppController; + +public class HomeController extends AppController { + + public void index() { + render("index"); + } + +} diff --git a/java-lite/src/main/java/app/models/Article.java b/java-lite/src/main/java/app/models/Article.java new file mode 100755 index 0000000000..db318f4468 --- /dev/null +++ b/java-lite/src/main/java/app/models/Article.java @@ -0,0 +1,50 @@ +package app.models; + +public class Article { + + private String title; + private String author; + private String words; + private String date; + + public Article(String title, String author, String words, String date) { + super(); + this.title = title; + this.author = author; + this.words = words; + this.date = date; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public String getWords() { + return words; + } + + public void setWords(String words) { + this.words = words; + } + + public String getDate() { + return date; + } + + public void setDate(String date) { + this.date = date; + } + +} \ No newline at end of file diff --git a/java-lite/src/main/java/app/services/ArticleService.java b/java-lite/src/main/java/app/services/ArticleService.java new file mode 100755 index 0000000000..ddd0b3ed10 --- /dev/null +++ b/java-lite/src/main/java/app/services/ArticleService.java @@ -0,0 +1,13 @@ +package app.services; + +import java.util.List; + +import app.models.Article; + +public interface ArticleService { + + List
getArticles(); + + Article search(String keyword); + +} diff --git a/java-lite/src/main/java/app/services/ArticleServiceImpl.java b/java-lite/src/main/java/app/services/ArticleServiceImpl.java new file mode 100755 index 0000000000..fc81576f91 --- /dev/null +++ b/java-lite/src/main/java/app/services/ArticleServiceImpl.java @@ -0,0 +1,34 @@ +package app.services; + +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; + +import app.models.Article; + +public class ArticleServiceImpl implements ArticleService { + + public List
getArticles() { + return fetchArticles(); + } + + public Article search(String keyword) { + Article ar = new Article("Article with " + keyword, "baeldung", "1250", Instant.now() + .toString()); + return ar; + } + + private List
fetchArticles() { + Article ar1 = new Article("Introduction to ActiveWeb", "baeldung", "1650", Instant.now() + .toString()); + + Article ar = new Article("Introduction to Mule", "baeldung", "1650", Instant.now() + .toString()); + List
articles = new ArrayList
(); + articles.add(ar); + articles.add(ar1); + return articles; + + } + +} diff --git a/java-lite/src/main/java/app/services/ArticleServiceModule.java b/java-lite/src/main/java/app/services/ArticleServiceModule.java new file mode 100755 index 0000000000..feae2a2ff7 --- /dev/null +++ b/java-lite/src/main/java/app/services/ArticleServiceModule.java @@ -0,0 +1,12 @@ +package app.services; + +import com.google.inject.AbstractModule; + +public class ArticleServiceModule extends AbstractModule { + + @Override + protected void configure() { + bind(ArticleService.class).to(ArticleServiceImpl.class) + .asEagerSingleton(); + } +} diff --git a/java-lite/src/main/webapp/WEB-INF/views/article/index.ftl b/java-lite/src/main/webapp/WEB-INF/views/article/index.ftl new file mode 100755 index 0000000000..2d5f211427 --- /dev/null +++ b/java-lite/src/main/webapp/WEB-INF/views/article/index.ftl @@ -0,0 +1,18 @@ +<@content for="title">Articles + + + + + + + + +<#list articles as article> + + + + + + + +
TitleAuthorWords #Date Published
${article.title}${article.author}${article.words}${article.date}
\ No newline at end of file diff --git a/java-lite/src/main/webapp/WEB-INF/views/article/search.ftl b/java-lite/src/main/webapp/WEB-INF/views/article/search.ftl new file mode 100755 index 0000000000..45a73808ed --- /dev/null +++ b/java-lite/src/main/webapp/WEB-INF/views/article/search.ftl @@ -0,0 +1,17 @@ +<@content for="title">Search + + + + + + + + + + + + + + + +
TitleAuthorWords #Date Published
${article.title}${article.author}${article.words}${article.date}
\ No newline at end of file diff --git a/java-lite/src/main/webapp/WEB-INF/views/common/error.ftl b/java-lite/src/main/webapp/WEB-INF/views/common/error.ftl new file mode 100755 index 0000000000..5fbf3c5243 --- /dev/null +++ b/java-lite/src/main/webapp/WEB-INF/views/common/error.ftl @@ -0,0 +1,3 @@ +<@content for="title">Simple Web App + +

Application error

diff --git a/java-lite/src/main/webapp/WEB-INF/views/home/index.ftl b/java-lite/src/main/webapp/WEB-INF/views/home/index.ftl new file mode 100755 index 0000000000..ae6a7c56a5 --- /dev/null +++ b/java-lite/src/main/webapp/WEB-INF/views/home/index.ftl @@ -0,0 +1,3 @@ +<@content for="title">Simple Web App + +

Baeldung ActiveWeb Demo Application

diff --git a/java-lite/src/main/webapp/WEB-INF/views/layouts/default_layout.ftl b/java-lite/src/main/webapp/WEB-INF/views/layouts/default_layout.ftl new file mode 100755 index 0000000000..2985e56278 --- /dev/null +++ b/java-lite/src/main/webapp/WEB-INF/views/layouts/default_layout.ftl @@ -0,0 +1,16 @@ +<#setting url_escaping_charset='ISO-8859-1'> + + + + + + +
+<#include "header.ftl" > +
+ ${page_content} +
+<#include "footer.ftl" > +
+ + diff --git a/java-lite/src/main/webapp/WEB-INF/views/layouts/footer.ftl b/java-lite/src/main/webapp/WEB-INF/views/layouts/footer.ftl new file mode 100755 index 0000000000..1408547424 --- /dev/null +++ b/java-lite/src/main/webapp/WEB-INF/views/layouts/footer.ftl @@ -0,0 +1,3 @@ + diff --git a/java-lite/src/main/webapp/WEB-INF/views/layouts/header.ftl b/java-lite/src/main/webapp/WEB-INF/views/layouts/header.ftl new file mode 100755 index 0000000000..8187435035 --- /dev/null +++ b/java-lite/src/main/webapp/WEB-INF/views/layouts/header.ftl @@ -0,0 +1,4 @@ + + diff --git a/java-lite/src/main/webapp/WEB-INF/web.xml b/java-lite/src/main/webapp/WEB-INF/web.xml index c285876c86..23bb8b865e 100644 --- a/java-lite/src/main/webapp/WEB-INF/web.xml +++ b/java-lite/src/main/webapp/WEB-INF/web.xml @@ -6,6 +6,10 @@ dispatcher org.javalite.activeweb.RequestDispatcher + + root_controller + home + exclusions css,images,js,ico diff --git a/java-lite/src/test/java/app/controllers/ArticleControllerSpec.java b/java-lite/src/test/java/app/controllers/ArticleControllerSpec.java new file mode 100755 index 0000000000..882441dad3 --- /dev/null +++ b/java-lite/src/test/java/app/controllers/ArticleControllerSpec.java @@ -0,0 +1,31 @@ +package app.controllers; + +import org.javalite.activeweb.ControllerSpec; +import org.junit.Before; +import org.junit.Test; + +import com.google.inject.Guice; + +import app.services.ArticleServiceModule; + +public class ArticleControllerSpec extends ControllerSpec { + + @Before + public void before() { + setInjector(Guice.createInjector(new ArticleServiceModule())); + } + + @Test + public void whenReturnedArticlesThenCorrect() { + request().get("index"); + a(responseContent()).shouldContain("Introduction to Mule"); + } + + @Test + public void givenKeywordWhenFoundArticleThenCorrect() { + request().param("key", "Java") + .get("search"); + a(responseContent()).shouldContain("Article with Java"); + } + +} diff --git a/javax-servlets/src/main/java/com/baeldung/controller/StudentServlet.java b/javax-servlets/src/main/java/com/baeldung/controller/StudentServlet.java new file mode 100644 index 0000000000..b1924198a4 --- /dev/null +++ b/javax-servlets/src/main/java/com/baeldung/controller/StudentServlet.java @@ -0,0 +1,39 @@ +package com.baeldung.controller; + +import com.baeldung.service.StudentService; + +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 java.io.IOException; + +@WebServlet(name = "StudentServlet", urlPatterns = "/student-record") +public class StudentServlet extends HttpServlet { + + private final StudentService studentService = new StudentService(); + + private void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + String studentID = request.getParameter("id"); + if (studentID != null) { + int id = Integer.parseInt(studentID); + studentService.getStudent(id) + .ifPresent(s -> request.setAttribute("studentRecord", s)); + } + + 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); + } +} diff --git a/javax-servlets/src/main/java/com/baeldung/model/Student.java b/javax-servlets/src/main/java/com/baeldung/model/Student.java new file mode 100644 index 0000000000..ce8a27375a --- /dev/null +++ b/javax-servlets/src/main/java/com/baeldung/model/Student.java @@ -0,0 +1,39 @@ +package com.baeldung.model; + +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; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } +} diff --git a/javax-servlets/src/main/java/com/baeldung/service/StudentService.java b/javax-servlets/src/main/java/com/baeldung/service/StudentService.java new file mode 100644 index 0000000000..525d47683f --- /dev/null +++ b/javax-servlets/src/main/java/com/baeldung/service/StudentService.java @@ -0,0 +1,21 @@ +package com.baeldung.service; + +import com.baeldung.model.Student; + +import java.util.Optional; + +public class StudentService { + + public Optional getStudent(int id) { + switch (id) { + case 1: + return Optional.of(new Student(1, "John", "Doe")); + case 2: + return Optional.of(new Student(2, "Jane", "Goodall")); + case 3: + return Optional.of(new Student(3, "Max", "Born")); + default: + return Optional.empty(); + } + } +} diff --git a/javax-servlets/src/main/java/com/baeldung/servlets/FormServlet.java b/javax-servlets/src/main/java/com/baeldung/servlets/FormServlet.java index fcd9143dff..c78129a9cf 100644 --- a/javax-servlets/src/main/java/com/baeldung/servlets/FormServlet.java +++ b/javax-servlets/src/main/java/com/baeldung/servlets/FormServlet.java @@ -1,7 +1,6 @@ package com.baeldung.servlets; import javax.servlet.RequestDispatcher; -import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; @@ -13,7 +12,7 @@ public class FormServlet extends HttpServlet { @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) - throws ServletException, IOException { + throws IOException { String height = request.getParameter("height"); String weight = request.getParameter("weight"); @@ -25,23 +24,20 @@ 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) { - response.sendRedirect("index.jsp"); } } @Override - protected void doGet(HttpServletRequest request, HttpServletResponse response) - throws ServletException, IOException { + protected void doGet(HttpServletRequest request, HttpServletResponse response) { // do something else here } private Double calculateBMI(Double weight, Double height) { - return weight / (height * height); } } \ No newline at end of file diff --git a/javax-servlets/web/index.jsp b/javax-servlets/src/main/webapp/WEB-INF/jsp/index.jsp similarity index 100% rename from javax-servlets/web/index.jsp rename to javax-servlets/src/main/webapp/WEB-INF/jsp/index.jsp diff --git a/javax-servlets/src/main/webapp/WEB-INF/jsp/student-record.jsp b/javax-servlets/src/main/webapp/WEB-INF/jsp/student-record.jsp new file mode 100644 index 0000000000..4b9d9b378f --- /dev/null +++ b/javax-servlets/src/main/webapp/WEB-INF/jsp/student-record.jsp @@ -0,0 +1,36 @@ +<%@ page language="java" contentType="text/html; charset=ISO-8859-1" + pageEncoding="ISO-8859-1"%> + +<%@ page import="com.baeldung.model.Student"%> + + + + +Student Record + + + <% + if (request.getAttribute("studentRecord") != null) { + Student student = (Student) request.getAttribute("studentRecord"); + %> + +

Student Record

+
+ ID: + <%=student.getId()%>
+
+ First Name: + <%=student.getFirstName()%>
+
+ Last Name: + <%=student.getLastName()%>
+ + <% + } else { + %> +

No student record found.

+ <% + } + %> + + \ No newline at end of file diff --git a/javax-servlets/web/WEB-INF/web.xml b/javax-servlets/src/main/webapp/WEB-INF/web.xml similarity index 100% rename from javax-servlets/web/WEB-INF/web.xml rename to javax-servlets/src/main/webapp/WEB-INF/web.xml diff --git a/javaxval/pom.xml b/javaxval/pom.xml index 6a83a25f01..a05ee43aaf 100644 --- a/javaxval/pom.xml +++ b/javaxval/pom.xml @@ -6,10 +6,11 @@ 0.1-SNAPSHOT - 2.0.0.Final - 6.0.2.Final + 2.0.1.Final + 6.0.7.Final 3.0.0 2.2.6 + 5.0.2.RELEASE @@ -21,12 +22,6 @@ - - javax.validation - validation-api - ${validation-api.version} - - org.hibernate hibernate-validator @@ -50,6 +45,16 @@ javax.el ${javax.el.version} + + org.springframework + spring-context + ${org.springframework.version} + + + org.springframework + spring-test + ${org.springframework.version} + diff --git a/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/MethodValidationConfig.java b/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/MethodValidationConfig.java new file mode 100644 index 0000000000..206a145337 --- /dev/null +++ b/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/MethodValidationConfig.java @@ -0,0 +1,38 @@ +package org.baeldung.javaxval.methodvalidation; + +import org.baeldung.javaxval.methodvalidation.model.Customer; +import org.baeldung.javaxval.methodvalidation.model.Reservation; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Scope; +import org.springframework.validation.beanvalidation.MethodValidationPostProcessor; + +import java.time.LocalDate; + +@Configuration +@ComponentScan({ "org.baeldung.javaxval.methodvalidation.model" }) +public class MethodValidationConfig { + + @Bean + public MethodValidationPostProcessor methodValidationPostProcessor() { + return new MethodValidationPostProcessor(); + } + + @Bean("customer") + @Scope(BeanDefinition.SCOPE_PROTOTYPE) + public Customer customer(String firstName, String lastName) { + + Customer customer = new Customer(firstName, lastName); + return customer; + } + + @Bean("reservation") + @Scope(BeanDefinition.SCOPE_PROTOTYPE) + public Reservation reservation(LocalDate begin, LocalDate end, Customer customer, int room) { + + Reservation reservation = new Reservation(begin, end, customer, room); + return reservation; + } +} diff --git a/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/constraints/ConsistentDateParameterValidator.java b/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/constraints/ConsistentDateParameterValidator.java new file mode 100644 index 0000000000..f1c97760d7 --- /dev/null +++ b/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/constraints/ConsistentDateParameterValidator.java @@ -0,0 +1,25 @@ +package org.baeldung.javaxval.methodvalidation.constraints; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; +import javax.validation.constraintvalidation.SupportedValidationTarget; +import javax.validation.constraintvalidation.ValidationTarget; +import java.time.LocalDate; + +@SupportedValidationTarget(ValidationTarget.PARAMETERS) +public class ConsistentDateParameterValidator implements ConstraintValidator { + + @Override + public boolean isValid(Object[] value, ConstraintValidatorContext context) { + + if (value[0] == null || value[1] == null) { + return true; + } + + if (!(value[0] instanceof LocalDate) || !(value[1] instanceof LocalDate)) { + throw new IllegalArgumentException("Illegal method signature, expected two parameters of type LocalDate."); + } + + return ((LocalDate) value[0]).isAfter(LocalDate.now()) && ((LocalDate) value[0]).isBefore((LocalDate) value[1]); + } +} diff --git a/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/constraints/ConsistentDateParameters.java b/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/constraints/ConsistentDateParameters.java new file mode 100644 index 0000000000..6b321f545c --- /dev/null +++ b/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/constraints/ConsistentDateParameters.java @@ -0,0 +1,23 @@ +package org.baeldung.javaxval.methodvalidation.constraints; + +import javax.validation.Constraint; +import javax.validation.Payload; +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +@Constraint(validatedBy = ConsistentDateParameterValidator.class) +@Target({ METHOD, CONSTRUCTOR }) +@Retention(RUNTIME) +@Documented +public @interface ConsistentDateParameters { + + String message() default "End date must be after begin date and both must be in the future"; + + Class[] groups() default {}; + + Class[] payload() default {}; +} diff --git a/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/constraints/ValidReservation.java b/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/constraints/ValidReservation.java new file mode 100644 index 0000000000..f9cdea1483 --- /dev/null +++ b/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/constraints/ValidReservation.java @@ -0,0 +1,24 @@ +package org.baeldung.javaxval.methodvalidation.constraints; + +import javax.validation.Constraint; +import javax.validation.Payload; +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.CONSTRUCTOR; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +@Constraint(validatedBy = ValidReservationValidator.class) +@Target({ METHOD, CONSTRUCTOR }) +@Retention(RUNTIME) +@Documented +public @interface ValidReservation { + + String message() default "End date must be after begin date and both must be in the future, room number must be bigger than 0"; + + Class[] groups() default {}; + + Class[] payload() default {}; +} diff --git a/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/constraints/ValidReservationValidator.java b/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/constraints/ValidReservationValidator.java new file mode 100644 index 0000000000..7b730480ed --- /dev/null +++ b/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/constraints/ValidReservationValidator.java @@ -0,0 +1,32 @@ +package org.baeldung.javaxval.methodvalidation.constraints; + +import org.baeldung.javaxval.methodvalidation.model.Reservation; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; +import java.time.LocalDate; + +public class ValidReservationValidator implements ConstraintValidator { + + @Override + public boolean isValid(Reservation reservation, ConstraintValidatorContext context) { + + if (reservation == null) { + return true; + } + + if (!(reservation instanceof Reservation)) { + throw new IllegalArgumentException("Illegal method signature, expected parameter of type Reservation."); + } + + if (reservation.getBegin() == null || reservation.getEnd() == null || reservation.getCustomer() == null) { + return false; + } + + return (reservation.getBegin() + .isAfter(LocalDate.now()) + && reservation.getBegin() + .isBefore(reservation.getEnd()) + && reservation.getRoom() > 0); + } +} diff --git a/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/model/Customer.java b/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/model/Customer.java new file mode 100644 index 0000000000..fe9ad7080e --- /dev/null +++ b/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/model/Customer.java @@ -0,0 +1,41 @@ +package org.baeldung.javaxval.methodvalidation.model; + +import org.springframework.validation.annotation.Validated; + +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +@Validated +public class Customer { + + @Size(min = 5, max = 200) + private String firstName; + + @Size(min = 5, max = 200) + private String lastName; + + public Customer(@Size(min = 5, max = 200) @NotNull String firstName, @Size(min = 5, max = 200) @NotNull String lastName) { + this.firstName = firstName; + this.lastName = lastName; + } + + public Customer() { + + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } +} diff --git a/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/model/Reservation.java b/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/model/Reservation.java new file mode 100644 index 0000000000..a8c01d2be1 --- /dev/null +++ b/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/model/Reservation.java @@ -0,0 +1,64 @@ +package org.baeldung.javaxval.methodvalidation.model; + +import org.baeldung.javaxval.methodvalidation.constraints.ConsistentDateParameters; +import org.baeldung.javaxval.methodvalidation.constraints.ValidReservation; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import javax.validation.constraints.Positive; +import java.time.LocalDate; + +@Validated +public class Reservation { + + private LocalDate begin; + + private LocalDate end; + + @Valid + private Customer customer; + + @Positive + private int room; + + @ConsistentDateParameters + @ValidReservation + public Reservation(LocalDate begin, LocalDate end, Customer customer, int room) { + this.begin = begin; + this.end = end; + this.customer = customer; + this.room = room; + } + + public LocalDate getBegin() { + return begin; + } + + public void setBegin(LocalDate begin) { + this.begin = begin; + } + + public LocalDate getEnd() { + return end; + } + + public void setEnd(LocalDate end) { + this.end = end; + } + + public Customer getCustomer() { + return customer; + } + + public void setCustomer(Customer customer) { + this.customer = customer; + } + + public int getRoom() { + return room; + } + + public void setRoom(int room) { + this.room = room; + } +} diff --git a/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/model/ReservationManagement.java b/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/model/ReservationManagement.java new file mode 100644 index 0000000000..f6fec1a15d --- /dev/null +++ b/javaxval/src/main/java/org/baeldung/javaxval/methodvalidation/model/ReservationManagement.java @@ -0,0 +1,50 @@ +package org.baeldung.javaxval.methodvalidation.model; + +import org.baeldung.javaxval.methodvalidation.constraints.ConsistentDateParameters; +import org.baeldung.javaxval.methodvalidation.constraints.ValidReservation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Controller; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import javax.validation.constraints.*; +import java.time.LocalDate; +import java.util.List; + +@Controller +@Validated +public class ReservationManagement { + + @Autowired + private ApplicationContext applicationContext; + + @ConsistentDateParameters + public void createReservation(LocalDate begin, LocalDate end, @NotNull Customer customer) { + + // ... + } + + public void createReservation(@NotNull @Future LocalDate begin, @Min(1) int duration, @NotNull Customer customer) { + + // ... + } + + public void createReservation(@Valid Reservation reservation) { + + // ... + } + + @NotNull + @Size(min = 1) + public List<@NotNull Customer> getAllCustomers() { + + return null; + } + + @Valid + public Reservation getReservationById(int id) { + + return null; + } +} diff --git a/javaxval/src/test/java/org/baeldung/javaxval/methodvalidation/ContainerValidationIntegrationTest.java b/javaxval/src/test/java/org/baeldung/javaxval/methodvalidation/ContainerValidationIntegrationTest.java new file mode 100644 index 0000000000..2363bf8f5d --- /dev/null +++ b/javaxval/src/test/java/org/baeldung/javaxval/methodvalidation/ContainerValidationIntegrationTest.java @@ -0,0 +1,97 @@ +package org.baeldung.javaxval.methodvalidation; + +import org.baeldung.javaxval.methodvalidation.model.Customer; +import org.baeldung.javaxval.methodvalidation.model.Reservation; +import org.baeldung.javaxval.methodvalidation.model.ReservationManagement; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.support.AnnotationConfigContextLoader; + +import javax.validation.ConstraintViolationException; +import java.time.LocalDate; +import java.util.List; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = { MethodValidationConfig.class }, loader = AnnotationConfigContextLoader.class) +public class ContainerValidationIntegrationTest { + + @Autowired + ReservationManagement reservationManagement; + + @Rule + public final ExpectedException exception = ExpectedException.none(); + + @Test + public void whenValidationWithInvalidMethodParameters_thenConstraintViolationException() { + + exception.expect(ConstraintViolationException.class); + reservationManagement.createReservation(LocalDate.now(), 0, null); + } + + @Test + public void whenValidationWithValidMethodParameters_thenNoException() { + + reservationManagement.createReservation(LocalDate.now() + .plusDays(1), 1, new Customer("William", "Smith")); + } + + @Test + public void whenCrossParameterValidationWithInvalidParameters_thenConstraintViolationException() { + + exception.expect(ConstraintViolationException.class); + reservationManagement.createReservation(LocalDate.now(), LocalDate.now(), null); + } + + @Test + public void whenCrossParameterValidationWithValidParameters_thenNoException() { + + reservationManagement.createReservation(LocalDate.now() + .plusDays(1), + LocalDate.now() + .plusDays(2), + new Customer("William", "Smith")); + } + + @Test + public void whenValidationWithInvalidReturnValue_thenConstraintViolationException() { + + exception.expect(ConstraintViolationException.class); + List list = reservationManagement.getAllCustomers(); + } + + @Test + public void whenValidationWithInvalidCascadedValue_thenConstraintViolationException() { + + Customer customer = new Customer(); + customer.setFirstName("John"); + customer.setLastName("Doe"); + Reservation reservation = new Reservation(LocalDate.now() + .plusDays(1), + LocalDate.now() + .plusDays(2), + customer, 1); + + exception.expect(ConstraintViolationException.class); + reservationManagement.createReservation(reservation); + } + + @Test + public void whenValidationWithValidCascadedValue_thenCNoException() { + + Customer customer = new Customer(); + customer.setFirstName("William"); + customer.setLastName("Smith"); + Reservation reservation = new Reservation(LocalDate.now() + .plusDays(1), + LocalDate.now() + .plusDays(2), + customer, 1); + + reservationManagement.createReservation(reservation); + } +} diff --git a/javaxval/src/test/java/org/baeldung/javaxval/methodvalidation/ValidationIntegrationTest.java b/javaxval/src/test/java/org/baeldung/javaxval/methodvalidation/ValidationIntegrationTest.java new file mode 100644 index 0000000000..6b53d3a107 --- /dev/null +++ b/javaxval/src/test/java/org/baeldung/javaxval/methodvalidation/ValidationIntegrationTest.java @@ -0,0 +1,209 @@ +package org.baeldung.javaxval.methodvalidation; + +import org.baeldung.javaxval.methodvalidation.model.Customer; +import org.baeldung.javaxval.methodvalidation.model.Reservation; +import org.baeldung.javaxval.methodvalidation.model.ReservationManagement; +import org.junit.Before; +import org.junit.Test; +import static org.junit.Assert.*; + +import javax.validation.ConstraintViolation; +import javax.validation.Validation; +import javax.validation.ValidatorFactory; +import javax.validation.executable.ExecutableValidator; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.time.LocalDate; +import java.util.Collections; +import java.util.Set; + +public class ValidationIntegrationTest { + + private ExecutableValidator executableValidator; + + @Before + public void getExecutableValidator() { + + ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); + this.executableValidator = factory.getValidator() + .forExecutables(); + } + + @Test + public void whenValidationWithInvalidMethodParameters_thenCorrectNumberOfVoilations() throws NoSuchMethodException { + + ReservationManagement object = new ReservationManagement(); + Method method = ReservationManagement.class.getMethod("createReservation", LocalDate.class, int.class, Customer.class); + Object[] parameterValues = { LocalDate.now(), 0, null }; + Set> violations = executableValidator.validateParameters(object, method, parameterValues); + + assertEquals(3, violations.size()); + } + + @Test + public void whenValidationWithValidMethodParameters_thenZeroVoilations() throws NoSuchMethodException { + + ReservationManagement object = new ReservationManagement(); + Method method = ReservationManagement.class.getMethod("createReservation", LocalDate.class, int.class, Customer.class); + Object[] parameterValues = { LocalDate.now() + .plusDays(1), 1, new Customer("John", "Doe") }; + Set> violations = executableValidator.validateParameters(object, method, parameterValues); + + assertEquals(0, violations.size()); + } + + @Test + public void whenCrossParameterValidationWithInvalidParameters_thenCorrectNumberOfVoilations() throws NoSuchMethodException { + + ReservationManagement object = new ReservationManagement(); + Method method = ReservationManagement.class.getMethod("createReservation", LocalDate.class, LocalDate.class, Customer.class); + Object[] parameterValues = { LocalDate.now(), LocalDate.now(), new Customer("John", "Doe") }; + Set> violations = executableValidator.validateParameters(object, method, parameterValues); + + assertEquals(1, violations.size()); + } + + @Test + public void whenCrossParameterValidationWithValidParameters_thenZeroVoilations() throws NoSuchMethodException { + + ReservationManagement object = new ReservationManagement(); + Method method = ReservationManagement.class.getMethod("createReservation", LocalDate.class, LocalDate.class, Customer.class); + Object[] parameterValues = { LocalDate.now() + .plusDays(1), + LocalDate.now() + .plusDays(2), + new Customer("John", "Doe") }; + Set> violations = executableValidator.validateParameters(object, method, parameterValues); + + assertEquals(0, violations.size()); + } + + @Test + public void whenValidationWithInvalidConstructorParameters_thenCorrectNumberOfVoilations() throws NoSuchMethodException { + + Constructor constructor = Customer.class.getConstructor(String.class, String.class); + Object[] parameterValues = { "John", "Doe" }; + Set> violations = executableValidator.validateConstructorParameters(constructor, parameterValues); + + assertEquals(2, violations.size()); + } + + @Test + public void whenValidationWithValidConstructorParameters_thenZeroVoilations() throws NoSuchMethodException { + + Constructor constructor = Customer.class.getConstructor(String.class, String.class); + Object[] parameterValues = { "William", "Smith" }; + Set> violations = executableValidator.validateConstructorParameters(constructor, parameterValues); + + assertEquals(0, violations.size()); + } + + @Test + public void whenCrossParameterValidationWithInvalidConstructorParameters_thenCorrectNumberOfVoilations() throws NoSuchMethodException { + + Constructor constructor = Reservation.class.getConstructor(LocalDate.class, LocalDate.class, Customer.class, int.class); + Object[] parameterValues = { LocalDate.now(), LocalDate.now(), new Customer("William", "Smith"), 1 }; + Set> violations = executableValidator.validateConstructorParameters(constructor, parameterValues); + + assertEquals(1, violations.size()); + } + + @Test + public void whenCrossParameterValidationWithValidConstructorParameters_thenZeroVoilations() throws NoSuchMethodException { + + Constructor constructor = Reservation.class.getConstructor(LocalDate.class, LocalDate.class, Customer.class, int.class); + Object[] parameterValues = { LocalDate.now() + .plusDays(1), + LocalDate.now() + .plusDays(2), + new Customer("William", "Smith"), 1 }; + Set> violations = executableValidator.validateConstructorParameters(constructor, parameterValues); + + assertEquals(0, violations.size()); + } + + @Test + public void whenValidationWithInvalidReturnValue_thenCorrectNumberOfVoilations() throws NoSuchMethodException { + + ReservationManagement object = new ReservationManagement(); + Method method = ReservationManagement.class.getMethod("getAllCustomers"); + Object returnValue = Collections. emptyList(); + Set> violations = executableValidator.validateReturnValue(object, method, returnValue); + + assertEquals(1, violations.size()); + } + + @Test + public void whenValidationWithValidReturnValue_thenZeroVoilations() throws NoSuchMethodException { + + ReservationManagement object = new ReservationManagement(); + Method method = ReservationManagement.class.getMethod("getAllCustomers"); + Object returnValue = Collections.singletonList(new Customer("William", "Smith")); + Set> violations = executableValidator.validateReturnValue(object, method, returnValue); + + assertEquals(0, violations.size()); + } + + @Test + public void whenValidationWithInvalidConstructorReturnValue_thenCorrectNumberOfVoilations() throws NoSuchMethodException { + + Constructor constructor = Reservation.class.getConstructor(LocalDate.class, LocalDate.class, Customer.class, int.class); + Reservation createdObject = new Reservation(LocalDate.now(), LocalDate.now(), new Customer("William", "Smith"), 0); + Set> violations = executableValidator.validateConstructorReturnValue(constructor, createdObject); + + assertEquals(1, violations.size()); + } + + @Test + public void whenValidationWithValidConstructorReturnValue_thenZeroVoilations() throws NoSuchMethodException { + + Constructor constructor = Reservation.class.getConstructor(LocalDate.class, LocalDate.class, Customer.class, int.class); + Reservation createdObject = new Reservation(LocalDate.now() + .plusDays(1), + LocalDate.now() + .plusDays(2), + new Customer("William", "Smith"), 1); + Set> violations = executableValidator.validateConstructorReturnValue(constructor, createdObject); + + assertEquals(0, violations.size()); + } + + @Test + public void whenValidationWithInvalidCascadedValue_thenCorrectNumberOfVoilations() throws NoSuchMethodException { + + ReservationManagement object = new ReservationManagement(); + Method method = ReservationManagement.class.getMethod("createReservation", Reservation.class); + Customer customer = new Customer(); + customer.setFirstName("John"); + customer.setLastName("Doe"); + Reservation reservation = new Reservation(LocalDate.now() + .plusDays(1), + LocalDate.now() + .plusDays(2), + customer, 1); + Object[] parameterValues = { reservation }; + Set> violations = executableValidator.validateParameters(object, method, parameterValues); + + assertEquals(2, violations.size()); + } + + @Test + public void whenValidationWithValidCascadedValue_thenCorrectNumberOfVoilations() throws NoSuchMethodException { + + ReservationManagement object = new ReservationManagement(); + Method method = ReservationManagement.class.getMethod("createReservation", Reservation.class); + Customer customer = new Customer(); + customer.setFirstName("William"); + customer.setLastName("Smith"); + Reservation reservation = new Reservation(LocalDate.now() + .plusDays(1), + LocalDate.now() + .plusDays(2), + customer, 1); + Object[] parameterValues = { reservation }; + Set> violations = executableValidator.validateParameters(object, method, parameterValues); + + assertEquals(0, violations.size()); + } + +} diff --git a/jgroups/README.md b/jgroups/README.md new file mode 100644 index 0000000000..bb2813c3d6 --- /dev/null +++ b/jgroups/README.md @@ -0,0 +1,15 @@ +## Reliable Messaging with JGroups Tutorial Project + +### Relevant Article: +- [Reliable Messaging with JGroups](http://www.baeldung.com/reliable-messaging-with-jgroups/) + +### Overview +This Maven project contains the Java code for the article linked above. + +### Package Organization +Java classes for the intro tutorial are in the org.baeldung.jgroups package. + + +### Running the tests + +``` diff --git a/jgroups/pom.xml b/jgroups/pom.xml new file mode 100644 index 0000000000..0e5971875e --- /dev/null +++ b/jgroups/pom.xml @@ -0,0 +1,36 @@ + + + 4.0.0 + jgroups + 0.1-SNAPSHOT + jar + jgroups + Reliable Messaging with JGroups Tutorial + + + com.baeldung + parent-modules + 1.0.0-SNAPSHOT + + + + + org.jgroups + jgroups + 4.0.10.Final + + + + commons-cli + commons-cli + 1.4 + + + + + 1.8 + UTF-8 + + + diff --git a/jgroups/src/main/java/com/baeldung/jgroups/JGroupsMessenger.java b/jgroups/src/main/java/com/baeldung/jgroups/JGroupsMessenger.java new file mode 100644 index 0000000000..70eacabf1e --- /dev/null +++ b/jgroups/src/main/java/com/baeldung/jgroups/JGroupsMessenger.java @@ -0,0 +1,212 @@ +package com.baeldung.jgroups; + +import org.apache.commons.cli.*; +import org.jgroups.*; +import org.jgroups.util.Util; + +import java.io.*; +import java.util.List; +import java.util.Optional; + +public class JGroupsMessenger extends ReceiverAdapter { + + private JChannel channel; + private String userName; + private String clusterName; + private View lastView; + private boolean running = true; + + // Our shared state + private Integer messageCount = 0; + + /** + * Connect to a JGroups cluster using command line options + * @param args command line arguments + * @throws Exception + */ + private void start(String[] args) throws Exception { + processCommandline(args); + + // Create the channel + // This file could be moved, or made a command line option. + channel = new JChannel("src/main/resources/udp.xml"); + + // Set a name + channel.name(userName); + + // Register for callbacks + channel.setReceiver(this); + + // Ignore our messages + channel.setDiscardOwnMessages(true); + + // Connect + channel.connect(clusterName); + + // Start state transfer + channel.getState(null, 0); + + // Do the things + processInput(); + + // Clean up + channel.close(); + + } + + /** + * Quick and dirty implementaton of commons cli for command line args + * @param args the command line args + * @throws ParseException + */ + private void processCommandline(String[] args) throws ParseException { + + // Options, parser, friendly help + Options options = new Options(); + CommandLineParser parser = new DefaultParser(); + HelpFormatter formatter = new HelpFormatter(); + + options.addOption("u", "user", true, "User name") + .addOption("c", "cluster", true, "Cluster name"); + + CommandLine line = parser.parse(options, args); + + if (line.hasOption("user")) { + userName = line.getOptionValue("user"); + } else { + formatter.printHelp("JGroupsMessenger: need a user name.\n", options); + System.exit(-1); + } + + if (line.hasOption("cluster")) { + clusterName = line.getOptionValue("cluster"); + } else { + formatter.printHelp("JGroupsMessenger: need a cluster name.\n", options); + System.exit(-1); + } + } + + // Start it up + public static void main(String[] args) throws Exception { + new JGroupsMessenger().start(args); + } + + + @Override + public void viewAccepted(View newView) { + + // Save view if this is the first + if (lastView == null) { + System.out.println("Received initial view:"); + newView.forEach(System.out::println); + } else { + // Compare to last view + System.out.println("Received new view."); + + List
newMembers = View.newMembers(lastView, newView); + System.out.println("New members: "); + newMembers.forEach(System.out::println); + + List
exMembers = View.leftMembers(lastView, newView); + System.out.println("Exited members:"); + exMembers.forEach(System.out::println); + } + lastView = newView; + } + + /** + * Loop on console input until we see 'x' to exit + */ + private void processInput() throws Exception { + + BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); + while (running) { + try { + + // Get a destination, means broadcast + Address destination = null; + System.out.print("Enter a destination: "); + System.out.flush(); + String destinationName = in.readLine().toLowerCase(); + + if (destinationName.equals("x")) { + running = false; + continue; + } else if (!destinationName.isEmpty()) { + destination = getAddress(destinationName) + . orElseThrow(() -> new Exception("Destination not found")); + } + + // Accept a string to send + System.out.print("Enter a message: "); + System.out.flush(); + String line = in.readLine().toLowerCase(); + sendMessage(destination, line); + } catch (IOException ioe) { + running = false; + } + } + System.out.println("Exiting."); + } + + /** + * Send message from here + * @param destination the destination + * @param messageString the message + */ + private void sendMessage(Address destination, String messageString) { + try { + System.out.println("Sending " + messageString + " to " + destination); + Message message = new Message(destination, messageString); + channel.send(message); + } catch (Exception exception) { + System.err.println("Exception sending message: " + exception.getMessage()); + running = false; + } + } + + @Override + public void receive(Message message) { + // Print source and dest with message + String line = "Message received from: " + message.getSrc() + " to: " + message.getDest() + " -> " + message.getObject(); + + // Only track the count of broadcast messages + // Tracking direct message would make for a pointless state + if (message.getDest() == null) { + messageCount++; + System.out.println("Message count: " + messageCount); + } + + System.out.println(line); + } + + @Override + public void getState(OutputStream output) throws Exception { + // Serialize into the stream + Util.objectToStream(messageCount, new DataOutputStream(output)); + } + + @Override + public void setState(InputStream input) { + + // NOTE: since we know that incrementing the count and transferring the state + // is done inside the JChannel's thread, we don't have to worry about synchronizing + // messageCount. For production code it should be synchronized! + try { + // Deserialize + messageCount = Util.objectFromStream(new DataInputStream(input)); + } catch (Exception e) { + System.out.println("Error deserialing state!"); + } + System.out.println(messageCount + " is the current messagecount."); + } + + + private Optional
getAddress(String name) { + View view = channel.view(); + return view.getMembers().stream().filter(address -> name.equals(address.toString())).findFirst(); + } + +} + + diff --git a/jgroups/src/main/resources/udp.xml b/jgroups/src/main/resources/udp.xml new file mode 100644 index 0000000000..5a9bfd0851 --- /dev/null +++ b/jgroups/src/main/resources/udp.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + diff --git a/json/pom.xml b/json/pom.xml index 958dd32f53..7c74d425af 100644 --- a/json/pom.xml +++ b/json/pom.xml @@ -31,6 +31,11 @@ ${fastjson.version} + + org.json + json + 20171018 + diff --git a/json/src/main/java/com/baeldung/jsonjava/CDLDemo.java b/json/src/main/java/com/baeldung/jsonjava/CDLDemo.java new file mode 100644 index 0000000000..f5fee0c4a9 --- /dev/null +++ b/json/src/main/java/com/baeldung/jsonjava/CDLDemo.java @@ -0,0 +1,59 @@ +package com.baeldung.jsonjava; + +import org.json.CDL; +import org.json.JSONArray; +import org.json.JSONTokener; + +public class CDLDemo { + public static void main(String[] args) { + System.out.println("7.1. Producing JSONArray Directly from Comma Delimited Text: "); + jsonArrayFromCDT(); + + System.out.println("\n7.2. Producing Comma Delimited Text from JSONArray: "); + cDTfromJSONArray(); + + System.out.println("\n7.3.1. Producing JSONArray of JSONObjects Using Comma Delimited Text: "); + jaOfJOFromCDT2(); + + System.out.println("\n7.3.2. Producing JSONArray of JSONObjects Using Comma Delimited Text: "); + jaOfJOFromCDT2(); + } + + public static void jsonArrayFromCDT() { + JSONArray ja = CDL.rowToJSONArray(new JSONTokener("England, USA, Canada")); + System.out.println(ja); + } + + public static void cDTfromJSONArray() { + JSONArray ja = new JSONArray("[\"England\",\"USA\",\"Canada\"]"); + String cdt = CDL.rowToString(ja); + System.out.println(cdt); + } + + public static void jaOfJOFromCDT() { + String string = + "name, city, age \n" + + "john, chicago, 22 \n" + + "gary, florida, 35 \n" + + "sal, vegas, 18"; + + JSONArray result = CDL.toJSONArray(string); + System.out.println(result.toString()); + } + + public static void jaOfJOFromCDT2() { + JSONArray ja = new JSONArray(); + ja.put("name"); + ja.put("city"); + ja.put("age"); + + String string = + "john, chicago, 22 \n" + + "gary, florida, 35 \n" + + "sal, vegas, 18"; + + JSONArray result = CDL.toJSONArray(ja, string); + System.out.println(result.toString()); + } + +} diff --git a/json/src/main/java/com/baeldung/jsonjava/CookieDemo.java b/json/src/main/java/com/baeldung/jsonjava/CookieDemo.java new file mode 100644 index 0000000000..bc39d13642 --- /dev/null +++ b/json/src/main/java/com/baeldung/jsonjava/CookieDemo.java @@ -0,0 +1,30 @@ +package com.baeldung.jsonjava; + +import org.json.Cookie; +import org.json.JSONObject; + +public class CookieDemo { + public static void main(String[] args) { + System.out.println("8.1. Converting a Cookie String into a JSONObject"); + cookieStringToJSONObject(); + + System.out.println("\n8.2. Converting a JSONObject into Cookie String"); + jSONObjectToCookieString(); + } + + public static void cookieStringToJSONObject() { + String cookie = "username=John Doe; expires=Thu, 18 Dec 2013 12:00:00 UTC; path=/"; + JSONObject cookieJO = Cookie.toJSONObject(cookie); + System.out.println(cookieJO); + } + + public static void jSONObjectToCookieString() { + JSONObject cookieJO = new JSONObject(); + cookieJO.put("name", "username"); + cookieJO.put("value", "John Doe"); + cookieJO.put("expires", "Thu, 18 Dec 2013 12:00:00 UTC"); + cookieJO.put("path", "/"); + String cookie = Cookie.toString(cookieJO); + System.out.println(cookie); + } +} diff --git a/json/src/main/java/com/baeldung/jsonjava/DemoBean.java b/json/src/main/java/com/baeldung/jsonjava/DemoBean.java new file mode 100644 index 0000000000..6d27b329c2 --- /dev/null +++ b/json/src/main/java/com/baeldung/jsonjava/DemoBean.java @@ -0,0 +1,26 @@ +package com.baeldung.jsonjava; + +public class DemoBean { + private int id; + private String name; + private boolean active; + + public int getId() { + return id; + } + public void setId(int id) { + this.id = id; + } + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + public boolean isActive() { + return active; + } + public void setActive(boolean active) { + this.active = active; + } +} diff --git a/json/src/main/java/com/baeldung/jsonjava/HTTPDemo.java b/json/src/main/java/com/baeldung/jsonjava/HTTPDemo.java new file mode 100644 index 0000000000..800018005c --- /dev/null +++ b/json/src/main/java/com/baeldung/jsonjava/HTTPDemo.java @@ -0,0 +1,27 @@ +package com.baeldung.jsonjava; + +import org.json.HTTP; +import org.json.JSONObject; + +public class HTTPDemo { + public static void main(String[] args) { + System.out.println("9.1. Converting JSONObject to HTTP Header: "); + jSONObjectToHTTPHeader(); + + System.out.println("\n9.2. Converting HTTP Header String Back to JSONObject: "); + hTTPHeaderToJSONObject(); + } + + public static void jSONObjectToHTTPHeader() { + JSONObject jo = new JSONObject(); + jo.put("Method", "POST"); + jo.put("Request-URI", "http://www.example.com/"); + jo.put("HTTP-Version", "HTTP/1.1"); + System.out.println(HTTP.toString(jo)); + } + + public static void hTTPHeaderToJSONObject() { + JSONObject obj = HTTP.toJSONObject("POST \"http://www.example.com/\" HTTP/1.1"); + System.out.println(obj); + } +} diff --git a/json/src/main/java/com/baeldung/jsonjava/JSONArrayDemo.java b/json/src/main/java/com/baeldung/jsonjava/JSONArrayDemo.java new file mode 100644 index 0000000000..2a4fab2eab --- /dev/null +++ b/json/src/main/java/com/baeldung/jsonjava/JSONArrayDemo.java @@ -0,0 +1,52 @@ +package com.baeldung.jsonjava; + +import java.util.ArrayList; +import java.util.List; + +import org.json.JSONArray; +import org.json.JSONObject; + +public class JSONArrayDemo { + public static void main(String[] args) { + System.out.println("5.1. Creating JSON Array: "); + creatingJSONArray(); + + System.out.println("\n5.2. Creating JSON Array from JSON string: "); + jsonArrayFromJSONString(); + + System.out.println("\n5.3. Creating JSON Array from Collection Object: "); + jsonArrayFromCollectionObj(); + } + + public static void creatingJSONArray() { + JSONArray ja = new JSONArray(); + ja.put(Boolean.TRUE); + ja.put("lorem ipsum"); + + // We can also put a JSONObject in JSONArray + JSONObject jo = new JSONObject(); + jo.put("name", "jon doe"); + jo.put("age", "22"); + jo.put("city", "chicago"); + + ja.put(jo); + + System.out.println(ja.toString()); + } + + public static void jsonArrayFromJSONString() { + JSONArray ja = new JSONArray("[true, \"lorem ipsum\", 215]"); + System.out.println(ja); + } + + public static void jsonArrayFromCollectionObj() { + List list = new ArrayList<>(); + list.add("California"); + list.add("Texas"); + list.add("Hawaii"); + list.add("Alaska"); + + JSONArray ja = new JSONArray(list); + System.out.println(ja); + } +} \ No newline at end of file diff --git a/json/src/main/java/com/baeldung/jsonjava/JSONObjectDemo.java b/json/src/main/java/com/baeldung/jsonjava/JSONObjectDemo.java new file mode 100644 index 0000000000..cfe8467c30 --- /dev/null +++ b/json/src/main/java/com/baeldung/jsonjava/JSONObjectDemo.java @@ -0,0 +1,59 @@ +package com.baeldung.jsonjava; + +import java.util.HashMap; +import java.util.Map; + +import org.json.JSONObject; + +public class JSONObjectDemo { + public static void main(String[] args) { + System.out.println("4.1. Creating JSONObject: "); + jsonFromJSONObject(); + + System.out.println("\n4.2. Creating JSONObject from Map: "); + jsonFromMap(); + + System.out.println("\n4.3. Creating JSONObject from JSON string: "); + jsonFromJSONString(); + + System.out.println("\n4.4. Creating JSONObject from Java Bean: "); + jsonFromDemoBean(); + } + + public static void jsonFromJSONObject() { + JSONObject jo = new JSONObject(); + jo.put("name", "jon doe"); + jo.put("age", "22"); + jo.put("city", "chicago"); + + System.out.println(jo.toString()); + } + + public static void jsonFromMap() { + Map map = new HashMap<>(); + map.put("name", "jon doe"); + map.put("age", "22"); + map.put("city", "chicago"); + JSONObject jo = new JSONObject(map); + + System.out.println(jo.toString()); + } + + public static void jsonFromJSONString() { + JSONObject jo = new JSONObject( + "{\"city\":\"chicago\",\"name\":\"jon doe\",\"age\":\"22\"}" + ); + + System.out.println(jo.toString()); + } + + public static void jsonFromDemoBean() { + DemoBean demo = new DemoBean(); + demo.setId(1); + demo.setName("lorem ipsum"); + demo.setActive(true); + + JSONObject jo = new JSONObject(demo); + System.out.println(jo); + } +} diff --git a/json/src/main/java/com/baeldung/jsonjava/JSONTokenerDemo.java b/json/src/main/java/com/baeldung/jsonjava/JSONTokenerDemo.java new file mode 100644 index 0000000000..fb9fea959c --- /dev/null +++ b/json/src/main/java/com/baeldung/jsonjava/JSONTokenerDemo.java @@ -0,0 +1,13 @@ +package com.baeldung.jsonjava; + +import org.json.JSONTokener; + +public class JSONTokenerDemo { + public static void main(String[] args) { + JSONTokener jt = new JSONTokener("Sample String"); + + while(jt.more()) { + System.out.println(jt.next()); + } + } +} diff --git a/json/src/test/java/com/baeldung/jsonjava/CDLIntegrationTest.java b/json/src/test/java/com/baeldung/jsonjava/CDLIntegrationTest.java new file mode 100644 index 0000000000..441c71e78e --- /dev/null +++ b/json/src/test/java/com/baeldung/jsonjava/CDLIntegrationTest.java @@ -0,0 +1,52 @@ +package com.baeldung.jsonjava; + +import static org.junit.Assert.assertEquals; + +import org.json.CDL; +import org.json.JSONArray; +import org.json.JSONTokener; +import org.junit.Test; + +public class CDLIntegrationTest { + @Test + public void givenCommaDelimitedText_thenConvertToJSONArray() { + JSONArray ja = CDL.rowToJSONArray(new JSONTokener("England, USA, Canada")); + assertEquals("[\"England\",\"USA\",\"Canada\"]", ja.toString()); + } + + @Test + public void givenJSONArray_thenConvertToCommaDelimitedText() { + JSONArray ja = new JSONArray("[\"England\",\"USA\",\"Canada\"]"); + String cdt = CDL.rowToString(ja); + assertEquals("England,USA,Canada", cdt.toString().trim()); + } + + @Test + public void givenCommaDelimitedText_thenGetJSONArrayOfJSONObjects() { + String string = + "name, city, age \n" + + "john, chicago, 22 \n" + + "gary, florida, 35 \n" + + "sal, vegas, 18"; + + JSONArray result = CDL.toJSONArray(string); + assertEquals("[{\"name\":\"john\",\"city\":\"chicago\",\"age\":\"22\"},{\"name\":\"gary\",\"city\":\"florida\",\"age\":\"35\"},{\"name\":\"sal\",\"city\":\"vegas\",\"age\":\"18\"}]", result.toString()); + } + + @Test + public void givenCommaDelimitedText_thenGetJSONArrayOfJSONObjects2() { + JSONArray ja = new JSONArray(); + ja.put("name"); + ja.put("city"); + ja.put("age"); + + String string = + "john, chicago, 22 \n" + + "gary, florida, 35 \n" + + "sal, vegas, 18"; + + JSONArray result = CDL.toJSONArray(ja, string); + assertEquals("[{\"name\":\"john\",\"city\":\"chicago\",\"age\":\"22\"},{\"name\":\"gary\",\"city\":\"florida\",\"age\":\"35\"},{\"name\":\"sal\",\"city\":\"vegas\",\"age\":\"18\"}]", result.toString()); + } + +} diff --git a/json/src/test/java/com/baeldung/jsonjava/CookieIntegrationTest.java b/json/src/test/java/com/baeldung/jsonjava/CookieIntegrationTest.java new file mode 100644 index 0000000000..c1a3505bbc --- /dev/null +++ b/json/src/test/java/com/baeldung/jsonjava/CookieIntegrationTest.java @@ -0,0 +1,29 @@ +package com.baeldung.jsonjava; + +import static org.junit.Assert.assertEquals; + +import org.json.Cookie; +import org.json.JSONObject; +import org.junit.Test; + +public class CookieIntegrationTest { + @Test + public void givenCookieString_thenConvertToJSONObject() { + String cookie = "username=John Doe; expires=Thu, 18 Dec 2013 12:00:00 UTC; path=/"; + JSONObject cookieJO = Cookie.toJSONObject(cookie); + + assertEquals("{\"path\":\"/\",\"expires\":\"Thu, 18 Dec 2013 12:00:00 UTC\",\"name\":\"username\",\"value\":\"John Doe\"}", cookieJO.toString()); + } + + @Test + public void givenJSONObject_thenConvertToCookieString() { + JSONObject cookieJO = new JSONObject(); + cookieJO.put("name", "username"); + cookieJO.put("value", "John Doe"); + cookieJO.put("expires", "Thu, 18 Dec 2013 12:00:00 UTC"); + cookieJO.put("path", "/"); + String cookie = Cookie.toString(cookieJO); + + assertEquals("username=John Doe;expires=Thu, 18 Dec 2013 12:00:00 UTC;path=/", cookie.toString()); + } +} diff --git a/json/src/test/java/com/baeldung/jsonjava/HTTPIntegrationTest.java b/json/src/test/java/com/baeldung/jsonjava/HTTPIntegrationTest.java new file mode 100644 index 0000000000..1aa0427c7e --- /dev/null +++ b/json/src/test/java/com/baeldung/jsonjava/HTTPIntegrationTest.java @@ -0,0 +1,25 @@ +package com.baeldung.jsonjava; + +import static org.junit.Assert.assertEquals; +import org.json.HTTP; +import org.json.JSONObject; +import org.junit.Test; + +public class HTTPIntegrationTest { + @Test + public void givenJSONObject_thenConvertToHTTPHeader() { + JSONObject jo = new JSONObject(); + jo.put("Method", "POST"); + jo.put("Request-URI", "http://www.example.com/"); + jo.put("HTTP-Version", "HTTP/1.1"); + + assertEquals("POST \"http://www.example.com/\" HTTP/1.1"+HTTP.CRLF+HTTP.CRLF, HTTP.toString(jo)); + } + + @Test + public void givenHTTPHeader_thenConvertToJSONObject() { + JSONObject obj = HTTP.toJSONObject("POST \"http://www.example.com/\" HTTP/1.1"); + + assertEquals("{\"Request-URI\":\"http://www.example.com/\",\"Method\":\"POST\",\"HTTP-Version\":\"HTTP/1.1\"}", obj.toString()); + } +} diff --git a/json/src/test/java/com/baeldung/jsonjava/JSONArrayIntegrationTest.java b/json/src/test/java/com/baeldung/jsonjava/JSONArrayIntegrationTest.java new file mode 100644 index 0000000000..c956232abe --- /dev/null +++ b/json/src/test/java/com/baeldung/jsonjava/JSONArrayIntegrationTest.java @@ -0,0 +1,47 @@ +package com.baeldung.jsonjava; + +import static org.junit.Assert.assertEquals; + +import java.util.ArrayList; +import java.util.List; + +import org.json.JSONArray; +import org.json.JSONObject; +import org.junit.Test; + +public class JSONArrayIntegrationTest { + @Test + public void givenJSONJava_thenCreateNewJSONArrayFromScratch() { + JSONArray ja = new JSONArray(); + ja.put(Boolean.TRUE); + ja.put("lorem ipsum"); + + // We can also put a JSONObject in JSONArray + JSONObject jo = new JSONObject(); + jo.put("name", "jon doe"); + jo.put("age", "22"); + jo.put("city", "chicago"); + + ja.put(jo); + + assertEquals("[true,\"lorem ipsum\",{\"city\":\"chicago\",\"name\":\"jon doe\",\"age\":\"22\"}]", ja.toString()); + } + + @Test + public void givenJsonString_thenCreateNewJSONArray() { + JSONArray ja = new JSONArray("[true, \"lorem ipsum\", 215]"); + assertEquals("[true,\"lorem ipsum\",215]", ja.toString()); + } + + @Test + public void givenListObject_thenConvertItToJSONArray() { + List list = new ArrayList<>(); + list.add("California"); + list.add("Texas"); + list.add("Hawaii"); + list.add("Alaska"); + + JSONArray ja = new JSONArray(list); + assertEquals("[\"California\",\"Texas\",\"Hawaii\",\"Alaska\"]", ja.toString()); + } +} \ No newline at end of file diff --git a/json/src/test/java/com/baeldung/jsonjava/JSONObjectIntegrationTest.java b/json/src/test/java/com/baeldung/jsonjava/JSONObjectIntegrationTest.java new file mode 100644 index 0000000000..70f7921797 --- /dev/null +++ b/json/src/test/java/com/baeldung/jsonjava/JSONObjectIntegrationTest.java @@ -0,0 +1,53 @@ +package com.baeldung.jsonjava; + +import static org.junit.Assert.assertEquals; + +import java.util.HashMap; +import java.util.Map; + +import org.json.JSONObject; +import org.junit.Test; + +public class JSONObjectIntegrationTest { + @Test + public void givenJSONJava_thenCreateNewJSONObject() { + JSONObject jo = new JSONObject(); + jo.put("name", "jon doe"); + jo.put("age", "22"); + jo.put("city", "chicago"); + + assertEquals("{\"city\":\"chicago\",\"name\":\"jon doe\",\"age\":\"22\"}", jo.toString()); + + } + + @Test + public void givenMapObject_thenCreateJSONObject() { + Map map = new HashMap<>(); + map.put("name", "jon doe"); + map.put("age", "22"); + map.put("city", "chicago"); + JSONObject jo = new JSONObject(map); + + assertEquals("{\"name\":\"jon doe\",\"city\":\"chicago\",\"age\":\"22\"}", jo.toString()); + } + + @Test + public void givenJsonString_thenCreateJSONObject() { + JSONObject jo = new JSONObject( + "{\"city\":\"chicago\",\"name\":\"jon doe\",\"age\":\"22\"}" + ); + + assertEquals("{\"city\":\"chicago\",\"name\":\"jon doe\",\"age\":\"22\"}", jo.toString()); + } + + @Test + public void givenDemoBean_thenCreateJSONObject() { + DemoBean demo = new DemoBean(); + demo.setId(1); + demo.setName("lorem ipsum"); + demo.setActive(true); + + JSONObject jo = new JSONObject(demo); + assertEquals("{\"name\":\"lorem ipsum\",\"active\":true,\"id\":1}", jo.toString()); + } +} diff --git a/json/src/test/java/com/baeldung/jsonjava/JSONTokenerIntegrationTest.java b/json/src/test/java/com/baeldung/jsonjava/JSONTokenerIntegrationTest.java new file mode 100644 index 0000000000..4fe8f27231 --- /dev/null +++ b/json/src/test/java/com/baeldung/jsonjava/JSONTokenerIntegrationTest.java @@ -0,0 +1,21 @@ +package com.baeldung.jsonjava; + +import static org.junit.Assert.assertEquals; + +import org.json.JSONTokener; +import org.junit.Test; + +public class JSONTokenerIntegrationTest { + @Test + public void givenString_convertItToJSONTokens() { + String str = "Sample String"; + JSONTokener jt = new JSONTokener(str); + + char[] expectedTokens = str.toCharArray(); + int index = 0; + + while(jt.more()) { + assertEquals(expectedTokens[index++], jt.next()); + } + } +} diff --git a/jsonld/.gitignore b/jsonld/.gitignore new file mode 100644 index 0000000000..2af7cefb0a --- /dev/null +++ b/jsonld/.gitignore @@ -0,0 +1,24 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +nbproject/private/ +build/ +nbbuild/ +dist/ +nbdist/ +.nb-gradle/ \ No newline at end of file diff --git a/jsonld/.mvn/wrapper/maven-wrapper.jar b/jsonld/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 0000000000..5fd4d5023f Binary files /dev/null and b/jsonld/.mvn/wrapper/maven-wrapper.jar differ diff --git a/jsonld/.mvn/wrapper/maven-wrapper.properties b/jsonld/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 0000000000..c954cec91c --- /dev/null +++ b/jsonld/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1 @@ +distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.3.9/apache-maven-3.3.9-bin.zip diff --git a/jsonld/README.md b/jsonld/README.md new file mode 100644 index 0000000000..51ca961bea --- /dev/null +++ b/jsonld/README.md @@ -0,0 +1,22 @@ +JSON-LD +======= + +Hypermedia serialization with JSON-LD. + +### Requirements + +- Maven +- JDK 8 +- JSON-LD + +### Running +To build and start the server simply type + +```bash +$ mvn clean install +$ mvn spring-boot:run +``` + +Now with default configurations it will be available at: [http://localhost:8080](http://localhost:8080) + +Enjoy it :) \ No newline at end of file diff --git a/jsonld/mvnw b/jsonld/mvnw new file mode 100755 index 0000000000..a1ba1bf554 --- /dev/null +++ b/jsonld/mvnw @@ -0,0 +1,233 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven2 Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # + # Look for the Apple JDKs first to preserve the existing behaviour, and then look + # for the new JDKs provided by Oracle. + # + if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK ] ; then + # + # Apple JDKs + # + export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home + fi + + if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Java/JavaVirtualMachines/CurrentJDK ] ; then + # + # Apple JDKs + # + export JAVA_HOME=/System/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home + fi + + if [ -z "$JAVA_HOME" ] && [ -L "/Library/Java/JavaVirtualMachines/CurrentJDK" ] ; then + # + # Oracle JDKs + # + export JAVA_HOME=/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home + fi + + if [ -z "$JAVA_HOME" ] && [ -x "/usr/libexec/java_home" ]; then + # + # Apple JDKs + # + export JAVA_HOME=`/usr/libexec/java_home` + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Migwn, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" + # TODO classpath? +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`which java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` +fi + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + local basedir=$(pwd) + local wdir=$(pwd) + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + wdir=$(cd "$wdir/.."; pwd) + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-$(find_maven_basedir)} +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} "$@" diff --git a/jsonld/mvnw.cmd b/jsonld/mvnw.cmd new file mode 100644 index 0000000000..2b934e89dd --- /dev/null +++ b/jsonld/mvnw.cmd @@ -0,0 +1,145 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven2 Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +set MAVEN_CMD_LINE_ARGS=%* + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" + +set WRAPPER_JAR="".\.mvn\wrapper\maven-wrapper.jar"" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CMD_LINE_ARGS% +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE% \ No newline at end of file diff --git a/jsonld/pom.xml b/jsonld/pom.xml new file mode 100644 index 0000000000..1574878667 --- /dev/null +++ b/jsonld/pom.xml @@ -0,0 +1,53 @@ + + + 4.0.0 + + jsonld + 0.0.1-SNAPSHOT + jar + + jsonld + Hypermedia serialization with JSON-LD + + + parent-boot-5 + com.baeldung + 0.0.1-SNAPSHOT + ../parent-boot-5 + + + + UTF-8 + UTF-8 + 1.8 + 0.11.1 + + + + + org.springframework.boot + spring-boot-starter + + + org.springframework.boot + spring-boot-starter-test + test + + + + com.github.jsonld-java + jsonld-java + ${jsonld.version} + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/jsonld/src/main/java/com/baeldung/JsonLdApplication.java b/jsonld/src/main/java/com/baeldung/JsonLdApplication.java new file mode 100644 index 0000000000..0b8f338127 --- /dev/null +++ b/jsonld/src/main/java/com/baeldung/JsonLdApplication.java @@ -0,0 +1,11 @@ +package com.baeldung; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class JsonLdApplication { + public static void main(String[] args) { + SpringApplication.run(JsonLdApplication.class, args); + } +} diff --git a/jsonld/src/main/resources/application.properties b/jsonld/src/main/resources/application.properties new file mode 100644 index 0000000000..b6bfd8f6f3 --- /dev/null +++ b/jsonld/src/main/resources/application.properties @@ -0,0 +1,14 @@ +# the db host +spring.data.mongodb.host=localhost +# the connection port (defaults to 27107) +spring.data.mongodb.port=27017 +# The database's name +spring.data.mongodb.database=Jenkins-Pipeline + +# Or this +# spring.data.mongodb.uri=mongodb://localhost/Jenkins-Pipeline + +# spring.data.mongodb.username= +# spring.data.mongodb.password= + +spring.data.mongodb.repositories.enabled=true \ No newline at end of file diff --git a/jsonld/src/test/java/com/baeldung/JsonLdSerializatorTest.java b/jsonld/src/test/java/com/baeldung/JsonLdSerializatorTest.java new file mode 100644 index 0000000000..762a4254dc --- /dev/null +++ b/jsonld/src/test/java/com/baeldung/JsonLdSerializatorTest.java @@ -0,0 +1,33 @@ +package com.baeldung; + +import com.github.jsonldjava.core.JsonLdError; +import com.github.jsonldjava.core.JsonLdOptions; +import com.github.jsonldjava.core.JsonLdProcessor; +import com.github.jsonldjava.utils.JsonUtils; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.assertNotEquals; + +@RunWith(SpringJUnit4ClassRunner.class) +@SpringBootTest +public class JsonLdSerializatorTest { + + @Test + public void whenInserting_andCount_thenWeDontGetZero() throws JsonLdError { + String inputStream = "{name:}"; + Object jsonObject = JsonUtils.fromInputStream(inputStream); + + Map context = new HashMap(); + JsonLdOptions options = new JsonLdOptions(); + Object compact = JsonLdProcessor.compact(jsonObject, context, options); + + assertNotEquals(0, 0); + } + +} diff --git a/libraries/README.md b/libraries/README.md index d001f13698..fbf2b4e876 100644 --- a/libraries/README.md +++ b/libraries/README.md @@ -59,6 +59,7 @@ - [Intro to JDO Queries 2/2](http://www.baeldung.com/jdo-queries) - [Guide to google-http-client](http://www.baeldung.com/google-http-client) - [Interact with Google Sheets from Java](http://www.baeldung.com/google-sheets-java-client) +- [Programatically Create, Configure, and Run a Tomcat Server] (http://www.baeldung.com/tomcat-programmatic-setup) diff --git a/libraries/pom.xml b/libraries/pom.xml index 3e802e76c8..64cc9c6a84 100644 --- a/libraries/pom.xml +++ b/libraries/pom.xml @@ -116,6 +116,12 @@ + + + org.asynchttpclient + async-http-client + ${async.http.client.version} + org.beykery @@ -643,6 +649,11 @@ google-http-client-gson ${googleclient.version} + + org.infinispan + infinispan-core + ${infinispan.version} + @@ -710,6 +721,18 @@ test test + + + + org.apache.tomcat + tomcat-catalina + ${tomcat.version} + + + org.milyn + milyn-smooks-all + ${smooks.version} + @@ -761,7 +784,7 @@ 1.1.3-rc.5 1.4.0 1.1.0 - 4.1.15.Final + 4.1.20.Final 4.1 4.12 0.10 @@ -789,6 +812,10 @@ 1.23.0 v4-rev493-1.21.0 1.0.0 + 1.7.0 3.0.14 + 8.5.24 + 2.2.0 + 9.1.5.Final - \ No newline at end of file + diff --git a/libraries/src/main/java/com/baeldung/infinispan/CacheConfiguration.java b/libraries/src/main/java/com/baeldung/infinispan/CacheConfiguration.java new file mode 100644 index 0000000000..58929c0111 --- /dev/null +++ b/libraries/src/main/java/com/baeldung/infinispan/CacheConfiguration.java @@ -0,0 +1,84 @@ +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() { + return new DefaultCacheManager(); + } + + public Cache transactionalCache(DefaultCacheManager cacheManager, CacheListener listener) { + return this.buildCache(TRANSACTIONAL_CACHE, cacheManager, listener, transactionalConfiguration()); + } + + public Cache simpleHelloWorldCache(DefaultCacheManager cacheManager, CacheListener listener) { + return this.buildCache(SIMPLE_HELLO_WORLD_CACHE, cacheManager, listener, new ConfigurationBuilder().build()); + } + + public Cache expiringHelloWorldCache(DefaultCacheManager cacheManager, CacheListener listener) { + return this.buildCache(EXPIRING_HELLO_WORLD_CACHE, cacheManager, listener, expiringConfiguration()); + } + + public Cache evictingHelloWorldCache(DefaultCacheManager cacheManager, CacheListener listener) { + return this.buildCache(EVICTING_HELLO_WORLD_CACHE, cacheManager, listener, evictingConfiguration()); + } + + public Cache passivatingHelloWorldCache(DefaultCacheManager cacheManager, CacheListener listener) { + return this.buildCache(PASSIVATING_HELLO_WORLD_CACHE, cacheManager, listener, passivatingConfiguration()); + } + + private Cache buildCache(String cacheName, DefaultCacheManager cacheManager, + CacheListener listener, Configuration configuration) { + + cacheManager.defineConfiguration(cacheName, configuration); + Cache cache = cacheManager.getCache(cacheName); + cache.addListener(listener); + return cache; + } + + private Configuration expiringConfiguration() { + return new ConfigurationBuilder().expiration().lifespan(1, TimeUnit.SECONDS) + .build(); + } + + private Configuration evictingConfiguration() { + return new ConfigurationBuilder() + .memory().evictionType(EvictionType.COUNT).size(1) + .build(); + } + + private Configuration passivatingConfiguration() { + return new ConfigurationBuilder() + .memory().evictionType(EvictionType.COUNT).size(1) + .persistence() + .passivation(true) + .addSingleFileStore() + .purgeOnStartup(true) + .location(System.getProperty("java.io.tmpdir")) + .build(); + } + + private Configuration transactionalConfiguration() { + return new ConfigurationBuilder() + .transaction().transactionMode(TransactionMode.TRANSACTIONAL) + .lockingMode(LockingMode.PESSIMISTIC) + .build(); + } + +} diff --git a/libraries/src/main/java/com/baeldung/infinispan/listener/CacheListener.java b/libraries/src/main/java/com/baeldung/infinispan/listener/CacheListener.java new file mode 100644 index 0000000000..942a2fb62d --- /dev/null +++ b/libraries/src/main/java/com/baeldung/infinispan/listener/CacheListener.java @@ -0,0 +1,53 @@ +package com.baeldung.infinispan.listener; + +import org.infinispan.notifications.Listener; +import org.infinispan.notifications.cachelistener.annotation.*; +import org.infinispan.notifications.cachelistener.event.*; + +@Listener +public class CacheListener { + + @CacheEntryCreated + public void entryCreated(CacheEntryCreatedEvent event) { + this.printLog("Adding key '" + event.getKey() + "' to cache", event); + } + + @CacheEntryExpired + public void entryExpired(CacheEntryExpiredEvent event) { + this.printLog("Expiring key '" + event.getKey() + "' from cache", event); + } + + @CacheEntryVisited + public void entryVisited(CacheEntryVisitedEvent event) { + this.printLog("Key '" + event.getKey() + "' was visited", event); + } + + @CacheEntryActivated + public void entryActivated(CacheEntryActivatedEvent event) { + this.printLog("Activating key '" + event.getKey() + "' on cache", event); + } + + @CacheEntryPassivated + public void entryPassivated(CacheEntryPassivatedEvent event) { + this.printLog("Passivating key '" + event.getKey() + "' from cache", event); + } + + @CacheEntryLoaded + public void entryLoaded(CacheEntryLoadedEvent event) { + this.printLog("Loading key '" + event.getKey() + "' to cache", event); + } + + @CacheEntriesEvicted + public void entriesEvicted(CacheEntriesEvictedEvent event) { + final StringBuilder builder = new StringBuilder(); + event.getEntries().forEach((key, value) -> builder.append(key).append(", ")); + System.out.println("Evicting following entries from cache: " + builder.toString()); + } + + private void printLog(String log, CacheEntryEvent event) { + if (!event.isPre()) { + System.out.println(log); + } + } + +} diff --git a/libraries/src/main/java/com/baeldung/infinispan/repository/HelloWorldRepository.java b/libraries/src/main/java/com/baeldung/infinispan/repository/HelloWorldRepository.java new file mode 100644 index 0000000000..85c0d539a3 --- /dev/null +++ b/libraries/src/main/java/com/baeldung/infinispan/repository/HelloWorldRepository.java @@ -0,0 +1,15 @@ +package com.baeldung.infinispan.repository; + +public class HelloWorldRepository { + + public String getHelloWorld() { + try { + System.out.println("Executing some heavy query"); + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + return "Hello World!"; + } + +} diff --git a/libraries/src/main/java/com/baeldung/infinispan/service/HelloWorldService.java b/libraries/src/main/java/com/baeldung/infinispan/service/HelloWorldService.java new file mode 100644 index 0000000000..3ecefcc21a --- /dev/null +++ b/libraries/src/main/java/com/baeldung/infinispan/service/HelloWorldService.java @@ -0,0 +1,80 @@ +package com.baeldung.infinispan.service; + +import com.baeldung.infinispan.listener.CacheListener; +import com.baeldung.infinispan.repository.HelloWorldRepository; +import org.infinispan.Cache; + +import java.util.concurrent.TimeUnit; + +public class HelloWorldService { + + private final HelloWorldRepository repository; + + private final Cache simpleHelloWorldCache; + private final Cache expiringHelloWorldCache; + private final Cache evictingHelloWorldCache; + private final Cache passivatingHelloWorldCache; + + public HelloWorldService(HelloWorldRepository repository, CacheListener listener, + Cache simpleHelloWorldCache, + Cache expiringHelloWorldCache, + Cache evictingHelloWorldCache, + Cache passivatingHelloWorldCache) { + + this.repository = repository; + + this.simpleHelloWorldCache = simpleHelloWorldCache; + this.expiringHelloWorldCache = expiringHelloWorldCache; + this.evictingHelloWorldCache = evictingHelloWorldCache; + this.passivatingHelloWorldCache = passivatingHelloWorldCache; + } + + public String findSimpleHelloWorld() { + String cacheKey = "simple-hello"; + return simpleHelloWorldCache.computeIfAbsent(cacheKey, k -> repository.getHelloWorld()); + } + + 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) { + return passivatingHelloWorldCache.computeIfAbsent(key, k -> repository.getHelloWorld()); + } + +} diff --git a/libraries/src/main/java/com/baeldung/infinispan/service/TransactionalService.java b/libraries/src/main/java/com/baeldung/infinispan/service/TransactionalService.java new file mode 100644 index 0000000000..b0dbf5475f --- /dev/null +++ b/libraries/src/main/java/com/baeldung/infinispan/service/TransactionalService.java @@ -0,0 +1,57 @@ +package com.baeldung.infinispan.service; + +import org.infinispan.Cache; +import org.springframework.util.StopWatch; + +import javax.transaction.TransactionManager; + +public class TransactionalService { + + private final Cache transactionalCache; + + private static final String KEY = "key"; + + public TransactionalService(Cache transactionalCache) { + this.transactionalCache = transactionalCache; + + transactionalCache.put(KEY, 0); + } + + public Integer getQuickHowManyVisits() { + try { + TransactionManager tm = transactionalCache.getAdvancedCache().getTransactionManager(); + tm.begin(); + Integer howManyVisits = transactionalCache.get(KEY); + howManyVisits++; + System.out.println("Ill try to set HowManyVisits to " + howManyVisits); + StopWatch watch = new StopWatch(); + watch.start(); + transactionalCache.put(KEY, howManyVisits); + watch.stop(); + System.out.println("I was able to set HowManyVisits to " + howManyVisits + + " after waiting " + watch.getTotalTimeSeconds() + " seconds"); + + tm.commit(); + return howManyVisits; + } catch (Exception e) { + e.printStackTrace(); + return 0; + } + } + + public void startBackgroundBatch() { + try { + TransactionManager tm = transactionalCache.getAdvancedCache().getTransactionManager(); + tm.begin(); + transactionalCache.put(KEY, 1000); + System.out.println("HowManyVisits should now be 1000, " + + "but we are holding the transaction"); + Thread.sleep(1000L); + tm.rollback(); + System.out.println("The slow batch suffered a rollback"); + } catch (Exception e) { + e.printStackTrace(); + } + } + +} diff --git a/libraries/src/main/java/com/baeldung/smooks/converter/OrderConverter.java b/libraries/src/main/java/com/baeldung/smooks/converter/OrderConverter.java new file mode 100644 index 0000000000..d11f5a29b2 --- /dev/null +++ b/libraries/src/main/java/com/baeldung/smooks/converter/OrderConverter.java @@ -0,0 +1,45 @@ +package com.baeldung.smooks.converter; + +import com.baeldung.smooks.model.Order; +import org.milyn.Smooks; +import org.milyn.payload.JavaResult; +import org.milyn.payload.StringResult; +import org.xml.sax.SAXException; + +import javax.xml.transform.stream.StreamSource; +import java.io.IOException; + +public class OrderConverter { + + public Order convertOrderXMLToOrderObject(String path) throws IOException, SAXException { + Smooks smooks = new Smooks(OrderConverter.class.getResourceAsStream("/smooks/smooks-mapping.xml")); + try { + JavaResult javaResult = new JavaResult(); + smooks.filterSource(new StreamSource(OrderConverter.class.getResourceAsStream(path)), javaResult); + return (Order) javaResult.getBean("order"); + } finally { + smooks.close(); + } + } + + + public String convertOrderXMLtoEDIFACT(String path) throws IOException, SAXException { + return convertDocumentWithTempalte(path, "/smooks/smooks-transform-edi.xml"); + } + + public String convertOrderXMLtoEmailMessage(String path) throws IOException, SAXException { + return convertDocumentWithTempalte(path, "/smooks/smooks-transform-email.xml"); + } + + private String convertDocumentWithTempalte(String path, String config) throws IOException, SAXException { + Smooks smooks = new Smooks(config); + + try { + StringResult stringResult = new StringResult(); + smooks.filterSource(new StreamSource(OrderConverter.class.getResourceAsStream(path)), stringResult); + return stringResult.toString(); + } finally { + smooks.close(); + } + } +} diff --git a/libraries/src/main/java/com/baeldung/smooks/converter/OrderValidator.java b/libraries/src/main/java/com/baeldung/smooks/converter/OrderValidator.java new file mode 100644 index 0000000000..3975921da0 --- /dev/null +++ b/libraries/src/main/java/com/baeldung/smooks/converter/OrderValidator.java @@ -0,0 +1,27 @@ +package com.baeldung.smooks.converter; + +import org.milyn.Smooks; +import org.milyn.payload.JavaResult; +import org.milyn.payload.StringResult; +import org.milyn.validation.ValidationResult; +import org.xml.sax.SAXException; + +import javax.xml.transform.stream.StreamSource; +import java.io.IOException; + +public class OrderValidator { + + public ValidationResult validate(String path) throws IOException, SAXException { + Smooks smooks = new Smooks(OrderValidator.class.getResourceAsStream("/smooks/smooks-validation.xml")); + + try { + StringResult xmlResult = new StringResult(); + JavaResult javaResult = new JavaResult(); + ValidationResult validationResult = new ValidationResult(); + smooks.filterSource(new StreamSource(OrderValidator.class.getResourceAsStream(path)), xmlResult, javaResult, validationResult); + return validationResult; + } finally { + smooks.close(); + } + } +} diff --git a/libraries/src/main/java/com/baeldung/smooks/model/Item.java b/libraries/src/main/java/com/baeldung/smooks/model/Item.java new file mode 100644 index 0000000000..a7f7783b3f --- /dev/null +++ b/libraries/src/main/java/com/baeldung/smooks/model/Item.java @@ -0,0 +1,71 @@ +package com.baeldung.smooks.model; + +public class Item { + + public Item() { + } + + public Item(String code, Double price, Integer quantity) { + this.code = code; + this.price = price; + this.quantity = quantity; + } + + private String code; + private Double price; + private Integer quantity; + + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public Double getPrice() { + return price; + } + + public void setPrice(Double price) { + this.price = price; + } + + public Integer getQuantity() { + return quantity; + } + + public void setQuantity(Integer quantity) { + this.quantity = quantity; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Item item = (Item) o; + + if (code != null ? !code.equals(item.code) : item.code != null) return false; + if (price != null ? !price.equals(item.price) : item.price != null) return false; + return quantity != null ? quantity.equals(item.quantity) : item.quantity == null; + } + + @Override + public int hashCode() { + int result = code != null ? code.hashCode() : 0; + result = 31 * result + (price != null ? price.hashCode() : 0); + result = 31 * result + (quantity != null ? quantity.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "Item{" + + "code='" + code + '\'' + + ", price=" + price + + ", quantity=" + quantity + + '}'; + } +} diff --git a/libraries/src/main/java/com/baeldung/smooks/model/Order.java b/libraries/src/main/java/com/baeldung/smooks/model/Order.java new file mode 100644 index 0000000000..047e1fe8a3 --- /dev/null +++ b/libraries/src/main/java/com/baeldung/smooks/model/Order.java @@ -0,0 +1,52 @@ +package com.baeldung.smooks.model; + +import java.util.Date; +import java.util.List; + +public class Order { + private Date creationDate; + private Long number; + private Status status; + private Supplier supplier; + private List items; + + public Date getCreationDate() { + return creationDate; + } + + public void setCreationDate(Date creationDate) { + this.creationDate = creationDate; + } + + public Long getNumber() { + return number; + } + + public void setNumber(Long number) { + this.number = number; + } + + public Status getStatus() { + return status; + } + + public void setStatus(Status status) { + this.status = status; + } + + public Supplier getSupplier() { + return supplier; + } + + public void setSupplier(Supplier supplier) { + this.supplier = supplier; + } + + public List getItems() { + return items; + } + + public void setItems(List items) { + this.items = items; + } +} diff --git a/libraries/src/main/java/com/baeldung/smooks/model/Status.java b/libraries/src/main/java/com/baeldung/smooks/model/Status.java new file mode 100644 index 0000000000..53c50bdf46 --- /dev/null +++ b/libraries/src/main/java/com/baeldung/smooks/model/Status.java @@ -0,0 +1,5 @@ +package com.baeldung.smooks.model; + +public enum Status { + NEW, IN_PROGRESS, FINISHED +} diff --git a/libraries/src/main/java/com/baeldung/smooks/model/Supplier.java b/libraries/src/main/java/com/baeldung/smooks/model/Supplier.java new file mode 100644 index 0000000000..31a9e1f43f --- /dev/null +++ b/libraries/src/main/java/com/baeldung/smooks/model/Supplier.java @@ -0,0 +1,49 @@ +package com.baeldung.smooks.model; + +public class Supplier { + + private String name; + private String phoneNumber; + + public Supplier() { + } + + public Supplier(String name, String phoneNumber) { + this.name = name; + this.phoneNumber = phoneNumber; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getPhoneNumber() { + return phoneNumber; + } + + public void setPhoneNumber(String phoneNumber) { + this.phoneNumber = phoneNumber; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Supplier supplier = (Supplier) o; + + if (name != null ? !name.equals(supplier.name) : supplier.name != null) return false; + return phoneNumber != null ? phoneNumber.equals(supplier.phoneNumber) : supplier.phoneNumber == null; + } + + @Override + public int hashCode() { + int result = name != null ? name.hashCode() : 0; + result = 31 * result + (phoneNumber != null ? phoneNumber.hashCode() : 0); + return result; + } +} diff --git a/libraries/src/main/java/com/baeldung/tomcat/MyFilter.java b/libraries/src/main/java/com/baeldung/tomcat/MyFilter.java new file mode 100644 index 0000000000..9cf4a0ed95 --- /dev/null +++ b/libraries/src/main/java/com/baeldung/tomcat/MyFilter.java @@ -0,0 +1,31 @@ +package com.baeldung.tomcat; + +import javax.servlet.*; +import javax.servlet.annotation.WebFilter; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * Created by adi on 1/14/18. + */ +@WebFilter(urlPatterns = "/my-servlet/*") +public class MyFilter implements Filter { + + @Override + public void init(FilterConfig filterConfig) { + + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + System.out.println("Filtering stuff..."); + HttpServletResponse httpResponse = (HttpServletResponse) response; + httpResponse.addHeader("myHeader", "myHeaderValue"); + chain.doFilter(request, httpResponse); + } + + @Override + public void destroy() { + + } +} diff --git a/libraries/src/main/java/com/baeldung/tomcat/MyServlet.java b/libraries/src/main/java/com/baeldung/tomcat/MyServlet.java new file mode 100644 index 0000000000..4bbf3c03a7 --- /dev/null +++ b/libraries/src/main/java/com/baeldung/tomcat/MyServlet.java @@ -0,0 +1,25 @@ +package com.baeldung.tomcat; + +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * Created by adi on 1/10/18. + */ +@WebServlet( + name = "com.baeldung.tomcat.programmatic.MyServlet", + urlPatterns = {"/my-servlet"} +) +public class MyServlet extends HttpServlet { + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { + resp.setStatus(HttpServletResponse.SC_OK); + resp.getWriter().write("test"); + resp.getWriter().flush(); + resp.getWriter().close(); + } +} diff --git a/libraries/src/main/java/com/baeldung/tomcat/ProgrammaticTomcat.java b/libraries/src/main/java/com/baeldung/tomcat/ProgrammaticTomcat.java new file mode 100644 index 0000000000..b84b6b5c6d --- /dev/null +++ b/libraries/src/main/java/com/baeldung/tomcat/ProgrammaticTomcat.java @@ -0,0 +1,63 @@ +package com.baeldung.tomcat; + +import org.apache.catalina.Context; +import org.apache.catalina.LifecycleException; +import org.apache.catalina.startup.Tomcat; +import org.apache.tomcat.util.descriptor.web.FilterDef; +import org.apache.tomcat.util.descriptor.web.FilterMap; + +import java.io.File; + +/** + * Created by adi on 1/10/18. + */ +public class ProgrammaticTomcat { + + private Tomcat tomcat = null; + + //uncomment for live test + // public static void main(String[] args) throws LifecycleException, ServletException, URISyntaxException, IOException { + // startTomcat(); + // } + + public void startTomcat() throws LifecycleException { + tomcat = new Tomcat(); + tomcat.setPort(8080); + tomcat.setHostname("localhost"); + String appBase = "."; + tomcat + .getHost() + .setAppBase(appBase); + + File docBase = new File(System.getProperty("java.io.tmpdir")); + Context context = tomcat.addContext("", docBase.getAbsolutePath()); + + //add a servlet + Class servletClass = MyServlet.class; + Tomcat.addServlet(context, servletClass.getSimpleName(), servletClass.getName()); + context.addServletMappingDecoded("/my-servlet/*", servletClass.getSimpleName()); + + //add a filter and filterMapping + Class filterClass = MyFilter.class; + FilterDef myFilterDef = new FilterDef(); + myFilterDef.setFilterClass(filterClass.getName()); + myFilterDef.setFilterName(filterClass.getSimpleName()); + context.addFilterDef(myFilterDef); + + FilterMap myFilterMap = new FilterMap(); + myFilterMap.setFilterName(filterClass.getSimpleName()); + myFilterMap.addURLPattern("/my-servlet/*"); + context.addFilterMap(myFilterMap); + + tomcat.start(); + //uncomment for live test + // tomcat + // .getServer() + // .await(); + } + + public void stopTomcat() throws LifecycleException { + tomcat.stop(); + tomcat.destroy(); + } +} diff --git a/libraries/src/main/resources/Greeting.sol b/libraries/src/main/resources/Greeting.sol new file mode 100644 index 0000000000..dde7b36cc3 --- /dev/null +++ b/libraries/src/main/resources/Greeting.sol @@ -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; + } +} \ No newline at end of file diff --git a/libraries/src/main/resources/smooks/email.ftl b/libraries/src/main/resources/smooks/email.ftl new file mode 100644 index 0000000000..8413046508 --- /dev/null +++ b/libraries/src/main/resources/smooks/email.ftl @@ -0,0 +1,8 @@ +<#setting locale="en_US"> +Hi, +Order number #${order.number} created on ${order.creationDate?string["yyyy-MM-dd"]} is currently in ${order.status} status. +Consider contact supplier "${supplier.name}" with phone number: "${supplier.phoneNumber}". +Order items: +<#list items as item> +${item.quantity} X ${item.code} (total price ${item.price * item.quantity}) + \ No newline at end of file diff --git a/libraries/src/main/resources/smooks/item-rules.csv b/libraries/src/main/resources/smooks/item-rules.csv new file mode 100644 index 0000000000..c93c453f25 --- /dev/null +++ b/libraries/src/main/resources/smooks/item-rules.csv @@ -0,0 +1 @@ +"max_total","item.quantity * item.price < 300.00" diff --git a/libraries/src/main/resources/smooks/order.ftl b/libraries/src/main/resources/smooks/order.ftl new file mode 100644 index 0000000000..9d40eb55c7 --- /dev/null +++ b/libraries/src/main/resources/smooks/order.ftl @@ -0,0 +1,7 @@ +<#setting locale="en_US"> +UNA:+.? ' +UNH+${order.number}+${order.status}+${order.creationDate?string["yyyy-MM-dd"]}' +CTA+${supplier.name}+${supplier.phoneNumber}' +<#list items as item> +LIN+${item.quantity}+${item.code}+${item.price}' + \ No newline at end of file diff --git a/libraries/src/main/resources/smooks/order.json b/libraries/src/main/resources/smooks/order.json new file mode 100644 index 0000000000..bf6bc5fe93 --- /dev/null +++ b/libraries/src/main/resources/smooks/order.json @@ -0,0 +1,21 @@ +{ + "creationDate":"2018-01-14", + "orderNumber":771, + "orderStatus":"IN_PROGRESS", + "supplier":{ + "name":"CompanyX", + "phone":"1234567" + }, + "orderItems":[ + { + "quantity":1, + "code":"PX1234", + "price":9.99 + }, + { + "quantity":2, + "code":"RX1990", + "price":120.32 + } + ] +} \ No newline at end of file diff --git a/libraries/src/main/resources/smooks/order.xml b/libraries/src/main/resources/smooks/order.xml new file mode 100644 index 0000000000..343c5cab38 --- /dev/null +++ b/libraries/src/main/resources/smooks/order.xml @@ -0,0 +1,20 @@ + + 771 + IN_PROGRESS + + CompanyX + 1234567 + + + + 1 + PX1234 + 9.99 + + + 2 + RX990 + 120.32 + + + \ No newline at end of file diff --git a/libraries/src/main/resources/smooks/smooks-mapping.xml b/libraries/src/main/resources/smooks/smooks-mapping.xml new file mode 100644 index 0000000000..7996834e38 --- /dev/null +++ b/libraries/src/main/resources/smooks/smooks-mapping.xml @@ -0,0 +1,29 @@ + + + + + + + + yyyy-MM-dd + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/libraries/src/main/resources/smooks/smooks-transform-edi.xml b/libraries/src/main/resources/smooks/smooks-transform-edi.xml new file mode 100644 index 0000000000..1dae4055a8 --- /dev/null +++ b/libraries/src/main/resources/smooks/smooks-transform-edi.xml @@ -0,0 +1,11 @@ + + + + + + + /smooks/order.ftl + + + \ No newline at end of file diff --git a/libraries/src/main/resources/smooks/smooks-transform-email.xml b/libraries/src/main/resources/smooks/smooks-transform-email.xml new file mode 100644 index 0000000000..101aa67f0d --- /dev/null +++ b/libraries/src/main/resources/smooks/smooks-transform-email.xml @@ -0,0 +1,12 @@ + + + + + + + + /smooks/email.ftl + + + \ No newline at end of file diff --git a/libraries/src/main/resources/smooks/smooks-validation.xml b/libraries/src/main/resources/smooks/smooks-validation.xml new file mode 100644 index 0000000000..b66722ffc5 --- /dev/null +++ b/libraries/src/main/resources/smooks/smooks-validation.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + diff --git a/libraries/src/main/resources/smooks/supplier.properties b/libraries/src/main/resources/smooks/supplier.properties new file mode 100644 index 0000000000..cc17e45eb4 --- /dev/null +++ b/libraries/src/main/resources/smooks/supplier.properties @@ -0,0 +1,2 @@ +supplierName=[A-Za-z0-9]* +supplierPhone=^[0-9\\-\\+]{9,15}$ diff --git a/libraries/src/test/java/com/baeldung/asynchttpclient/AsyncHttpClientTestCase.java b/libraries/src/test/java/com/baeldung/asynchttpclient/AsyncHttpClientTestCase.java new file mode 100644 index 0000000000..1398c2ba41 --- /dev/null +++ b/libraries/src/test/java/com/baeldung/asynchttpclient/AsyncHttpClientTestCase.java @@ -0,0 +1,209 @@ +package com.baeldung.asynchttpclient; + +import io.netty.handler.codec.http.HttpHeaders; +import org.asynchttpclient.AsyncCompletionHandler; +import org.asynchttpclient.AsyncHandler; +import org.asynchttpclient.AsyncHttpClient; +import org.asynchttpclient.AsyncHttpClientConfig; +import org.asynchttpclient.BoundRequestBuilder; +import org.asynchttpclient.Dsl; +import org.asynchttpclient.HttpResponseBodyPart; +import org.asynchttpclient.HttpResponseStatus; +import org.asynchttpclient.ListenableFuture; +import org.asynchttpclient.Request; +import org.asynchttpclient.Response; +import org.asynchttpclient.ws.WebSocket; +import org.asynchttpclient.ws.WebSocketListener; +import org.asynchttpclient.ws.WebSocketUpgradeHandler; +import org.junit.Before; +import org.junit.Test; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +public class AsyncHttpClientTestCase { + + private static AsyncHttpClient HTTP_CLIENT; + + @Before + public void setup() { + AsyncHttpClientConfig clientConfig = Dsl.config().setConnectTimeout(15000).setRequestTimeout(15000).build(); + HTTP_CLIENT = Dsl.asyncHttpClient(clientConfig); + } + + @Test + public void givenHttpClient_executeSyncGetRequest() { + + BoundRequestBuilder boundGetRequest = HTTP_CLIENT.prepareGet("http://www.baeldung.com"); + + Future responseFuture = boundGetRequest.execute(); + try { + Response response = responseFuture.get(5000, TimeUnit.MILLISECONDS); + assertNotNull(response); + assertEquals(200, response.getStatusCode()); + } catch (InterruptedException | ExecutionException | TimeoutException e) { + e.printStackTrace(); + } + + try { + Thread.sleep(5000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + @Test + public void givenHttpClient_executeAsyncGetRequest() { + + // execute an unbound GET request + Request unboundGetRequest = Dsl.get("http://www.baeldung.com").build(); + + HTTP_CLIENT.executeRequest(unboundGetRequest, new AsyncCompletionHandler() { + @Override + public Integer onCompleted(Response response) { + + int resposeStatusCode = response.getStatusCode(); + assertEquals(200, resposeStatusCode); + return resposeStatusCode; + } + }); + + // execute a bound GET request + BoundRequestBuilder boundGetRequest = HTTP_CLIENT.prepareGet("http://www.baeldung.com"); + + boundGetRequest.execute(new AsyncCompletionHandler() { + @Override + public Integer onCompleted(Response response) { + int resposeStatusCode = response.getStatusCode(); + assertEquals(200, resposeStatusCode); + return resposeStatusCode; + } + }); + + try { + Thread.sleep(5000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + @Test + public void givenHttpClient_executeAsyncGetRequestWithAsyncHandler() { + + // execute an unbound GET request + Request unboundGetRequest = Dsl.get("http://www.baeldung.com").build(); + + HTTP_CLIENT.executeRequest(unboundGetRequest, new AsyncHandler() { + + int responseStatusCode = -1; + + @Override + public State onStatusReceived(HttpResponseStatus responseStatus) { + responseStatusCode = responseStatus.getStatusCode(); + return State.CONTINUE; + } + + @Override + public State onHeadersReceived(HttpHeaders headers) { + return State.CONTINUE; + } + + @Override + public State onBodyPartReceived(HttpResponseBodyPart bodyPart) { + return State.CONTINUE; + } + + @Override + public void onThrowable(Throwable t) { + + } + + @Override + public Integer onCompleted() { + assertEquals(200, responseStatusCode); + return responseStatusCode; + } + }); + + try { + Thread.sleep(5000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + @Test + public void givenHttpClient_executeAsyncGetRequestWithListanableFuture() { + // execute an unbound GET request + Request unboundGetRequest = Dsl.get("http://www.baeldung.com").build(); + + ListenableFuture listenableFuture = HTTP_CLIENT.executeRequest(unboundGetRequest); + listenableFuture.addListener(() -> { + Response response; + try { + response = listenableFuture.get(5000, TimeUnit.MILLISECONDS); + assertEquals(200, response.getStatusCode()); + } catch (InterruptedException | ExecutionException | TimeoutException e) { + e.printStackTrace(); + } + }, Executors.newCachedThreadPool()); + + try { + Thread.sleep(5000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + @Test + public void givenWebSocketClient_tryToConnect() { + + WebSocketUpgradeHandler.Builder upgradeHandlerBuilder = new WebSocketUpgradeHandler.Builder(); + WebSocketUpgradeHandler wsHandler = upgradeHandlerBuilder.addWebSocketListener(new WebSocketListener() { + @Override + public void onOpen(WebSocket websocket) { + // WebSocket connection opened + } + + @Override + public void onClose(WebSocket websocket, int code, String reason) { + // WebSocket connection closed + } + + @Override + public void onError(Throwable t) { + // WebSocket connection error + assertTrue(t.getMessage().contains("Request timeout")); + } + }).build(); + + WebSocket WEBSOCKET_CLIENT = null; + try { + WEBSOCKET_CLIENT = Dsl.asyncHttpClient() + .prepareGet("ws://localhost:5590/websocket") + .addHeader("header_name", "header_value") + .addQueryParam("key", "value") + .setRequestTimeout(5000) + .execute(wsHandler).get(); + + if (WEBSOCKET_CLIENT.isOpen()) { + WEBSOCKET_CLIENT.sendPingFrame(); + WEBSOCKET_CLIENT.sendTextFrame("test message"); + WEBSOCKET_CLIENT.sendBinaryFrame(new byte[]{'t', 'e', 's', 't'}); + } + } catch (InterruptedException | ExecutionException e) { + e.printStackTrace(); + } finally { + if (WEBSOCKET_CLIENT != null && WEBSOCKET_CLIENT.isOpen()) { + WEBSOCKET_CLIENT.sendCloseFrame(200, "OK"); + } + } + } +} diff --git a/libraries/src/test/java/com/baeldung/infinispan/ConfigurationTest.java b/libraries/src/test/java/com/baeldung/infinispan/ConfigurationTest.java new file mode 100644 index 0000000000..c9ebe77679 --- /dev/null +++ b/libraries/src/test/java/com/baeldung/infinispan/ConfigurationTest.java @@ -0,0 +1,62 @@ +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.function.Supplier; + +public class ConfigurationTest { + + private DefaultCacheManager cacheManager; + + private HelloWorldRepository repository = new HelloWorldRepository(); + + protected HelloWorldService helloWorldService; + protected TransactionalService transactionalService; + + @Before + public void setup() { + CacheConfiguration configuration = new CacheConfiguration(); + CacheListener listener = new CacheListener(); + + cacheManager = configuration.cacheManager(); + + Cache transactionalCache = + configuration.transactionalCache(cacheManager, listener); + + Cache simpleHelloWorldCache = + configuration.simpleHelloWorldCache(cacheManager, listener); + + Cache expiringHelloWorldCache = + configuration.expiringHelloWorldCache(cacheManager, listener); + + Cache evictingHelloWorldCache = + configuration.evictingHelloWorldCache(cacheManager, listener); + + Cache passivatingHelloWorldCache = + configuration.passivatingHelloWorldCache(cacheManager, listener); + + this.helloWorldService = new HelloWorldService(repository, + listener, simpleHelloWorldCache, expiringHelloWorldCache, evictingHelloWorldCache, + passivatingHelloWorldCache); + + this.transactionalService = new TransactionalService(transactionalCache); + } + + @After + public void tearDown() { + cacheManager.stop(); + } + + protected long timeThis(Supplier supplier) { + long millis = System.currentTimeMillis(); + supplier.get(); + return System.currentTimeMillis() - millis; + } +} diff --git a/libraries/src/test/java/com/baeldung/infinispan/service/HelloWorldServiceUnitTest.java b/libraries/src/test/java/com/baeldung/infinispan/service/HelloWorldServiceUnitTest.java new file mode 100644 index 0000000000..c9ecd57995 --- /dev/null +++ b/libraries/src/test/java/com/baeldung/infinispan/service/HelloWorldServiceUnitTest.java @@ -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); + + } + +} diff --git a/libraries/src/test/java/com/baeldung/infinispan/service/TransactionalServiceUnitTest.java b/libraries/src/test/java/com/baeldung/infinispan/service/TransactionalServiceUnitTest.java new file mode 100644 index 0000000000..99efacd18a --- /dev/null +++ b/libraries/src/test/java/com/baeldung/infinispan/service/TransactionalServiceUnitTest.java @@ -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); + } + +} diff --git a/libraries/src/test/java/com/baeldung/smooks/converter/SmooksIntegrationTest.java b/libraries/src/test/java/com/baeldung/smooks/converter/SmooksIntegrationTest.java new file mode 100644 index 0000000000..4d2cb71329 --- /dev/null +++ b/libraries/src/test/java/com/baeldung/smooks/converter/SmooksIntegrationTest.java @@ -0,0 +1,70 @@ +package com.baeldung.smooks.converter; + +import com.baeldung.smooks.model.Item; +import com.baeldung.smooks.model.Order; +import com.baeldung.smooks.model.Status; +import com.baeldung.smooks.model.Supplier; +import org.junit.Test; +import org.milyn.validation.ValidationResult; +import java.text.SimpleDateFormat; +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; + + +public class SmooksIntegrationTest { + + private static final String EDIFACT_MESSAGE = + "UNA:+.? '\r\n" + + "UNH+771+IN_PROGRESS+2018-01-14'\r\n" + + "CTA+CompanyX+1234567'\r\n" + + "LIN+1+PX1234+9.99'\r\n" + + "LIN+2+RX990+120.32'\r\n"; + private static final String EMAIL_MESSAGE = + "Hi,\r\n" + + "Order number #771 created on 2018-01-14 is currently in IN_PROGRESS status.\r\n" + + "Consider contact supplier \"CompanyX\" with phone number: \"1234567\".\r\n" + + "Order items:\r\n" + + "1 X PX1234 (total price 9.99)\r\n" + + "2 X RX990 (total price 240.64)\r\n"; + + @Test + public void givenOrderXML_whenConvert_thenPOJOsConstructedCorrectly() throws Exception { + + OrderConverter xmlToJavaOrderConverter = new OrderConverter(); + Order order = xmlToJavaOrderConverter.convertOrderXMLToOrderObject("/smooks/order.xml"); + + assertThat(order.getNumber(),is(771L)); + assertThat(order.getStatus(),is(Status.IN_PROGRESS)); + assertThat(order.getCreationDate(),is(new SimpleDateFormat("yyyy-MM-dd").parse("2018-01-14"))); + assertThat(order.getSupplier(),is(new Supplier("CompanyX","1234567"))); + assertThat(order.getItems(),containsInAnyOrder( + new Item("PX1234",9.99,1), + new Item("RX990",120.32,2)) + ); + + } + + @Test + public void givenIncorrectOrderXML_whenValidate_thenExpectValidationErrors() throws Exception { + OrderValidator orderValidator = new OrderValidator(); + ValidationResult validationResult = orderValidator.validate("/smooks/order.xml"); + + assertThat(validationResult.getErrors(), hasSize(1)); + // 1234567 didn't match ^[0-9\\-\\+]{9,15}$ + assertThat(validationResult.getErrors().get(0).getFailRuleResult().getRuleName(),is("supplierPhone")); + } + + @Test + public void givenOrderXML_whenApplyEDITemplate_thenConvertedToEDIFACT() throws Exception { + OrderConverter orderConverter = new OrderConverter(); + String edifact = orderConverter.convertOrderXMLtoEDIFACT("/smooks/order.xml"); + assertThat(edifact,is(EDIFACT_MESSAGE)); + } + + @Test + public void givenOrderXML_whenApplyEmailTemplate_thenConvertedToEmailMessage() throws Exception { + OrderConverter orderConverter = new OrderConverter(); + String emailMessage = orderConverter.convertOrderXMLtoEmailMessage("/smooks/order.xml"); + assertThat(emailMessage,is(EMAIL_MESSAGE)); + } +} \ No newline at end of file diff --git a/libraries/src/test/java/com/baeldung/tomcat/ProgrammaticTomcatTest.java b/libraries/src/test/java/com/baeldung/tomcat/ProgrammaticTomcatTest.java new file mode 100644 index 0000000000..d559c3d408 --- /dev/null +++ b/libraries/src/test/java/com/baeldung/tomcat/ProgrammaticTomcatTest.java @@ -0,0 +1,62 @@ +package com.baeldung.tomcat; + +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.util.EntityUtils; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.BlockJUnit4ClassRunner; + + +import static junit.framework.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +/** + * Created by adi on 1/14/18. + */ +@RunWith(BlockJUnit4ClassRunner.class) +public class ProgrammaticTomcatTest { + + private ProgrammaticTomcat tomcat = new ProgrammaticTomcat(); + + @Before + public void setUp() throws Exception { + tomcat.startTomcat(); + } + + @After + public void tearDown() throws Exception { + tomcat.stopTomcat(); + } + + @Test + public void givenTomcatStarted_whenAccessServlet_responseIsTestAndResponseHeaderIsSet() throws Exception { + CloseableHttpClient httpClient = HttpClientBuilder + .create() + .build(); + HttpGet getServlet = new HttpGet("http://localhost:8080/my-servlet"); + + HttpResponse response = httpClient.execute(getServlet); + assertEquals(HttpStatus.SC_OK, response + .getStatusLine() + .getStatusCode()); + + String myHeaderValue = response + .getFirstHeader("myHeader") + .getValue(); + assertEquals("myHeaderValue", myHeaderValue); + + HttpEntity responseEntity = response.getEntity(); + assertNotNull(responseEntity); + + String responseString = EntityUtils.toString(responseEntity, "UTF-8"); + assertEquals("test", responseString); + } + +} diff --git a/logging-modules/README.md b/logging-modules/README.md index 8ae7316047..6de71adb43 100644 --- a/logging-modules/README.md +++ b/logging-modules/README.md @@ -4,3 +4,4 @@ ### Relevant Articles: - [Creating a Custom Logback Appender](http://www.baeldung.com/custom-logback-appender) +- [Get Log Output in JSON Format](http://www.baeldung.com/java-log-json-output) diff --git a/mesos-marathon/README.md b/mesos-marathon/README.md index 3223eb2478..1d4d4995a8 100644 --- a/mesos-marathon/README.md +++ b/mesos-marathon/README.md @@ -1,3 +1,5 @@ ### Relevant articles - [Simple Jenkins Pipeline with Marathon and Mesos](http://www.baeldung.com/jenkins-pipeline-with-marathon-mesos) + + To run the pipeline, please modify the dockerise.sh file with your own useranema and password for docker login. diff --git a/microprofile/pom.xml b/microprofile/pom.xml new file mode 100644 index 0000000000..ce8a2d13ca --- /dev/null +++ b/microprofile/pom.xml @@ -0,0 +1,87 @@ + + + 4.0.0 + + com.baeldung + microprofile + 1.0-SNAPSHOT + war + + + UTF-8 + UTF-8 + 1.8 + 1.8 + library + ${project.build.directory}/${app.name}-service.jar + runnable + + + + + org.eclipse.microprofile + microprofile + 1.2 + provided + pom + + + + + + + maven-war-plugin + + false + pom.xml + + + + net.wasdev.wlp.maven.plugins + liberty-maven-plugin + 2.1.2 + + + io.openliberty + openliberty-runtime + 17.0.0.4 + zip + + ${basedir}/src/main/liberty/config/server.xml + ${package.file} + ${packaging.type} + false + project + + / + ${project.artifactId}-${project.version}.war + 9080 + 9443 + + + + + install-server + prepare-package + + install-server + create-server + install-feature + + + + package-server-with-apps + package + + install-apps + package-server + + + + + + + + diff --git a/microprofile/src/main/java/com/baeldung/microprofile/LibraryApplication.java b/microprofile/src/main/java/com/baeldung/microprofile/LibraryApplication.java new file mode 100644 index 0000000000..f5eccf969e --- /dev/null +++ b/microprofile/src/main/java/com/baeldung/microprofile/LibraryApplication.java @@ -0,0 +1,8 @@ +package com.baeldung.microprofile; + +import javax.ws.rs.ApplicationPath; +import javax.ws.rs.core.Application; + +@ApplicationPath("/library") +public class LibraryApplication extends Application { +} diff --git a/microprofile/src/main/java/com/baeldung/microprofile/model/Book.java b/microprofile/src/main/java/com/baeldung/microprofile/model/Book.java new file mode 100644 index 0000000000..44b7f5428d --- /dev/null +++ b/microprofile/src/main/java/com/baeldung/microprofile/model/Book.java @@ -0,0 +1,50 @@ +package com.baeldung.microprofile.model; + +public class Book { + + private String id; + private String isbn; + private String name; + private String author; + private Integer pages; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getIsbn() { + return isbn; + } + + public void setIsbn(String isbn) { + this.isbn = isbn; + } + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public Integer getPages() { + return pages; + } + + public void setPages(Integer pages) { + this.pages = pages; + } +} diff --git a/microprofile/src/main/java/com/baeldung/microprofile/providers/BookListMessageBodyWriter.java b/microprofile/src/main/java/com/baeldung/microprofile/providers/BookListMessageBodyWriter.java new file mode 100644 index 0000000000..f7d0bfc5f7 --- /dev/null +++ b/microprofile/src/main/java/com/baeldung/microprofile/providers/BookListMessageBodyWriter.java @@ -0,0 +1,42 @@ +package com.baeldung.microprofile.providers; + +import com.baeldung.microprofile.model.Book; +import com.baeldung.microprofile.util.BookMapper; + +import javax.json.Json; +import javax.json.JsonArray; +import javax.json.JsonWriter; +import javax.ws.rs.Produces; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.ext.MessageBodyWriter; +import javax.ws.rs.ext.Provider; +import java.io.IOException; +import java.io.OutputStream; +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; +import java.util.List; + +@Provider +@Produces(MediaType.APPLICATION_JSON) +public class BookListMessageBodyWriter implements MessageBodyWriter> { + + @Override + public boolean isWriteable(Class clazz, Type genericType, Annotation[] annotations, MediaType mediaType) { + return true; + } + + @Override + public long getSize(List books, Class type, Type genericType, Annotation[] annotations, MediaType mediaType) { + return 0; + } + + @Override + public void writeTo(List books, Class type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders, OutputStream entityStream) throws IOException, WebApplicationException { + JsonWriter jsonWriter = Json.createWriter(entityStream); + JsonArray jsonArray = BookMapper.map(books); + jsonWriter.writeArray(jsonArray); + jsonWriter.close(); + } +} diff --git a/microprofile/src/main/java/com/baeldung/microprofile/providers/BookMessageBodyReader.java b/microprofile/src/main/java/com/baeldung/microprofile/providers/BookMessageBodyReader.java new file mode 100644 index 0000000000..26ce4c1b64 --- /dev/null +++ b/microprofile/src/main/java/com/baeldung/microprofile/providers/BookMessageBodyReader.java @@ -0,0 +1,30 @@ +package com.baeldung.microprofile.providers; + +import com.baeldung.microprofile.model.Book; +import com.baeldung.microprofile.util.BookMapper; + +import javax.ws.rs.Consumes; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.ext.MessageBodyReader; +import javax.ws.rs.ext.Provider; +import java.io.IOException; +import java.io.InputStream; +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; + +@Provider +@Consumes(MediaType.APPLICATION_JSON) +public class BookMessageBodyReader implements MessageBodyReader { + + @Override + public boolean isReadable(Class type, Type genericType, Annotation[] annotations, MediaType mediaType) { + return type.equals(Book.class); + } + + @Override + public Book readFrom(Class type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders, InputStream entityStream) throws IOException, WebApplicationException { + return BookMapper.map(entityStream); + } +} \ No newline at end of file diff --git a/microprofile/src/main/java/com/baeldung/microprofile/providers/BookMessageBodyWriter.java b/microprofile/src/main/java/com/baeldung/microprofile/providers/BookMessageBodyWriter.java new file mode 100644 index 0000000000..9bc6e89958 --- /dev/null +++ b/microprofile/src/main/java/com/baeldung/microprofile/providers/BookMessageBodyWriter.java @@ -0,0 +1,57 @@ +package com.baeldung.microprofile.providers; + +import com.baeldung.microprofile.model.Book; +import com.baeldung.microprofile.util.BookMapper; + +import javax.json.Json; +import javax.json.JsonObject; +import javax.json.JsonWriter; +import javax.ws.rs.Produces; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.ext.MessageBodyWriter; +import javax.ws.rs.ext.Provider; +import java.io.IOException; +import java.io.OutputStream; +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; + +@Provider +@Produces(MediaType.APPLICATION_JSON) +public class BookMessageBodyWriter implements MessageBodyWriter { + @Override + public boolean isWriteable(Class type, Type genericType, Annotation[] annotations, MediaType mediaType) { + return type.equals(Book.class); + } + + /* + Deprecated in JAX RS 2.0 + */ + @Override + public long getSize(Book book, Class type, Type genericType, Annotation[] annotations, MediaType mediaType) { + return 0; + } + + /** + * Marsahl Book to OutputStream + * + * @param book + * @param type + * @param genericType + * @param annotations + * @param mediaType + * @param httpHeaders + * @param entityStream + * @throws IOException + * @throws WebApplicationException + */ + @Override + public void writeTo(Book book, Class type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders, OutputStream entityStream) throws IOException, WebApplicationException { + JsonWriter jsonWriter = Json.createWriter(entityStream); + JsonObject jsonObject = BookMapper.map(book); + jsonWriter.writeObject(jsonObject); + jsonWriter.close(); + } + +} diff --git a/microprofile/src/main/java/com/baeldung/microprofile/repo/BookManager.java b/microprofile/src/main/java/com/baeldung/microprofile/repo/BookManager.java new file mode 100644 index 0000000000..924cf0ce71 --- /dev/null +++ b/microprofile/src/main/java/com/baeldung/microprofile/repo/BookManager.java @@ -0,0 +1,53 @@ +package com.baeldung.microprofile.repo; + +import com.baeldung.microprofile.model.Book; + +import javax.enterprise.context.ApplicationScoped; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicInteger; + +@ApplicationScoped +public class BookManager { + + private DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMM"); + private AtomicInteger bookIdGenerator = new AtomicInteger(0); + + private ConcurrentMap inMemoryStore = new ConcurrentHashMap<>(); + + public BookManager() { + Book book = new Book(); + book.setId(getNextId()); + book.setName("Building Microservice With Eclipse MicroProfile"); + book.setIsbn("1"); + book.setAuthor("baeldung"); + book.setPages(420); + inMemoryStore.put(book.getId(), book); + } + + private String getNextId() { + String date = LocalDate.now().format(formatter); + return String.format("%04d-%s", bookIdGenerator.incrementAndGet(), date); + } + + public String add(Book book) { + String id = getNextId(); + book.setId(id); + inMemoryStore.put(id, book); + return id; + } + + public Book get(String id) { + return inMemoryStore.get(id); + } + + public List getAll() { + List books = new ArrayList<>(); + books.addAll(inMemoryStore.values()); + return books; + } +} diff --git a/microprofile/src/main/java/com/baeldung/microprofile/util/BookMapper.java b/microprofile/src/main/java/com/baeldung/microprofile/util/BookMapper.java new file mode 100644 index 0000000000..861b172299 --- /dev/null +++ b/microprofile/src/main/java/com/baeldung/microprofile/util/BookMapper.java @@ -0,0 +1,72 @@ +package com.baeldung.microprofile.util; + +import com.baeldung.microprofile.model.Book; + +import javax.json.*; +import java.io.InputStream; +import java.util.List; + +public class BookMapper { + + public static JsonObject map(Book book) { + JsonObjectBuilder builder = Json.createObjectBuilder(); + addValue(builder, "id", book.getId()); + addValue(builder, "isbn", book.getIsbn()); + addValue(builder, "name", book.getName()); + addValue(builder, "author", book.getAuthor()); + addValue(builder, "pages", book.getPages()); + return builder.build(); + } + + private static void addValue(JsonObjectBuilder builder, String key, Object value) { + if (value != null) { + builder.add(key, value.toString()); + } else { + builder.addNull(key); + } + } + + public static JsonArray map(List books) { + final JsonArrayBuilder arrayBuilder = Json.createArrayBuilder(); + books.forEach(book -> { + JsonObject jsonObject = map(book); + arrayBuilder.add(jsonObject); + }); + return arrayBuilder.build(); + } + + public static Book map(InputStream is) { + try(JsonReader jsonReader = Json.createReader(is)) { + JsonObject jsonObject = jsonReader.readObject(); + Book book = new Book(); + book.setId(getStringFromJson("id", jsonObject)); + book.setIsbn(getStringFromJson("isbn", jsonObject)); + book.setName(getStringFromJson("name", jsonObject)); + book.setAuthor(getStringFromJson("author", jsonObject)); + book.setPages(getIntFromJson("pages",jsonObject)); + return book; + } + } + + private static String getStringFromJson(String key, JsonObject json) { + String returnedString = null; + if (json.containsKey(key)) { + JsonString value = json.getJsonString(key); + if (value != null) { + returnedString = value.getString(); + } + } + return returnedString; + } + + private static Integer getIntFromJson(String key, JsonObject json) { + Integer returnedValue = null; + if (json.containsKey(key)) { + JsonNumber value = json.getJsonNumber(key); + if (value != null) { + returnedValue = value.intValue(); + } + } + return returnedValue; + } +} diff --git a/microprofile/src/main/java/com/baeldung/microprofile/web/BookEndpoint.java b/microprofile/src/main/java/com/baeldung/microprofile/web/BookEndpoint.java new file mode 100644 index 0000000000..13143a5644 --- /dev/null +++ b/microprofile/src/main/java/com/baeldung/microprofile/web/BookEndpoint.java @@ -0,0 +1,42 @@ +package com.baeldung.microprofile.web; + +import com.baeldung.microprofile.model.Book; +import com.baeldung.microprofile.repo.BookManager; + +import javax.enterprise.context.RequestScoped; +import javax.inject.Inject; +import javax.ws.rs.*; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriBuilder; + +@Path("books") +@RequestScoped +public class BookEndpoint { + + @Inject + private BookManager bookManager; + + @GET + @Path("{id}") + @Produces(MediaType.APPLICATION_JSON) + public Response getBook(@PathParam("id") String id) { + Book book = bookManager.get(id); + return Response.ok(book).build(); + } + + @GET + @Produces(MediaType.APPLICATION_JSON) + public Response getAllBooks() { + return Response.ok(bookManager.getAll()).build(); + } + + @POST + @Consumes(MediaType.APPLICATION_JSON) + public Response add(Book book) { + String bookId = bookManager.add(book); + return Response.created( + UriBuilder.fromResource(this.getClass()).path(bookId).build()) + .build(); + } +} diff --git a/microprofile/src/main/liberty/config/server.xml b/microprofile/src/main/liberty/config/server.xml new file mode 100644 index 0000000000..2b855bee05 --- /dev/null +++ b/microprofile/src/main/liberty/config/server.xml @@ -0,0 +1,11 @@ + + + jaxrs-2.0 + cdi-1.2 + jsonp-1.0 + + + + + diff --git a/out/production/generated-sources8/src.main.resources.reladomo.ReladomoClassList.xml.log b/out/production/generated-sources8/src.main.resources.reladomo.ReladomoClassList.xml.log new file mode 100644 index 0000000000..0bd4e29a45 --- /dev/null +++ b/out/production/generated-sources8/src.main.resources.reladomo.ReladomoClassList.xml.log @@ -0,0 +1,2 @@ +f5a6ba3b942a82fcbfb72e61502d5c30 +9201deea diff --git a/out/production/introduction/views/index.scala.html b/out/production/introduction/views/index.scala.html new file mode 100644 index 0000000000..4539f5a10b --- /dev/null +++ b/out/production/introduction/views/index.scala.html @@ -0,0 +1,20 @@ +@* + * This template takes a single argument, a String containing a + * message to display. + *@ +@(message: String) + +@* + * Call the `main` template with two arguments. The first + * argument is a `String` with the title of the page, the second + * argument is an `Html` object containing the body of the page. + *@ +@main("Welcome to Play") { + + @* + * Get an `Html` object by calling the built-in Play welcome + * template and passing a `String` message. + *@ + @play20.welcome(message, style = "Java") + +} diff --git a/out/production/introduction/views/main.scala.html b/out/production/introduction/views/main.scala.html new file mode 100644 index 0000000000..9414f4be6e --- /dev/null +++ b/out/production/introduction/views/main.scala.html @@ -0,0 +1,23 @@ +@* + * This template is called from the `index` template. This template + * handles the rendering of the page header and body tags. It takes + * two arguments, a `String` for the title of the page and an `Html` + * object to insert into the body of the page. + *@ +@(title: String)(content: Html) + + + + + @* Here's where we render the page title `String`. *@ + @title + + + + + + @* And here's where we render the `Html` object containing + * the page content. *@ + @content + + diff --git a/out/production/main122/.gitignore b/out/production/main122/.gitignore new file mode 100644 index 0000000000..83c05e60c8 --- /dev/null +++ b/out/production/main122/.gitignore @@ -0,0 +1,13 @@ +*.class + +#folders# +/target +/neoDb* +/data +/src/main/webapp/WEB-INF/classes +*/META-INF/* + +# Packaged files # +*.jar +*.war +*.ear \ No newline at end of file diff --git a/out/production/main151/com/baeldung/.gitignore b/out/production/main151/com/baeldung/.gitignore new file mode 100644 index 0000000000..83c05e60c8 --- /dev/null +++ b/out/production/main151/com/baeldung/.gitignore @@ -0,0 +1,13 @@ +*.class + +#folders# +/target +/neoDb* +/data +/src/main/webapp/WEB-INF/classes +*/META-INF/* + +# Packaged files # +*.jar +*.war +*.ear \ No newline at end of file diff --git a/out/production/main151/com/baeldung/README.md b/out/production/main151/com/baeldung/README.md new file mode 100644 index 0000000000..51809b2882 --- /dev/null +++ b/out/production/main151/com/baeldung/README.md @@ -0,0 +1,2 @@ +### Relevant Articles: +- [SHA-256 Hashing in Java](http://www.baeldung.com/sha-256-hashing-java) diff --git a/out/production/main155/com/baeldung/git/README.md b/out/production/main155/com/baeldung/git/README.md new file mode 100644 index 0000000000..7e6a597c28 --- /dev/null +++ b/out/production/main155/com/baeldung/git/README.md @@ -0,0 +1,2 @@ +### Relevant Articles: +- [Injecting Git Information Into Spring](http://www.baeldung.com/spring-git-information) diff --git a/out/production/main173/log4j.properties b/out/production/main173/log4j.properties new file mode 100644 index 0000000000..5fe42d854c --- /dev/null +++ b/out/production/main173/log4j.properties @@ -0,0 +1,9 @@ +# Set root logger level to DEBUG and its only appender to A1. +log4j.rootLogger=DEBUG, A1 + +# A1 is set to be a ConsoleAppender. +log4j.appender.A1=org.apache.log4j.ConsoleAppender + +# A1 uses PatternLayout. +log4j.appender.A1.layout=org.apache.log4j.PatternLayout +log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n diff --git a/out/production/main180/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/README.txt b/out/production/main180/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/README.txt new file mode 100644 index 0000000000..bffe24e485 --- /dev/null +++ b/out/production/main180/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/README.txt @@ -0,0 +1,76 @@ +About the application +--------------------- +This application demonstrates the usage of JavaEE Web Annotations. + + +Contents of the application +--------------------------- +1. AccountServlet.java - Demonstrates the @WebServlet and @ServletSecurity annotation. + +NOTES: @WebServlet annotation designates the AccountServlet class as a Servlet component. + The usage of its parameters 'urlPatterns' & 'initParams' can be observed. + An initialization parameter 'type' is being set to denote the type of the bank account. + + @ServletSecurity annotation imposes security constraints on the AccountServlet based on + the tomcat-users.xml. +   + This code assumes that your tomcat-users.xml looks as follows: + + + + + + + +   +N.B : To see @ServletSecurity annotation in action, please uncomment the annotation code + for @ServletSecurity. + + +2. BankAppServletContextListener.java - Demonstrates the @WebListener annotation for denoting a class as a ServletContextListener. + +NOTES: Sets a Servlet context attribute ATTR_DEFAULT_LANGUAGE to 'english' on web application start up, + which can then be used throughout the application. + + +3. LogInFilter.java - Demonstrates the @WebFilter annotation. + +NOTES: @WebFilter annotation designates the LogInFilter class as a Filter component. + It filters all requests to the bank account servlet and redirects them to + the login page. + +N.B : To see @WebFilter annotation in action, please uncomment the annotation code for @WebFilter. + + +4. UploadCustomerDocumentsServlet.java - Demonstrates the @MultipartConfig annotation. + +NOTES: @MultipartConfig anotation designates the UploadCustomerDocumentsServlet Servlet component, + to handle multipart/form-data requests. + To see it in action, deploy the web application an access the url: http://:/JavaEEAnnotationsSample/upload.jsp + Once you upload a file from here, it will get uploaded to D:/custDocs (assuming such a folder exists). + + +5. index.jsp - This is the welcome page. + +NOTES: You can enter a deposit amount here and click on the 'Deposit' button to see the AccountServlet in action. + +6. login.jsp - All requests to the AccountServlet are redirected to this page, if the LogInFilter is imposed. + +7. upload.jsp - Demonstrates the usage of handling multipart/form-data requests by the UploadCustomerDocumentsServlet. + + +Building and Running the application +------------------------------------ +To build the application: + +1. Open the project in eclipse +2. Right click on it in eclispe and choose Run As > Maven build +3. Give 'clean install' under Goals +4. This should build the WAR file of the application + +To run the application: + +1. Right click on the project +2. Run as > Run on Server +3. This will start you Tomcat server and deploy the application (Provided that you have configured Tomcat in your eclipse) +4. You should now be able to access the url : http://:/JavaEEAnnotationsSample diff --git a/out/production/main180/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/pom.xml b/out/production/main180/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/pom.xml new file mode 100644 index 0000000000..de69efa43a --- /dev/null +++ b/out/production/main180/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/pom.xml @@ -0,0 +1,57 @@ + + 4.0.0 + com.baeldung.javaeeannotations + JavaEEAnnotationsSample + 0.0.1-SNAPSHOT + war + JavaEEAnnotationsSample + JavaEEAnnotationsSample + + + + + javax.annotation + javax.annotation-api + 1.3 + + + + javax.servlet + javax.servlet-api + 3.1.0 + + + + javax.servlet.jsp + jsp-api + 2.1 + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.7.0 + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-war-plugin + 2.4 + + src/main/webapp + SpringFieldConstructorInjection + false + + + + + JavaEEAnnotationsSample + + \ No newline at end of file diff --git a/out/production/main180/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/webapp/WEB-INF/web.xml b/out/production/main180/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000000..a92885ec11 --- /dev/null +++ b/out/production/main180/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,10 @@ + + + + BASIC + default + + diff --git a/out/production/main180/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/webapp/index.jsp b/out/production/main180/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/webapp/index.jsp new file mode 100644 index 0000000000..c49dec859e --- /dev/null +++ b/out/production/main180/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/webapp/index.jsp @@ -0,0 +1,16 @@ +<%@ page language="java" contentType="text/html; charset=ISO-8859-1" + pageEncoding="ISO-8859-1"%> + + + + +My Account + + +
+ Amount: +    + +
+ + \ No newline at end of file diff --git a/out/production/main180/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/webapp/login.jsp b/out/production/main180/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/webapp/login.jsp new file mode 100644 index 0000000000..6892cb0420 --- /dev/null +++ b/out/production/main180/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/webapp/login.jsp @@ -0,0 +1,12 @@ +<%@ page language="java" contentType="text/html; charset=ISO-8859-1" + pageEncoding="ISO-8859-1"%> + + + + +Login + + +Login Here... + + \ No newline at end of file diff --git a/out/production/main180/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/webapp/upload.jsp b/out/production/main180/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/webapp/upload.jsp new file mode 100644 index 0000000000..3601322ef0 --- /dev/null +++ b/out/production/main180/com/baeldung/javaeeannotations/JavaEEAnnotationsSample/src/main/webapp/upload.jsp @@ -0,0 +1,16 @@ +<%@ page language="java" contentType="text/html; charset=ISO-8859-1" + pageEncoding="ISO-8859-1"%> + + + + +Insert title here + + +
+ +
+ +
+ + \ No newline at end of file diff --git a/out/production/main180/com/baeldung/jaxws/wsdl/employeeservicetopdown.wsdl b/out/production/main180/com/baeldung/jaxws/wsdl/employeeservicetopdown.wsdl new file mode 100644 index 0000000000..426717f90e --- /dev/null +++ b/out/production/main180/com/baeldung/jaxws/wsdl/employeeservicetopdown.wsdl @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/out/production/main195/com/baeldung/java/nio/selector/README.md b/out/production/main195/com/baeldung/java/nio/selector/README.md new file mode 100644 index 0000000000..b28aae1397 --- /dev/null +++ b/out/production/main195/com/baeldung/java/nio/selector/README.md @@ -0,0 +1,2 @@ +###Relevant Articles: +- [Introduction to the Java NIO Selector](http://www.baeldung.com/java-nio-selector) diff --git a/out/production/main216/com/baeldung/googlehttpclientguide/logging.properties b/out/production/main216/com/baeldung/googlehttpclientguide/logging.properties new file mode 100644 index 0000000000..02489378df --- /dev/null +++ b/out/production/main216/com/baeldung/googlehttpclientguide/logging.properties @@ -0,0 +1,10 @@ +# Properties file which configures the operation of the JDK logging facility. +# The system will look for this config file to be specified as a system property: +# -Djava.util.logging.config.file=${project_loc:dailymotion-simple-cmdline-sample}/logging.properties + +# Set up the console handler (uncomment "level" to show more fine-grained messages) +handlers = java.util.logging.ConsoleHandler +java.util.logging.ConsoleHandler.level = ALL + +# Set up logging of HTTP requests and responses (uncomment "level" to show) +com.google.api.client.http.level = ALL diff --git a/out/production/main231/com/baeldung/wicket/examples/HelloWorld.html b/out/production/main231/com/baeldung/wicket/examples/HelloWorld.html new file mode 100644 index 0000000000..497e98e01a --- /dev/null +++ b/out/production/main231/com/baeldung/wicket/examples/HelloWorld.html @@ -0,0 +1,52 @@ + + + + +Wicket Intro Examples + + + +
+
+
+

Wicket Introduction Examples:

+ + Hello World! +
+
+ Cafes +
+
+
+
+ + diff --git a/out/production/main231/com/baeldung/wicket/examples/cafeaddress/CafeAddress.html b/out/production/main231/com/baeldung/wicket/examples/cafeaddress/CafeAddress.html new file mode 100644 index 0000000000..c5ada2323d --- /dev/null +++ b/out/production/main231/com/baeldung/wicket/examples/cafeaddress/CafeAddress.html @@ -0,0 +1,15 @@ + + + + +Cafes + + +
+ +

+ Address: address +

+
+ + diff --git a/out/production/main231/com/baeldung/wicket/examples/helloworld/HelloWorld.html b/out/production/main231/com/baeldung/wicket/examples/helloworld/HelloWorld.html new file mode 100644 index 0000000000..c56d07fc10 --- /dev/null +++ b/out/production/main231/com/baeldung/wicket/examples/helloworld/HelloWorld.html @@ -0,0 +1,5 @@ + + + + + diff --git a/out/production/main234/com/baeldung/activiti/security.rar b/out/production/main234/com/baeldung/activiti/security.rar new file mode 100644 index 0000000000..38c4946168 Binary files /dev/null and b/out/production/main234/com/baeldung/activiti/security.rar differ diff --git a/out/production/main237/com/baeldung/datetime/README.md b/out/production/main237/com/baeldung/datetime/README.md new file mode 100644 index 0000000000..1e4adbb612 --- /dev/null +++ b/out/production/main237/com/baeldung/datetime/README.md @@ -0,0 +1,2 @@ +### Relevant Articles: +- [Introduction to the Java 8 Date/Time API](http://www.baeldung.com/java-8-date-time-intro) diff --git a/out/production/main291/xml-bean-config.xml b/out/production/main291/xml-bean-config.xml new file mode 100644 index 0000000000..3b880bbd70 --- /dev/null +++ b/out/production/main291/xml-bean-config.xml @@ -0,0 +1,12 @@ + + + + + + + + + + \ No newline at end of file diff --git a/out/production/main30/com/baeldung/factorybean/README.md b/out/production/main30/com/baeldung/factorybean/README.md new file mode 100644 index 0000000000..13f9f379e0 --- /dev/null +++ b/out/production/main30/com/baeldung/factorybean/README.md @@ -0,0 +1,2 @@ +### Relevant Articles: +- [How to use the Spring FactoryBean?](http://www.baeldung.com/spring-factorybean) diff --git a/out/production/main330/com/baeldung/.gitignore b/out/production/main330/com/baeldung/.gitignore new file mode 100644 index 0000000000..83c05e60c8 --- /dev/null +++ b/out/production/main330/com/baeldung/.gitignore @@ -0,0 +1,13 @@ +*.class + +#folders# +/target +/neoDb* +/data +/src/main/webapp/WEB-INF/classes +*/META-INF/* + +# Packaged files # +*.jar +*.war +*.ear \ No newline at end of file diff --git a/out/production/main330/com/baeldung/README.md b/out/production/main330/com/baeldung/README.md new file mode 100644 index 0000000000..51809b2882 --- /dev/null +++ b/out/production/main330/com/baeldung/README.md @@ -0,0 +1,2 @@ +### Relevant Articles: +- [SHA-256 Hashing in Java](http://www.baeldung.com/sha-256-hashing-java) diff --git a/out/production/main330/com/baeldung/enums/README.md b/out/production/main330/com/baeldung/enums/README.md new file mode 100644 index 0000000000..6ccfa725f5 --- /dev/null +++ b/out/production/main330/com/baeldung/enums/README.md @@ -0,0 +1,2 @@ +### Relevant Articles: +- [A Guide to Java Enums](http://www.baeldung.com/a-guide-to-java-enums) diff --git a/out/production/main330/com/baeldung/networking/README.md b/out/production/main330/com/baeldung/networking/README.md new file mode 100644 index 0000000000..b9e827f085 --- /dev/null +++ b/out/production/main330/com/baeldung/networking/README.md @@ -0,0 +1,5 @@ +### Relevant Articles: +- [A Guide To UDP In Java](http://www.baeldung.com/udp-in-java) +- [A Guide To HTTP Cookies In Java](http://www.baeldung.com/cookies-java) +- [A Guide to the Java URL](http://www.baeldung.com/java-url) +- [Working with Network Interfaces in Java](http://www.baeldung.com/java-network-interfaces) diff --git a/out/production/main330/com/baeldung/printscreen/README.md b/out/production/main330/com/baeldung/printscreen/README.md new file mode 100644 index 0000000000..7b3b40c102 --- /dev/null +++ b/out/production/main330/com/baeldung/printscreen/README.md @@ -0,0 +1,2 @@ +### Relevant Articles: +- [How to Print Screen in Java](http://www.baeldung.com/print-screen-in-java) diff --git a/out/production/main330/log4j.properties b/out/production/main330/log4j.properties new file mode 100644 index 0000000000..5fe42d854c --- /dev/null +++ b/out/production/main330/log4j.properties @@ -0,0 +1,9 @@ +# Set root logger level to DEBUG and its only appender to A1. +log4j.rootLogger=DEBUG, A1 + +# A1 is set to be a ConsoleAppender. +log4j.appender.A1=org.apache.log4j.ConsoleAppender + +# A1 uses PatternLayout. +log4j.appender.A1.layout=org.apache.log4j.PatternLayout +log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n diff --git a/out/production/main351/com/baeldung/produceimage/README.md b/out/production/main351/com/baeldung/produceimage/README.md new file mode 100644 index 0000000000..acd546598d --- /dev/null +++ b/out/production/main351/com/baeldung/produceimage/README.md @@ -0,0 +1,3 @@ +### Relevant articles + +- [Returning an Image or a File with Spring](http://www.baeldung.com/spring-controller-return-image-file) diff --git a/out/production/main96/com/baeldung/git/README.md b/out/production/main96/com/baeldung/git/README.md new file mode 100644 index 0000000000..7e6a597c28 --- /dev/null +++ b/out/production/main96/com/baeldung/git/README.md @@ -0,0 +1,2 @@ +### Relevant Articles: +- [Injecting Git Information Into Spring](http://www.baeldung.com/spring-git-information) diff --git a/out/production/routing-in-play/views/index.scala.html b/out/production/routing-in-play/views/index.scala.html new file mode 100644 index 0000000000..4539f5a10b --- /dev/null +++ b/out/production/routing-in-play/views/index.scala.html @@ -0,0 +1,20 @@ +@* + * This template takes a single argument, a String containing a + * message to display. + *@ +@(message: String) + +@* + * Call the `main` template with two arguments. The first + * argument is a `String` with the title of the page, the second + * argument is an `Html` object containing the body of the page. + *@ +@main("Welcome to Play") { + + @* + * Get an `Html` object by calling the built-in Play welcome + * template and passing a `String` message. + *@ + @play20.welcome(message, style = "Java") + +} diff --git a/out/production/routing-in-play/views/main.scala.html b/out/production/routing-in-play/views/main.scala.html new file mode 100644 index 0000000000..9414f4be6e --- /dev/null +++ b/out/production/routing-in-play/views/main.scala.html @@ -0,0 +1,23 @@ +@* + * This template is called from the `index` template. This template + * handles the rendering of the page header and body tags. It takes + * two arguments, a `String` for the title of the page and an `Html` + * object to insert into the body of the page. + *@ +@(title: String)(content: Html) + + + + + @* Here's where we render the page title `String`. *@ + @title + + + + + + @* And here's where we render the `Html` object containing + * the page content. *@ + @content + + diff --git a/out/test/test105/com/baeldung/cglib/proxy/README.md b/out/test/test105/com/baeldung/cglib/proxy/README.md new file mode 100644 index 0000000000..abeabc6162 --- /dev/null +++ b/out/test/test105/com/baeldung/cglib/proxy/README.md @@ -0,0 +1,3 @@ +### Relevant articles + +- [Introduction to cglib](http://www.baeldung.com/cglib) diff --git a/out/test/test143/com/baeldung/java9/README.MD b/out/test/test143/com/baeldung/java9/README.MD new file mode 100644 index 0000000000..2f44a2336b --- /dev/null +++ b/out/test/test143/com/baeldung/java9/README.MD @@ -0,0 +1,2 @@ +### Relevant Artiles: +- [Filtering a Stream of Optionals in Java](http://www.baeldung.com/java-filter-stream-of-optional) diff --git a/out/test/test174/org/baeldung/hamcrest/README.md b/out/test/test174/org/baeldung/hamcrest/README.md new file mode 100644 index 0000000000..7266ecda3a --- /dev/null +++ b/out/test/test174/org/baeldung/hamcrest/README.md @@ -0,0 +1,2 @@ +### Relevant Articles: +- [Testing with Hamcrest](http://www.baeldung.com/java-junit-hamcrest-guide) diff --git a/out/test/test191/com/baeldung/web/controller/README.md b/out/test/test191/com/baeldung/web/controller/README.md new file mode 100644 index 0000000000..9923962dde --- /dev/null +++ b/out/test/test191/com/baeldung/web/controller/README.md @@ -0,0 +1,2 @@ +### Relevant Articles: +- [WebAppConfiguration in Spring Tests](http://www.baeldung.com/spring-webappconfiguration) diff --git a/out/test/test197/com/baeldung/java/nio2/README.md b/out/test/test197/com/baeldung/java/nio2/README.md new file mode 100644 index 0000000000..569be82d27 --- /dev/null +++ b/out/test/test197/com/baeldung/java/nio2/README.md @@ -0,0 +1,11 @@ +### Relevant Articles: +- [Introduction to the Java NIO2 File API](http://www.baeldung.com/java-nio-2-file-api) +- [Java NIO2 Path API](http://www.baeldung.com/java-nio-2-path) +- [A Guide To NIO2 Asynchronous File Channel](http://www.baeldung.com/java-nio2-async-file-channel) +- [Guide to Selenium with JUnit / TestNG](http://www.baeldung.com/java-selenium-with-junit-and-testng) +- [A Guide to NIO2 Asynchronous Socket Channel](http://www.baeldung.com/java-nio2-async-socket-channel) +- [A Guide To NIO2 FileVisitor](http://www.baeldung.com/java-nio2-file-visitor) +- [A Guide To NIO2 File Attribute APIs](http://www.baeldung.com/java-nio2-file-attribute) +- [How to use the Spring FactoryBean?](http://www.baeldung.com/spring-factorybean) +- [A Guide to WatchService in Java NIO2](http://www.baeldung.com/java-nio2-watchservice) +- [Guide to Java NIO2 Asynchronous Channel APIs](http://www.baeldung.com/java-nio-2-async-channels) diff --git a/out/test/test237/META-INF/persistence.xml b/out/test/test237/META-INF/persistence.xml new file mode 100644 index 0000000000..922aedbc39 --- /dev/null +++ b/out/test/test237/META-INF/persistence.xml @@ -0,0 +1,20 @@ + + + + org.baeldung.persistence.model.Foo + org.baeldung.persistence.model.Bar + + + + + + + + + + + + + diff --git a/out/test/test95/com/baeldung/hexToAscii/README.md b/out/test/test95/com/baeldung/hexToAscii/README.md new file mode 100644 index 0000000000..c6d5826333 --- /dev/null +++ b/out/test/test95/com/baeldung/hexToAscii/README.md @@ -0,0 +1,2 @@ +### Relevant Articles: +- [Convert Hex to ASCII in Java](http://www.baeldung.com/java-convert-hex-to-ascii) diff --git a/out/test/test95/com/baeldung/java/conversion/README.md b/out/test/test95/com/baeldung/java/conversion/README.md new file mode 100644 index 0000000000..7c81180249 --- /dev/null +++ b/out/test/test95/com/baeldung/java/conversion/README.md @@ -0,0 +1,2 @@ +Relevant Articles: +- [Java String Conversions](http://www.baeldung.com/java-string-conversions) diff --git a/out/test/test95/org/baeldung/java/collections/README.md b/out/test/test95/org/baeldung/java/collections/README.md new file mode 100644 index 0000000000..317d81fae7 --- /dev/null +++ b/out/test/test95/org/baeldung/java/collections/README.md @@ -0,0 +1,3 @@ +### Relevant Articles: +- [Join and Split Arrays and Collections in Java](http://www.baeldung.com/java-join-and-split) +- [Introduction to Java Servlets](http://www.baeldung.com/intro-to-servlets) diff --git a/out/test/test95/org/baeldung/java/lists/README.md b/out/test/test95/org/baeldung/java/lists/README.md new file mode 100644 index 0000000000..2a1e8aeeaa --- /dev/null +++ b/out/test/test95/org/baeldung/java/lists/README.md @@ -0,0 +1,2 @@ +### Relevant Articles: +- [Check If Two Lists are Equal in Java](http://www.baeldung.com/java-test-a-list-for-ordinality-and-equality) diff --git a/out/test/test98/com/baeldung/applicationcontext/README.md b/out/test/test98/com/baeldung/applicationcontext/README.md new file mode 100644 index 0000000000..211007e0cf --- /dev/null +++ b/out/test/test98/com/baeldung/applicationcontext/README.md @@ -0,0 +1,3 @@ +### Relevant Articles: +- [Introduction to Java Servlets](http://www.baeldung.com/intro-to-servlets) +- [Intro to the Spring ClassPathXmlApplicationContext](http://www.baeldung.com/spring-classpathxmlapplicationcontext) diff --git a/out/test/test98/com/baeldung/beanfactory/README.md b/out/test/test98/com/baeldung/beanfactory/README.md new file mode 100644 index 0000000000..cff20a184b --- /dev/null +++ b/out/test/test98/com/baeldung/beanfactory/README.md @@ -0,0 +1,2 @@ +### Relevant Articles: +- [Guide to the Spring BeanFactory](http://www.baeldung.com/spring-beanfactory) diff --git a/persistence-modules/spring-data-dynamodb/pom.xml b/persistence-modules/spring-data-dynamodb/pom.xml index bf90779c29..c3ea9abf08 100644 --- a/persistence-modules/spring-data-dynamodb/pom.xml +++ b/persistence-modules/spring-data-dynamodb/pom.xml @@ -23,6 +23,10 @@ 4.4.1 1.11.64 3.3.7-1 + 1.0.392 + 1.11.106 + 1.11.86 + https://s3-us-west-2.amazonaws.com/dynamodb-local/release @@ -103,6 +107,57 @@ httpclient ${httpclient.version} + + + + + com.amazonaws + DynamoDBLocal + ${dynamodblocal.version} + test + + + com.almworks.sqlite4java + sqlite4java + ${sqlite4java.version} + test + + + com.almworks.sqlite4java + sqlite4java-win32-x86 + ${sqlite4java.version} + dll + test + + + com.almworks.sqlite4java + sqlite4java-win32-x64 + ${sqlite4java.version} + dll + test + + + com.almworks.sqlite4java + libsqlite4java-osx + ${sqlite4java.version} + dylib + test + + + com.almworks.sqlite4java + libsqlite4java-linux-i386 + ${sqlite4java.version} + so + test + + + com.almworks.sqlite4java + libsqlite4java-linux-amd64 + ${sqlite4java.version} + so + test + + @@ -120,6 +175,25 @@ org.apache.maven.plugins maven-war-plugin + + org.apache.maven.plugins + maven-dependency-plugin + 2.10 + + + copy-dependencies + test-compile + + copy-dependencies + + + test + so,dll,dylib + ${project.basedir}/native-libs + + + + @@ -142,6 +216,11 @@ false + + dynamodb-local + DynamoDB Local Release Repository + ${dynamodblocal.repository.url} + diff --git a/persistence-modules/spring-data-dynamodb/src/test/java/com/baeldung/spring/data/dynamodb/repository/ProductInfoRepositoryIntegrationTest.java b/persistence-modules/spring-data-dynamodb/src/test/java/com/baeldung/spring/data/dynamodb/repository/ProductInfoRepositoryIntegrationTest.java index 2ff418b4ec..6cbd5b0a5a 100644 --- a/persistence-modules/spring-data-dynamodb/src/test/java/com/baeldung/spring/data/dynamodb/repository/ProductInfoRepositoryIntegrationTest.java +++ b/persistence-modules/spring-data-dynamodb/src/test/java/com/baeldung/spring/data/dynamodb/repository/ProductInfoRepositoryIntegrationTest.java @@ -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.LocalDbCreationRule; 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 LocalDbCreationRule dynamoDB = new LocalDbCreationRule(); + 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) 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 result = (List) 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))); } } diff --git a/persistence-modules/spring-data-dynamodb/src/test/java/com/baeldung/spring/data/dynamodb/repository/rule/LocalDbCreationRule.java b/persistence-modules/spring-data-dynamodb/src/test/java/com/baeldung/spring/data/dynamodb/repository/rule/LocalDbCreationRule.java new file mode 100644 index 0000000000..555d558b06 --- /dev/null +++ b/persistence-modules/spring-data-dynamodb/src/test/java/com/baeldung/spring/data/dynamodb/repository/rule/LocalDbCreationRule.java @@ -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 LocalDbCreationRule extends ExternalResource { + + protected DynamoDBProxyServer server; + + public LocalDbCreationRule() { + 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() { + this.stopUnchecked(server); + } + + protected void stopUnchecked(DynamoDBProxyServer dynamoDbServer) { + try { + dynamoDbServer.stop(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + +} diff --git a/persistence-modules/spring-data-redis/pom.xml b/persistence-modules/spring-data-redis/pom.xml index 6cb49f11cf..0b9075147d 100644 --- a/persistence-modules/spring-data-redis/pom.xml +++ b/persistence-modules/spring-data-redis/pom.xml @@ -16,11 +16,13 @@ UTF-8 - 4.3.7.RELEASE - 1.8.1.RELEASE + 5.0.3.RELEASE + 2.0.3.RELEASE 3.2.4 2.9.0 0.10.0 + 2.0.3.RELEASE + @@ -73,6 +75,12 @@ nosqlunit-redis ${nosqlunit.version} + + + org.springframework.data + spring-data-commons + ${spring-data-commons.version} + diff --git a/persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/redis/config/RedisConfig.java b/persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/redis/config/RedisConfig.java index 4fd83a2bb6..4ea8bb4bc0 100644 --- a/persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/redis/config/RedisConfig.java +++ b/persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/redis/config/RedisConfig.java @@ -1,8 +1,5 @@ package com.baeldung.spring.data.redis.config; -import com.baeldung.spring.data.redis.queue.MessagePublisher; -import com.baeldung.spring.data.redis.queue.RedisMessagePublisher; -import com.baeldung.spring.data.redis.queue.RedisMessageSubscriber; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @@ -11,10 +8,16 @@ import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.listener.ChannelTopic; import org.springframework.data.redis.listener.RedisMessageListenerContainer; import org.springframework.data.redis.listener.adapter.MessageListenerAdapter; +import org.springframework.data.redis.repository.configuration.EnableRedisRepositories; import org.springframework.data.redis.serializer.GenericToStringSerializer; +import com.baeldung.spring.data.redis.queue.MessagePublisher; +import com.baeldung.spring.data.redis.queue.RedisMessagePublisher; +import com.baeldung.spring.data.redis.queue.RedisMessageSubscriber; + @Configuration @ComponentScan("com.baeldung.spring.data.redis") +@EnableRedisRepositories(basePackages = "com.baeldung.spring.data.redis.repo") public class RedisConfig { @Bean diff --git a/persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/redis/model/Student.java b/persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/redis/model/Student.java index 10ba0f5ef4..b97ed23387 100644 --- a/persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/redis/model/Student.java +++ b/persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/redis/model/Student.java @@ -2,6 +2,9 @@ package com.baeldung.spring.data.redis.model; import java.io.Serializable; +import org.springframework.data.redis.core.RedisHash; + +@RedisHash("Student") public class Student implements Serializable { public enum Gender { diff --git a/persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/redis/repo/StudentRepository.java b/persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/redis/repo/StudentRepository.java index 250c227f00..39f13bb6a7 100644 --- a/persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/redis/repo/StudentRepository.java +++ b/persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/redis/repo/StudentRepository.java @@ -1,18 +1,9 @@ package com.baeldung.spring.data.redis.repo; +import org.springframework.data.repository.CrudRepository; +import org.springframework.stereotype.Repository; + import com.baeldung.spring.data.redis.model.Student; -import java.util.Map; - -public interface StudentRepository { - - void saveStudent(Student person); - - void updateStudent(Student student); - - Student findStudent(String id); - - Map findAllStudents(); - - void deleteStudent(String id); -} +@Repository +public interface StudentRepository extends CrudRepository {} diff --git a/persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/redis/repo/StudentRepositoryImpl.java b/persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/redis/repo/StudentRepositoryImpl.java deleted file mode 100644 index f13bef0f54..0000000000 --- a/persistence-modules/spring-data-redis/src/main/java/com/baeldung/spring/data/redis/repo/StudentRepositoryImpl.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.baeldung.spring.data.redis.repo; - -import com.baeldung.spring.data.redis.model.Student; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.redis.core.HashOperations; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.stereotype.Repository; - -import javax.annotation.PostConstruct; -import java.util.Map; - -@Repository -public class StudentRepositoryImpl implements StudentRepository { - - private static final String KEY = "Student"; - - private RedisTemplate redisTemplate; - private HashOperations hashOperations; - - @Autowired - public StudentRepositoryImpl(RedisTemplate redisTemplate) { - this.redisTemplate = redisTemplate; - } - - @PostConstruct - private void init() { - hashOperations = redisTemplate.opsForHash(); - } - - public void saveStudent(final Student student) { - hashOperations.put(KEY, student.getId(), student); - } - - public void updateStudent(final Student student) { - hashOperations.put(KEY, student.getId(), student); - } - - public Student findStudent(final String id) { - return (Student) hashOperations.get(KEY, id); - } - - public Map findAllStudents() { - return hashOperations.entries(KEY); - } - - public void deleteStudent(final String id) { - hashOperations.delete(KEY, id); - } -} diff --git a/persistence-modules/spring-data-redis/src/test/java/com/baeldung/spring/data/redis/repo/StudentRepositoryIntegrationTest.java b/persistence-modules/spring-data-redis/src/test/java/com/baeldung/spring/data/redis/repo/StudentRepositoryIntegrationTest.java index 1028c0bc24..66ef3c21b2 100644 --- a/persistence-modules/spring-data-redis/src/test/java/com/baeldung/spring/data/redis/repo/StudentRepositoryIntegrationTest.java +++ b/persistence-modules/spring-data-redis/src/test/java/com/baeldung/spring/data/redis/repo/StudentRepositoryIntegrationTest.java @@ -1,17 +1,20 @@ package com.baeldung.spring.data.redis.repo; -import com.baeldung.spring.data.redis.config.RedisConfig; -import com.baeldung.spring.data.redis.model.Student; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import java.util.Map; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; +import com.baeldung.spring.data.redis.config.RedisConfig; +import com.baeldung.spring.data.redis.model.Student; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = RedisConfig.class) @@ -23,18 +26,18 @@ public class StudentRepositoryIntegrationTest { @Test public void whenSavingStudent_thenAvailableOnRetrieval() throws Exception { final Student student = new Student("Eng2015001", "John Doe", Student.Gender.MALE, 1); - studentRepository.saveStudent(student); - final Student retrievedStudent = studentRepository.findStudent(student.getId()); + studentRepository.save(student); + final Student retrievedStudent = studentRepository.findById(student.getId()).get(); assertEquals(student.getId(), retrievedStudent.getId()); } @Test public void whenUpdatingStudent_thenAvailableOnRetrieval() throws Exception { final Student student = new Student("Eng2015001", "John Doe", Student.Gender.MALE, 1); - studentRepository.saveStudent(student); + studentRepository.save(student); student.setName("Richard Watson"); - studentRepository.saveStudent(student); - final Student retrievedStudent = studentRepository.findStudent(student.getId()); + studentRepository.save(student); + final Student retrievedStudent = studentRepository.findById(student.getId()).get(); assertEquals(student.getName(), retrievedStudent.getName()); } @@ -42,18 +45,19 @@ public class StudentRepositoryIntegrationTest { public void whenSavingStudents_thenAllShouldAvailableOnRetrieval() throws Exception { final Student engStudent = new Student("Eng2015001", "John Doe", Student.Gender.MALE, 1); final Student medStudent = new Student("Med2015001", "Gareth Houston", Student.Gender.MALE, 2); - studentRepository.saveStudent(engStudent); - studentRepository.saveStudent(medStudent); - final Map retrievedStudent = studentRepository.findAllStudents(); - assertEquals(retrievedStudent.size(), 2); + studentRepository.save(engStudent); + studentRepository.save(medStudent); + List students = new ArrayList<>(); + studentRepository.findAll().forEach(students::add); + assertEquals(students.size(), 2); } @Test public void whenDeletingStudent_thenNotAvailableOnRetrieval() throws Exception { final Student student = new Student("Eng2015001", "John Doe", Student.Gender.MALE, 1); - studentRepository.saveStudent(student); - studentRepository.deleteStudent(student.getId()); - final Student retrievedStudent = studentRepository.findStudent(student.getId()); + studentRepository.save(student); + studentRepository.deleteById(student.getId()); + final Student retrievedStudent = studentRepository.findById(student.getId()).orElse(null); assertNull(retrievedStudent); } } \ No newline at end of file diff --git a/persistence-modules/spring-hibernate-5/src/test/java/com/baeldung/hibernate/bootstrap/HibernateBootstrapIntegrationTest.java b/persistence-modules/spring-hibernate-5/src/test/java/com/baeldung/hibernate/bootstrap/HibernateBootstrapIntegrationTest.java index ffe82b7ced..c41423643a 100644 --- a/persistence-modules/spring-hibernate-5/src/test/java/com/baeldung/hibernate/bootstrap/HibernateBootstrapIntegrationTest.java +++ b/persistence-modules/spring-hibernate-5/src/test/java/com/baeldung/hibernate/bootstrap/HibernateBootstrapIntegrationTest.java @@ -8,11 +8,16 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.annotation.Commit; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.support.AnnotationConfigContextLoader; +import org.springframework.test.context.transaction.TestTransaction; import org.springframework.transaction.annotation.Transactional; +import static junit.framework.TestCase.assertFalse; +import static junit.framework.TestCase.assertTrue; + @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = { HibernateConf.class }) @Transactional @@ -35,4 +40,146 @@ public class HibernateBootstrapIntegrationTest { Assert.assertNotNull(searchEntity); } + @Test + public void whenProgrammaticTransactionCommit_thenEntityIsInDatabase() { + assertTrue(TestTransaction.isActive()); + + //Save an entity and commit. + Session session = sessionFactory.getCurrentSession(); + + TestEntity newEntity = new TestEntity(); + newEntity.setId(1); + session.save(newEntity); + + TestEntity searchEntity = session.find(TestEntity.class, 1); + + Assert.assertNotNull(searchEntity); + assertTrue(TestTransaction.isFlaggedForRollback()); + + TestTransaction.flagForCommit(); + TestTransaction.end(); + + assertFalse(TestTransaction.isFlaggedForRollback()); + assertFalse(TestTransaction.isActive()); + + //Check that the entity is still there in a new transaction, + //then delete it, but don't commit. + TestTransaction.start(); + + assertTrue(TestTransaction.isFlaggedForRollback()); + assertTrue(TestTransaction.isActive()); + + session = sessionFactory.getCurrentSession(); + searchEntity = session.find(TestEntity.class, 1); + + Assert.assertNotNull(searchEntity); + + session.delete(searchEntity); + session.flush(); + + TestTransaction.end(); + + assertFalse(TestTransaction.isActive()); + + //Check that the entity is still there in a new transaction, + //then delete it and commit. + TestTransaction.start(); + + session = sessionFactory.getCurrentSession(); + searchEntity = session.find(TestEntity.class, 1); + + Assert.assertNotNull(searchEntity); + + session.delete(searchEntity); + session.flush(); + + assertTrue(TestTransaction.isActive()); + + TestTransaction.flagForCommit(); + TestTransaction.end(); + + assertFalse(TestTransaction.isActive()); + + //Check that the entity is no longer there in a new transaction. + TestTransaction.start(); + + assertTrue(TestTransaction.isActive()); + + session = sessionFactory.getCurrentSession(); + searchEntity = session.find(TestEntity.class, 1); + + Assert.assertNull(searchEntity); + } + + @Test + @Commit + public void givenTransactionCommitDefault_whenProgrammaticTransactionCommit_thenEntityIsInDatabase() { + assertTrue(TestTransaction.isActive()); + + //Save an entity and commit. + Session session = sessionFactory.getCurrentSession(); + + TestEntity newEntity = new TestEntity(); + newEntity.setId(1); + session.save(newEntity); + + TestEntity searchEntity = session.find(TestEntity.class, 1); + + Assert.assertNotNull(searchEntity); + assertFalse(TestTransaction.isFlaggedForRollback()); + + TestTransaction.end(); + + assertFalse(TestTransaction.isFlaggedForRollback()); + assertFalse(TestTransaction.isActive()); + + //Check that the entity is still there in a new transaction, + //then delete it, but don't commit. + TestTransaction.start(); + + assertFalse(TestTransaction.isFlaggedForRollback()); + assertTrue(TestTransaction.isActive()); + + session = sessionFactory.getCurrentSession(); + searchEntity = session.find(TestEntity.class, 1); + + Assert.assertNotNull(searchEntity); + + session.delete(searchEntity); + session.flush(); + + TestTransaction.flagForRollback(); + TestTransaction.end(); + + assertFalse(TestTransaction.isActive()); + + //Check that the entity is still there in a new transaction, + //then delete it and commit. + TestTransaction.start(); + + session = sessionFactory.getCurrentSession(); + searchEntity = session.find(TestEntity.class, 1); + + Assert.assertNotNull(searchEntity); + + session.delete(searchEntity); + session.flush(); + + assertTrue(TestTransaction.isActive()); + + TestTransaction.end(); + + assertFalse(TestTransaction.isActive()); + + //Check that the entity is no longer there in a new transaction. + TestTransaction.start(); + + assertTrue(TestTransaction.isActive()); + + session = sessionFactory.getCurrentSession(); + searchEntity = session.find(TestEntity.class, 1); + + Assert.assertNull(searchEntity); + } + } diff --git a/persistence-modules/spring-jpa/pom.xml b/persistence-modules/spring-jpa/pom.xml index 04c64fafc3..bc0b2381f3 100644 --- a/persistence-modules/spring-jpa/pom.xml +++ b/persistence-modules/spring-jpa/pom.xml @@ -13,7 +13,7 @@ com.baeldung parent-modules 1.0.0-SNAPSHOT - ../ + ../../ diff --git a/persistence-modules/spring-jpa/src/main/java/org/baeldung/inmemory/persistence/dao/StudentRepository.java b/persistence-modules/spring-jpa/src/main/java/org/baeldung/inmemory/persistence/dao/StudentRepository.java index bfcf6f5cdc..f856b78c52 100644 --- a/persistence-modules/spring-jpa/src/main/java/org/baeldung/inmemory/persistence/dao/StudentRepository.java +++ b/persistence-modules/spring-jpa/src/main/java/org/baeldung/inmemory/persistence/dao/StudentRepository.java @@ -2,6 +2,17 @@ package org.baeldung.inmemory.persistence.dao; import org.baeldung.inmemory.persistence.model.Student; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +import java.util.List; public interface StudentRepository extends JpaRepository { + + @Query("SELECT s FROM Student s JOIN s.tags t WHERE t = LOWER(:tag)") + List retrieveByTag(@Param("tag") String tag); + + @Query("SELECT s FROM Student s JOIN s.tags t WHERE s.name = LOWER(:name) AND t = LOWER(:tag)") + List retrieveByNameFilterByTag(@Param("name") String name, @Param("tag") String tag); + } diff --git a/persistence-modules/spring-jpa/src/main/java/org/baeldung/inmemory/persistence/model/Student.java b/persistence-modules/spring-jpa/src/main/java/org/baeldung/inmemory/persistence/model/Student.java index b50fe9122e..2e4e3ea2cb 100644 --- a/persistence-modules/spring-jpa/src/main/java/org/baeldung/inmemory/persistence/model/Student.java +++ b/persistence-modules/spring-jpa/src/main/java/org/baeldung/inmemory/persistence/model/Student.java @@ -1,7 +1,10 @@ package org.baeldung.inmemory.persistence.model; +import javax.persistence.ElementCollection; import javax.persistence.Entity; import javax.persistence.Id; +import java.util.ArrayList; +import java.util.List; @Entity public class Student { @@ -10,6 +13,9 @@ public class Student { private long id; private String name; + @ElementCollection + private List tags = new ArrayList<>(); + public Student() { } @@ -35,4 +41,11 @@ public class Student { this.name = name; } + public List getTags() { + return tags; + } + + public void setTags(List tags) { + this.tags.addAll(tags); + } } diff --git a/persistence-modules/spring-jpa/src/test/java/org/baeldung/persistence/repository/InMemoryDBIntegrationTest.java b/persistence-modules/spring-jpa/src/test/java/org/baeldung/persistence/repository/InMemoryDBIntegrationTest.java index 8380ab5434..28d7e3772c 100644 --- a/persistence-modules/spring-jpa/src/test/java/org/baeldung/persistence/repository/InMemoryDBIntegrationTest.java +++ b/persistence-modules/spring-jpa/src/test/java/org/baeldung/persistence/repository/InMemoryDBIntegrationTest.java @@ -12,6 +12,9 @@ import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; +import java.util.Arrays; +import java.util.List; + import static org.junit.Assert.assertEquals; @RunWith(SpringJUnit4ClassRunner.class) @@ -34,4 +37,46 @@ public class InMemoryDBIntegrationTest { assertEquals("name incorrect", NAME, student2.getName()); } + @Test + public void givenStudentWithTags_whenSave_thenGetByTagOk(){ + Student student = new Student(ID, NAME); + student.setTags(Arrays.asList("full time", "computer science")); + studentRepository.save(student); + + Student student2 = studentRepository.retrieveByTag("full time").get(0); + assertEquals("name incorrect", NAME, student2.getName()); + } + + @Test + public void givenMultipleStudentsWithTags_whenSave_thenGetByTagReturnsCorrectCount(){ + Student student = new Student(0, "Larry"); + student.setTags(Arrays.asList("full time", "computer science")); + studentRepository.save(student); + + Student student2 = new Student(1, "Curly"); + student2.setTags(Arrays.asList("part time", "rocket science")); + studentRepository.save(student2); + + Student student3 = new Student(2, "Moe"); + student3.setTags(Arrays.asList("full time", "philosophy")); + studentRepository.save(student3); + + Student student4 = new Student(3, "Shemp"); + student4.setTags(Arrays.asList("part time", "mathematics")); + studentRepository.save(student4); + + List students = studentRepository.retrieveByTag("full time"); + assertEquals("size incorrect", 2, students.size()); + } + + @Test + public void givenStudentWithTags_whenSave_thenGetByNameAndTagOk(){ + Student student = new Student(ID, NAME); + student.setTags(Arrays.asList("full time", "computer science")); + studentRepository.save(student); + + Student student2 = studentRepository.retrieveByNameFilterByTag("John", "full time").get(0); + assertEquals("name incorrect", NAME, student2.getName()); + } + } diff --git a/pom.xml b/pom.xml index 4a25459fcb..beb377a40b 100644 --- a/pom.xml +++ b/pom.xml @@ -29,7 +29,7 @@ parent-boot-5 - asm + asm atomix apache-cayenne aws @@ -49,7 +49,9 @@ core-java core-java-io core-java-8 + core-groovy core-java-concurrency + couchbase deltaspike @@ -65,6 +67,7 @@ geotools testing-modules/groovy-spock + google-cloud gson guava guava-modules/guava-18 @@ -88,11 +91,12 @@ vavr java-lite - java-rmi + java-rmi java-vavr-stream javax-servlets javaxval jaxb + jgroups jee-7 jjwt @@ -106,7 +110,7 @@ libraries libraries-data - linkrest + linkrest logging-modules/log-mdc logging-modules/log4j logging-modules/log4j2 @@ -246,9 +250,10 @@ spring-zuul spring-reactor spring-vertx - + spring-jinq + spring-rest-embedded-tomcat - + testing-modules/testing testing-modules/testng @@ -275,7 +280,7 @@ saas deeplearning4j lucene - vraptor + vraptor persistence-modules/java-cockroachdb diff --git a/reactor-core/pom.xml b/reactor-core/pom.xml index 12f481c96f..d387471d56 100644 --- a/reactor-core/pom.xml +++ b/reactor-core/pom.xml @@ -26,11 +26,17 @@ ${assertj.version} test - + + + io.projectreactor + reactor-test + ${reactor-core.version} + test + - 3.0.5.RELEASE + 3.1.3.RELEASE 3.6.1 diff --git a/reactor-core/src/test/java/com/baeldung/reactor/core/CombiningPublishersTest.java b/reactor-core/src/test/java/com/baeldung/reactor/core/CombiningPublishersTest.java new file mode 100644 index 0000000000..81dfda3bb3 --- /dev/null +++ b/reactor-core/src/test/java/com/baeldung/reactor/core/CombiningPublishersTest.java @@ -0,0 +1,180 @@ +package com.baeldung.reactor.core; + +import java.time.Duration; + +import org.junit.Test; + +import reactor.core.publisher.Flux; +import reactor.test.StepVerifier; + +public class CombiningPublishersTest { + + private static Integer min = 1; + private static Integer max = 5; + + private static Flux evenNumbers = Flux.range(min, max).filter(x -> x % 2 == 0); + private static Flux oddNumbers = Flux.range(min, max).filter(x -> x % 2 > 0); + + + @Test + public void givenFluxes_whenMergeIsInvoked_thenMerge() { + Flux fluxOfIntegers = Flux.merge( + evenNumbers, + oddNumbers); + + StepVerifier.create(fluxOfIntegers) + .expectNext(2) + .expectNext(4) + .expectNext(1) + .expectNext(3) + .expectNext(5) + .expectComplete() + .verify(); + } + + @Test + public void givenFluxes_whenMergeWithDelayedElementsIsInvoked_thenMergeWithDelayedElements() { + Flux fluxOfIntegers = Flux.merge( + evenNumbers.delayElements(Duration.ofMillis(500L)), + oddNumbers.delayElements(Duration.ofMillis(300L))); + + StepVerifier.create(fluxOfIntegers) + .expectNext(1) + .expectNext(2) + .expectNext(3) + .expectNext(5) + .expectNext(4) + .expectComplete() + .verify(); + } + + @Test + public void givenFluxes_whenConcatIsInvoked_thenConcat() { + Flux fluxOfIntegers = Flux.concat( + evenNumbers.delayElements(Duration.ofMillis(500L)), + oddNumbers.delayElements(Duration.ofMillis(300L))); + + StepVerifier.create(fluxOfIntegers) + .expectNext(2) + .expectNext(4) + .expectNext(1) + .expectNext(3) + .expectNext(5) + .expectComplete() + .verify(); + } + + @Test + public void givenFluxes_whenConcatWithIsInvoked_thenConcatWith() { + Flux fluxOfIntegers = evenNumbers + .concatWith(oddNumbers); + + StepVerifier.create(fluxOfIntegers) + .expectNext(2) + .expectNext(4) + .expectNext(1) + .expectNext(3) + .expectNext(5) + .expectComplete() + .verify(); + } + + @Test + public void givenFluxes_whenCombineLatestIsInvoked_thenCombineLatest() { + Flux fluxOfIntegers = Flux.combineLatest( + evenNumbers, + oddNumbers, + (a, b) -> a + b); + + StepVerifier.create(fluxOfIntegers) + .expectNext(5) + .expectNext(7) + .expectNext(9) + .expectComplete() + .verify(); + + } + + @Test + public void givenFluxes_whenCombineLatestIsInvoked_thenCombineLatest1() { + StepVerifier.create(Flux.combineLatest(obj -> (int) obj[1], evenNumbers, oddNumbers)) + .expectNext(1) + .expectNext(3) + .expectNext(5) + .verifyComplete(); + } + + @Test + public void givenFluxes_whenMergeSequentialIsInvoked_thenMergeSequential() { + Flux fluxOfIntegers = Flux.mergeSequential( + evenNumbers, + oddNumbers); + + StepVerifier.create(fluxOfIntegers) + .expectNext(2) + .expectNext(4) + .expectNext(1) + .expectNext(3) + .expectNext(5) + .expectComplete() + .verify(); + } + + + @Test + public void givenFluxes_whenMergeDelayErrorIsInvoked_thenMergeDelayError() { + Flux fluxOfIntegers = Flux.mergeDelayError(1, + evenNumbers.delayElements(Duration.ofMillis(500L)), + oddNumbers.delayElements(Duration.ofMillis(300L))); + + StepVerifier.create(fluxOfIntegers) + .expectNext(1) + .expectNext(2) + .expectNext(3) + .expectNext(5) + .expectNext(4) + .expectComplete() + .verify(); + } + + @Test + public void givenFluxes_whenMergeWithIsInvoked_thenMergeWith() { + Flux fluxOfIntegers = evenNumbers.mergeWith(oddNumbers); + + StepVerifier.create(fluxOfIntegers) + .expectNext(2) + .expectNext(4) + .expectNext(1) + .expectNext(3) + .expectNext(5) + .expectComplete() + .verify(); + } + + @Test + public void givenFluxes_whenZipIsInvoked_thenZip() { + Flux fluxOfIntegers = Flux.zip( + evenNumbers, + oddNumbers, + (a, b) -> a + b); + + StepVerifier.create(fluxOfIntegers) + .expectNext(3) + .expectNext(7) + .expectComplete() + .verify(); + } + + @Test + public void givenFluxes_whenZipWithIsInvoked_thenZipWith() { + Flux fluxOfIntegers = evenNumbers + .zipWith(oddNumbers, + (a, b) -> a * b); + + StepVerifier.create(fluxOfIntegers) + .expectNext(2) + .expectNext(12) + .expectComplete() + .verify(); + } +} diff --git a/rxjava/pom.xml b/rxjava/pom.xml index 0f950914ff..d88dfcaa9b 100644 --- a/rxjava/pom.xml +++ b/rxjava/pom.xml @@ -31,6 +31,19 @@ 1.0.0 + + io.reactivex + rxjava-string + 1.1.1 + + + + junit + junit + 4.12 + test + + com.jayway.awaitility awaitility diff --git a/rxjava/src/test/java/com/baeldung/rxjava/FlowableTest.java b/rxjava/src/test/java/com/baeldung/rxjava/FlowableTest.java new file mode 100644 index 0000000000..b9d1d64c24 --- /dev/null +++ b/rxjava/src/test/java/com/baeldung/rxjava/FlowableTest.java @@ -0,0 +1,93 @@ +package com.baeldung.rxjava; + +import io.reactivex.BackpressureStrategy; +import io.reactivex.Flowable; +import io.reactivex.FlowableOnSubscribe; +import io.reactivex.Observable; +import io.reactivex.exceptions.MissingBackpressureException; +import io.reactivex.schedulers.Schedulers; +import io.reactivex.subscribers.TestSubscriber; + +import org.junit.Test; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +public class FlowableTest { + + @Test public void whenFlowableIsCreated_thenItIsProperlyInitialized() { + Flowable integerFlowable = Flowable.just(1, 2, 3, 4); + assertNotNull(integerFlowable); + } + + @Test public void whenFlowableIsCreatedFromObservable_thenItIsProperlyInitialized() throws InterruptedException { + Observable integerObservable = Observable.just(1, 2, 3); + Flowable integerFlowable = integerObservable.toFlowable(BackpressureStrategy.BUFFER); + assertNotNull(integerFlowable); + + } + + @Test public void whenFlowableIsCreatedFromFlowableOnSubscribe_thenItIsProperlyInitialized() throws InterruptedException { + FlowableOnSubscribe flowableOnSubscribe = flowableEmitter -> flowableEmitter.onNext(1); + Flowable integerFlowable = Flowable.create(flowableOnSubscribe, BackpressureStrategy.BUFFER); + assertNotNull(integerFlowable); + } + + @Test public void thenAllValuesAreBufferedAndReceived() { + List testList = IntStream.range(0, 100000).boxed().collect(Collectors.toList()); + Observable observable = Observable.fromIterable(testList); + TestSubscriber testSubscriber = observable.toFlowable(BackpressureStrategy.BUFFER).observeOn(Schedulers.computation()).test(); + + testSubscriber.awaitTerminalEvent(); + + List receivedInts = testSubscriber.getEvents().get(0).stream().mapToInt(object -> (int) object).boxed().collect(Collectors.toList()); + + assertEquals(testList, receivedInts); + } + + @Test public void whenDropStrategyUsed_thenOnBackpressureDropped() { + List testList = IntStream.range(0, 100000).boxed().collect(Collectors.toList()); + + Observable observable = Observable.fromIterable(testList); + TestSubscriber testSubscriber = observable.toFlowable(BackpressureStrategy.DROP).observeOn(Schedulers.computation()).test(); + testSubscriber.awaitTerminalEvent(); + List receivedInts = testSubscriber.getEvents().get(0).stream().mapToInt(object -> (int) object).boxed().collect(Collectors.toList()); + + assertThat(receivedInts.size() < testList.size()); + assertThat(!receivedInts.contains(100000)); + } + + @Test public void whenMissingStrategyUsed_thenException() { + Observable observable = Observable.range(1, 100000); + TestSubscriber subscriber = observable.toFlowable(BackpressureStrategy.MISSING).observeOn(Schedulers.computation()).test(); + + subscriber.awaitTerminalEvent(); + subscriber.assertError(MissingBackpressureException.class); + } + + @Test public void whenErrorStrategyUsed_thenExceptionIsThrown() { + Observable observable = Observable.range(1, 100000); + TestSubscriber subscriber = observable.toFlowable(BackpressureStrategy.ERROR).observeOn(Schedulers.computation()).test(); + + subscriber.awaitTerminalEvent(); + subscriber.assertError(MissingBackpressureException.class); + } + + @Test public void whenLatestStrategyUsed_thenTheLastElementReceived() { + List testList = IntStream.range(0, 100000).boxed().collect(Collectors.toList()); + Observable observable = Observable.fromIterable(testList); + TestSubscriber testSubscriber = observable.toFlowable(BackpressureStrategy.LATEST).observeOn(Schedulers.computation()).test(); + + testSubscriber.awaitTerminalEvent(); + List receivedInts = testSubscriber.getEvents().get(0).stream().mapToInt(object -> (int) object).boxed().collect(Collectors.toList()); + + assertThat(receivedInts.size() < testList.size()); + assertThat(receivedInts.contains(100000)); + } + +} \ No newline at end of file diff --git a/rxjava/src/test/java/com/baeldung/rxjava/operators/RxStringOperatorsTest.java b/rxjava/src/test/java/com/baeldung/rxjava/operators/RxStringOperatorsTest.java new file mode 100644 index 0000000000..5e58b32d8b --- /dev/null +++ b/rxjava/src/test/java/com/baeldung/rxjava/operators/RxStringOperatorsTest.java @@ -0,0 +1,145 @@ +package com.baeldung.rxjava.operators; + +import java.io.ByteArrayInputStream; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; + +import org.junit.Assert; +import org.junit.Test; + +import rx.Observable; +import rx.observables.StringObservable; +import rx.observers.TestSubscriber; + + +public class RxStringOperatorsTest +{ + + @Test + public void givenStringObservable_whenFromInputStream_ThenSuccessfull() + { + //given + ByteArrayInputStream is = new ByteArrayInputStream("Lorem ipsum loream, Lorem ipsum lore".getBytes(StandardCharsets.UTF_8)); + TestSubscriber subscriber = TestSubscriber.create(); + + // when + StringObservable.decode(StringObservable.from(is), StandardCharsets.UTF_8) + .subscribe(subscriber); + + // then + subscriber.assertCompleted(); + subscriber.assertNoErrors(); + subscriber.assertValueCount(1); + subscriber.assertValues("Lorem ipsum loream, Lorem ipsum lore"); + } + @Test + public void givenStringObservable_whenEncodingString_ThenSuccessfullObtainingByteStream() + { + //given + Observable sourceObservable = Observable.just("Lorem ipsum loream"); + TestSubscriber subscriber = TestSubscriber.create(); + + // when + StringObservable.encode(sourceObservable, StandardCharsets.UTF_8) + .subscribe(subscriber); + + // then + subscriber.assertCompleted(); + subscriber.assertNoErrors(); + subscriber.assertValueCount(1); + subscriber.getOnNextEvents() + .stream() + .forEach(bytes -> Assert.assertTrue(Arrays.equals(bytes, "Lorem ipsum loream".getBytes(StandardCharsets.UTF_8)))); + } + + @Test + public void givenStringObservable_whenConcatenatingStrings_ThenSuccessfullObtainingSingleString() + { + //given + Observable sourceObservable = Observable.just("Lorem ipsum loream","Lorem ipsum lore"); + TestSubscriber subscriber = TestSubscriber.create(); + + // when + StringObservable.stringConcat(sourceObservable) + .subscribe(subscriber); + + // then + subscriber.assertCompleted(); + subscriber.assertNoErrors(); + subscriber.assertValueCount(1); + subscriber.assertValues("Lorem ipsum loreamLorem ipsum lore"); + } + + + @Test + public void givenStringObservable_whenDecodingByteArray_ThenSuccessfullObtainingStringStream() + { + //given + Observable sourceObservable = Observable.just("Lorem ipsum loream".getBytes(StandardCharsets.UTF_8)); + TestSubscriber subscriber = TestSubscriber.create(); + + // when + StringObservable.decode(sourceObservable, StandardCharsets.UTF_8) + .subscribe(subscriber); + + // then + subscriber.assertCompleted(); + subscriber.assertNoErrors(); + subscriber.assertValueCount(1); + subscriber.assertValues("Lorem ipsum loream"); + } + + @Test + public void givenStringObservable_whenStringSplitted_ThenSuccessfullObtainingStringsStream() + { + //given + Observable sourceObservable = Observable.just("Lorem ipsum loream,Lorem ipsum lore"); + TestSubscriber subscriber = TestSubscriber.create(); + + // when + StringObservable.split(sourceObservable,",") + .subscribe(subscriber); + + // then + subscriber.assertCompleted(); + subscriber.assertNoErrors(); + subscriber.assertValueCount(2); + subscriber.assertValues("Lorem ipsum loream", "Lorem ipsum lore"); + } + + @Test + public void givenStringObservable_whenSplittingByLine_ThenSuccessfullObtainingStringsStream() { + //given + Observable sourceObservable = Observable.just("Lorem ipsum loream\nLorem ipsum lore"); + TestSubscriber subscriber = TestSubscriber.create(); + + // when + StringObservable.byLine(sourceObservable) + .subscribe(subscriber); + + // then + subscriber.assertCompleted(); + subscriber.assertNoErrors(); + subscriber.assertValueCount(2); + subscriber.assertValues("Lorem ipsum loream", "Lorem ipsum lore"); + } + + + @Test + public void givenStringObservable_whenJoiningStrings_ThenSuccessfullObtainingSingleString() { + //given + Observable sourceObservable = Observable.just("Lorem ipsum loream","Lorem ipsum lore"); + TestSubscriber subscriber = TestSubscriber.create(); + + // when + StringObservable.join(sourceObservable,",") + .subscribe(subscriber); + + // then + subscriber.assertCompleted(); + subscriber.assertNoErrors(); + subscriber.assertValueCount(1); + subscriber.assertValues("Lorem ipsum loream,Lorem ipsum lore"); + } + +} diff --git a/spring-5-security/pom.xml b/spring-5-security/pom.xml index 0a1d1f5df0..ffe6865704 100644 --- a/spring-5-security/pom.xml +++ b/spring-5-security/pom.xml @@ -12,7 +12,7 @@ org.springframework.boot spring-boot-starter-parent - 2.0.0.M7 + 2.0.0.RC2 diff --git a/spring-5-security/src/main/java/com/baeldung/dsl/ClientErrorLoggingConfigurer.java b/spring-5-security/src/main/java/com/baeldung/dsl/ClientErrorLoggingConfigurer.java new file mode 100644 index 0000000000..5a9479b664 --- /dev/null +++ b/spring-5-security/src/main/java/com/baeldung/dsl/ClientErrorLoggingConfigurer.java @@ -0,0 +1,32 @@ +package com.baeldung.dsl; + +import java.util.List; + +import org.springframework.http.HttpStatus; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; +import org.springframework.security.web.access.intercept.FilterSecurityInterceptor; + +public class ClientErrorLoggingConfigurer extends AbstractHttpConfigurer { + + private List errorCodes; + + public ClientErrorLoggingConfigurer(List 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); + } + +} diff --git a/spring-5-security/src/main/java/com/baeldung/dsl/ClientErrorLoggingFilter.java b/spring-5-security/src/main/java/com/baeldung/dsl/ClientErrorLoggingFilter.java new file mode 100644 index 0000000000..56f7cea3b8 --- /dev/null +++ b/spring-5-security/src/main/java/com/baeldung/dsl/ClientErrorLoggingFilter.java @@ -0,0 +1,54 @@ +package com.baeldung.dsl; + +import java.io.IOException; +import java.util.List; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletResponse; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.springframework.http.HttpStatus; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.web.filter.GenericFilterBean; + +public class ClientErrorLoggingFilter extends GenericFilterBean { + + private static final Logger logger = LogManager.getLogger(ClientErrorLoggingFilter.class); + + private List errorCodes; + + public ClientErrorLoggingFilter(List errorCodes) { + this.errorCodes = errorCodes; + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + + Authentication auth = SecurityContextHolder.getContext() + .getAuthentication(); + + if (auth != null) { + int status = ((HttpServletResponse) response).getStatus(); + if (status >= 400 && status < 500) { + if (errorCodes == null) { + logger.debug("User " + auth.getName() + " encountered error " + status); + } else { + if (errorCodes.stream() + .filter(s -> s.value() == status) + .findFirst() + .isPresent()) { + logger.debug("User " + auth.getName() + " encountered error " + status); + } + } + } + } + + chain.doFilter(request, response); + } + +} diff --git a/spring-5-security/src/main/java/com/baeldung/dsl/CustomConfigurerApplication.java b/spring-5-security/src/main/java/com/baeldung/dsl/CustomConfigurerApplication.java new file mode 100644 index 0000000000..2cd3d7fc7f --- /dev/null +++ b/spring-5-security/src/main/java/com/baeldung/dsl/CustomConfigurerApplication.java @@ -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); + } + +} diff --git a/spring-5-security/src/main/java/com/baeldung/dsl/MyController.java b/spring-5-security/src/main/java/com/baeldung/dsl/MyController.java new file mode 100644 index 0000000000..c69046afb5 --- /dev/null +++ b/spring-5-security/src/main/java/com/baeldung/dsl/MyController.java @@ -0,0 +1,14 @@ +package com.baeldung.dsl; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class MyController { + + @GetMapping("/admin") + public String getAdminPage() { + return "Hello Admin"; + } + +} diff --git a/spring-5-security/src/main/java/com/baeldung/dsl/SecurityConfig.java b/spring-5-security/src/main/java/com/baeldung/dsl/SecurityConfig.java new file mode 100644 index 0000000000..382e222f64 --- /dev/null +++ b/spring-5-security/src/main/java/com/baeldung/dsl/SecurityConfig.java @@ -0,0 +1,50 @@ +package com.baeldung.dsl; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; + +@Configuration +public class SecurityConfig extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http.authorizeRequests() + .antMatchers("/admin*") + .hasAnyRole("ADMIN") + .anyRequest() + .authenticated() + .and() + .formLogin() + .and() + .apply(clientErrorLogging()); + } + + @Bean + public 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(); + } + +} diff --git a/spring-5-security/src/main/java/com/baeldung/passwordstorage/BaeldungPasswordEncoderSetup.java b/spring-5-security/src/main/java/com/baeldung/passwordstorage/BaeldungPasswordEncoderSetup.java new file mode 100644 index 0000000000..94987029db --- /dev/null +++ b/spring-5-security/src/main/java/com/baeldung/passwordstorage/BaeldungPasswordEncoderSetup.java @@ -0,0 +1,35 @@ +package com.baeldung.passwordstorage; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.ApplicationListener; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.authentication.event.AuthenticationSuccessEvent; +import org.springframework.security.core.Authentication; +import org.springframework.security.crypto.password.PasswordEncoder; + +@Configuration +public class BaeldungPasswordEncoderSetup { + + private final static Logger LOG = LoggerFactory.getLogger(BaeldungPasswordEncoderSetup.class); + + @Bean + public ApplicationListener authenticationSuccessListener(final PasswordEncoder encoder) { + + return (AuthenticationSuccessEvent event) -> { + final Authentication auth = event.getAuthentication(); + + if (auth instanceof UsernamePasswordAuthenticationToken && auth.getCredentials() != null) { + + final CharSequence clearTextPass = (CharSequence) auth.getCredentials(); // 1 + final String newPasswordHash = encoder.encode(clearTextPass); // 2 + + LOG.info("New password hash {} for user {}", newPasswordHash, auth.getName()); + + ((UsernamePasswordAuthenticationToken) auth).eraseCredentials(); // 3 + } + }; + } +} diff --git a/spring-5-security/src/main/java/com/baeldung/passwordstorage/PasswordStorageApplication.java b/spring-5-security/src/main/java/com/baeldung/passwordstorage/PasswordStorageApplication.java new file mode 100644 index 0000000000..173d979a45 --- /dev/null +++ b/spring-5-security/src/main/java/com/baeldung/passwordstorage/PasswordStorageApplication.java @@ -0,0 +1,13 @@ +package com.baeldung.passwordstorage; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class PasswordStorageApplication { + + public static void main(String[] args) { + SpringApplication.run(PasswordStorageApplication.class, args); + } + +} diff --git a/spring-5-security/src/main/java/com/baeldung/passwordstorage/PasswordStorageWebSecurityConfigurer.java b/spring-5-security/src/main/java/com/baeldung/passwordstorage/PasswordStorageWebSecurityConfigurer.java new file mode 100644 index 0000000000..22ef2f0835 --- /dev/null +++ b/spring-5-security/src/main/java/com/baeldung/passwordstorage/PasswordStorageWebSecurityConfigurer.java @@ -0,0 +1,53 @@ +package com.baeldung.passwordstorage; + +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.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.DelegatingPasswordEncoder; +import org.springframework.security.crypto.password.NoOpPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.crypto.password.StandardPasswordEncoder; +import org.springframework.security.crypto.scrypt.SCryptPasswordEncoder; +import org.springframework.security.provisioning.InMemoryUserDetailsManager; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +@Configuration +public class PasswordStorageWebSecurityConfigurer extends WebSecurityConfigurerAdapter { + + + @Override + protected void configure(AuthenticationManagerBuilder auth) throws Exception { + auth.eraseCredentials(false) // 4 + .userDetailsService(getUserDefaultDetailsService()) + .passwordEncoder(passwordEncoder()); + } + + @Bean + public UserDetailsService getUserDefaultDetailsService() { + User testUser = new User("baeldung", "{noop}SpringSecurity5", Collections.emptyList()); + return new InMemoryUserDetailsManager(testUser); + } + + @Bean + public PasswordEncoder passwordEncoder() { + // set up the list of supported encoders and their prefixes + PasswordEncoder defaultEncoder = new StandardPasswordEncoder(); + Map encoders = new HashMap<>(); + encoders.put("bcrypt", new BCryptPasswordEncoder()); + encoders.put("scrypt", new SCryptPasswordEncoder()); + encoders.put("noop", NoOpPasswordEncoder.getInstance()); + + DelegatingPasswordEncoder passwordEncoder = new DelegatingPasswordEncoder("bcrypt", encoders); + passwordEncoder.setDefaultPasswordEncoderForMatches(defaultEncoder); + + return passwordEncoder; + } + +} diff --git a/spring-5-security/src/main/resources/application.properties b/spring-5-security/src/main/resources/application.properties index ccec014c2b..781ee76826 100644 --- a/spring-5-security/src/main/resources/application.properties +++ b/spring-5-security/src/main/resources/application.properties @@ -1,3 +1,5 @@ server.port=8081 -logging.level.root=INFO \ No newline at end of file +logging.level.root=INFO + +logging.level.com.baeldung.dsl.ClientErrorLoggingFilter=DEBUG diff --git a/spring-5/pom.xml b/spring-5/pom.xml index 19dd65d78f..3b21f86e60 100644 --- a/spring-5/pom.xml +++ b/spring-5/pom.xml @@ -14,7 +14,7 @@ org.springframework.boot spring-boot-starter-parent - 2.0.0.M7 + 2.0.0.RC2 @@ -39,10 +39,14 @@ org.springframework.boot spring-boot-starter-webflux - + org.springframework.boot spring-boot-starter-hateoas + + org.springframework.boot + spring-boot-starter-thymeleaf + org.projectreactor reactor-spring diff --git a/spring-5/src/main/java/com/baeldung/execption/ActorController.java b/spring-5/src/main/java/com/baeldung/execption/ActorController.java new file mode 100644 index 0000000000..6c9c46253a --- /dev/null +++ b/spring-5/src/main/java/com/baeldung/execption/ActorController.java @@ -0,0 +1,41 @@ +package com.baeldung.execption; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.server.ResponseStatusException; + +@RestController +public class ActorController { + + @Autowired + ActorService actorService; + + @GetMapping("/actor/{id}") + public String getActorName(@PathVariable("id") int id) { + try { + return actorService.getActor(id); + } catch (ActorNotFoundException ex) { + throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Actor Not Found", ex); + } + } + + @DeleteMapping("/actor/{id}") + public String getActor(@PathVariable("id") int id) { + return actorService.removeActor(id); + } + + @PutMapping("/actor/{id}/{name}") + public String updateActorName(@PathVariable("id") int id, @PathVariable("name") String name) { + try { + return actorService.updateActor(id, name); + } catch (ActorNotFoundException ex) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Provide correct Actor Id", ex); + } + } + +} diff --git a/spring-5/src/main/java/com/baeldung/execption/ActorNotFoundException.java b/spring-5/src/main/java/com/baeldung/execption/ActorNotFoundException.java new file mode 100644 index 0000000000..642c075b5d --- /dev/null +++ b/spring-5/src/main/java/com/baeldung/execption/ActorNotFoundException.java @@ -0,0 +1,13 @@ +package com.baeldung.execption; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(code = HttpStatus.NOT_FOUND, reason = "Actor Not Found") +public class ActorNotFoundException extends Exception { + private static final long serialVersionUID = 1L; + + public ActorNotFoundException(String errorMessage) { + super(errorMessage); + } +} diff --git a/spring-5/src/main/java/com/baeldung/execption/ActorService.java b/spring-5/src/main/java/com/baeldung/execption/ActorService.java new file mode 100644 index 0000000000..956fa92015 --- /dev/null +++ b/spring-5/src/main/java/com/baeldung/execption/ActorService.java @@ -0,0 +1,35 @@ +package com.baeldung.execption; + +import java.util.Arrays; +import java.util.List; + +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Service; +import org.springframework.web.server.ResponseStatusException; + +@Service +public class ActorService { + List actors = Arrays.asList("Jack Nicholson", "Marlon Brando", "Robert De Niro", "Al Pacino", "Tom Hanks"); + + public String getActor(int index) throws ActorNotFoundException { + if (index >= actors.size()) { + throw new ActorNotFoundException("Actor Not Found in Repsoitory"); + } + return actors.get(index); + } + + public String updateActor(int index, String actorName) throws ActorNotFoundException { + if (index >= actors.size()) { + throw new ActorNotFoundException("Actor Not Found in Repsoitory"); + } + actors.set(index, actorName); + return actorName; + } + + public String removeActor(int index) { + if (index >= actors.size()) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Actor Not Found in Repsoitory"); + } + return actors.remove(index); + } +} diff --git a/spring-5/src/main/java/com/baeldung/execption/SpringExceptionApplication.java b/spring-5/src/main/java/com/baeldung/execption/SpringExceptionApplication.java new file mode 100644 index 0000000000..1670da54c3 --- /dev/null +++ b/spring-5/src/main/java/com/baeldung/execption/SpringExceptionApplication.java @@ -0,0 +1,14 @@ +package com.baeldung.execption; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; +import org.springframework.context.annotation.ComponentScan; + +@SpringBootApplication(exclude = SecurityAutoConfiguration.class) +@ComponentScan(basePackages = { "com.baeldung.execption" }) +public class SpringExceptionApplication { + public static void main(String[] args) { + SpringApplication.run(SpringExceptionApplication.class, args); + } +} \ No newline at end of file diff --git a/spring-5/src/main/java/com/baeldung/sessionattrs/Config.java b/spring-5/src/main/java/com/baeldung/sessionattrs/Config.java new file mode 100644 index 0000000000..9d5c9d9f42 --- /dev/null +++ b/spring-5/src/main/java/com/baeldung/sessionattrs/Config.java @@ -0,0 +1,44 @@ +package com.baeldung.sessionattrs; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Scope; +import org.springframework.context.annotation.ScopedProxyMode; +import org.springframework.core.Ordered; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.thymeleaf.templatemode.TemplateMode; +import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver; +import org.thymeleaf.templateresolver.ITemplateResolver; + +@EnableWebMvc +@Configuration +public class Config implements WebMvcConfigurer { + + @Override + public void addViewControllers(ViewControllerRegistry registry) { + registry.addViewController("/").setViewName("index"); + registry.setOrder(Ordered.HIGHEST_PRECEDENCE); + } + + @Bean + @Scope( + value = WebApplicationContext.SCOPE_SESSION, + proxyMode = ScopedProxyMode.TARGET_CLASS) + public TodoList todos() { + return new TodoList(); + } + + @Bean + public ITemplateResolver templateResolver() { + ClassLoaderTemplateResolver resolver + = new ClassLoaderTemplateResolver(); + resolver.setPrefix("templates/sessionattrs/"); + resolver.setSuffix(".html"); + resolver.setTemplateMode(TemplateMode.HTML); + resolver.setCharacterEncoding("UTF-8"); + return resolver; + } +} diff --git a/spring-5/src/main/java/com/baeldung/sessionattrs/SessionAttrsApplication.java b/spring-5/src/main/java/com/baeldung/sessionattrs/SessionAttrsApplication.java new file mode 100644 index 0000000000..7b9f8a700f --- /dev/null +++ b/spring-5/src/main/java/com/baeldung/sessionattrs/SessionAttrsApplication.java @@ -0,0 +1,16 @@ +package com.baeldung.sessionattrs; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; + +@SpringBootApplication( + exclude = {SecurityAutoConfiguration.class, + DataSourceAutoConfiguration.class}) +public class SessionAttrsApplication { + + public static void main(String[] args) { + SpringApplication.run(SessionAttrsApplication.class, args); + } +} diff --git a/spring-5/src/main/java/com/baeldung/sessionattrs/TodoControllerWithScopedProxy.java b/spring-5/src/main/java/com/baeldung/sessionattrs/TodoControllerWithScopedProxy.java new file mode 100644 index 0000000000..0c3bd6c8b6 --- /dev/null +++ b/spring-5/src/main/java/com/baeldung/sessionattrs/TodoControllerWithScopedProxy.java @@ -0,0 +1,45 @@ +package com.baeldung.sessionattrs; + +import java.time.LocalDateTime; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +@Controller +@RequestMapping("/scopedproxy") +public class TodoControllerWithScopedProxy { + + private TodoList todos; + + public TodoControllerWithScopedProxy(TodoList todos) { + this.todos = todos; + } + + @GetMapping("/form") + public String showForm(Model model) { + if (!todos.isEmpty()) { + model.addAttribute("todo", todos.peekLast()); + } else { + model.addAttribute("todo", new TodoItem()); + } + + return "scopedproxyform"; + } + + @PostMapping("/form") + public String create(@ModelAttribute TodoItem todo) { + todo.setCreateDate(LocalDateTime.now()); + todos.add(todo); + return "redirect:/scopedproxy/todos.html"; + } + + @GetMapping("/todos.html") + public String list(Model model) { + model.addAttribute("todos", todos); + return "scopedproxytodos"; + } +} diff --git a/spring-5/src/main/java/com/baeldung/sessionattrs/TodoControllerWithSessionAttributes.java b/spring-5/src/main/java/com/baeldung/sessionattrs/TodoControllerWithSessionAttributes.java new file mode 100644 index 0000000000..fc7e57b1db --- /dev/null +++ b/spring-5/src/main/java/com/baeldung/sessionattrs/TodoControllerWithSessionAttributes.java @@ -0,0 +1,55 @@ +package com.baeldung.sessionattrs; + +import java.time.LocalDateTime; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.SessionAttributes; +import org.springframework.web.servlet.mvc.support.RedirectAttributes; +import org.springframework.web.servlet.view.RedirectView; + +@Controller +@RequestMapping("/sessionattributes") +@SessionAttributes("todos") +public class TodoControllerWithSessionAttributes { + + @GetMapping("/form") + public String showForm( + Model model, + @ModelAttribute("todos") TodoList todos) { + if (!todos.isEmpty()) { + model.addAttribute("todo", todos.peekLast()); + } else { + model.addAttribute("todo", new TodoItem()); + } + return "sessionattributesform"; + } + + @PostMapping("/form") + public RedirectView create( + @ModelAttribute TodoItem todo, + @ModelAttribute("todos") TodoList todos, + RedirectAttributes attributes) { + todo.setCreateDate(LocalDateTime.now()); + todos.add(todo); + attributes.addFlashAttribute("todos", todos); + return new RedirectView("/sessionattributes/todos.html"); + } + + @GetMapping("/todos.html") + public String list( + Model model, + @ModelAttribute("todos") TodoList todos) { + model.addAttribute("todos", todos); + return "sessionattributestodos"; + } + + @ModelAttribute("todos") + public TodoList todos() { + return new TodoList(); + } +} diff --git a/spring-5/src/main/java/com/baeldung/sessionattrs/TodoItem.java b/spring-5/src/main/java/com/baeldung/sessionattrs/TodoItem.java new file mode 100644 index 0000000000..619d61d5f0 --- /dev/null +++ b/spring-5/src/main/java/com/baeldung/sessionattrs/TodoItem.java @@ -0,0 +1,39 @@ +package com.baeldung.sessionattrs; + +import java.time.LocalDateTime; + +public class TodoItem { + + private String description; + private LocalDateTime createDate; + + public TodoItem(String description, LocalDateTime createDate) { + this.description = description; + this.createDate = createDate; + } + + public TodoItem() { + // default no arg constructor + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public LocalDateTime getCreateDate() { + return createDate; + } + + public void setCreateDate(LocalDateTime createDate) { + this.createDate = createDate; + } + + @Override + public String toString() { + return "TodoItem [description=" + description + ", createDate=" + createDate + "]"; + } +} diff --git a/spring-5/src/main/java/com/baeldung/sessionattrs/TodoList.java b/spring-5/src/main/java/com/baeldung/sessionattrs/TodoList.java new file mode 100644 index 0000000000..cad7811da4 --- /dev/null +++ b/spring-5/src/main/java/com/baeldung/sessionattrs/TodoList.java @@ -0,0 +1,8 @@ +package com.baeldung.sessionattrs; + +import java.util.ArrayDeque; + +@SuppressWarnings("serial") +public class TodoList extends ArrayDeque{ + +} diff --git a/spring-5/src/main/resources/templates/sessionattrs/index.html b/spring-5/src/main/resources/templates/sessionattrs/index.html new file mode 100644 index 0000000000..72427cd62b --- /dev/null +++ b/spring-5/src/main/resources/templates/sessionattrs/index.html @@ -0,0 +1,27 @@ + + + + Session Scope in Spring MVC + + + + + + + +
+

+

Session Scope in Spring MVC - Example

+

+
+ + + \ No newline at end of file diff --git a/spring-5/src/main/resources/templates/sessionattrs/scopedproxyform.html b/spring-5/src/main/resources/templates/sessionattrs/scopedproxyform.html new file mode 100644 index 0000000000..e72651556b --- /dev/null +++ b/spring-5/src/main/resources/templates/sessionattrs/scopedproxyform.html @@ -0,0 +1,27 @@ + + + + Session Scope in Spring MVC + + + + + + + +
+

+

Scoped Proxy Example

+

+
+
+
Enter a TODO
+
+
+ + +
+
+
+ + \ No newline at end of file diff --git a/spring-5/src/main/resources/templates/sessionattrs/scopedproxytodos.html b/spring-5/src/main/resources/templates/sessionattrs/scopedproxytodos.html new file mode 100644 index 0000000000..5493b5cf64 --- /dev/null +++ b/spring-5/src/main/resources/templates/sessionattrs/scopedproxytodos.html @@ -0,0 +1,48 @@ + + + + Session Scope in Spring MVC + + + + + + + +
+

+

Scoped Proxy Example

+

+
+
+
+
+ Add New +
+
+
+
+
+
TODO List
+ + + + + + + + + + + +
DescriptionCreate Date
DescriptionCreate Date
+
+
+
+
+ + \ No newline at end of file diff --git a/spring-5/src/main/resources/templates/sessionattrs/sessionattributesform.html b/spring-5/src/main/resources/templates/sessionattrs/sessionattributesform.html new file mode 100644 index 0000000000..28e1d5d2c1 --- /dev/null +++ b/spring-5/src/main/resources/templates/sessionattrs/sessionattributesform.html @@ -0,0 +1,27 @@ + + + + Session Scope in Spring MVC + + + + + + + +
+

+

Session Attributes Example

+

+
+
+
Enter a TODO
+
+
+ + +
+
+
+ + \ No newline at end of file diff --git a/spring-5/src/main/resources/templates/sessionattrs/sessionattributestodos.html b/spring-5/src/main/resources/templates/sessionattrs/sessionattributestodos.html new file mode 100644 index 0000000000..4bae12ffb9 --- /dev/null +++ b/spring-5/src/main/resources/templates/sessionattrs/sessionattributestodos.html @@ -0,0 +1,48 @@ + + + + Session Scope in Spring MVC + + + + + + + +
+

+

Session Attributes Example

+

+
+
+
+
+ Add New +
+
+
+
+
+
TODO List
+ + + + + + + + + + + +
DescriptionCreate Date
DescriptionCreate Date
+
+
+
+
+ + \ No newline at end of file diff --git a/spring-5/src/test/java/com/baeldung/sessionattrs/SessionAttrsApplicationTests.java b/spring-5/src/test/java/com/baeldung/sessionattrs/SessionAttrsApplicationTests.java new file mode 100644 index 0000000000..0b15a2114d --- /dev/null +++ b/spring-5/src/test/java/com/baeldung/sessionattrs/SessionAttrsApplicationTests.java @@ -0,0 +1,16 @@ +package com.baeldung.sessionattrs; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest +public class SessionAttrsApplicationTests { + + @Test + public void contextLoads() { + } + +} diff --git a/spring-5/src/test/java/com/baeldung/sessionattrs/TestConfig.java b/spring-5/src/test/java/com/baeldung/sessionattrs/TestConfig.java new file mode 100644 index 0000000000..07d65dd7c2 --- /dev/null +++ b/spring-5/src/test/java/com/baeldung/sessionattrs/TestConfig.java @@ -0,0 +1,17 @@ +package com.baeldung.sessionattrs; + +import org.springframework.beans.factory.config.CustomScopeConfigurer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.support.SimpleThreadScope; + +@Configuration +public class TestConfig { + + @Bean + public CustomScopeConfigurer customScopeConfigurer() { + CustomScopeConfigurer configurer = new CustomScopeConfigurer(); + configurer.addScope("session", new SimpleThreadScope()); + return configurer; + } +} diff --git a/spring-5/src/test/java/com/baeldung/sessionattrs/TodoControllerWithScopedProxyTest.java b/spring-5/src/test/java/com/baeldung/sessionattrs/TodoControllerWithScopedProxyTest.java new file mode 100644 index 0000000000..3db7c183ce --- /dev/null +++ b/spring-5/src/test/java/com/baeldung/sessionattrs/TodoControllerWithScopedProxyTest.java @@ -0,0 +1,68 @@ +package com.baeldung.sessionattrs; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Import; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.util.StringUtils; +import org.springframework.web.context.WebApplicationContext; + +@RunWith(SpringRunner.class) +@SpringBootTest +@AutoConfigureMockMvc +@Import(TestConfig.class) +public class TodoControllerWithScopedProxyTest { + + @Autowired + private MockMvc mockMvc; + + @Autowired + private WebApplicationContext wac; + + @Before + public void setup() { + this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac) + .build(); + } + + @Test + public void whenFirstRequest_thenContainsAllCategoriesAndUnintializedTodo() throws Exception { + MvcResult result = mockMvc.perform(get("/scopedproxy/form")) + .andExpect(status().isOk()) + .andExpect(model().attributeExists("todo")) + .andReturn(); + + TodoItem item = (TodoItem) result.getModelAndView().getModel().get("todo"); + assertTrue(StringUtils.isEmpty(item.getDescription())); + } + + @Test + public void whenSubmit_thenSubsequentFormRequestContainsMostRecentTodo() throws Exception { + mockMvc.perform(post("/scopedproxy/form") + .param("description", "newtodo")) + .andExpect(status().is3xxRedirection()) + .andReturn(); + + MvcResult result = mockMvc.perform(get("/scopedproxy/form")) + .andExpect(status().isOk()) + .andExpect(model().attributeExists("todo")) + .andReturn(); + TodoItem item = (TodoItem) result.getModelAndView().getModel().get("todo"); + assertEquals("newtodo", item.getDescription()); + } + +} diff --git a/spring-5/src/test/java/com/baeldung/sessionattrs/TodoControllerWithSessionAttributesTest.java b/spring-5/src/test/java/com/baeldung/sessionattrs/TodoControllerWithSessionAttributesTest.java new file mode 100644 index 0000000000..a09fac9699 --- /dev/null +++ b/spring-5/src/test/java/com/baeldung/sessionattrs/TodoControllerWithSessionAttributesTest.java @@ -0,0 +1,68 @@ +package com.baeldung.sessionattrs; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.util.StringUtils; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.servlet.FlashMap; + +@RunWith(SpringRunner.class) +@SpringBootTest +@AutoConfigureMockMvc +public class TodoControllerWithSessionAttributesTest { + + @Autowired + private MockMvc mockMvc; + + @Autowired + private WebApplicationContext wac; + + @Before + public void setup() { + this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac) + .build(); + } + + @Test + public void whenFirstRequest_thenContainsUnintializedTodo() throws Exception { + MvcResult result = mockMvc.perform(get("/sessionattributes/form")) + .andExpect(status().isOk()) + .andExpect(model().attributeExists("todo")) + .andReturn(); + + TodoItem item = (TodoItem) result.getModelAndView().getModel().get("todo"); + assertTrue(StringUtils.isEmpty(item.getDescription())); + } + + @Test + public void whenSubmit_thenSubsequentFormRequestContainsMostRecentTodo() throws Exception { + FlashMap flashMap = mockMvc.perform(post("/sessionattributes/form") + .param("description", "newtodo")) + .andExpect(status().is3xxRedirection()) + .andReturn().getFlashMap(); + + MvcResult result = mockMvc.perform(get("/sessionattributes/form") + .sessionAttrs(flashMap)) + .andExpect(status().isOk()) + .andExpect(model().attributeExists("todo")) + .andReturn(); + TodoItem item = (TodoItem) result.getModelAndView().getModel().get("todo"); + assertEquals("newtodo", item.getDescription()); + } + +} diff --git a/spring-batch/pom.xml b/spring-batch/pom.xml index f372ebd724..f72024d32b 100644 --- a/spring-batch/pom.xml +++ b/spring-batch/pom.xml @@ -18,9 +18,10 @@ UTF-8 - 4.3.4.RELEASE - 3.0.7.RELEASE + 5.0.3.RELEASE + 4.0.0.RELEASE 3.15.1 + 4.1 @@ -51,6 +52,16 @@ spring-batch-core ${spring.batch.version}
+ + org.springframework.batch + spring-batch-test + ${spring.batch.version} + + + com.opencsv + opencsv + ${opencsv.version} + diff --git a/spring-batch/src/main/java/org/baeldung/taskletsvschunks/chunks/LineProcessor.java b/spring-batch/src/main/java/org/baeldung/taskletsvschunks/chunks/LineProcessor.java new file mode 100644 index 0000000000..5b6cd9add3 --- /dev/null +++ b/spring-batch/src/main/java/org/baeldung/taskletsvschunks/chunks/LineProcessor.java @@ -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, 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; + } +} diff --git a/spring-batch/src/main/java/org/baeldung/taskletsvschunks/chunks/LineReader.java b/spring-batch/src/main/java/org/baeldung/taskletsvschunks/chunks/LineReader.java new file mode 100644 index 0000000000..5f6b6de218 --- /dev/null +++ b/spring-batch/src/main/java/org/baeldung/taskletsvschunks/chunks/LineReader.java @@ -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, 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; + } +} diff --git a/spring-batch/src/main/java/org/baeldung/taskletsvschunks/chunks/LinesWriter.java b/spring-batch/src/main/java/org/baeldung/taskletsvschunks/chunks/LinesWriter.java new file mode 100644 index 0000000000..66f9103a56 --- /dev/null +++ b/spring-batch/src/main/java/org/baeldung/taskletsvschunks/chunks/LinesWriter.java @@ -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, 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 lines) throws Exception { + for (Line line : lines) { + fu.writeLine(line); + logger.debug("Wrote line " + line.toString()); + } + } +} diff --git a/spring-batch/src/main/java/org/baeldung/taskletsvschunks/config/ChunksConfig.java b/spring-batch/src/main/java/org/baeldung/taskletsvschunks/config/ChunksConfig.java new file mode 100644 index 0000000000..601ffb7f27 --- /dev/null +++ b/spring-batch/src/main/java/org/baeldung/taskletsvschunks/config/ChunksConfig.java @@ -0,0 +1,90 @@ +package org.baeldung.taskletsvschunks.config; + +import org.baeldung.taskletsvschunks.chunks.LineProcessor; +import org.baeldung.taskletsvschunks.chunks.LineReader; +import org.baeldung.taskletsvschunks.chunks.LinesWriter; +import org.baeldung.taskletsvschunks.model.Line; +import org.springframework.batch.core.Job; +import org.springframework.batch.core.Step; +import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing; +import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; +import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; +import org.springframework.batch.core.launch.JobLauncher; +import org.springframework.batch.core.launch.support.SimpleJobLauncher; +import org.springframework.batch.core.repository.JobRepository; +import org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean; +import org.springframework.batch.item.ItemProcessor; +import org.springframework.batch.item.ItemReader; +import org.springframework.batch.item.ItemWriter; +import org.springframework.batch.support.transaction.ResourcelessTransactionManager; +import org.springframework.batch.test.JobLauncherTestUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.transaction.PlatformTransactionManager; + +@Configuration +@EnableBatchProcessing +public class ChunksConfig { + + @Autowired private JobBuilderFactory jobs; + + @Autowired private StepBuilderFactory steps; + + @Bean + public JobLauncherTestUtils jobLauncherTestUtils() { + return new JobLauncherTestUtils(); + } + + @Bean + public JobRepository jobRepository() throws Exception { + MapJobRepositoryFactoryBean factory = new MapJobRepositoryFactoryBean(); + factory.setTransactionManager(transactionManager()); + return (JobRepository) factory.getObject(); + } + + @Bean + public PlatformTransactionManager transactionManager() { + return new ResourcelessTransactionManager(); + } + + @Bean + public JobLauncher jobLauncher() throws Exception { + SimpleJobLauncher jobLauncher = new SimpleJobLauncher(); + jobLauncher.setJobRepository(jobRepository()); + return jobLauncher; + } + + @Bean + public ItemReader itemReader() { + return new LineReader(); + } + + @Bean + public ItemProcessor itemProcessor() { + return new LineProcessor(); + } + + @Bean + public ItemWriter itemWriter() { + return new LinesWriter(); + } + + @Bean + protected Step processLines(ItemReader reader, ItemProcessor processor, ItemWriter writer) { + return steps.get("processLines"). chunk(2) + .reader(reader) + .processor(processor) + .writer(writer) + .build(); + } + + @Bean + public Job job() { + return jobs + .get("chunksJob") + .start(processLines(itemReader(), itemProcessor(), itemWriter())) + .build(); + } + +} diff --git a/spring-batch/src/main/java/org/baeldung/taskletsvschunks/config/TaskletsConfig.java b/spring-batch/src/main/java/org/baeldung/taskletsvschunks/config/TaskletsConfig.java new file mode 100644 index 0000000000..b9d06d2639 --- /dev/null +++ b/spring-batch/src/main/java/org/baeldung/taskletsvschunks/config/TaskletsConfig.java @@ -0,0 +1,103 @@ +package org.baeldung.taskletsvschunks.config; + +import org.baeldung.taskletsvschunks.tasklets.LinesProcessor; +import org.baeldung.taskletsvschunks.tasklets.LinesReader; +import org.baeldung.taskletsvschunks.tasklets.LinesWriter; +import org.springframework.batch.core.Job; +import org.springframework.batch.core.Step; +import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing; +import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; +import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; +import org.springframework.batch.core.launch.JobLauncher; +import org.springframework.batch.core.launch.support.SimpleJobLauncher; +import org.springframework.batch.core.repository.JobRepository; +import org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean; +import org.springframework.batch.support.transaction.ResourcelessTransactionManager; +import org.springframework.batch.test.JobLauncherTestUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.transaction.PlatformTransactionManager; + +@Configuration +@EnableBatchProcessing +public class TaskletsConfig { + + @Autowired private JobBuilderFactory jobs; + + @Autowired private StepBuilderFactory steps; + + @Bean + public JobLauncherTestUtils jobLauncherTestUtils() { + return new JobLauncherTestUtils(); + } + + @Bean + public JobRepository jobRepository() throws Exception { + MapJobRepositoryFactoryBean factory = new MapJobRepositoryFactoryBean(); + factory.setTransactionManager(transactionManager()); + return (JobRepository) factory.getObject(); + } + + @Bean + public PlatformTransactionManager transactionManager() { + return new ResourcelessTransactionManager(); + } + + @Bean + public JobLauncher jobLauncher() throws Exception { + SimpleJobLauncher jobLauncher = new SimpleJobLauncher(); + jobLauncher.setJobRepository(jobRepository()); + return jobLauncher; + } + + @Bean + public LinesReader linesReader() { + return new LinesReader(); + } + + @Bean + public LinesProcessor linesProcessor() { + return new LinesProcessor(); + } + + @Bean + public LinesWriter linesWriter() { + return new LinesWriter(); + } + + @Bean + protected Step readLines() { + return steps + .get("readLines") + .tasklet(linesReader()) + .build(); + } + + @Bean + protected Step processLines() { + return steps + .get("processLines") + .tasklet(linesProcessor()) + .build(); + } + + @Bean + protected Step writeLines() { + return steps + .get("writeLines") + .tasklet(linesWriter()) + .build(); + } + + @Bean + public Job job() { + return jobs + .get("taskletsJob") + .start(readLines()) + .next(processLines()) + .next(writeLines()) + .build(); + } + +} diff --git a/spring-batch/src/main/java/org/baeldung/taskletsvschunks/model/Line.java b/spring-batch/src/main/java/org/baeldung/taskletsvschunks/model/Line.java new file mode 100644 index 0000000000..fee6fd31a6 --- /dev/null +++ b/spring-batch/src/main/java/org/baeldung/taskletsvschunks/model/Line.java @@ -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(); + } +} diff --git a/spring-batch/src/main/java/org/baeldung/taskletsvschunks/tasklets/LinesProcessor.java b/spring-batch/src/main/java/org/baeldung/taskletsvschunks/tasklets/LinesProcessor.java new file mode 100644 index 0000000000..ba7a3088d5 --- /dev/null +++ b/spring-batch/src/main/java/org/baeldung/taskletsvschunks/tasklets/LinesProcessor.java @@ -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 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) executionContext.get("lines"); + logger.debug("Lines Processor initialized."); + } + + @Override + public ExitStatus afterStep(StepExecution stepExecution) { + logger.debug("Lines Processor ended."); + return ExitStatus.COMPLETED; + } +} diff --git a/spring-batch/src/main/java/org/baeldung/taskletsvschunks/tasklets/LinesReader.java b/spring-batch/src/main/java/org/baeldung/taskletsvschunks/tasklets/LinesReader.java new file mode 100644 index 0000000000..9905ee8f8a --- /dev/null +++ b/spring-batch/src/main/java/org/baeldung/taskletsvschunks/tasklets/LinesReader.java @@ -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 lines; + private FileUtils fu; + + @Override + public void beforeStep(StepExecution stepExecution) { + lines = new ArrayList(); + 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; + } +} diff --git a/spring-batch/src/main/java/org/baeldung/taskletsvschunks/tasklets/LinesWriter.java b/spring-batch/src/main/java/org/baeldung/taskletsvschunks/tasklets/LinesWriter.java new file mode 100644 index 0000000000..937288a890 --- /dev/null +++ b/spring-batch/src/main/java/org/baeldung/taskletsvschunks/tasklets/LinesWriter.java @@ -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 lines; + private FileUtils fu; + + @Override + public void beforeStep(StepExecution stepExecution) { + ExecutionContext executionContext = stepExecution + .getJobExecution() + .getExecutionContext(); + this.lines = (List) 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; + } +} diff --git a/spring-batch/src/main/java/org/baeldung/taskletsvschunks/utils/FileUtils.java b/spring-batch/src/main/java/org/baeldung/taskletsvschunks/utils/FileUtils.java new file mode 100644 index 0000000000..df36d5c756 --- /dev/null +++ b/spring-batch/src/main/java/org/baeldung/taskletsvschunks/utils/FileUtils.java @@ -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."); + } + } + +} diff --git a/spring-batch/src/main/resources/logback.xml b/spring-batch/src/main/resources/logback.xml new file mode 100644 index 0000000000..b110d1c226 --- /dev/null +++ b/spring-batch/src/main/resources/logback.xml @@ -0,0 +1,20 @@ + + + + + + %d{yyyy-MM-dd HH:mm:ss} [%thread] %level %logger{35} - %msg%n + + + + + + + + + + + + + \ No newline at end of file diff --git a/spring-batch/src/main/resources/taskletsvschunks/input/tasklets-vs-chunks.csv b/spring-batch/src/main/resources/taskletsvschunks/input/tasklets-vs-chunks.csv new file mode 100644 index 0000000000..214bd3cb70 --- /dev/null +++ b/spring-batch/src/main/resources/taskletsvschunks/input/tasklets-vs-chunks.csv @@ -0,0 +1,6 @@ +Mae Hodges,10/22/1972 +Gary Potter,02/22/1953 +Betty Wise,02/17/1968 +Wayne Rose,04/06/1977 +Adam Caldwell,09/27/1995 +Lucille Phillips,05/14/1992 \ No newline at end of file diff --git a/spring-batch/src/test/java/org/baeldung/taskletsvschunks/chunks/ChunksTest.java b/spring-batch/src/test/java/org/baeldung/taskletsvschunks/chunks/ChunksTest.java new file mode 100644 index 0000000000..2a71970637 --- /dev/null +++ b/spring-batch/src/test/java/org/baeldung/taskletsvschunks/chunks/ChunksTest.java @@ -0,0 +1,25 @@ +package org.baeldung.taskletsvschunks.chunks; + +import org.baeldung.taskletsvschunks.config.ChunksConfig; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.batch.core.ExitStatus; +import org.springframework.batch.core.JobExecution; +import org.springframework.batch.test.JobLauncherTestUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = ChunksConfig.class) +public class ChunksTest { + + @Autowired private JobLauncherTestUtils jobLauncherTestUtils; + + @Test + public void givenChunksJob_WhenJobEnds_ThenStatusCompleted() throws Exception { + JobExecution jobExecution = jobLauncherTestUtils.launchJob(); + Assert.assertEquals(ExitStatus.COMPLETED, jobExecution.getExitStatus()); + } +} \ No newline at end of file diff --git a/spring-batch/src/test/java/org/baeldung/taskletsvschunks/tasklets/TaskletsTest.java b/spring-batch/src/test/java/org/baeldung/taskletsvschunks/tasklets/TaskletsTest.java new file mode 100644 index 0000000000..20379b58fe --- /dev/null +++ b/spring-batch/src/test/java/org/baeldung/taskletsvschunks/tasklets/TaskletsTest.java @@ -0,0 +1,25 @@ +package org.baeldung.taskletsvschunks.tasklets; + +import org.baeldung.taskletsvschunks.config.TaskletsConfig; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.batch.core.ExitStatus; +import org.springframework.batch.core.JobExecution; +import org.springframework.batch.test.JobLauncherTestUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = TaskletsConfig.class) +public class TaskletsTest { + + @Autowired private JobLauncherTestUtils jobLauncherTestUtils; + + @Test + public void givenTaskletsJob_WhenJobEnds_ThenStatusCompleted() throws Exception { + JobExecution jobExecution = jobLauncherTestUtils.launchJob(); + Assert.assertEquals(ExitStatus.COMPLETED, jobExecution.getExitStatus()); + } +} \ No newline at end of file diff --git a/spring-cloud/pom.xml b/spring-cloud/pom.xml index d94b334bc8..c093b87be3 100644 --- a/spring-cloud/pom.xml +++ b/spring-cloud/pom.xml @@ -21,7 +21,8 @@ spring-cloud-aws spring-cloud-consul spring-cloud-zuul-eureka-integration - + spring-cloud-contract + pom spring-cloud diff --git a/spring-cloud/spring-cloud-contract/pom.xml b/spring-cloud/spring-cloud-contract/pom.xml new file mode 100644 index 0000000000..3981aae2ac --- /dev/null +++ b/spring-cloud/spring-cloud-contract/pom.xml @@ -0,0 +1,23 @@ + + + 4.0.0 + + + com.baeldung.spring.cloud + spring-cloud + 1.0.0-SNAPSHOT + + + spring-cloud-contract-producer + spring-cloud-contract-consumer + + pom + + com.baeldung.spring.cloud + spring-cloud-contract + 1.0.0-SNAPSHOT + + + \ No newline at end of file diff --git a/spring-cloud/spring-cloud-contract/spring-cloud-contract-consumer/pom.xml b/spring-cloud/spring-cloud-contract/spring-cloud-contract-consumer/pom.xml new file mode 100644 index 0000000000..67fea178eb --- /dev/null +++ b/spring-cloud/spring-cloud-contract/spring-cloud-contract-consumer/pom.xml @@ -0,0 +1,68 @@ + + + 4.0.0 + + com.baeldung.spring.cloud + spring-cloud-contract-consumer + 1.0.0-SNAPSHOT + jar + + spring-cloud-contract-consumer + Spring Cloud Consumer Sample + + + com.baeldung.spring.cloud + spring-cloud-contract + 1.0.0-SNAPSHOT + .. + + + + UTF-8 + UTF-8 + 1.8 + + + + + org.springframework.cloud + spring-cloud-contract-wiremock + 1.2.2.RELEASE + test + + + org.springframework.cloud + spring-cloud-contract-stub-runner + 1.2.2.RELEASE + test + + + org.springframework.boot + spring-boot-starter-web + 1.5.9.RELEASE + + + org.springframework.boot + spring-boot-starter-data-rest + 1.5.9.RELEASE + + + com.baeldung.spring.cloud + spring-cloud-contract-producer + 1.0.0-SNAPSHOT + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + diff --git a/spring-cloud/spring-cloud-contract/spring-cloud-contract-consumer/src/main/java/com/baeldung/spring/cloud/springcloudcontractconsumer/SpringCloudContractConsumerApplication.java b/spring-cloud/spring-cloud-contract/spring-cloud-contract-consumer/src/main/java/com/baeldung/spring/cloud/springcloudcontractconsumer/SpringCloudContractConsumerApplication.java new file mode 100644 index 0000000000..7383ae5afa --- /dev/null +++ b/spring-cloud/spring-cloud-contract/spring-cloud-contract-consumer/src/main/java/com/baeldung/spring/cloud/springcloudcontractconsumer/SpringCloudContractConsumerApplication.java @@ -0,0 +1,18 @@ +package com.baeldung.spring.cloud.springcloudcontractconsumer; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.web.client.RestTemplate; + +@SpringBootApplication +public class SpringCloudContractConsumerApplication { + public static void main(String[] args) { + SpringApplication.run(SpringCloudContractConsumerApplication.class, args); + } + + @Bean + RestTemplate restTemplate() { + return new RestTemplate(); + } +} diff --git a/spring-cloud/spring-cloud-contract/spring-cloud-contract-consumer/src/main/java/com/baeldung/spring/cloud/springcloudcontractconsumer/controller/BasicMathController.java b/spring-cloud/spring-cloud-contract/spring-cloud-contract-consumer/src/main/java/com/baeldung/spring/cloud/springcloudcontractconsumer/controller/BasicMathController.java new file mode 100644 index 0000000000..f164af89e6 --- /dev/null +++ b/spring-cloud/spring-cloud-contract/spring-cloud-contract-consumer/src/main/java/com/baeldung/spring/cloud/springcloudcontractconsumer/controller/BasicMathController.java @@ -0,0 +1,31 @@ +package com.baeldung.spring.cloud.springcloudcontractconsumer.controller; + + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.*; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.client.RestTemplate; + + +@RestController +public class BasicMathController { + + @Autowired + private RestTemplate restTemplate; + + @GetMapping("/calculate") + public String checkOddAndEven(@RequestParam("number") String number) { + HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.add("Content-Type", "application/json"); + + ResponseEntity responseEntity = restTemplate.exchange( + "http://localhost:8090/validate/prime-number?number=" + number, + HttpMethod.GET, + new HttpEntity<>(httpHeaders), + String.class); + + return responseEntity.getBody(); + } +} diff --git a/spring-cloud/spring-cloud-contract/spring-cloud-contract-consumer/src/main/resources/application.yml b/spring-cloud/spring-cloud-contract/spring-cloud-contract-consumer/src/main/resources/application.yml new file mode 100644 index 0000000000..e69de29bb2 diff --git a/spring-cloud/spring-cloud-contract/spring-cloud-contract-consumer/src/test/java/com/baeldung/spring/cloud/springcloudcontractconsumer/controller/BasicMathControllerIntegrationTest.java b/spring-cloud/spring-cloud-contract/spring-cloud-contract-consumer/src/test/java/com/baeldung/spring/cloud/springcloudcontractconsumer/controller/BasicMathControllerIntegrationTest.java new file mode 100644 index 0000000000..5cf5c6d3b8 --- /dev/null +++ b/spring-cloud/spring-cloud-contract/spring-cloud-contract-consumer/src/test/java/com/baeldung/spring/cloud/springcloudcontractconsumer/controller/BasicMathControllerIntegrationTest.java @@ -0,0 +1,44 @@ +package com.baeldung.spring.cloud.springcloudcontractconsumer.controller; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.json.AutoConfigureJsonTesters; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner; +import org.springframework.http.MediaType; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; + +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK) +@AutoConfigureMockMvc +@AutoConfigureJsonTesters +@AutoConfigureStubRunner(workOffline = true, + ids = "com.baeldung.spring.cloud:spring-cloud-contract-producer:+:stubs:8090") +public class BasicMathControllerIntegrationTest { + + @Autowired + private MockMvc mockMvc; + + @Test + public void given_WhenPassEvenNumberInQueryParam_ThenReturnEven() throws Exception { + mockMvc.perform(MockMvcRequestBuilders.get("/calculate?number=2") + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(content().string("Even")); + } + + @Test + public void given_WhenPassOddNumberInQueryParam_ThenReturnOdd() throws Exception { + mockMvc.perform(MockMvcRequestBuilders.get("/calculate?number=1") + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(content().string("Odd")); + } +} diff --git a/spring-cloud/spring-cloud-contract/spring-cloud-contract-producer/pom.xml b/spring-cloud/spring-cloud-contract/spring-cloud-contract-producer/pom.xml new file mode 100644 index 0000000000..ac27dbb645 --- /dev/null +++ b/spring-cloud/spring-cloud-contract/spring-cloud-contract-producer/pom.xml @@ -0,0 +1,74 @@ + + + 4.0.0 + + com.baeldung.spring.cloud + spring-cloud-contract-producer + 1.0.0-SNAPSHOT + jar + + spring-cloud-contract-producer + Spring Cloud Producer Sample + + + com.baeldung.spring.cloud + spring-cloud-contract + 1.0.0-SNAPSHOT + .. + + + + UTF-8 + UTF-8 + 1.8 + Edgware.SR1 + + + + + org.springframework.cloud + spring-cloud-starter-contract-verifier + test + + + org.springframework.boot + spring-boot-starter-web + 1.5.9.RELEASE + + + org.springframework.boot + spring-boot-starter-data-rest + 1.5.9.RELEASE + + + + + + org.springframework.cloud + spring-cloud-contract-maven-plugin + 1.2.2.RELEASE + true + + com.baeldung.spring.cloud.springcloudcontractproducer.BaseTestClass + + + + + + + + + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud.version} + pom + import + + + + + + diff --git a/spring-cloud/spring-cloud-contract/spring-cloud-contract-producer/src/main/java/com/baeldung/spring/cloud/springcloudcontractproducer/SpringCloudContractProducerApplication.java b/spring-cloud/spring-cloud-contract/spring-cloud-contract-producer/src/main/java/com/baeldung/spring/cloud/springcloudcontractproducer/SpringCloudContractProducerApplication.java new file mode 100644 index 0000000000..770c68c817 --- /dev/null +++ b/spring-cloud/spring-cloud-contract/spring-cloud-contract-producer/src/main/java/com/baeldung/spring/cloud/springcloudcontractproducer/SpringCloudContractProducerApplication.java @@ -0,0 +1,11 @@ +package com.baeldung.spring.cloud.springcloudcontractproducer; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SpringCloudContractProducerApplication { + public static void main(String[] args) { + SpringApplication.run(SpringCloudContractProducerApplication.class, args); + } +} diff --git a/spring-cloud/spring-cloud-contract/spring-cloud-contract-producer/src/main/java/com/baeldung/spring/cloud/springcloudcontractproducer/controller/EvenOddController.java b/spring-cloud/spring-cloud-contract/spring-cloud-contract-producer/src/main/java/com/baeldung/spring/cloud/springcloudcontractproducer/controller/EvenOddController.java new file mode 100644 index 0000000000..e61cc1120c --- /dev/null +++ b/spring-cloud/spring-cloud-contract/spring-cloud-contract-producer/src/main/java/com/baeldung/spring/cloud/springcloudcontractproducer/controller/EvenOddController.java @@ -0,0 +1,15 @@ +package com.baeldung.spring.cloud.springcloudcontractproducer.controller; + + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class EvenOddController { + + @GetMapping("/validate/prime-number") + public String isNumberPrime(@RequestParam("number") String number) { + return Integer.parseInt(number) % 2 == 0 ? "Even" : "Odd"; + } +} diff --git a/spring-cloud/spring-cloud-contract/spring-cloud-contract-producer/src/main/resources/application.properties b/spring-cloud/spring-cloud-contract/spring-cloud-contract-producer/src/main/resources/application.properties new file mode 100644 index 0000000000..e69de29bb2 diff --git a/spring-cloud/spring-cloud-contract/spring-cloud-contract-producer/src/test/java/com/baeldung/spring/cloud/springcloudcontractproducer/BaseTestClass.java b/spring-cloud/spring-cloud-contract/spring-cloud-contract-producer/src/test/java/com/baeldung/spring/cloud/springcloudcontractproducer/BaseTestClass.java new file mode 100644 index 0000000000..253924b247 --- /dev/null +++ b/spring-cloud/spring-cloud-contract/spring-cloud-contract-producer/src/test/java/com/baeldung/spring/cloud/springcloudcontractproducer/BaseTestClass.java @@ -0,0 +1,29 @@ +package com.baeldung.spring.cloud.springcloudcontractproducer; + +import com.baeldung.spring.cloud.springcloudcontractproducer.controller.EvenOddController; +import io.restassured.module.mockmvc.RestAssuredMockMvc; +import org.junit.Before; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cloud.contract.verifier.messaging.boot.AutoConfigureMessageVerifier; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.test.web.servlet.setup.StandaloneMockMvcBuilder; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK) +@DirtiesContext +@AutoConfigureMessageVerifier +public class BaseTestClass { + + @Autowired + private EvenOddController evenOddController; + + @Before + public void setup() { + StandaloneMockMvcBuilder standaloneMockMvcBuilder = MockMvcBuilders.standaloneSetup(evenOddController); + RestAssuredMockMvc.standaloneSetup(standaloneMockMvcBuilder); + } +} diff --git a/spring-cloud/spring-cloud-contract/spring-cloud-contract-producer/src/test/resources/contracts/shouldReturnEvenWhenRequestParamIsEven.groovy b/spring-cloud/spring-cloud-contract/spring-cloud-contract-producer/src/test/resources/contracts/shouldReturnEvenWhenRequestParamIsEven.groovy new file mode 100644 index 0000000000..78c36d7334 --- /dev/null +++ b/spring-cloud/spring-cloud-contract/spring-cloud-contract-producer/src/test/resources/contracts/shouldReturnEvenWhenRequestParamIsEven.groovy @@ -0,0 +1,17 @@ +import org.springframework.cloud.contract.spec.Contract + +Contract.make { + description "should return even when number input is even" + request { + method GET() + url("/validate/prime-number") { + queryParameters { + parameter("number", "2") + } + } + } + response { + body("Even") + status 200 + } +} \ No newline at end of file diff --git a/spring-cloud/spring-cloud-contract/spring-cloud-contract-producer/src/test/resources/contracts/shouldReturnOddWhenRequestParamIsOdd.groovy b/spring-cloud/spring-cloud-contract/spring-cloud-contract-producer/src/test/resources/contracts/shouldReturnOddWhenRequestParamIsOdd.groovy new file mode 100644 index 0000000000..215f987bbf --- /dev/null +++ b/spring-cloud/spring-cloud-contract/spring-cloud-contract-producer/src/test/resources/contracts/shouldReturnOddWhenRequestParamIsOdd.groovy @@ -0,0 +1,17 @@ +import org.springframework.cloud.contract.spec.Contract + +Contract.make { + description "should return odd when number input is odd" + request { + method GET() + url("/validate/prime-number") { + queryParameters { + parameter("number", "1") + } + } + } + response { + body("Odd") + status 200 + } +} \ No newline at end of file diff --git a/spring-cloud/spring-cloud-gateway/gateway-service/pom.xml b/spring-cloud/spring-cloud-gateway/gateway-service/pom.xml deleted file mode 100644 index 14cde4901a..0000000000 --- a/spring-cloud/spring-cloud-gateway/gateway-service/pom.xml +++ /dev/null @@ -1,79 +0,0 @@ - - 4.0.0 - - gateway-service - 1.0.0-SNAPSHOT - jar - - Spring Cloud Gateway Service - - - com.baeldung.spring.cloud - spring-cloud-gateway - 1.0.0-SNAPSHOT - .. - - - - 2.0.0.M2 - - - - - org.springframework.boot - spring-boot-actuator - ${version} - - - org.springframework.boot - spring-boot-starter-webflux - ${version} - - - org.springframework.cloud - spring-cloud-gateway-core - ${version} - - - org.springframework.cloud - spring-cloud-starter-eureka - ${version} - - - org.hibernate - hibernate-validator-cdi - 6.0.2.Final - - - javax.validation - validation-api - 2.0.0.Final - - - io.projectreactor.ipc - reactor-netty - 0.7.0.M1 - - - - - - spring-snapshots - Spring Snapshots - https://repo.spring.io/snapshot - - true - - - - spring-milestones - Spring Milestones - https://repo.spring.io/milestone - - false - - - - - \ No newline at end of file diff --git a/spring-cloud/spring-cloud-gateway/pom.xml b/spring-cloud/spring-cloud-gateway/pom.xml index 5142b25400..90737f369d 100644 --- a/spring-cloud/spring-cloud-gateway/pom.xml +++ b/spring-cloud/spring-cloud-gateway/pom.xml @@ -4,13 +4,8 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - com.baeldung.spring.cloud spring-cloud-gateway - 1.0.0-SNAPSHOT - - gateway-service - - pom + jar Spring Cloud Gateway @@ -25,7 +20,61 @@ UTF-8 3.7.0 1.4.2.RELEASE + 2.0.0.M6 + + + + org.springframework.boot + spring-boot-actuator + ${version} + + + org.springframework.boot + spring-boot-starter-webflux + ${version} + + + org.springframework.cloud + spring-cloud-gateway-core + ${version} + + + + org.hibernate + hibernate-validator-cdi + 6.0.2.Final + + + javax.validation + validation-api + 2.0.0.Final + + + io.projectreactor.ipc + reactor-netty + 0.7.0.M1 + + + + + + spring-snapshots + Spring Snapshots + https://repo.spring.io/snapshot + + true + + + + spring-milestones + Spring Milestones + https://repo.spring.io/milestone + + false + + + diff --git a/spring-cloud/spring-cloud-gateway/gateway-service/src/main/java/com/baeldung/spring/cloud/GatewayApplication.java b/spring-cloud/spring-cloud-gateway/src/main/java/com/baeldung/spring/cloud/GatewayApplication.java similarity index 100% rename from spring-cloud/spring-cloud-gateway/gateway-service/src/main/java/com/baeldung/spring/cloud/GatewayApplication.java rename to spring-cloud/spring-cloud-gateway/src/main/java/com/baeldung/spring/cloud/GatewayApplication.java diff --git a/spring-cloud/spring-cloud-gateway/gateway-service/src/main/resources/application.yml b/spring-cloud/spring-cloud-gateway/src/main/resources/application.yml similarity index 100% rename from spring-cloud/spring-cloud-gateway/gateway-service/src/main/resources/application.yml rename to spring-cloud/spring-cloud-gateway/src/main/resources/application.yml diff --git a/spring-cloud/spring-cloud-security/oauth2client/pom.xml b/spring-cloud/spring-cloud-security/auth-client/pom.xml similarity index 97% rename from spring-cloud/spring-cloud-security/oauth2client/pom.xml rename to spring-cloud/spring-cloud-security/auth-client/pom.xml index fd1c6964e1..5213b93f9a 100644 --- a/spring-cloud/spring-cloud-security/oauth2client/pom.xml +++ b/spring-cloud/spring-cloud-security/auth-client/pom.xml @@ -3,11 +3,11 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 com.baeldung - oauth2client + auth-client 0.0.1-SNAPSHOT jar - oauth2client + auth-client Demo project for Spring Boot diff --git a/spring-cloud/spring-cloud-security/oauth2client/src/main/java/com/baeldung/CloudSite.java b/spring-cloud/spring-cloud-security/auth-client/src/main/java/com/baeldung/CloudSite.java similarity index 100% rename from spring-cloud/spring-cloud-security/oauth2client/src/main/java/com/baeldung/CloudSite.java rename to spring-cloud/spring-cloud-security/auth-client/src/main/java/com/baeldung/CloudSite.java diff --git a/spring-cloud/spring-cloud-security/oauth2client/src/main/java/com/baeldung/config/SiteSecurityConfigurer.java b/spring-cloud/spring-cloud-security/auth-client/src/main/java/com/baeldung/config/SiteSecurityConfigurer.java similarity index 100% rename from spring-cloud/spring-cloud-security/oauth2client/src/main/java/com/baeldung/config/SiteSecurityConfigurer.java rename to spring-cloud/spring-cloud-security/auth-client/src/main/java/com/baeldung/config/SiteSecurityConfigurer.java diff --git a/spring-cloud/spring-cloud-security/oauth2client/src/main/java/com/baeldung/controller/CloudSiteController.java b/spring-cloud/spring-cloud-security/auth-client/src/main/java/com/baeldung/controller/CloudSiteController.java similarity index 100% rename from spring-cloud/spring-cloud-security/oauth2client/src/main/java/com/baeldung/controller/CloudSiteController.java rename to spring-cloud/spring-cloud-security/auth-client/src/main/java/com/baeldung/controller/CloudSiteController.java diff --git a/spring-cloud/spring-cloud-security/oauth2client/src/main/java/com/baeldung/filters/SimpleFilter.java b/spring-cloud/spring-cloud-security/auth-client/src/main/java/com/baeldung/filters/SimpleFilter.java similarity index 100% rename from spring-cloud/spring-cloud-security/oauth2client/src/main/java/com/baeldung/filters/SimpleFilter.java rename to spring-cloud/spring-cloud-security/auth-client/src/main/java/com/baeldung/filters/SimpleFilter.java diff --git a/spring-cloud/spring-cloud-security/auth-client/src/main/resources/application.properties b/spring-cloud/spring-cloud-security/auth-client/src/main/resources/application.properties new file mode 100644 index 0000000000..e69de29bb2 diff --git a/spring-cloud/spring-cloud-security/oauth2client/src/main/resources/application.yml b/spring-cloud/spring-cloud-security/auth-client/src/main/resources/application.yml similarity index 100% rename from spring-cloud/spring-cloud-security/oauth2client/src/main/resources/application.yml rename to spring-cloud/spring-cloud-security/auth-client/src/main/resources/application.yml diff --git a/spring-cloud/spring-cloud-security/oauth2client/src/main/resources/templates/personinfo.html b/spring-cloud/spring-cloud-security/auth-client/src/main/resources/templates/personinfo.html similarity index 100% rename from spring-cloud/spring-cloud-security/oauth2client/src/main/resources/templates/personinfo.html rename to spring-cloud/spring-cloud-security/auth-client/src/main/resources/templates/personinfo.html diff --git a/spring-cloud/spring-cloud-security/oauth2client/src/test/java/com/example/springoath2/Springoath2ApplicationTests.java b/spring-cloud/spring-cloud-security/auth-client/src/test/java/com/example/springoath2/Springoath2ApplicationTests.java similarity index 100% rename from spring-cloud/spring-cloud-security/oauth2client/src/test/java/com/example/springoath2/Springoath2ApplicationTests.java rename to spring-cloud/spring-cloud-security/auth-client/src/test/java/com/example/springoath2/Springoath2ApplicationTests.java diff --git a/spring-cloud/spring-cloud-security/personresource/pom.xml b/spring-cloud/spring-cloud-security/auth-resource/pom.xml similarity index 96% rename from spring-cloud/spring-cloud-security/personresource/pom.xml rename to spring-cloud/spring-cloud-security/auth-resource/pom.xml index ca1ff82515..2c54d24e7d 100644 --- a/spring-cloud/spring-cloud-security/personresource/pom.xml +++ b/spring-cloud/spring-cloud-security/auth-resource/pom.xml @@ -4,11 +4,11 @@ 4.0.0 com.baeldung - personresource + auth-resource 0.0.1-SNAPSHOT jar - personresource + auth-resource Demo project for Spring Boot diff --git a/spring-cloud/spring-cloud-security/personresource/src/main/java/com/baeldung/Application.java b/spring-cloud/spring-cloud-security/auth-resource/src/main/java/com/baeldung/Application.java similarity index 100% rename from spring-cloud/spring-cloud-security/personresource/src/main/java/com/baeldung/Application.java rename to spring-cloud/spring-cloud-security/auth-resource/src/main/java/com/baeldung/Application.java diff --git a/spring-cloud/spring-cloud-security/personresource/src/main/java/com/baeldung/config/ResourceConfigurer.java b/spring-cloud/spring-cloud-security/auth-resource/src/main/java/com/baeldung/config/ResourceConfigurer.java similarity index 100% rename from spring-cloud/spring-cloud-security/personresource/src/main/java/com/baeldung/config/ResourceConfigurer.java rename to spring-cloud/spring-cloud-security/auth-resource/src/main/java/com/baeldung/config/ResourceConfigurer.java diff --git a/spring-cloud/spring-cloud-security/personresource/src/main/java/com/baeldung/controller/PersonInfoController.java b/spring-cloud/spring-cloud-security/auth-resource/src/main/java/com/baeldung/controller/PersonInfoController.java similarity index 100% rename from spring-cloud/spring-cloud-security/personresource/src/main/java/com/baeldung/controller/PersonInfoController.java rename to spring-cloud/spring-cloud-security/auth-resource/src/main/java/com/baeldung/controller/PersonInfoController.java diff --git a/spring-cloud/spring-cloud-security/personresource/src/main/java/com/baeldung/model/Person.java b/spring-cloud/spring-cloud-security/auth-resource/src/main/java/com/baeldung/model/Person.java similarity index 100% rename from spring-cloud/spring-cloud-security/personresource/src/main/java/com/baeldung/model/Person.java rename to spring-cloud/spring-cloud-security/auth-resource/src/main/java/com/baeldung/model/Person.java diff --git a/spring-cloud/spring-cloud-security/personresource/src/main/resources/application.yml b/spring-cloud/spring-cloud-security/auth-resource/src/main/resources/application.yml similarity index 100% rename from spring-cloud/spring-cloud-security/personresource/src/main/resources/application.yml rename to spring-cloud/spring-cloud-security/auth-resource/src/main/resources/application.yml diff --git a/spring-cloud/spring-cloud-security/personresource/src/test/java/com/baeldung/service/personservice/PersonserviceApplicationTests.java b/spring-cloud/spring-cloud-security/auth-resource/src/test/java/com/baeldung/service/personservice/PersonserviceApplicationTests.java similarity index 100% rename from spring-cloud/spring-cloud-security/personresource/src/test/java/com/baeldung/service/personservice/PersonserviceApplicationTests.java rename to spring-cloud/spring-cloud-security/auth-resource/src/test/java/com/baeldung/service/personservice/PersonserviceApplicationTests.java diff --git a/spring-cloud/spring-cloud-security/authserver/pom.xml b/spring-cloud/spring-cloud-security/auth-server/pom.xml similarity index 97% rename from spring-cloud/spring-cloud-security/authserver/pom.xml rename to spring-cloud/spring-cloud-security/auth-server/pom.xml index ed88ac046b..ab30f3f2ec 100644 --- a/spring-cloud/spring-cloud-security/authserver/pom.xml +++ b/spring-cloud/spring-cloud-security/auth-server/pom.xml @@ -4,7 +4,7 @@ 4.0.0 com.baeldung - authserver + auth-server 0.0.1-SNAPSHOT diff --git a/spring-cloud/spring-cloud-security/authserver/src/main/java/com/baeldung/AuthServer.java b/spring-cloud/spring-cloud-security/auth-server/src/main/java/com/baeldung/AuthServer.java similarity index 100% rename from spring-cloud/spring-cloud-security/authserver/src/main/java/com/baeldung/AuthServer.java rename to spring-cloud/spring-cloud-security/auth-server/src/main/java/com/baeldung/AuthServer.java diff --git a/spring-cloud/spring-cloud-security/authserver/src/main/java/com/baeldung/config/AuthServerConfigurer.java b/spring-cloud/spring-cloud-security/auth-server/src/main/java/com/baeldung/config/AuthServerConfigurer.java similarity index 100% rename from spring-cloud/spring-cloud-security/authserver/src/main/java/com/baeldung/config/AuthServerConfigurer.java rename to spring-cloud/spring-cloud-security/auth-server/src/main/java/com/baeldung/config/AuthServerConfigurer.java diff --git a/spring-cloud/spring-cloud-security/authserver/src/main/java/com/baeldung/config/ResourceServerConfigurer.java b/spring-cloud/spring-cloud-security/auth-server/src/main/java/com/baeldung/config/ResourceServerConfigurer.java similarity index 100% rename from spring-cloud/spring-cloud-security/authserver/src/main/java/com/baeldung/config/ResourceServerConfigurer.java rename to spring-cloud/spring-cloud-security/auth-server/src/main/java/com/baeldung/config/ResourceServerConfigurer.java diff --git a/spring-cloud/spring-cloud-security/authserver/src/main/java/com/baeldung/config/WebMvcConfigurer.java b/spring-cloud/spring-cloud-security/auth-server/src/main/java/com/baeldung/config/WebMvcConfigurer.java similarity index 100% rename from spring-cloud/spring-cloud-security/authserver/src/main/java/com/baeldung/config/WebMvcConfigurer.java rename to spring-cloud/spring-cloud-security/auth-server/src/main/java/com/baeldung/config/WebMvcConfigurer.java diff --git a/spring-cloud/spring-cloud-security/authserver/src/main/java/com/baeldung/config/WebSecurityConfigurer.java b/spring-cloud/spring-cloud-security/auth-server/src/main/java/com/baeldung/config/WebSecurityConfigurer.java similarity index 100% rename from spring-cloud/spring-cloud-security/authserver/src/main/java/com/baeldung/config/WebSecurityConfigurer.java rename to spring-cloud/spring-cloud-security/auth-server/src/main/java/com/baeldung/config/WebSecurityConfigurer.java diff --git a/spring-cloud/spring-cloud-security/authserver/src/main/java/com/baeldung/controller/ResourceController.java b/spring-cloud/spring-cloud-security/auth-server/src/main/java/com/baeldung/controller/ResourceController.java similarity index 100% rename from spring-cloud/spring-cloud-security/authserver/src/main/java/com/baeldung/controller/ResourceController.java rename to spring-cloud/spring-cloud-security/auth-server/src/main/java/com/baeldung/controller/ResourceController.java diff --git a/spring-cloud/spring-cloud-security/authserver/src/main/resources/application.yml b/spring-cloud/spring-cloud-security/auth-server/src/main/resources/application.yml similarity index 100% rename from spring-cloud/spring-cloud-security/authserver/src/main/resources/application.yml rename to spring-cloud/spring-cloud-security/auth-server/src/main/resources/application.yml diff --git a/spring-cloud/spring-cloud-security/authserver/src/main/resources/certificate/mykeystore.jks b/spring-cloud/spring-cloud-security/auth-server/src/main/resources/certificate/mykeystore.jks similarity index 100% rename from spring-cloud/spring-cloud-security/authserver/src/main/resources/certificate/mykeystore.jks rename to spring-cloud/spring-cloud-security/auth-server/src/main/resources/certificate/mykeystore.jks diff --git a/spring-cloud/spring-cloud-security/authserver/src/main/resources/templates/login.html b/spring-cloud/spring-cloud-security/auth-server/src/main/resources/templates/login.html similarity index 100% rename from spring-cloud/spring-cloud-security/authserver/src/main/resources/templates/login.html rename to spring-cloud/spring-cloud-security/auth-server/src/main/resources/templates/login.html diff --git a/spring-cloud/spring-cloud-task/springcloudtaskbatch/.gitignore b/spring-cloud/spring-cloud-task/springcloudtaskbatch/.gitignore new file mode 100644 index 0000000000..f675857856 --- /dev/null +++ b/spring-cloud/spring-cloud-task/springcloudtaskbatch/.gitignore @@ -0,0 +1,2 @@ +/target/ +/.settings/ \ No newline at end of file diff --git a/spring-cloud/spring-cloud-task/springcloudtaskbatch/pom.xml b/spring-cloud/spring-cloud-task/springcloudtaskbatch/pom.xml new file mode 100644 index 0000000000..4805f5296c --- /dev/null +++ b/spring-cloud/spring-cloud-task/springcloudtaskbatch/pom.xml @@ -0,0 +1,81 @@ + + 4.0.0 + org.baeldung.cloud + springcloudtask + 0.0.1-SNAPSHOT + + + org.springframework.boot + spring-boot-starter-parent + 1.5.10.RELEASE + + + + + com.baeldung.TaskDemo + UTF-8 + UTF-8 + 1.8 + 1.2.2.RELEASE + + + + + + + org.springframework.boot + spring-boot-starter + + + org.springframework.boot + spring-boot-starter-data-jpa + + + mysql + mysql-connector-java + + + org.springframework.cloud + spring-cloud-starter-task + + + + org.springframework.cloud + spring-cloud-task-core + + + + org.springframework.boot + spring-boot-starter-batch + + + + org.springframework.cloud + spring-cloud-task-batch + + + + + + + org.springframework.cloud + spring-cloud-task-dependencies + ${spring-cloud-task.version} + pom + import + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/spring-cloud/spring-cloud-task/springcloudtaskbatch/src/main/java/com/baeldung/task/HelloWorldTaskConfigurer.java b/spring-cloud/spring-cloud-task/springcloudtaskbatch/src/main/java/com/baeldung/task/HelloWorldTaskConfigurer.java new file mode 100644 index 0000000000..dc2ba53138 --- /dev/null +++ b/spring-cloud/spring-cloud-task/springcloudtaskbatch/src/main/java/com/baeldung/task/HelloWorldTaskConfigurer.java @@ -0,0 +1,14 @@ +package com.baeldung.task; + +import javax.sql.DataSource; + +import org.springframework.cloud.task.configuration.DefaultTaskConfigurer; + +public class HelloWorldTaskConfigurer + extends + DefaultTaskConfigurer { + + public HelloWorldTaskConfigurer(DataSource dataSource) { + super(dataSource); + } +} \ No newline at end of file diff --git a/spring-cloud/spring-cloud-task/springcloudtaskbatch/src/main/java/com/baeldung/task/JobConfiguration.java b/spring-cloud/spring-cloud-task/springcloudtaskbatch/src/main/java/com/baeldung/task/JobConfiguration.java new file mode 100644 index 0000000000..6c215ad53d --- /dev/null +++ b/spring-cloud/spring-cloud-task/springcloudtaskbatch/src/main/java/com/baeldung/task/JobConfiguration.java @@ -0,0 +1,105 @@ +package com.baeldung.task; + +import java.util.Arrays; +import java.util.List; +import java.util.logging.Logger; + +import org.springframework.batch.core.Job; +import org.springframework.batch.core.Step; +import org.springframework.batch.core.StepContribution; +import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; +import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; +import org.springframework.batch.core.scope.context.ChunkContext; +import org.springframework.batch.core.step.tasklet.Tasklet; +import org.springframework.batch.item.ItemProcessor; +import org.springframework.batch.item.ItemWriter; +import org.springframework.batch.item.support.ListItemReader; +import org.springframework.batch.repeat.RepeatStatus; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class JobConfiguration { + + private final static Logger LOGGER = Logger + .getLogger(JobConfiguration.class.getName()); + + @Autowired + private JobBuilderFactory jobBuilderFactory; + + @Autowired + private StepBuilderFactory stepBuilderFactory; + + @Bean + public Step step1() { + return this.stepBuilderFactory.get("job1step1") + .tasklet(new Tasklet() { + @Override + public RepeatStatus execute( + StepContribution contribution, + ChunkContext chunkContext) + throws Exception { + LOGGER.info("Tasklet has run"); + return RepeatStatus.FINISHED; + } + }).build(); + } + + @Bean + public Step step2() { + return this.stepBuilderFactory + .get("job1step2") + . chunk(3) + .reader( + new ListItemReader<>(Arrays.asList("7", + "2", "3", "10", "5", "6"))) + .processor( + new ItemProcessor() { + @Override + public String process(String item) + throws Exception { + LOGGER.info("Processing of chunks"); + return String.valueOf(Integer + .parseInt(item) * -1); + } + }) + .writer(new ItemWriter() { + @Override + public void write( + List items) + throws Exception { + for (String item : items) { + LOGGER.info(">> " + item); + } + } + }).build(); + } + + @Bean + public Job job1() { + return this.jobBuilderFactory.get("job1") + .start(step1()) + .next(step2()) + .build(); + } + + @Bean + public Job job2() { + return jobBuilderFactory.get("job2") + .start(stepBuilderFactory.get("job2step1") + .tasklet(new Tasklet() { + @Override + public RepeatStatus execute( + StepContribution contribution, + ChunkContext chunkContext) + throws Exception { + LOGGER + .info("This job is from Baeldung"); + return RepeatStatus.FINISHED; + } + }) + .build()) + .build(); + } +} \ No newline at end of file diff --git a/spring-cloud/spring-cloud-task/springcloudtaskbatch/src/main/java/com/baeldung/task/TaskDemo.java b/spring-cloud/spring-cloud-task/springcloudtaskbatch/src/main/java/com/baeldung/task/TaskDemo.java new file mode 100644 index 0000000000..be2a173589 --- /dev/null +++ b/spring-cloud/spring-cloud-task/springcloudtaskbatch/src/main/java/com/baeldung/task/TaskDemo.java @@ -0,0 +1,56 @@ +package com.baeldung.task; + +import java.util.logging.Logger; + +import javax.sql.DataSource; + +import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.task.configuration.EnableTask; +import org.springframework.context.annotation.Bean; +import org.springframework.stereotype.Component; + +@SpringBootApplication +@EnableTask +@EnableBatchProcessing +public class TaskDemo { + + private final static Logger LOGGER = Logger + .getLogger(TaskDemo.class.getName()); + + @Autowired + private DataSource dataSource; + + @Bean + public HelloWorldTaskConfigurer getTaskConfigurer() + { + return new HelloWorldTaskConfigurer(dataSource); + } + + @Bean + public TaskListener taskListener() { + return new TaskListener(); + } + + public static void main(String[] args) { + SpringApplication.run(TaskDemo.class, args); + } + + @Component + public static class HelloWorldApplicationRunner + implements + ApplicationRunner { + + @Override + public void run(ApplicationArguments arg0) + throws Exception { + // TODO Auto-generated method stub + LOGGER + .info("Hello World from Spring Cloud Task!"); + } + } +} \ No newline at end of file diff --git a/spring-cloud/spring-cloud-task/springcloudtaskbatch/src/main/java/com/baeldung/task/TaskListener.java b/spring-cloud/spring-cloud-task/springcloudtaskbatch/src/main/java/com/baeldung/task/TaskListener.java new file mode 100644 index 0000000000..8250153b66 --- /dev/null +++ b/spring-cloud/spring-cloud-task/springcloudtaskbatch/src/main/java/com/baeldung/task/TaskListener.java @@ -0,0 +1,31 @@ +package com.baeldung.task; + +import java.util.logging.Logger; + +import org.springframework.cloud.task.listener.TaskExecutionListener; +import org.springframework.cloud.task.repository.TaskExecution; + +public class TaskListener implements TaskExecutionListener { + + private final static Logger LOGGER = Logger + .getLogger(TaskListener.class.getName()); + + @Override + public void onTaskEnd(TaskExecution arg0) { + // TODO Auto-generated method stub + LOGGER.info("End of Task"); + } + + @Override + public void onTaskFailed(TaskExecution arg0, + Throwable arg1) { + // TODO Auto-generated method stub + + } + + @Override + public void onTaskStartup(TaskExecution arg0) { + // TODO Auto-generated method stub + LOGGER.info("Task Startup"); + } +} \ No newline at end of file diff --git a/spring-cloud/spring-cloud-task/springcloudtaskbatch/src/main/resources/application.yml b/spring-cloud/spring-cloud-task/springcloudtaskbatch/src/main/resources/application.yml new file mode 100644 index 0000000000..1187c12fe7 --- /dev/null +++ b/spring-cloud/spring-cloud-task/springcloudtaskbatch/src/main/resources/application.yml @@ -0,0 +1,26 @@ +logging: + level: + org: + springframework: + cloud: + task=DEBUG + +spring: + application: + name=helloWorld + datasource: + url: jdbc:mysql://localhost:3306/springcloud?useSSL=false + username: root + password: + jpa: + hibernate: + ddl-auto: create-drop + properties: + hibernate: + dialect: org.hibernate.dialect.MySQL5Dialect + batch: + initialize-schema: always +maven: + remoteRepositories: + springRepo: + url: https://repo.spring.io/libs-snapshot \ No newline at end of file diff --git a/spring-cloud/spring-cloud-task/springcloudtasksink/.gitignore b/spring-cloud/spring-cloud-task/springcloudtasksink/.gitignore new file mode 100644 index 0000000000..2af7cefb0a --- /dev/null +++ b/spring-cloud/spring-cloud-task/springcloudtasksink/.gitignore @@ -0,0 +1,24 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +nbproject/private/ +build/ +nbbuild/ +dist/ +nbdist/ +.nb-gradle/ \ No newline at end of file diff --git a/spring-cloud/spring-cloud-task/springcloudtasksink/pom.xml b/spring-cloud/spring-cloud-task/springcloudtasksink/pom.xml new file mode 100644 index 0000000000..b717fffc7c --- /dev/null +++ b/spring-cloud/spring-cloud-task/springcloudtasksink/pom.xml @@ -0,0 +1,88 @@ + + + 4.0.0 + + com.baeldung + SpringCloudTaskSink + 0.0.1-SNAPSHOT + jar + + SpringCloudTaskSink + Demo project for Spring Boot + + + org.springframework.boot + spring-boot-starter-parent + 1.5.10.RELEASE + + + + + UTF-8 + UTF-8 + 1.8 + 1.2.2.RELEASE + Edgware.SR2 + + + + + org.springframework.cloud + spring-cloud-starter-stream-rabbit + + + org.springframework.cloud + spring-cloud-starter-task + + + org.springframework.cloud + spring-cloud-stream-test-support + test + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.boot + spring-boot-starter-test + test + + + + org.springframework.cloud + spring-cloud-deployer-local + 1.3.0.RELEASE + + + + + + + org.springframework.cloud + spring-cloud-task-dependencies + ${spring-cloud-task.version} + pom + import + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud.version} + pom + import + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/spring-cloud/spring-cloud-task/springcloudtasksink/src/main/java/com/baeldung/SpringCloudTaskFinal/SpringCloudTaskSinkApplication.java b/spring-cloud/spring-cloud-task/springcloudtasksink/src/main/java/com/baeldung/SpringCloudTaskFinal/SpringCloudTaskSinkApplication.java new file mode 100644 index 0000000000..62085e5fa5 --- /dev/null +++ b/spring-cloud/spring-cloud-task/springcloudtasksink/src/main/java/com/baeldung/SpringCloudTaskFinal/SpringCloudTaskSinkApplication.java @@ -0,0 +1,16 @@ +package com.baeldung.SpringCloudTaskFinal; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.task.launcher.annotation.EnableTaskLauncher; + +@SpringBootApplication +@EnableTaskLauncher +public class SpringCloudTaskSinkApplication { + + public static void main(String[] args) { + SpringApplication.run( + SpringCloudTaskSinkApplication.class, args); + } + +} \ No newline at end of file diff --git a/spring-cloud/spring-cloud-task/springcloudtasksink/src/main/java/com/baeldung/SpringCloudTaskFinal/TaskSinkConfiguration.java b/spring-cloud/spring-cloud-task/springcloudtasksink/src/main/java/com/baeldung/SpringCloudTaskFinal/TaskSinkConfiguration.java new file mode 100644 index 0000000000..638de58ecb --- /dev/null +++ b/spring-cloud/spring-cloud-task/springcloudtasksink/src/main/java/com/baeldung/SpringCloudTaskFinal/TaskSinkConfiguration.java @@ -0,0 +1,18 @@ +package com.baeldung.SpringCloudTaskFinal; + +import static org.mockito.Mockito.mock; + +import org.springframework.cloud.deployer.spi.task.TaskLauncher; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + + +@Configuration +public class TaskSinkConfiguration { + + @Bean + public TaskLauncher taskLauncher() { + return mock(TaskLauncher.class); + } + +} \ No newline at end of file diff --git a/spring-cloud/spring-cloud-task/springcloudtasksink/src/main/resources/application.properties b/spring-cloud/spring-cloud-task/springcloudtasksink/src/main/resources/application.properties new file mode 100644 index 0000000000..1660dc8516 --- /dev/null +++ b/spring-cloud/spring-cloud-task/springcloudtasksink/src/main/resources/application.properties @@ -0,0 +1 @@ +maven.remoteRepositories.springRepo.url=https://repo.spring.io/libs-snapshot \ No newline at end of file diff --git a/spring-cloud/spring-cloud-task/springcloudtasksink/src/test/java/com/baeldung/SpringCloudTaskFinal/SpringCloudTaskSinkApplicationTests.java b/spring-cloud/spring-cloud-task/springcloudtasksink/src/test/java/com/baeldung/SpringCloudTaskFinal/SpringCloudTaskSinkApplicationTests.java new file mode 100644 index 0000000000..1f47eada14 --- /dev/null +++ b/spring-cloud/spring-cloud-task/springcloudtasksink/src/test/java/com/baeldung/SpringCloudTaskFinal/SpringCloudTaskSinkApplicationTests.java @@ -0,0 +1,72 @@ +package com.baeldung.SpringCloudTaskFinal; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cloud.deployer.spi.core.AppDeploymentRequest; +import org.springframework.cloud.deployer.spi.task.TaskLauncher; +import org.springframework.cloud.stream.messaging.Sink; +import org.springframework.cloud.task.launcher.TaskLaunchRequest; +import org.springframework.context.ApplicationContext; +import org.springframework.messaging.support.GenericMessage; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.verify; + +@RunWith(SpringRunner.class) +@SpringBootTest( + classes = SpringCloudTaskSinkApplication.class) +public class SpringCloudTaskSinkApplicationTests { + + @Autowired + ApplicationContext context; + + @Autowired + private Sink sink; + + @Test + public void testTaskLaunch() throws IOException { + + TaskLauncher taskLauncher = + context.getBean(TaskLauncher.class); + + Map prop = new HashMap(); + prop.put("server.port", "0"); + TaskLaunchRequest request = new TaskLaunchRequest( + "maven://org.springframework.cloud.task.app:" + + "timestamp-task:jar:1.0.1.RELEASE", null, + prop, + null, null); + GenericMessage message = new GenericMessage( + request); + this.sink.input().send(message); + + ArgumentCaptor deploymentRequest = ArgumentCaptor + .forClass(AppDeploymentRequest.class); + + verify(taskLauncher).launch( + deploymentRequest.capture()); + + AppDeploymentRequest actualRequest = deploymentRequest + .getValue(); + + // Verifying the co-ordinate of launched Task here. + assertTrue(actualRequest.getCommandlineArguments() + .isEmpty()); + assertEquals("0", actualRequest.getDefinition() + .getProperties().get("server.port")); + assertTrue(actualRequest + .getResource() + .toString() + .contains( + "org.springframework.cloud.task.app:timestamp-task:jar:1.0.1.RELEASE")); + } +} \ No newline at end of file diff --git a/spring-data-spring-security/README.md b/spring-data-spring-security/README.md new file mode 100644 index 0000000000..15b4b50870 --- /dev/null +++ b/spring-data-spring-security/README.md @@ -0,0 +1,14 @@ +# About this project +This project contains examples from the [Spring Data with Spring Security](http://www.baeldung.com/spring-data-with-spring-security) article from Baeldung. + +# Running the project +The application uses [Spring Boot](http://projects.spring.io/spring-boot/), so it is easy to run. You can start it any of a few ways: +* Run the `main` method from `SpringDataRestApplication` +* Use the Maven Spring Boot plugin: `mvn spring-boot:run` +* Package the application as a JAR and run it using `java -jar spring-data-spring-security.jar` + +# Viewing the running application +To view the running application, visit [http://localhost:8080](http://localhost:8080) in your browser + +###Relevant Articles: +- [Spring Data with Spring Security](http://www.baeldung.com/spring-data-with-spring-security) diff --git a/spring-data-spring-security/pom.xml b/spring-data-spring-security/pom.xml new file mode 100644 index 0000000000..d6b671ee57 --- /dev/null +++ b/spring-data-spring-security/pom.xml @@ -0,0 +1,67 @@ + + + 4.0.0 + + com.baeldung + spring-data-spring-security + 1.0 + jar + + intro-spring-data-spring-security + Spring Data with Spring Security + + + parent-boot-5 + com.baeldung + 0.0.1-SNAPSHOT + ../parent-boot-5 + + + + + org.springframework.boot + spring-boot-starter + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.springframework.security + spring-security-data + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.security + spring-security-test + test + + + org.apache.tomcat.embed + tomcat-embed-jasper + + + + com.h2database + h2 + + + javax.servlet + jstl + + + + + ${project.artifactId} + + + + diff --git a/spring-data-spring-security/src/main/java/com/baeldung/AppConfig.java b/spring-data-spring-security/src/main/java/com/baeldung/AppConfig.java new file mode 100644 index 0000000000..16bbe8b326 --- /dev/null +++ b/spring-data-spring-security/src/main/java/com/baeldung/AppConfig.java @@ -0,0 +1,64 @@ +package com.baeldung; + +import java.util.Properties; + +import javax.sql.DataSource; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Import; +import org.springframework.context.annotation.PropertySource; +import org.springframework.core.env.Environment; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.jdbc.datasource.DriverManagerDataSource; +import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; +import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; + +@SpringBootApplication +@PropertySource("classpath:persistence-h2.properties") +@EnableJpaRepositories(basePackages = { "com.baeldung.data.repositories" }) +@EnableWebMvc +@Import(SpringSecurityConfig.class) +public class AppConfig extends WebMvcConfigurerAdapter { + + @Autowired + private Environment env; + + @Bean + public DataSource dataSource() { + final DriverManagerDataSource dataSource = new DriverManagerDataSource(); + dataSource.setDriverClassName(env.getProperty("driverClassName")); + dataSource.setUrl(env.getProperty("url")); + dataSource.setUsername(env.getProperty("user")); + dataSource.setPassword(env.getProperty("password")); + return dataSource; + } + + @Bean + public LocalContainerEntityManagerFactoryBean entityManagerFactory() { + final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean(); + em.setDataSource(dataSource()); + em.setPackagesToScan(new String[] { "com.baeldung.models" }); + em.setJpaVendorAdapter(new HibernateJpaVendorAdapter()); + em.setJpaProperties(additionalProperties()); + return em; + } + + final Properties additionalProperties() { + final Properties hibernateProperties = new Properties(); + if (env.getProperty("hibernate.hbm2ddl.auto") != null) { + hibernateProperties.setProperty("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto")); + } + if (env.getProperty("hibernate.dialect") != null) { + hibernateProperties.setProperty("hibernate.dialect", env.getProperty("hibernate.dialect")); + } + if (env.getProperty("hibernate.show_sql") != null) { + hibernateProperties.setProperty("hibernate.show_sql", env.getProperty("hibernate.show_sql")); + } + return hibernateProperties; + } + +} diff --git a/spring-data-spring-security/src/main/java/com/baeldung/SpringSecurityConfig.java b/spring-data-spring-security/src/main/java/com/baeldung/SpringSecurityConfig.java new file mode 100644 index 0000000000..ee13678a24 --- /dev/null +++ b/spring-data-spring-security/src/main/java/com/baeldung/SpringSecurityConfig.java @@ -0,0 +1,89 @@ +package com.baeldung; + +import javax.annotation.PostConstruct; +import javax.sql.DataSource; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.authentication.dao.DaoAuthenticationProvider; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.builders.WebSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.data.repository.query.SecurityEvaluationContextExtension; +import org.springframework.web.context.WebApplicationContext; + +import com.baeldung.security.AuthenticationSuccessHandlerImpl; +import com.baeldung.security.CustomUserDetailsService; + +@Configuration +@EnableWebSecurity +@ComponentScan("com.baeldung.security") +public class SpringSecurityConfig extends WebSecurityConfigurerAdapter { + + @Autowired + private WebApplicationContext applicationContext; + private CustomUserDetailsService userDetailsService; + @Autowired + private AuthenticationSuccessHandlerImpl successHandler; + @Autowired + private DataSource dataSource; + + @PostConstruct + public void completeSetup() { + userDetailsService = applicationContext.getBean(CustomUserDetailsService.class); + } + + @Override + protected void configure(final AuthenticationManagerBuilder auth) throws Exception { + auth.userDetailsService(userDetailsService) + .passwordEncoder(encoder()) + .and() + .authenticationProvider(authenticationProvider()) + .jdbcAuthentication() + .dataSource(dataSource); + } + + @Override + public void configure(WebSecurity web) throws Exception { + web.ignoring() + .antMatchers("/resources/**"); + } + + @Override + protected void configure(final HttpSecurity http) throws Exception { + http.authorizeRequests() + .antMatchers("/login") + .permitAll() + .and() + .formLogin() + .permitAll() + .successHandler(successHandler) + .and() + .csrf() + .disable(); + } + + @Bean + public DaoAuthenticationProvider authenticationProvider() { + final DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider(); + authProvider.setUserDetailsService(userDetailsService); + authProvider.setPasswordEncoder(encoder()); + return authProvider; + } + + @Bean + public PasswordEncoder encoder() { + return new BCryptPasswordEncoder(11); + } + + @Bean + public SecurityEvaluationContextExtension securityEvaluationContextExtension() { + return new SecurityEvaluationContextExtension(); + } +} diff --git a/spring-data-spring-security/src/main/java/com/baeldung/data/repositories/TweetRepository.java b/spring-data-spring-security/src/main/java/com/baeldung/data/repositories/TweetRepository.java new file mode 100644 index 0000000000..7d6446ed0d --- /dev/null +++ b/spring-data-spring-security/src/main/java/com/baeldung/data/repositories/TweetRepository.java @@ -0,0 +1,14 @@ +package com.baeldung.data.repositories; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.PagingAndSortingRepository; + +import com.baeldung.models.Tweet; + +public interface TweetRepository extends PagingAndSortingRepository { + + @Query("select twt from Tweet twt JOIN twt.likes as lk where lk = ?#{ principal?.username } or twt.owner = ?#{ principal?.username }") + Page getMyTweetsAndTheOnesILiked(Pageable pageable); +} diff --git a/spring-data-spring-security/src/main/java/com/baeldung/data/repositories/UserRepository.java b/spring-data-spring-security/src/main/java/com/baeldung/data/repositories/UserRepository.java new file mode 100644 index 0000000000..9f13c3197e --- /dev/null +++ b/spring-data-spring-security/src/main/java/com/baeldung/data/repositories/UserRepository.java @@ -0,0 +1,27 @@ +package com.baeldung.data.repositories; + +import java.util.Date; +import java.util.List; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; + +import com.baeldung.models.AppUser; +import com.baeldung.models.Tweet; + +public interface UserRepository extends CrudRepository { + AppUser findByUsername(String username); + + List findByName(String name); + + @Query("UPDATE AppUser u SET u.lastLogin=:lastLogin WHERE u.username = ?#{ principal?.username }") + @Modifying + @Transactional + public void updateLastLogin(@Param("lastLogin") Date lastLogin); +} diff --git a/spring-data-spring-security/src/main/java/com/baeldung/models/AppUser.java b/spring-data-spring-security/src/main/java/com/baeldung/models/AppUser.java new file mode 100644 index 0000000000..e48233f90a --- /dev/null +++ b/spring-data-spring-security/src/main/java/com/baeldung/models/AppUser.java @@ -0,0 +1,83 @@ +package com.baeldung.models; + +import java.util.Date; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +@Entity +@Table(name = "users") +public class AppUser { + + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE) + private long id; + + private String name; + @Column(unique = true) + private String username; + private String password; + private boolean enabled = true; + private Date lastLogin; + + private AppUser() { + } + + public AppUser(String name, String email, String password) { + this.username = email; + this.name = name; + this.password = password; + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public Date getLastLogin() { + return lastLogin; + } + + public void setLastLogin(Date lastLogin) { + this.lastLogin = lastLogin; + } +} diff --git a/spring-data-spring-security/src/main/java/com/baeldung/models/Tweet.java b/spring-data-spring-security/src/main/java/com/baeldung/models/Tweet.java new file mode 100644 index 0000000000..b2e45009f6 --- /dev/null +++ b/spring-data-spring-security/src/main/java/com/baeldung/models/Tweet.java @@ -0,0 +1,63 @@ +package com.baeldung.models; + +import java.util.HashSet; +import java.util.Set; + +import javax.persistence.ElementCollection; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; + +@Entity +public class Tweet { + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE) + private long id; + private String tweet; + private String owner; + @ElementCollection(targetClass = String.class, fetch = FetchType.EAGER) + private Set likes = new HashSet(); + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + private Tweet() { + } + + public Tweet(String tweet, String owner) { + this.tweet = tweet; + this.owner = owner; + } + + public String getTweet() { + return tweet; + } + + public void setTweet(String tweet) { + this.tweet = tweet; + } + + public String getOwner() { + return owner; + } + + public void setOwner(String owner) { + this.owner = owner; + } + + public Set getLikes() { + return likes; + } + + public void setLikes(Set likes) { + this.likes = likes; + } + +} diff --git a/spring-data-spring-security/src/main/java/com/baeldung/security/AppUserPrincipal.java b/spring-data-spring-security/src/main/java/com/baeldung/security/AppUserPrincipal.java new file mode 100644 index 0000000000..195f9f7bf6 --- /dev/null +++ b/spring-data-spring-security/src/main/java/com/baeldung/security/AppUserPrincipal.java @@ -0,0 +1,67 @@ +package com.baeldung.security; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; + +import com.baeldung.models.AppUser; + +public class AppUserPrincipal implements UserDetails { + + private final AppUser user; + + // + + public AppUserPrincipal(AppUser user) { + this.user = user; + } + + // + + @Override + public String getUsername() { + return user.getUsername(); + } + + @Override + public String getPassword() { + return user.getPassword(); + } + + @Override + public Collection getAuthorities() { + final List authorities = Collections.singletonList(new SimpleGrantedAuthority("User")); + return authorities; + } + + @Override + public boolean isAccountNonExpired() { + return true; + } + + @Override + public boolean isAccountNonLocked() { + return true; + } + + @Override + public boolean isCredentialsNonExpired() { + return true; + } + + @Override + public boolean isEnabled() { + return true; + } + + // + + public AppUser getAppUser() { + return user; + } + +} diff --git a/spring-data-spring-security/src/main/java/com/baeldung/security/AuthenticationSuccessHandlerImpl.java b/spring-data-spring-security/src/main/java/com/baeldung/security/AuthenticationSuccessHandlerImpl.java new file mode 100644 index 0000000000..3fc2bc6559 --- /dev/null +++ b/spring-data-spring-security/src/main/java/com/baeldung/security/AuthenticationSuccessHandlerImpl.java @@ -0,0 +1,28 @@ +package com.baeldung.security; + +import java.io.IOException; +import java.util.Date; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.Authentication; +import org.springframework.security.web.authentication.AuthenticationSuccessHandler; +import org.springframework.stereotype.Component; + +import com.baeldung.data.repositories.UserRepository; + +@Component +public class AuthenticationSuccessHandlerImpl implements AuthenticationSuccessHandler { + + @Autowired + private UserRepository userRepository; + + @Override + public void onAuthenticationSuccess(HttpServletRequest arg0, HttpServletResponse arg1, Authentication arg2) throws IOException, ServletException { + userRepository.updateLastLogin(new Date()); + } + +} diff --git a/spring-data-spring-security/src/main/java/com/baeldung/security/CustomUserDetailsService.java b/spring-data-spring-security/src/main/java/com/baeldung/security/CustomUserDetailsService.java new file mode 100644 index 0000000000..016f4f7fa9 --- /dev/null +++ b/spring-data-spring-security/src/main/java/com/baeldung/security/CustomUserDetailsService.java @@ -0,0 +1,40 @@ +package com.baeldung.security; + +import javax.annotation.PostConstruct; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Service; +import org.springframework.web.context.WebApplicationContext; + +import com.baeldung.data.repositories.UserRepository; +import com.baeldung.models.AppUser; + +@Service +public class CustomUserDetailsService implements UserDetailsService { + + @Autowired + private WebApplicationContext applicationContext; + private UserRepository userRepository; + + public CustomUserDetailsService() { + super(); + } + + @PostConstruct + public void completeSetup() { + userRepository = applicationContext.getBean(UserRepository.class); + } + + @Override + public UserDetails loadUserByUsername(final String username) { + final AppUser appUser = userRepository.findByUsername(username); + if (appUser == null) { + throw new UsernameNotFoundException(username); + } + return new AppUserPrincipal(appUser); + } + +} diff --git a/spring-data-spring-security/src/main/java/com/baeldung/util/DummyContentUtil.java b/spring-data-spring-security/src/main/java/com/baeldung/util/DummyContentUtil.java new file mode 100644 index 0000000000..f1640264d2 --- /dev/null +++ b/spring-data-spring-security/src/main/java/com/baeldung/util/DummyContentUtil.java @@ -0,0 +1,63 @@ +package com.baeldung.util; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Random; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; + +import com.baeldung.models.AppUser; +import com.baeldung.models.Tweet; + +public class DummyContentUtil { + + public static final List generateDummyUsers() { + List appUsers = new ArrayList<>(); + BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); + appUsers.add(new AppUser("Lionel Messi", "lionel@messi.com", passwordEncoder.encode("li1234"))); + appUsers.add(new AppUser("Cristiano Ronaldo", "cristiano@ronaldo.com", passwordEncoder.encode("c1234"))); + appUsers.add(new AppUser("Neymar Dos Santos", "neymar@neymar.com", passwordEncoder.encode("n1234"))); + appUsers.add(new AppUser("Luiz Suarez", "luiz@suarez.com", passwordEncoder.encode("lu1234"))); + appUsers.add(new AppUser("Andres Iniesta", "andres@iniesta.com", passwordEncoder.encode("a1234"))); + appUsers.add(new AppUser("Ivan Rakitic", "ivan@rakitic.com", passwordEncoder.encode("i1234"))); + appUsers.add(new AppUser("Ousman Dembele", "ousman@dembele.com", passwordEncoder.encode("o1234"))); + appUsers.add(new AppUser("Sergio Busquet", "sergio@busquet.com", passwordEncoder.encode("s1234"))); + appUsers.add(new AppUser("Gerard Pique", "gerard@pique.com", passwordEncoder.encode("g1234"))); + appUsers.add(new AppUser("Ter Stergen", "ter@stergen.com", passwordEncoder.encode("t1234"))); + return appUsers; + } + + public static final List generateDummyTweets(List users) { + List tweets = new ArrayList<>(); + Random random = new Random(); + IntStream.range(0, 9) + .sequential() + .forEach(i -> { + Tweet twt = new Tweet(String.format("Tweet %d", i), users.get(random.nextInt(users.size())) + .getUsername()); + twt.getLikes() + .addAll(users.subList(0, random.nextInt(users.size())) + .stream() + .map(AppUser::getUsername) + .collect(Collectors.toSet())); + tweets.add(twt); + }); + return tweets; + } + + public static Collection getAuthorities() { + Collection grantedAuthorities = new ArrayList(); + GrantedAuthority grantedAuthority = new GrantedAuthority() { + public String getAuthority() { + return "ROLE_USER"; + } + }; + grantedAuthorities.add(grantedAuthority); + return grantedAuthorities; + } + +} diff --git a/spring-data-spring-security/src/main/resources/application.properties b/spring-data-spring-security/src/main/resources/application.properties new file mode 100644 index 0000000000..e69de29bb2 diff --git a/spring-data-spring-security/src/main/resources/persistence-h2.properties b/spring-data-spring-security/src/main/resources/persistence-h2.properties new file mode 100644 index 0000000000..a4b2af6361 --- /dev/null +++ b/spring-data-spring-security/src/main/resources/persistence-h2.properties @@ -0,0 +1,8 @@ +driverClassName=org.h2.Driver +url=jdbc:h2:mem:myDb;DB_CLOSE_DELAY=-1 +username=sa +password= + +hibernate.dialect=org.hibernate.dialect.H2Dialect +hibernate.show_sql=false +hibernate.hbm2ddl.auto=create-drop \ No newline at end of file diff --git a/spring-data-spring-security/src/test/java/com/baeldung/relationships/SpringDataWithSecurityTest.java b/spring-data-spring-security/src/test/java/com/baeldung/relationships/SpringDataWithSecurityTest.java new file mode 100644 index 0000000000..dbbfe7e85e --- /dev/null +++ b/spring-data-spring-security/src/test/java/com/baeldung/relationships/SpringDataWithSecurityTest.java @@ -0,0 +1,100 @@ +package com.baeldung.relationships; + +import static org.springframework.util.Assert.isTrue; + +import java.util.Date; +import java.util.List; + +import javax.servlet.ServletContext; + +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.InvalidDataAccessApiUsageException; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.context.web.WebAppConfiguration; +import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; + +import com.baeldung.AppConfig; +import com.baeldung.data.repositories.TweetRepository; +import com.baeldung.data.repositories.UserRepository; +import com.baeldung.models.AppUser; +import com.baeldung.models.Tweet; +import com.baeldung.security.AppUserPrincipal; +import com.baeldung.util.DummyContentUtil; + +@RunWith(SpringRunner.class) +@WebAppConfiguration +@ContextConfiguration +@DirtiesContext +public class SpringDataWithSecurityTest { + AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext(); + @Autowired + private ServletContext servletContext; + private static UserRepository userRepository; + private static TweetRepository tweetRepository; + + @Before + public void testInit() { + ctx.register(AppConfig.class); + ctx.setServletContext(servletContext); + ctx.refresh(); + userRepository = ctx.getBean(UserRepository.class); + tweetRepository = ctx.getBean(TweetRepository.class); + List appUsers = (List) userRepository.save(DummyContentUtil.generateDummyUsers()); + tweetRepository.save(DummyContentUtil.generateDummyTweets(appUsers)); + } + + @AfterClass + public static void tearDown() { + tweetRepository.deleteAll(); + userRepository.deleteAll(); + } + + @Test + public void givenAppUser_whenLoginSuccessful_shouldUpdateLastLogin() { + AppUser appUser = userRepository.findByUsername("lionel@messi.com"); + Authentication auth = new UsernamePasswordAuthenticationToken(new AppUserPrincipal(appUser), null, DummyContentUtil.getAuthorities()); + SecurityContextHolder.getContext() + .setAuthentication(auth); + userRepository.updateLastLogin(new Date()); + } + + @Test(expected = InvalidDataAccessApiUsageException.class) + public void givenNoAppUserInSecurityContext_whenUpdateLastLoginAttempted_shouldFail() { + userRepository.updateLastLogin(new Date()); + } + + @Test + public void givenAppUser_whenLoginSuccessful_shouldReadMyPagedTweets() { + AppUser appUser = userRepository.findByUsername("lionel@messi.com"); + Authentication auth = new UsernamePasswordAuthenticationToken(new AppUserPrincipal(appUser), null, DummyContentUtil.getAuthorities()); + SecurityContextHolder.getContext() + .setAuthentication(auth); + Page page = null; + do { + page = tweetRepository.getMyTweetsAndTheOnesILiked(new PageRequest(page != null ? page.getNumber() + 1 : 0, 5)); + for (Tweet twt : page.getContent()) { + isTrue((twt.getOwner() == appUser.getUsername()) || (twt.getLikes() + .contains(appUser.getUsername())), "I do not have any Tweets"); + } + } while (page.hasNext()); + } + + @Test(expected = InvalidDataAccessApiUsageException.class) + public void givenNoAppUser_whenPaginatedResultsRetrievalAttempted_shouldFail() { + Page page = null; + do { + page = tweetRepository.getMyTweetsAndTheOnesILiked(new PageRequest(page != null ? page.getNumber() + 1 : 0, 5)); + } while (page != null && page.hasNext()); + } +} diff --git a/spring-dispatcher-servlet/src/main/java/com/baeldung/springdispatcherservlet/controller/MultipartController.java b/spring-dispatcher-servlet/src/main/java/com/baeldung/springdispatcherservlet/controller/MultipartController.java index 1cc8261f7c..a693bf039f 100644 --- a/spring-dispatcher-servlet/src/main/java/com/baeldung/springdispatcherservlet/controller/MultipartController.java +++ b/spring-dispatcher-servlet/src/main/java/com/baeldung/springdispatcherservlet/controller/MultipartController.java @@ -25,14 +25,20 @@ public class MultipartController { try { InputStream in = file.getInputStream(); String path = new File(".").getAbsolutePath(); - FileOutputStream f = new FileOutputStream(path.substring(0, path.length()-1)+ "/uploads/" + file.getOriginalFilename()); - int ch; - while ((ch = in.read()) != -1) { - f.write(ch); + FileOutputStream f = new FileOutputStream(path.substring(0, path.length() - 1) + "/uploads/" + file.getOriginalFilename()); + try { + int ch; + while ((ch = in.read()) != -1) { + f.write(ch); + } + modelAndView.getModel().put("message", "File uploaded successfully!"); + } catch (Exception e) { + System.out.println("Exception uploading multipart: " + e); + } finally { + f.flush(); + f.close(); + in.close(); } - f.flush(); - f.close(); - modelAndView.getModel().put("message", "File uploaded successfully!"); } catch (Exception e) { System.out.println("Exception uploading multipart: " + e); } diff --git a/spring-integration/pom.xml b/spring-integration/pom.xml index 4e210122b0..43e45dfd17 100644 --- a/spring-integration/pom.xml +++ b/spring-integration/pom.xml @@ -18,7 +18,7 @@ UTF-8 - 4.3.5.RELEASE + 5.0.1.RELEASE 1.1.4.RELEASE 1.4.7 1.1.1 @@ -68,7 +68,7 @@ org.springframework.integration spring-integration-core - ${spring.integration.version} + ${spring.version} javax.activation @@ -84,17 +84,17 @@ org.springframework.integration spring-integration-twitter - ${spring.integration.version} + ${spring.version} org.springframework.integration spring-integration-mail - ${spring.integration.version} + ${spring.version} org.springframework.integration spring-integration-ftp - ${spring.integration.version} + ${spring.version} org.springframework.social @@ -104,7 +104,30 @@ org.springframework.integration spring-integration-file - ${spring.integration.version} + ${spring.version} + + + + org.springframework.security + spring-security-core + ${spring.version} + + + org.springframework.security + spring-security-config + ${spring.version} + + + org.springframework.integration + spring-integration-security + ${spring.version} + + + + org.springframework.security + spring-security-test + ${spring.version} + test junit diff --git a/spring-integration/src/main/java/com/baeldung/si/security/MessageConsumer.java b/spring-integration/src/main/java/com/baeldung/si/security/MessageConsumer.java new file mode 100644 index 0000000000..af925c63a7 --- /dev/null +++ b/spring-integration/src/main/java/com/baeldung/si/security/MessageConsumer.java @@ -0,0 +1,45 @@ +package com.baeldung.si.security; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.logging.Logger; + +import org.springframework.integration.annotation.ServiceActivator; +import org.springframework.messaging.Message; +import org.springframework.stereotype.Service; + +@Service +public class MessageConsumer { + + private String messageContent; + + private Map messagePSContent = new ConcurrentHashMap<>(); + + public String getMessageContent() { + return messageContent; + } + + public void setMessageContent(String messageContent) { + this.messageContent = messageContent; + } + + public Map getMessagePSContent() { + return messagePSContent; + } + + public void setMessagePSContent(Map messagePSContent) { + this.messagePSContent = messagePSContent; + } + + @ServiceActivator(inputChannel = "endDirectChannel") + public void endDirectFlow(Message message) { + setMessageContent(message.getPayload().toString()); + } + + @ServiceActivator(inputChannel = "finalPSResult") + public void endPSFlow(Message message) { + Logger.getAnonymousLogger().info(Thread.currentThread().getName() + " has completed ---------------------------"); + messagePSContent.put(Thread.currentThread().getName(), (String) message.getPayload()); + } + +} diff --git a/spring-integration/src/main/java/com/baeldung/si/security/SecuredDirectChannel.java b/spring-integration/src/main/java/com/baeldung/si/security/SecuredDirectChannel.java new file mode 100644 index 0000000000..964a07d7d7 --- /dev/null +++ b/spring-integration/src/main/java/com/baeldung/si/security/SecuredDirectChannel.java @@ -0,0 +1,50 @@ +package com.baeldung.si.security; + +import java.util.logging.Logger; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.integration.annotation.ServiceActivator; +import org.springframework.integration.channel.DirectChannel; +import org.springframework.integration.config.EnableIntegration; +import org.springframework.integration.security.channel.ChannelSecurityInterceptor; +import org.springframework.integration.security.channel.SecuredChannel; +import org.springframework.messaging.Message; +import org.springframework.security.access.AccessDecisionManager; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.authentication.AuthenticationManager; + +@Configuration +@EnableIntegration +public class SecuredDirectChannel { + + @Bean(name = "startDirectChannel") + @SecuredChannel(interceptor = "channelSecurityInterceptor", sendAccess = { "ROLE_VIEWER", "jane" }) + public DirectChannel startDirectChannel() { + return new DirectChannel(); + } + + @ServiceActivator(inputChannel = "startDirectChannel", outputChannel = "endDirectChannel") + @PreAuthorize("hasRole('ROLE_LOGGER')") + public Message logMessage(Message message) { + Logger.getAnonymousLogger().info(message.toString()); + return message; + } + + @Bean(name = "endDirectChannel") + @SecuredChannel(interceptor = "channelSecurityInterceptor", sendAccess = { "ROLE_EDITOR" }) + public DirectChannel endDirectChannel() { + return new DirectChannel(); + } + + @Autowired + @Bean + public ChannelSecurityInterceptor channelSecurityInterceptor(AuthenticationManager authenticationManager, AccessDecisionManager customAccessDecisionManager) { + ChannelSecurityInterceptor channelSecurityInterceptor = new ChannelSecurityInterceptor(); + channelSecurityInterceptor.setAuthenticationManager(authenticationManager); + channelSecurityInterceptor.setAccessDecisionManager(customAccessDecisionManager); + return channelSecurityInterceptor; + } + +} diff --git a/spring-integration/src/main/java/com/baeldung/si/security/SecurityConfig.java b/spring-integration/src/main/java/com/baeldung/si/security/SecurityConfig.java new file mode 100644 index 0000000000..9c5b38b909 --- /dev/null +++ b/spring-integration/src/main/java/com/baeldung/si/security/SecurityConfig.java @@ -0,0 +1,46 @@ +package com.baeldung.si.security; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.integration.security.channel.ChannelSecurityInterceptor; +import org.springframework.security.access.AccessDecisionManager; +import org.springframework.security.access.AccessDecisionVoter; +import org.springframework.security.access.vote.AffirmativeBased; +import org.springframework.security.access.vote.RoleVoter; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration; + +@Configuration +@EnableGlobalMethodSecurity(prePostEnabled = true) +public class SecurityConfig extends GlobalMethodSecurityConfiguration { + + @Override + @Bean + public AuthenticationManager authenticationManager() throws Exception { + return super.authenticationManager(); + } + + @Bean + public AccessDecisionManager customAccessDecisionManager() { + List> decisionVoters = new ArrayList<>(); + decisionVoters.add(new RoleVoter()); + decisionVoters.add(new UsernameAccessDecisionVoter()); + AccessDecisionManager accessDecisionManager = new AffirmativeBased(decisionVoters); + return accessDecisionManager; + } + + @Autowired + @Bean + public ChannelSecurityInterceptor channelSecurityInterceptor(AuthenticationManager authenticationManager, AccessDecisionManager customAccessDecisionManager) { + ChannelSecurityInterceptor channelSecurityInterceptor = new ChannelSecurityInterceptor(); + channelSecurityInterceptor.setAuthenticationManager(authenticationManager); + channelSecurityInterceptor.setAccessDecisionManager(customAccessDecisionManager); + return channelSecurityInterceptor; + } + +} diff --git a/spring-integration/src/main/java/com/baeldung/si/security/SecurityPubSubChannel.java b/spring-integration/src/main/java/com/baeldung/si/security/SecurityPubSubChannel.java new file mode 100644 index 0000000000..11409bb89b --- /dev/null +++ b/spring-integration/src/main/java/com/baeldung/si/security/SecurityPubSubChannel.java @@ -0,0 +1,82 @@ +package com.baeldung.si.security; + +import java.util.stream.Collectors; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.integration.annotation.ServiceActivator; +import org.springframework.integration.channel.DirectChannel; +import org.springframework.integration.channel.PublishSubscribeChannel; +import org.springframework.integration.config.EnableIntegration; +import org.springframework.integration.config.GlobalChannelInterceptor; +import org.springframework.integration.security.channel.SecuredChannel; +import org.springframework.integration.security.channel.SecurityContextPropagationChannelInterceptor; +import org.springframework.integration.support.DefaultMessageBuilderFactory; +import org.springframework.integration.support.MessageBuilder; +import org.springframework.messaging.Message; +import org.springframework.messaging.support.ChannelInterceptor; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; + +@Configuration +@EnableIntegration +public class SecurityPubSubChannel { + + @Bean(name = "startPSChannel") + @SecuredChannel(interceptor = "channelSecurityInterceptor", sendAccess = "ROLE_VIEWER") + public PublishSubscribeChannel startChannel() { + return new PublishSubscribeChannel(executor()); + } + + @ServiceActivator(inputChannel = "startPSChannel", outputChannel = "finalPSResult") + @PreAuthorize("hasRole('ROLE_LOGGER')") + public Message changeMessageToRole(Message message) { + return buildNewMessage(getRoles(), message); + } + + @ServiceActivator(inputChannel = "startPSChannel", outputChannel = "finalPSResult") + @PreAuthorize("hasRole('ROLE_VIEWER')") + public Message changeMessageToUserName(Message message) { + return buildNewMessage(getUsername(), message); + } + + @Bean(name = "finalPSResult") + public DirectChannel finalPSResult() { + return new DirectChannel(); + } + + @Bean + @GlobalChannelInterceptor(patterns = { "startPSChannel", "endDirectChannel" }) + public ChannelInterceptor securityContextPropagationInterceptor() { + return new SecurityContextPropagationChannelInterceptor(); + } + + @Bean + public ThreadPoolTaskExecutor executor() { + ThreadPoolTaskExecutor pool = new ThreadPoolTaskExecutor(); + pool.setCorePoolSize(10); + pool.setMaxPoolSize(10); + pool.setWaitForTasksToCompleteOnShutdown(true); + return pool; + } + + public String getRoles() { + SecurityContext securityContext = SecurityContextHolder.getContext(); + return securityContext.getAuthentication().getAuthorities().stream().map(auth -> auth.getAuthority()).collect(Collectors.joining(",")); + } + + public String getUsername() { + SecurityContext securityContext = SecurityContextHolder.getContext(); + return securityContext.getAuthentication().getName(); + } + + public Message buildNewMessage(String content, Message message) { + DefaultMessageBuilderFactory builderFactory = new DefaultMessageBuilderFactory(); + MessageBuilder messageBuilder = builderFactory.withPayload(content); + messageBuilder.copyHeaders(message.getHeaders()); + return messageBuilder.build(); + } + +} diff --git a/spring-integration/src/main/java/com/baeldung/si/security/UsernameAccessDecisionVoter.java b/spring-integration/src/main/java/com/baeldung/si/security/UsernameAccessDecisionVoter.java new file mode 100644 index 0000000000..052f79ddf7 --- /dev/null +++ b/spring-integration/src/main/java/com/baeldung/si/security/UsernameAccessDecisionVoter.java @@ -0,0 +1,45 @@ +package com.baeldung.si.security; + +import java.util.Collection; + +import org.springframework.security.access.AccessDecisionVoter; +import org.springframework.security.access.ConfigAttribute; +import org.springframework.security.core.Authentication; + +public class UsernameAccessDecisionVoter implements AccessDecisionVoter { + private String rolePrefix = "ROLE_"; + + @Override + public boolean supports(ConfigAttribute attribute) { + if ((attribute.getAttribute() != null) + && !attribute.getAttribute().startsWith(rolePrefix)) { + return true; + }else { + return false; + } + } + + @Override + public boolean supports(Class clazz) { + return true; + } + + @Override + public int vote(Authentication authentication, Object object, Collection attributes) { + if (authentication == null) { + return ACCESS_DENIED; + } + String name = authentication.getName(); + int result = ACCESS_ABSTAIN; + for (ConfigAttribute attribute : attributes) { + if (this.supports(attribute)) { + result = ACCESS_DENIED; + if (attribute.getAttribute().equals(name)) { + return ACCESS_GRANTED; + } + } + } + return result; + } + +} diff --git a/spring-integration/src/test/java/com/baeldung/si/TestSpringIntegrationSecurity.java b/spring-integration/src/test/java/com/baeldung/si/TestSpringIntegrationSecurity.java new file mode 100644 index 0000000000..9ae82af2dc --- /dev/null +++ b/spring-integration/src/test/java/com/baeldung/si/TestSpringIntegrationSecurity.java @@ -0,0 +1,81 @@ +package com.baeldung.si; + +import static org.junit.Assert.assertEquals; + +import org.hamcrest.core.IsInstanceOf; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.messaging.SubscribableChannel; +import org.springframework.messaging.support.GenericMessage; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.baeldung.si.security.MessageConsumer; +import com.baeldung.si.security.SecuredDirectChannel; +import com.baeldung.si.security.SecurityConfig; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = { SecurityConfig.class, SecuredDirectChannel.class, MessageConsumer.class }) +public class TestSpringIntegrationSecurity { + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + @Autowired + SubscribableChannel startDirectChannel; + + @Autowired + MessageConsumer messageConsumer; + + final String DIRECT_CHANNEL_MESSAGE = "Direct channel message"; + + @Test(expected = AuthenticationCredentialsNotFoundException.class) + public void givenNoUser_whenSendToDirectChannel_thenCredentialNotFound() { + startDirectChannel.send(new GenericMessage(DIRECT_CHANNEL_MESSAGE)); + } + + @Test + @WithMockUser(username = "jane", roles = { "LOGGER" }) + public void givenRoleLogger_whenSendMessageToDirectChannel_thenAccessDenied() { + expectedException.expectCause(IsInstanceOf. instanceOf(AccessDeniedException.class)); + + startDirectChannel.send(new GenericMessage(DIRECT_CHANNEL_MESSAGE)); + } + + @Test + @WithMockUser(username = "jane") + public void givenJane_whenSendMessageToDirectChannel_thenAccessDenied() { + expectedException.expectCause(IsInstanceOf. instanceOf(AccessDeniedException.class)); + + startDirectChannel.send(new GenericMessage(DIRECT_CHANNEL_MESSAGE)); + } + + @Test + @WithMockUser(roles = { "VIEWER" }) + public void givenRoleViewer_whenSendToDirectChannel_thenAccessDenied() { + expectedException.expectCause(IsInstanceOf. instanceOf(AccessDeniedException.class)); + + startDirectChannel.send(new GenericMessage(DIRECT_CHANNEL_MESSAGE)); + } + + @Test + @WithMockUser(roles = { "LOGGER", "VIEWER", "EDITOR" }) + public void givenRoleLoggerAndUser_whenSendMessageToDirectChannel_thenFlowCompletedSuccessfully() { + startDirectChannel.send(new GenericMessage(DIRECT_CHANNEL_MESSAGE)); + assertEquals(DIRECT_CHANNEL_MESSAGE, messageConsumer.getMessageContent()); + } + + @Test + @WithMockUser(username = "jane", roles = { "LOGGER", "EDITOR" }) + public void givenJaneLoggerEditor_whenSendToDirectChannel_thenFlowCompleted() { + startDirectChannel.send(new GenericMessage(DIRECT_CHANNEL_MESSAGE)); + assertEquals(DIRECT_CHANNEL_MESSAGE, messageConsumer.getMessageContent()); + } + +} \ No newline at end of file diff --git a/spring-integration/src/test/java/com/baeldung/si/TestSpringIntegrationSecurityExecutor.java b/spring-integration/src/test/java/com/baeldung/si/TestSpringIntegrationSecurityExecutor.java new file mode 100644 index 0000000000..b06136a7ca --- /dev/null +++ b/spring-integration/src/test/java/com/baeldung/si/TestSpringIntegrationSecurityExecutor.java @@ -0,0 +1,68 @@ +package com.baeldung.si; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.messaging.SubscribableChannel; +import org.springframework.messaging.support.GenericMessage; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.baeldung.si.security.MessageConsumer; +import com.baeldung.si.security.SecurityConfig; +import com.baeldung.si.security.SecurityPubSubChannel; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = { SecurityPubSubChannel.class, MessageConsumer.class, SecurityConfig.class }) +public class TestSpringIntegrationSecurityExecutor { + + @Autowired + SubscribableChannel startPSChannel; + + @Autowired + MessageConsumer messageConsumer; + + @Autowired + ThreadPoolTaskExecutor executor; + + final String DIRECT_CHANNEL_MESSAGE = "Direct channel message"; + + @Before + public void clearData() { + messageConsumer.setMessagePSContent(new ConcurrentHashMap<>()); + executor.setWaitForTasksToCompleteOnShutdown(true); + } + + @Test + @WithMockUser(username = "user", roles = { "VIEWER" }) + public void givenRoleUser_whenSendMessageToPSChannel_thenNoMessageArrived() throws IllegalStateException, InterruptedException { + startPSChannel.send(new GenericMessage(DIRECT_CHANNEL_MESSAGE)); + + executor.getThreadPoolExecutor().awaitTermination(2, TimeUnit.SECONDS); + + assertEquals(1, messageConsumer.getMessagePSContent().size()); + assertTrue(messageConsumer.getMessagePSContent().values().contains("user")); + } + + @Test + @WithMockUser(username = "user", roles = { "LOGGER", "VIEWER" }) + public void givenRoleUserAndLogger_whenSendMessageToPSChannel_then2GetMessages() throws IllegalStateException, InterruptedException { + startPSChannel.send(new GenericMessage(DIRECT_CHANNEL_MESSAGE)); + + executor.getThreadPoolExecutor().awaitTermination(2, TimeUnit.SECONDS); + + assertEquals(2, messageConsumer.getMessagePSContent().size()); + assertTrue(messageConsumer.getMessagePSContent().values().contains("user")); + assertTrue(messageConsumer.getMessagePSContent().values().contains("ROLE_LOGGER,ROLE_VIEWER")); + } + +} diff --git a/spring-integration/src/test/resources/logback-test.xml b/spring-integration/src/test/resources/logback-test.xml new file mode 100644 index 0000000000..a807be0ca2 --- /dev/null +++ b/spring-integration/src/test/resources/logback-test.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/spring-jinq/README.md b/spring-jinq/README.md new file mode 100644 index 0000000000..10d7903f49 --- /dev/null +++ b/spring-jinq/README.md @@ -0,0 +1,4 @@ +## Relevant articles: + +- [Introduction to Jinq with Spring](http://www.baeldung.com/spring-jinq) + diff --git a/spring-jinq/pom.xml b/spring-jinq/pom.xml new file mode 100644 index 0000000000..a895ae8dd4 --- /dev/null +++ b/spring-jinq/pom.xml @@ -0,0 +1,83 @@ + + + + com.baeldung + parent-modules + 1.0.0-SNAPSHOT + + + 4.0.0 + spring-jinq + 0.1-SNAPSHOT + + spring-jinq + + jar + + + UTF-8 + 1.8 + + 1.8.22 + + + + + + org.springframework.boot + spring-boot-dependencies + 1.5.9.RELEASE + pom + import + + + + + + + org.jinq + jinq-jpa + ${jinq.version} + + + + + com.h2database + h2 + + + + org.hibernate + hibernate-entitymanager + + + + + org.springframework + spring-orm + + + + + org.springframework.boot + spring-boot-starter-test + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + ${java.version} + ${java.version} + ${project.build.sourceEncoding} + false + + + + + + diff --git a/spring-jinq/src/main/java/com/baeldung/spring/jinq/JinqApplication.java b/spring-jinq/src/main/java/com/baeldung/spring/jinq/JinqApplication.java new file mode 100644 index 0000000000..d53b585d36 --- /dev/null +++ b/spring-jinq/src/main/java/com/baeldung/spring/jinq/JinqApplication.java @@ -0,0 +1,12 @@ +package com.baeldung.spring.jinq; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class JinqApplication { + + public static void main(String[] args) { + SpringApplication.run(JinqApplication.class, args); + } +} diff --git a/spring-jinq/src/main/java/com/baeldung/spring/jinq/config/JinqProviderConfiguration.java b/spring-jinq/src/main/java/com/baeldung/spring/jinq/config/JinqProviderConfiguration.java new file mode 100644 index 0000000000..6d921045b7 --- /dev/null +++ b/spring-jinq/src/main/java/com/baeldung/spring/jinq/config/JinqProviderConfiguration.java @@ -0,0 +1,18 @@ +package com.baeldung.spring.jinq.config; + +import javax.persistence.EntityManagerFactory; + +import org.jinq.jpa.JinqJPAStreamProvider; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class JinqProviderConfiguration { + + @Bean + @Autowired + JinqJPAStreamProvider jinqProvider(EntityManagerFactory emf) { + return new JinqJPAStreamProvider(emf); + } +} diff --git a/spring-jinq/src/main/java/com/baeldung/spring/jinq/entities/Car.java b/spring-jinq/src/main/java/com/baeldung/spring/jinq/entities/Car.java new file mode 100644 index 0000000000..263e6c7622 --- /dev/null +++ b/spring-jinq/src/main/java/com/baeldung/spring/jinq/entities/Car.java @@ -0,0 +1,58 @@ +package com.baeldung.spring.jinq.entities; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.OneToOne; + +@Entity(name = "CAR") +public class Car { + private String model; + private String description; + private int year; + private String engine; + private Manufacturer manufacturer; + + @Id + public String getModel() { + return model; + } + + public void setModel(String model) { + this.model = model; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public int getYear() { + return year; + } + + public void setYear(int year) { + this.year = year; + } + + public String getEngine() { + return engine; + } + + public void setEngine(String engine) { + this.engine = engine; + } + + @OneToOne + @JoinColumn(name = "name") + public Manufacturer getManufacturer() { + return manufacturer; + } + + public void setManufacturer(Manufacturer manufacturer) { + this.manufacturer = manufacturer; + } +} diff --git a/spring-jinq/src/main/java/com/baeldung/spring/jinq/entities/Manufacturer.java b/spring-jinq/src/main/java/com/baeldung/spring/jinq/entities/Manufacturer.java new file mode 100644 index 0000000000..f6e5fd23de --- /dev/null +++ b/spring-jinq/src/main/java/com/baeldung/spring/jinq/entities/Manufacturer.java @@ -0,0 +1,42 @@ +package com.baeldung.spring.jinq.entities; + +import java.util.List; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.OneToMany; + +@Entity(name = "MANUFACTURER") +public class Manufacturer { + + private String name; + private String city; + private List cars; + + @Id + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + @OneToMany(mappedBy = "model") + public List getCars() { + return cars; + } + + public void setCars(List cars) { + this.cars = cars; + } + +} diff --git a/spring-jinq/src/main/java/com/baeldung/spring/jinq/repositories/BaseJinqRepositoryImpl.java b/spring-jinq/src/main/java/com/baeldung/spring/jinq/repositories/BaseJinqRepositoryImpl.java new file mode 100644 index 0000000000..42b81ecc59 --- /dev/null +++ b/spring-jinq/src/main/java/com/baeldung/spring/jinq/repositories/BaseJinqRepositoryImpl.java @@ -0,0 +1,26 @@ +package com.baeldung.spring.jinq.repositories; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; + +import org.jinq.jpa.JPAJinqStream; +import org.jinq.jpa.JinqJPAStreamProvider; +import org.springframework.beans.factory.annotation.Autowired; + +public abstract class BaseJinqRepositoryImpl { + @Autowired + private JinqJPAStreamProvider jinqDataProvider; + + @PersistenceContext + private EntityManager entityManager; + + protected abstract Class entityType(); + + public JPAJinqStream stream() { + return streamOf(entityType()); + } + + protected JPAJinqStream streamOf(Class clazz) { + return jinqDataProvider.streamAll(entityManager, clazz); + } +} diff --git a/spring-jinq/src/main/java/com/baeldung/spring/jinq/repositories/CarRepository.java b/spring-jinq/src/main/java/com/baeldung/spring/jinq/repositories/CarRepository.java new file mode 100644 index 0000000000..56f6106e08 --- /dev/null +++ b/spring-jinq/src/main/java/com/baeldung/spring/jinq/repositories/CarRepository.java @@ -0,0 +1,27 @@ +package com.baeldung.spring.jinq.repositories; + +import java.util.List; +import java.util.Optional; + +import org.jinq.tuples.Pair; +import org.jinq.tuples.Tuple3; + +import com.baeldung.spring.jinq.entities.Car; +import com.baeldung.spring.jinq.entities.Manufacturer; + +public interface CarRepository { + + Optional findByModel(String model); + + List findByModelAndDescription(String model, String desc); + + List> findWithModelYearAndEngine(); + + Optional findManufacturerByModel(String model); + + List> findCarsPerManufacturer(); + + long countCarsByModel(String model); + + List findAll(int skip, int limit); +} diff --git a/spring-jinq/src/main/java/com/baeldung/spring/jinq/repositories/CarRepositoryImpl.java b/spring-jinq/src/main/java/com/baeldung/spring/jinq/repositories/CarRepositoryImpl.java new file mode 100644 index 0000000000..bf16c87461 --- /dev/null +++ b/spring-jinq/src/main/java/com/baeldung/spring/jinq/repositories/CarRepositoryImpl.java @@ -0,0 +1,72 @@ +package com.baeldung.spring.jinq.repositories; + +import java.util.List; +import java.util.Optional; + +import org.jinq.orm.stream.JinqStream; +import org.jinq.tuples.Pair; +import org.jinq.tuples.Tuple3; +import org.springframework.stereotype.Repository; + +import com.baeldung.spring.jinq.entities.Car; +import com.baeldung.spring.jinq.entities.Manufacturer; + +@Repository +public class CarRepositoryImpl extends BaseJinqRepositoryImpl implements CarRepository { + + @Override + public Optional findByModel(String model) { + return stream().where(c -> c.getModel() + .equals(model)) + .findFirst(); + } + + @Override + public List findByModelAndDescription(String model, String desc) { + return stream().where(c -> c.getModel() + .equals(model) + && c.getDescription() + .contains(desc)) + .toList(); + } + + @Override + public List> findWithModelYearAndEngine() { + return stream().select(c -> new Tuple3<>(c.getModel(), c.getYear(), c.getEngine())) + .toList(); + } + + @Override + public Optional findManufacturerByModel(String model) { + return stream().where(c -> c.getModel() + .equals(model)) + .select(c -> c.getManufacturer()) + .findFirst(); + } + + @Override + public List> findCarsPerManufacturer() { + return streamOf(Manufacturer.class).join(m -> JinqStream.from(m.getCars())) + .toList(); + } + + @Override + public long countCarsByModel(String model) { + return stream().where(c -> c.getModel() + .equals(model)) + .count(); + } + + @Override + public List findAll(int skip, int limit) { + return stream().skip(skip) + .limit(limit) + .toList(); + } + + @Override + protected Class entityType() { + return Car.class; + } + +} diff --git a/spring-jinq/src/main/resources/application.properties b/spring-jinq/src/main/resources/application.properties new file mode 100644 index 0000000000..dc73bed0c5 --- /dev/null +++ b/spring-jinq/src/main/resources/application.properties @@ -0,0 +1,7 @@ +spring.datasource.url=jdbc:h2:~/jinq +spring.datasource.username=sa +spring.datasource.password= + +spring.jpa.hibernate.ddl-auto=create-drop +spring.jpa.show-sql=true +spring.jpa.properties.hibernate.format_sql=true \ No newline at end of file diff --git a/spring-jinq/src/test/java/com/baeldung/spring/jinq/repositories/CarRepositoryIntegrationTest.java b/spring-jinq/src/test/java/com/baeldung/spring/jinq/repositories/CarRepositoryIntegrationTest.java new file mode 100644 index 0000000000..9cb126cbaa --- /dev/null +++ b/spring-jinq/src/test/java/com/baeldung/spring/jinq/repositories/CarRepositoryIntegrationTest.java @@ -0,0 +1,42 @@ +package com.baeldung.spring.jinq.repositories; + +import static org.assertj.core.api.Assertions.assertThat; + +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 com.baeldung.spring.jinq.JinqApplication; + +@ContextConfiguration(classes = JinqApplication.class) +@RunWith(SpringJUnit4ClassRunner.class) +public class CarRepositoryIntegrationTest { + + @Autowired + private CarRepository repository; + + @Test + public void givenACar_whenFilter_thenShouldBeFound() { + assertThat(repository.findByModel("model1") + .isPresent()).isFalse(); + } + + @Test + public void givenACar_whenMultipleFilters_thenShouldBeFound() { + assertThat(repository.findByModelAndDescription("model1", "desc") + .isEmpty()).isTrue(); + } + + @Test + public void whenUseASelectClause() { + assertThat(repository.findWithModelYearAndEngine() + .isEmpty()).isTrue(); + } + + @Test + public void whenUsingOneToOneRelationship() { + assertThat(repository.findManufacturerByModel("model1")).isNotNull(); + } +} diff --git a/spring-mvc-java/pom.xml b/spring-mvc-java/pom.xml index b939f0496d..9d90ba2dbf 100644 --- a/spring-mvc-java/pom.xml +++ b/spring-mvc-java/pom.xml @@ -297,7 +297,7 @@ 4.3.4.RELEASE 4.2.0.RELEASE 2.1.5.RELEASE - 2.8.5 + 2.9.4 5.2.5.Final diff --git a/spring-mvc-kotlin/pom.xml b/spring-mvc-kotlin/pom.xml index 2d1dac5e29..28a5681c03 100644 --- a/spring-mvc-kotlin/pom.xml +++ b/spring-mvc-kotlin/pom.xml @@ -17,38 +17,64 @@ war + + UTF-8 + 5.2.13.Final + 1.2.21 + 4.3.10.RELEASE + 3.0.7.RELEASE + 1.4.196 + + org.jetbrains.kotlin - kotlin-stdlib-jre8 - 1.1.4 + kotlin-stdlib-jdk8 + ${kotlin.version} org.springframework spring-web - 4.3.10.RELEASE + ${spring.version} org.springframework spring-webmvc - 4.3.10.RELEASE + ${spring.version} org.thymeleaf thymeleaf - 3.0.7.RELEASE + ${thymeleaf.version} org.thymeleaf thymeleaf-spring4 - 3.0.7.RELEASE + ${thymeleaf.version} + + + org.hibernate + hibernate-core + ${hibernate.version} + + + org.hibernate + hibernate-testing + ${hibernate.version} + test + + + com.h2database + h2 + ${h2.version} + test org.springframework spring-test - 4.3.10.RELEASE + ${spring.version} test @@ -60,10 +86,11 @@ kotlin-maven-plugin org.jetbrains.kotlin - 1.1.4 + ${kotlin.version} spring + jpa 1.8 @@ -87,7 +114,12 @@ org.jetbrains.kotlin kotlin-maven-allopen - 1.1.4-3 + ${kotlin.version} + + + org.jetbrains.kotlin + kotlin-maven-noarg + ${kotlin.version} diff --git a/spring-mvc-kotlin/src/main/kotlin/com/baeldung/kotlin/jpa/Person.kt b/spring-mvc-kotlin/src/main/kotlin/com/baeldung/kotlin/jpa/Person.kt new file mode 100644 index 0000000000..801bd1b0a5 --- /dev/null +++ b/spring-mvc-kotlin/src/main/kotlin/com/baeldung/kotlin/jpa/Person.kt @@ -0,0 +1,15 @@ +package com.baeldung.jpa + +import javax.persistence.Entity +import javax.persistence.GeneratedValue +import javax.persistence.GenerationType +import javax.persistence.Id +import javax.persistence.Table + +@Entity +@Table(name = "person") +data class Person( + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + val id: Int, + val name: String) \ No newline at end of file diff --git a/spring-mvc-kotlin/src/test/kotlin/com/baeldung/kotlin/jpa/HibernateKotlinIntegrationTest.kt b/spring-mvc-kotlin/src/test/kotlin/com/baeldung/kotlin/jpa/HibernateKotlinIntegrationTest.kt new file mode 100644 index 0000000000..8f54373406 --- /dev/null +++ b/spring-mvc-kotlin/src/test/kotlin/com/baeldung/kotlin/jpa/HibernateKotlinIntegrationTest.kt @@ -0,0 +1,44 @@ +package com.baeldung.kotlin.jpa + +import com.baeldung.jpa.Person +import org.hibernate.cfg.Configuration +import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase +import org.hibernate.testing.transaction.TransactionUtil.doInHibernate +import org.junit.Assert.assertTrue +import org.junit.Test +import java.io.IOException +import java.util.* + + +class HibernateKotlinIntegrationTest : BaseCoreFunctionalTestCase() { + + private val properties: Properties + @Throws(IOException::class) + get() { + val properties = Properties() + properties.load(javaClass.classLoader.getResourceAsStream("hibernate.properties")) + return properties + } + + override fun getAnnotatedClasses(): Array> { + return arrayOf(Person::class.java) + } + + override fun configure(configuration: Configuration) { + super.configure(configuration) + configuration.properties = properties + } + + @Test + fun givenPerson_whenSaved_thenFound() { + val personToSave = Person(0, "John") + doInHibernate(({ this.sessionFactory() }), { session -> + session.persist(personToSave) + assertTrue(session.contains(personToSave)) + }) + doInHibernate(({ this.sessionFactory() }), { session -> + val personFound = session.find(Person::class.java, personToSave.id) + assertTrue(personToSave == personFound) + }) + } +} \ No newline at end of file diff --git a/spring-mvc-kotlin/src/test/resources/hibernate.properties b/spring-mvc-kotlin/src/test/resources/hibernate.properties new file mode 100644 index 0000000000..7b8764637b --- /dev/null +++ b/spring-mvc-kotlin/src/test/resources/hibernate.properties @@ -0,0 +1,9 @@ +hibernate.connection.driver_class=org.h2.Driver +hibernate.connection.url=jdbc:h2:mem:mydb1;DB_CLOSE_DELAY=-1 +hibernate.connection.username=sa +hibernate.connection.autocommit=true +jdbc.password= + +hibernate.dialect=org.hibernate.dialect.H2Dialect +hibernate.show_sql=true +hibernate.hbm2ddl.auto=create-drop \ No newline at end of file diff --git a/spring-mvc-simple/pom.xml b/spring-mvc-simple/pom.xml index 595e58f5f3..c0e4b63897 100644 --- a/spring-mvc-simple/pom.xml +++ b/spring-mvc-simple/pom.xml @@ -31,9 +31,17 @@ 5.0.2 1.0.2 1.9.0 + 2.9.4 + 1.4.9 + 5.1.0 + + org.springframework + spring-oxm + 5.0.2.RELEASE + javax.servlet javax.servlet-api @@ -121,6 +129,28 @@ rome ${rome.version} + + + com.fasterxml.jackson.core + jackson-databind + ${jackson.version} + + + com.fasterxml.jackson.dataformat + jackson-dataformat-xml + ${jackson.version} + + + + com.thoughtworks.xstream + xstream + ${xstream.version} + + + com.github.scribejava + scribejava-apis + ${scribejava.version} + diff --git a/spring-mvc-simple/src/main/java/com/baeldung/spring/configuration/ApplicationConfiguration.java b/spring-mvc-simple/src/main/java/com/baeldung/spring/configuration/ApplicationConfiguration.java index b9a8336bf2..3275d919ea 100644 --- a/spring-mvc-simple/src/main/java/com/baeldung/spring/configuration/ApplicationConfiguration.java +++ b/spring-mvc-simple/src/main/java/com/baeldung/spring/configuration/ApplicationConfiguration.java @@ -1,19 +1,34 @@ package com.baeldung.spring.configuration; +import com.baeldung.spring.controller.rss.ArticleRssFeedViewResolver; +import com.fasterxml.jackson.dataformat.xml.XmlMapper; +import com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.http.converter.StringHttpMessageConverter; +import org.springframework.http.converter.feed.RssChannelHttpMessageConverter; +import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter; +import org.springframework.web.accept.ContentNegotiationManager; import org.springframework.web.multipart.MultipartResolver; import org.springframework.web.multipart.commons.CommonsMultipartResolver; +import org.springframework.web.servlet.ViewResolver; import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer; import org.springframework.web.servlet.config.annotation.EnableWebMvc; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; +import org.springframework.web.servlet.view.ContentNegotiatingViewResolver; import org.springframework.web.servlet.view.InternalResourceViewResolver; +import java.util.ArrayList; +import java.util.List; + @Configuration @EnableWebMvc @ComponentScan(basePackages = { "com.baeldung.springmvcforms", "com.baeldung.spring.controller", "com.baeldung.spring.validator" }) -class ApplicationConfiguration implements WebMvcConfigurer { +class ApplicationConfiguration extends WebMvcConfigurerAdapter { @Override public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { @@ -21,11 +36,19 @@ class ApplicationConfiguration implements WebMvcConfigurer { } @Bean - public InternalResourceViewResolver jspViewResolver() { - InternalResourceViewResolver bean = new InternalResourceViewResolver(); - bean.setPrefix("/WEB-INF/views/"); - bean.setSuffix(".jsp"); - return bean; + public ContentNegotiatingViewResolver viewResolver(ContentNegotiationManager cnManager) { + ContentNegotiatingViewResolver cnvResolver = new ContentNegotiatingViewResolver(); + cnvResolver.setContentNegotiationManager(cnManager); + List resolvers = new ArrayList<>(); + + InternalResourceViewResolver bean = new InternalResourceViewResolver("/WEB-INF/views/",".jsp"); + ArticleRssFeedViewResolver articleRssFeedViewResolver = new ArticleRssFeedViewResolver(); + + resolvers.add(bean); + resolvers.add(articleRssFeedViewResolver); + + cnvResolver.setViewResolvers(resolvers); + return cnvResolver; } @Bean @@ -34,4 +57,20 @@ class ApplicationConfiguration implements WebMvcConfigurer { multipartResolver.setMaxUploadSize(5242880); return multipartResolver; } + + @Override + public void configureMessageConverters(List> converters) { + Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.xml(); + builder.indentOutput(true); + + XmlMapper xmlMapper = builder.createXmlMapper(true).build(); + xmlMapper.configure(ToXmlGenerator.Feature.WRITE_XML_DECLARATION, true); + + converters.add(new StringHttpMessageConverter()); + converters.add(new RssChannelHttpMessageConverter()); + converters.add(new MappingJackson2HttpMessageConverter()); + converters.add(new MappingJackson2XmlHttpMessageConverter(xmlMapper)); + + super.configureMessageConverters(converters); + } } diff --git a/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/rss/ArticleFeed.java b/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/rss/ArticleFeed.java new file mode 100644 index 0000000000..71b225bf3f --- /dev/null +++ b/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/rss/ArticleFeed.java @@ -0,0 +1,29 @@ +package com.baeldung.spring.controller.rss; + +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +@JacksonXmlRootElement(localName="articles") +public class ArticleFeed extends RssData implements Serializable { + + @JacksonXmlProperty(localName = "item") + @JacksonXmlElementWrapper(useWrapping = false) + private List items = new ArrayList(); + + public void addItem(ArticleItem articleItem) { + this.items.add(articleItem); + } + + public List getItems() { + return items; + } + + public void setItems(List items) { + this.items = items; + } +} diff --git a/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/rss/ArticleItem.java b/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/rss/ArticleItem.java new file mode 100644 index 0000000000..6c91819676 --- /dev/null +++ b/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/rss/ArticleItem.java @@ -0,0 +1,22 @@ +package com.baeldung.spring.controller.rss; + +import java.io.Serializable; + +public class ArticleItem extends RssData implements Serializable { + private String author; + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + @Override + public String toString() { + return "ArticleItem{" + + "author='" + author + '\'' + + '}'; + } +} diff --git a/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/rss/ArticleRssController.java b/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/rss/ArticleRssController.java index 1f51b238ac..b0cce99d33 100644 --- a/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/rss/ArticleRssController.java +++ b/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/rss/ArticleRssController.java @@ -2,13 +2,45 @@ package com.baeldung.spring.controller.rss; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +import java.util.Date; @Controller public class ArticleRssController { - @GetMapping(value = "/rss", produces = "application/*") - public String articleFeed() { + @GetMapping(value = "/rss1") + public String articleMvcFeed() { return "articleFeedView"; } + @GetMapping(value = "/rss2") + @ResponseBody + public ArticleFeed articleRestFeed2() { + ArticleFeed feed = new ArticleFeed(); + feed.setLink("http://localhost:8080/spring-mvc-simple/rss"); + feed.setTitle("Article Feed"); + feed.setDescription("Article Feed Description"); + feed.setPublishedDate(new Date()); + + ArticleItem item1 = new ArticleItem(); + item1.setLink("http://www.baeldung.com/netty-exception-handling"); + item1.setTitle("Exceptions in Netty"); + item1.setDescription("In this quick article, we’ll be looking at exception handling in Netty."); + item1.setPublishedDate(new Date()); + item1.setAuthor("Carlos"); + + ArticleItem item2 = new ArticleItem(); + item2.setLink("http://www.baeldung.com/cockroachdb-java"); + item2.setTitle("Guide to CockroachDB in Java"); + item2.setDescription("This tutorial is an introductory guide to using CockroachDB with Java."); + item2.setPublishedDate(new Date()); + item2.setAuthor("Baeldung"); + + feed.addItem(item1); + feed.addItem(item2); + + return feed; + } + } diff --git a/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/rss/ArticleRssFeedViewResolver.java b/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/rss/ArticleRssFeedViewResolver.java new file mode 100644 index 0000000000..6be06c4812 --- /dev/null +++ b/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/rss/ArticleRssFeedViewResolver.java @@ -0,0 +1,15 @@ +package com.baeldung.spring.controller.rss; + +import org.springframework.web.servlet.View; +import org.springframework.web.servlet.ViewResolver; + +import java.util.Locale; + +public class ArticleRssFeedViewResolver implements ViewResolver { + + @Override + public View resolveViewName(String s, Locale locale) throws Exception { + ArticleFeedView articleFeedView = new ArticleFeedView(); + return articleFeedView; + } +} diff --git a/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/rss/RssData.java b/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/rss/RssData.java new file mode 100644 index 0000000000..258712eb2d --- /dev/null +++ b/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/rss/RssData.java @@ -0,0 +1,56 @@ +package com.baeldung.spring.controller.rss; + +import java.io.Serializable; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; + +public class RssData implements Serializable { + private String link; + private String title; + private String description; + private String publishedDate; + + public String getLink() { + return link; + } + + public void setLink(String link) { + this.link = link; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getPublishedDate() { + return publishedDate; + } + + public void setPublishedDate(Date publishedDate) { + DateFormat df = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss"); + this.publishedDate = df.format(publishedDate); + } + + @Override + public String toString() { + return "RssData{" + + "link='" + link + '\'' + + ", title='" + title + '\'' + + ", description='" + description + '\'' + + ", publishedDate=" + publishedDate + + '}'; + } +} diff --git a/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/scribe/ScribeController.java b/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/scribe/ScribeController.java new file mode 100644 index 0000000000..c5c97ff009 --- /dev/null +++ b/spring-mvc-simple/src/main/java/com/baeldung/spring/controller/scribe/ScribeController.java @@ -0,0 +1,55 @@ +package com.baeldung.spring.controller.scribe; + +import com.github.scribejava.apis.TwitterApi; +import com.github.scribejava.core.builder.ServiceBuilder; +import com.github.scribejava.core.model.*; +import com.github.scribejava.core.oauth.OAuth10aService; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.servlet.view.RedirectView; + +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.util.concurrent.ExecutionException; + +@Controller +@RequestMapping("twitter") +public class ScribeController { + + private OAuth10aService createTwitterService() { + return new ServiceBuilder("PSRszoHhRDVhyo2RIkThEbWko") + .apiSecret("prpJbz03DcGRN46sb4ucdSYtVxG8unUKhcnu3an5ItXbEOuenL") + .callback("http://localhost:8080/spring-mvc-simple/twitter/callback") + .build(TwitterApi.instance()); + } + + @GetMapping(value = "/authorization") + public RedirectView authorization(HttpServletRequest servletReq) throws InterruptedException, ExecutionException, IOException { + OAuth10aService twitterService = createTwitterService(); + + OAuth1RequestToken requestToken = twitterService.getRequestToken(); + String authorizationUrl = twitterService.getAuthorizationUrl(requestToken); + servletReq.getSession().setAttribute("requestToken", requestToken); + + RedirectView redirectView = new RedirectView(); + redirectView.setUrl(authorizationUrl); + return redirectView; + } + + @GetMapping(value = "/callback", produces = "text/plain") + @ResponseBody + public String callback(HttpServletRequest servletReq, @RequestParam("oauth_verifier") String oauthV) throws InterruptedException, ExecutionException, IOException { + OAuth10aService twitterService = createTwitterService(); + OAuth1RequestToken requestToken = (OAuth1RequestToken) servletReq.getSession().getAttribute("requestToken"); + OAuth1AccessToken accessToken = twitterService.getAccessToken(requestToken, oauthV); + + OAuthRequest request = new OAuthRequest(Verb.GET, "https://api.twitter.com/1.1/account/verify_credentials.json"); + twitterService.signRequest(accessToken, request); + Response response = twitterService.execute(request); + + return response.getBody(); + } +} diff --git a/spring-security-openid/pom.xml b/spring-security-openid/pom.xml index 4c8112a163..aeabb161c9 100644 --- a/spring-security-openid/pom.xml +++ b/spring-security-openid/pom.xml @@ -46,6 +46,11 @@ 1.0.9.RELEASE + + com.auth0 + jwks-rsa + 0.3.0 + diff --git a/spring-security-openid/src/main/java/org/baeldung/security/OpenIdConnectFilter.java b/spring-security-openid/src/main/java/org/baeldung/security/OpenIdConnectFilter.java index c0970ab3cf..f12169cb27 100644 --- a/spring-security-openid/src/main/java/org/baeldung/security/OpenIdConnectFilter.java +++ b/spring-security-openid/src/main/java/org/baeldung/security/OpenIdConnectFilter.java @@ -1,12 +1,16 @@ package org.baeldung.security; import java.io.IOException; +import java.net.URL; +import java.security.interfaces.RSAPublicKey; +import java.util.Date; import java.util.Map; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.springframework.beans.factory.annotation.Value; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; @@ -14,16 +18,28 @@ import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.jwt.Jwt; import org.springframework.security.jwt.JwtHelper; +import org.springframework.security.jwt.crypto.sign.RsaVerifier; import org.springframework.security.oauth2.client.OAuth2RestOperations; import org.springframework.security.oauth2.client.OAuth2RestTemplate; import org.springframework.security.oauth2.common.OAuth2AccessToken; -import org.springframework.security.oauth2.common.exceptions.InvalidTokenException; import org.springframework.security.oauth2.common.exceptions.OAuth2Exception; import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter; +import com.auth0.jwk.Jwk; +import com.auth0.jwk.JwkProvider; +import com.auth0.jwk.UrlJwkProvider; import com.fasterxml.jackson.databind.ObjectMapper; public class OpenIdConnectFilter extends AbstractAuthenticationProcessingFilter { + @Value("${google.clientId}") + private String clientId; + + @Value("${google.issuer}") + private String issuer; + + @Value("${google.jwkUrl}") + private String jwkUrl; + public OAuth2RestOperations restTemplate; public OpenIdConnectFilter(String defaultFilterProcessesUrl) { @@ -42,19 +58,35 @@ public class OpenIdConnectFilter extends AbstractAuthenticationProcessingFilter } try { final String idToken = accessToken.getAdditionalInformation().get("id_token").toString(); - final Jwt tokenDecoded = JwtHelper.decode(idToken); - System.out.println("===== : " + tokenDecoded.getClaims()); - + String kid = JwtHelper.headers(idToken) + .get("kid"); + final Jwt tokenDecoded = JwtHelper.decodeAndVerify(idToken, verifier(kid)); final Map authInfo = new ObjectMapper().readValue(tokenDecoded.getClaims(), Map.class); - + verifyClaims(authInfo); final OpenIdConnectUserDetails user = new OpenIdConnectUserDetails(authInfo, accessToken); return new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities()); - } catch (final InvalidTokenException e) { + } catch (final Exception e) { throw new BadCredentialsException("Could not obtain user details from token", e); } } + public void verifyClaims(Map claims) { + int exp = (int) claims.get("exp"); + Date expireDate = new Date(exp * 1000L); + Date now = new Date(); + if (expireDate.before(now) || !claims.get("iss").equals(issuer) || !claims.get("aud").equals(clientId)) { + throw new RuntimeException("Invalid claims"); + } + } + + + private RsaVerifier verifier(String kid) throws Exception { + JwkProvider provider = new UrlJwkProvider(new URL(jwkUrl)); + Jwk jwk = provider.get(kid); + return new RsaVerifier((RSAPublicKey) jwk.getPublicKey()); + } + public void setRestTemplate(OAuth2RestTemplate restTemplate2) { restTemplate = restTemplate2; diff --git a/spring-security-openid/src/main/resources/application.properties.sample.properties b/spring-security-openid/src/main/resources/application.properties.sample.properties index 3b4f7716f0..49022bf280 100644 --- a/spring-security-openid/src/main/resources/application.properties.sample.properties +++ b/spring-security-openid/src/main/resources/application.properties.sample.properties @@ -3,4 +3,6 @@ google.clientId=TODO google.clientSecret=TODO google.accessTokenUri=https://www.googleapis.com/oauth2/v3/token google.userAuthorizationUri=https://accounts.google.com/o/oauth2/auth -google.redirectUri=http://localhost:8081/google-login \ No newline at end of file +google.redirectUri=http://localhost:8081/google-login +google.issuer=accounts.google.com +google.jwkUrl=https://www.googleapis.com/oauth2/v2/certs \ No newline at end of file diff --git a/spring-swagger-codegen/spring-swagger-codegen-api-client/src/main/gen/com/baeldung/petstore/client/invoker/BuildConfig.java b/spring-swagger-codegen/spring-swagger-codegen-api-client/src/main/gen/com/baeldung/petstore/client/invoker/BuildConfig.java new file mode 100644 index 0000000000..85233bc278 --- /dev/null +++ b/spring-swagger-codegen/spring-swagger-codegen-api-client/src/main/gen/com/baeldung/petstore/client/invoker/BuildConfig.java @@ -0,0 +1,8 @@ +/*___Generated_by_IDEA___*/ + +package com.baeldung.petstore.client.invoker; + +/* This stub is only used by the IDE. It is NOT the BuildConfig class actually packed into the APK */ +public final class BuildConfig { + public final static boolean DEBUG = Boolean.parseBoolean(null); +} \ No newline at end of file diff --git a/spring-swagger-codegen/spring-swagger-codegen-api-client/src/main/gen/com/baeldung/petstore/client/invoker/Manifest.java b/spring-swagger-codegen/spring-swagger-codegen-api-client/src/main/gen/com/baeldung/petstore/client/invoker/Manifest.java new file mode 100644 index 0000000000..06c202e733 --- /dev/null +++ b/spring-swagger-codegen/spring-swagger-codegen-api-client/src/main/gen/com/baeldung/petstore/client/invoker/Manifest.java @@ -0,0 +1,7 @@ +/*___Generated_by_IDEA___*/ + +package com.baeldung.petstore.client.invoker; + +/* This stub is only used by the IDE. It is NOT the Manifest class actually packed into the APK */ +public final class Manifest { +} \ No newline at end of file diff --git a/spring-swagger-codegen/spring-swagger-codegen-api-client/src/main/gen/com/baeldung/petstore/client/invoker/R.java b/spring-swagger-codegen/spring-swagger-codegen-api-client/src/main/gen/com/baeldung/petstore/client/invoker/R.java new file mode 100644 index 0000000000..41e2b545fb --- /dev/null +++ b/spring-swagger-codegen/spring-swagger-codegen-api-client/src/main/gen/com/baeldung/petstore/client/invoker/R.java @@ -0,0 +1,7 @@ +/*___Generated_by_IDEA___*/ + +package com.baeldung.petstore.client.invoker; + +/* This stub is only used by the IDE. It is NOT the R class actually packed into the APK */ +public final class R { +} \ No newline at end of file diff --git a/testing-modules/junit-5/pom.xml b/testing-modules/junit-5/pom.xml index 585232b3fe..28a29d8545 100644 --- a/testing-modules/junit-5/pom.xml +++ b/testing-modules/junit-5/pom.xml @@ -20,7 +20,7 @@ UTF-8 1.8 - 5.0.2 + 5.1.0 1.0.1 4.12.1 2.8.2 diff --git a/testing-modules/testing/README.md b/testing-modules/testing/README.md index 3511bb1bb9..2894da3496 100644 --- a/testing-modules/testing/README.md +++ b/testing-modules/testing/README.md @@ -17,3 +17,4 @@ - [Introduction to Jukito](http://www.baeldung.com/jukito) - [Custom JUnit 4 Test Runners](http://www.baeldung.com/junit-4-custom-runners) - [Guide to JSpec](http://www.baeldung.com/jspec) +- [Custom Assertions with AssertJ](http://www.baeldung.com/assertj-custom-assertion) diff --git a/testing-modules/testing/pom.xml b/testing-modules/testing/pom.xml index 1fd6357b87..91792a4681 100644 --- a/testing-modules/testing/pom.xml +++ b/testing-modules/testing/pom.xml @@ -154,6 +154,16 @@ + + org.assertj + assertj-assertions-generator-maven-plugin + ${assertj-generator.version} + + + com.baeldung.testing.assertj.custom.Person + + + @@ -163,7 +173,8 @@ 0.7.7.201606060606 21.0 3.1.0 - 3.6.1 + 3.9.0 + 2.1.0 0.32 1.1.0 0.12 diff --git a/testing-modules/testing/src/main/java/com/baeldung/testing/assertj/Member.java b/testing-modules/testing/src/main/java/com/baeldung/testing/assertj/Member.java new file mode 100644 index 0000000000..a0b3d0daac --- /dev/null +++ b/testing-modules/testing/src/main/java/com/baeldung/testing/assertj/Member.java @@ -0,0 +1,19 @@ +package com.baeldung.testing.assertj; + +public class Member { + private String name; + private int age; + + public Member(String name, int age) { + this.name = name; + this.age = age; + } + + public String getName() { + return name; + } + + public int getAge() { + return age; + } +} diff --git a/testing-modules/testing/src/main/java/com/baeldung/testing/assertj/custom/Person.java b/testing-modules/testing/src/main/java/com/baeldung/testing/assertj/custom/Person.java new file mode 100644 index 0000000000..34afc480e4 --- /dev/null +++ b/testing-modules/testing/src/main/java/com/baeldung/testing/assertj/custom/Person.java @@ -0,0 +1,32 @@ +package com.baeldung.testing.assertj.custom; + +import java.util.ArrayList; +import java.util.List; + +public class Person { + private String fullName; + private int age; + private List nicknames; + + public Person(String fullName, int age) { + this.fullName = fullName; + this.age = age; + this.nicknames = new ArrayList<>(); + } + + public void addNickname(String nickname) { + nicknames.add(nickname); + } + + public String getFullName() { + return fullName; + } + + public int getAge() { + return age; + } + + public List getNicknames() { + return nicknames; + } +} diff --git a/testing-modules/testing/src/test/java/com/baeldung/testing/assertj/AssertJConditionUnitTest.java b/testing-modules/testing/src/test/java/com/baeldung/testing/assertj/AssertJConditionUnitTest.java new file mode 100644 index 0000000000..153af828f1 --- /dev/null +++ b/testing-modules/testing/src/test/java/com/baeldung/testing/assertj/AssertJConditionUnitTest.java @@ -0,0 +1,72 @@ +package com.baeldung.testing.assertj; + +import static org.assertj.core.api.Assertions.allOf; +import static org.assertj.core.api.Assertions.anyOf; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.not; +import static org.junit.Assert.fail; + +import java.util.ArrayList; +import java.util.List; + +import org.assertj.core.api.Condition; +import org.junit.Test; + +public class AssertJConditionUnitTest { + private Condition senior = new Condition<>(m -> m.getAge() >= 60, "senior"); + private Condition nameJohn = new Condition<>(m -> m.getName().equalsIgnoreCase("John"), "name John"); + + @Test + public void whenUsingMemberAgeCondition_thenCorrect() { + Member member = new Member("John", 65); + assertThat(member).is(senior); + + try { + assertThat(member).isNot(senior); + fail(); + } catch (AssertionError e) { + assertThat(e).hasMessageContaining("not to be "); + } + } + + @Test + public void whenUsingMemberNameCondition_thenCorrect() { + Member member = new Member("Jane", 60); + assertThat(member).doesNotHave(nameJohn); + + try { + assertThat(member).has(nameJohn); + fail(); + } catch (AssertionError e) { + assertThat(e).hasMessageContaining("to have:\n "); + } + } + + @Test + public void whenCollectionConditionsAreSatisfied_thenCorrect() { + List members = new ArrayList<>(); + members.add(new Member("Alice", 50)); + members.add(new Member("Bob", 60)); + + assertThat(members).haveExactly(1, senior); + assertThat(members).doNotHave(nameJohn); + } + + @Test + public void whenCombiningAllOfConditions_thenCorrect() { + Member john = new Member("John", 60); + Member jane = new Member("Jane", 50); + + assertThat(john).is(allOf(senior, nameJohn)); + assertThat(jane).is(allOf(not(nameJohn), not(senior))); + } + + @Test + public void whenCombiningAnyOfConditions_thenCorrect() { + Member john = new Member("John", 50); + Member jane = new Member("Jane", 60); + + assertThat(john).is(anyOf(senior, nameJohn)); + assertThat(jane).is(anyOf(nameJohn, senior)); + } +} diff --git a/testing-modules/testing/src/test/java/com/baeldung/testing/assertj/custom/AssertJCustomAssertionsUnitTest.java b/testing-modules/testing/src/test/java/com/baeldung/testing/assertj/custom/AssertJCustomAssertionsUnitTest.java new file mode 100644 index 0000000000..4c09311bac --- /dev/null +++ b/testing-modules/testing/src/test/java/com/baeldung/testing/assertj/custom/AssertJCustomAssertionsUnitTest.java @@ -0,0 +1,44 @@ +package com.baeldung.testing.assertj.custom; + +import static com.baeldung.testing.assertj.custom.Assertions.assertThat; +import static org.junit.Assert.fail; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +public class AssertJCustomAssertionsUnitTest { + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Test + public void whenPersonNameMatches_thenCorrect() { + Person person = new Person("John Doe", 20); + assertThat(person).hasFullName("John Doe"); + } + + @Test + public void whenPersonAgeLessThanEighteen_thenNotAdult() { + Person person = new Person("Jane Roe", 16); + + try { + assertThat(person).isAdult(); + fail(); + } catch (AssertionError e) { + org.assertj.core.api.Assertions.assertThat(e).hasMessage("Expected person to be adult"); + } + } + + @Test + public void whenPersonDoesNotHaveAMatchingNickname_thenIncorrect() { + Person person = new Person("John Doe", 20); + person.addNickname("Nick"); + + try { + assertThat(person).hasNickname("John"); + fail(); + } catch (AssertionError e) { + org.assertj.core.api.Assertions.assertThat(e).hasMessage("Expected person to have nickname John"); + } + } +} diff --git a/testing-modules/testing/src/test/java/com/baeldung/testing/assertj/custom/Assertions.java b/testing-modules/testing/src/test/java/com/baeldung/testing/assertj/custom/Assertions.java new file mode 100644 index 0000000000..fcffb8fc6c --- /dev/null +++ b/testing-modules/testing/src/test/java/com/baeldung/testing/assertj/custom/Assertions.java @@ -0,0 +1,9 @@ +package com.baeldung.testing.assertj.custom; + +public class Assertions { + public static PersonAssert assertThat(Person actual) { + return new PersonAssert(actual); + } + + // static factory methods of other assertion classes +} diff --git a/testing-modules/testing/src/test/java/com/baeldung/testing/assertj/custom/PersonAssert.java b/testing-modules/testing/src/test/java/com/baeldung/testing/assertj/custom/PersonAssert.java new file mode 100644 index 0000000000..d6cc585e96 --- /dev/null +++ b/testing-modules/testing/src/test/java/com/baeldung/testing/assertj/custom/PersonAssert.java @@ -0,0 +1,38 @@ +package com.baeldung.testing.assertj.custom; + +import org.assertj.core.api.AbstractAssert; + +public class PersonAssert extends AbstractAssert { + + public PersonAssert(Person actual) { + super(actual, PersonAssert.class); + } + + public static PersonAssert assertThat(Person actual) { + return new PersonAssert(actual); + } + + public PersonAssert hasFullName(String fullName) { + isNotNull(); + if (!actual.getFullName().equals(fullName)) { + failWithMessage("Expected person to have full name %s but was %s", fullName, actual.getFullName()); + } + return this; + } + + public PersonAssert isAdult() { + isNotNull(); + if (actual.getAge() < 18) { + failWithMessage("Expected person to be adult"); + } + return this; + } + + public PersonAssert hasNickname(String nickName) { + isNotNull(); + if (!actual.getNicknames().contains(nickName)) { + failWithMessage("Expected person to have nickname %s", nickName); + } + return this; + } +} diff --git a/testing-modules/testing/src/test/java/com/baeldung/testing/assertj/exceptions/Java7StyleAssertions.java b/testing-modules/testing/src/test/java/com/baeldung/testing/assertj/exceptions/Java7StyleAssertions.java new file mode 100644 index 0000000000..07a5be1118 --- /dev/null +++ b/testing-modules/testing/src/test/java/com/baeldung/testing/assertj/exceptions/Java7StyleAssertions.java @@ -0,0 +1,24 @@ +package com.baeldung.testing.assertj.exceptions; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; +import static org.assertj.core.api.Assertions.failBecauseExceptionWasNotThrown; + +import org.junit.Test; + +public class Java7StyleAssertions { + + @Test + public void whenDividingByZero_thenArithmeticException() { + try { + int numerator = 10; + int denominator = 0; + int quotient = numerator / denominator; + fail("ArithmeticException expected because dividing by zero yields an ArithmeticException."); + failBecauseExceptionWasNotThrown(ArithmeticException.class); + } catch (Exception e) { + assertThat(e).hasMessage("/ by zero"); + assertThat(e).isInstanceOf(ArithmeticException.class); + } + } +} diff --git a/testing-modules/testing/src/test/java/com/baeldung/testing/assertj/exceptions/Java8StyleAssertions.java b/testing-modules/testing/src/test/java/com/baeldung/testing/assertj/exceptions/Java8StyleAssertions.java new file mode 100644 index 0000000000..973b921654 --- /dev/null +++ b/testing-modules/testing/src/test/java/com/baeldung/testing/assertj/exceptions/Java8StyleAssertions.java @@ -0,0 +1,66 @@ +package com.baeldung.testing.assertj.exceptions; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.assertj.core.api.Assertions.catchThrowable; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import org.junit.Test; + +public class Java8StyleAssertions { + + @Test + public void whenGettingOutOfBoundsItem_thenIndexOutOfBoundsException() { + assertThatThrownBy(() -> { + ArrayList myStringList = new ArrayList(Arrays.asList("Strine one", "String two")); + myStringList.get(2); + }).isInstanceOf(IndexOutOfBoundsException.class) + .hasMessageStartingWith("Index: 2") + .hasMessageContaining("2") + .hasMessageEndingWith("Size: 2") + .hasMessageContaining("Index: 2, Size: 2") + .hasMessage("Index: %s, Size: %s", 2, 2) + .hasMessageMatching("Index: \\d+, Size: \\d+") + .hasNoCause(); + } + + @Test + public void whenWrappingException_thenCauseInstanceOfWrappedExceptionType() { + assertThatThrownBy(() -> { + try { + throw new IOException(); + } catch (IOException e) { + throw new RuntimeException(e); + } + }).isInstanceOf(RuntimeException.class) + .hasCauseInstanceOf(IOException.class) + .hasStackTraceContaining("IOException"); + } + + @Test + public void whenDividingByZero_thenArithmeticException() { + assertThatExceptionOfType(ArithmeticException.class).isThrownBy(() -> { + int numerator = 10; + int denominator = 0; + int quotient = numerator / denominator; + }) + .withMessageContaining("/ by zero"); + + // Alternatively: + + // when + Throwable thrown = catchThrowable(() -> { + int numerator = 10; + int denominator = 0; + int quotient = numerator / denominator; + }); + + // then + assertThat(thrown).isInstanceOf(ArithmeticException.class) + .hasMessageContaining("/ by zero"); + + } +} diff --git a/vavr/src/test/java/com/baeldung/vavr/VavrUnitTest.java b/vavr/src/test/java/com/baeldung/vavr/VavrUnitTest.java index 08a5e20b40..7beb75632e 100644 --- a/vavr/src/test/java/com/baeldung/vavr/VavrUnitTest.java +++ b/vavr/src/test/java/com/baeldung/vavr/VavrUnitTest.java @@ -216,11 +216,11 @@ public class VavrUnitTest { assertEquals(-1, errorSentinel); } - // @Test(expected = ArithmeticException.class) - // public void givenBadCode_whenTryHandles_thenCorrect3() { - // Try result = Try.of(() -> 1 / 0); - // result.getOrElseThrow(ArithmeticException::new); - // } + @Test(expected = RuntimeException.class) + public void givenBadCode_whenTryHandles_thenCorrect3() { + Try result = Try.of(() -> 1 / 0); + result.getOrElseThrow(e->new RuntimeException(e));//re-throw different ex type + } // lazy @Test