Merge branch 'master' into JAVA-4
This commit is contained in:
		
						commit
						f5eb0cc202
					
				| @ -10,7 +10,6 @@ This module contains articles about algorithms. Some classes of algorithms, e.g. | ||||
| - [Find If Two Numbers Are Relatively Prime in Java](https://www.baeldung.com/java-two-relatively-prime-numbers) | ||||
| - [Knapsack Problem Implementation in Java](https://www.baeldung.com/java-knapsack) | ||||
| - [How to Determine if a Binary Tree is Balanced](https://www.baeldung.com/java-balanced-binary-tree) | ||||
| - [The Caesar Cipher in Java](https://www.baeldung.com/java-caesar-cipher) | ||||
| - [Overview of Combinatorial Problems in Java](https://www.baeldung.com/java-combinatorial-algorithms) | ||||
| - [Prim’s Algorithm](https://www.baeldung.com/java-prim-algorithm) | ||||
| - [Maximum Subarray Problem](https://www.baeldung.com/java-maximum-subarray) | ||||
|  | ||||
| @ -39,6 +39,16 @@ | ||||
|             <artifactId>guava</artifactId> | ||||
|             <version>${guava.version}</version> | ||||
|         </dependency> | ||||
|         <dependency> | ||||
|             <groupId>com.fasterxml.jackson.core</groupId> | ||||
|             <artifactId>jackson-databind</artifactId> | ||||
|             <version>${jackson.version}</version> | ||||
|         </dependency> | ||||
|         <dependency> | ||||
|             <groupId>org.junit.platform</groupId> | ||||
|             <artifactId>junit-platform-commons</artifactId> | ||||
|             <version>${junit.platform.version}</version> | ||||
|         </dependency> | ||||
| 
 | ||||
|         <dependency> | ||||
|             <groupId>org.assertj</groupId> | ||||
| @ -66,6 +76,8 @@ | ||||
|         <commons-codec.version>1.11</commons-codec.version> | ||||
|         <commons-math3.version>3.6.1</commons-math3.version> | ||||
|         <guava.version>28.1-jre</guava.version> | ||||
|         <jackson.version>2.10.2</jackson.version> | ||||
|         <junit.platform.version>1.6.0</junit.platform.version> | ||||
|     </properties> | ||||
| 
 | ||||
| </project> | ||||
| @ -0,0 +1,61 @@ | ||||
| package com.baeldung.algorithms.boruvka; | ||||
| 
 | ||||
| public class BoruvkaMST { | ||||
| 
 | ||||
|     private static Tree mst = new Tree(); | ||||
|     private static int totalWeight; | ||||
| 
 | ||||
|     public BoruvkaMST(Graph graph) { | ||||
|         DisjointSet dSet = new DisjointSet(graph.getNodes()); | ||||
| 
 | ||||
|         // repeat at most log N times or until we have N-1 edges | ||||
|         for (int t = 1; t < graph.getNodes() && mst.getEdgeCount() < graph.getNodes() - 1; t = t + t) { | ||||
| 
 | ||||
|             // foreach tree in forest, find closest edge | ||||
|             Edge[] closestEdgeArray = new Edge[graph.getNodes()]; | ||||
|             for (Edge edge : graph.getAllEdges()) { | ||||
|                 int first = edge.getFirst(); | ||||
|                 int second = edge.getSecond(); | ||||
|                 int firstParent = dSet.getParent(first); | ||||
|                 int secondParent = dSet.getParent(second); | ||||
|                 if (firstParent == secondParent) { | ||||
|                     continue; // same tree | ||||
|                 } | ||||
|                 if (closestEdgeArray[firstParent] == null || edge.getWeight() < closestEdgeArray[firstParent].getWeight()) { | ||||
|                     closestEdgeArray[firstParent] = edge; | ||||
|                 } | ||||
|                 if (closestEdgeArray[secondParent] == null || edge.getWeight() < closestEdgeArray[secondParent].getWeight()) { | ||||
|                     closestEdgeArray[secondParent] = edge; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             // add newly discovered edges to MST | ||||
|             for (int i = 0; i < graph.getNodes(); i++) { | ||||
|                 Edge edge = closestEdgeArray[i]; | ||||
|                 if (edge != null) { | ||||
|                     int first = edge.getFirst(); | ||||
|                     int second = edge.getSecond(); | ||||
|                     // don't add the same edge twice | ||||
|                     if (dSet.getParent(first) != dSet.getParent(second)) { | ||||
|                         mst.addEdge(edge); | ||||
|                         totalWeight += edge.getWeight(); | ||||
|                         dSet.union(first, second); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public Iterable<Edge> getMST() { | ||||
|         return mst; | ||||
|     } | ||||
| 
 | ||||
|     public int getTotalWeight() { | ||||
|         return totalWeight; | ||||
|     } | ||||
| 
 | ||||
|     public String toString() { | ||||
|         return "MST: " + mst.toString() + " | Total Weight: " + totalWeight; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,49 @@ | ||||
| package com.baeldung.algorithms.boruvka; | ||||
| 
 | ||||
| import java.util.Arrays; | ||||
| 
 | ||||
| public class DisjointSet { | ||||
| 
 | ||||
|     private int[] nodeParents; | ||||
|     private int[] nodeRanks; | ||||
| 
 | ||||
|     public DisjointSet(int n) { | ||||
|         nodeParents = new int[n]; | ||||
|         nodeRanks = new int[n]; | ||||
|         for (int i = 0; i < n; i++) { | ||||
|             nodeParents[i] = i; | ||||
|             nodeRanks[i] = 0; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public int getParent(int node) { | ||||
|         while (node != nodeParents[node]) { | ||||
|             node = nodeParents[node]; | ||||
|         } | ||||
|         return node; | ||||
|     } | ||||
| 
 | ||||
|     public void union(int node1, int node2) { | ||||
|         int node1Parent = getParent(node1); | ||||
|         int node2Parent = getParent(node2); | ||||
|         if (node1Parent == node2Parent) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         if (nodeRanks[node1Parent] < nodeRanks[node2Parent]) { | ||||
|             nodeParents[node1Parent] = node2Parent; | ||||
|         } | ||||
|         else if (nodeRanks[node1Parent] > nodeRanks[node2Parent]) { | ||||
|             nodeParents[node2Parent] = node1Parent; | ||||
|         } | ||||
|         else { | ||||
|             nodeParents[node2Parent] = node1Parent; | ||||
|             nodeRanks[node1Parent]++; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public String toString() { | ||||
|         return "Parent: " + Arrays.toString(nodeParents) + "Rank: " + Arrays.toString(nodeRanks); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,40 @@ | ||||
| package com.baeldung.algorithms.boruvka; | ||||
| 
 | ||||
| public class Edge { | ||||
| 
 | ||||
|     private final int first; | ||||
|     private final int second; | ||||
|     private final int weight; | ||||
| 
 | ||||
|     public Edge(int first, int second, int weight) { | ||||
|         this.first = first; | ||||
|         this.second = second; | ||||
|         this.weight = weight; | ||||
|     } | ||||
| 
 | ||||
|     public double getWeight() { | ||||
|         return weight; | ||||
|     } | ||||
| 
 | ||||
|     public int getFirst() { | ||||
|         return first; | ||||
|     } | ||||
|      | ||||
|     public int getSecond() { | ||||
|         return second; | ||||
|     } | ||||
| 
 | ||||
|     public int getOtherNode(int firstNode) { | ||||
|         int secondNode = 0; | ||||
|         if (firstNode == first) | ||||
|             secondNode = second; | ||||
|         else if (firstNode == second) | ||||
|             secondNode = first; | ||||
|         return secondNode; | ||||
|     } | ||||
| 
 | ||||
|     public String toString() { | ||||
|         return String.format("%d-%d %d", first, second, weight); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,64 @@ | ||||
| package com.baeldung.algorithms.boruvka; | ||||
| 
 | ||||
| import java.io.IOException; | ||||
| 
 | ||||
| import com.fasterxml.jackson.core.JsonParseException; | ||||
| import com.fasterxml.jackson.databind.JsonMappingException; | ||||
| 
 | ||||
| public class Graph { | ||||
| 
 | ||||
|     private int nodes; | ||||
|     private int edges; | ||||
|     private Tree[] trees; | ||||
| 
 | ||||
|     public Graph(Input jsonGraph) throws JsonParseException, JsonMappingException, IOException { | ||||
|         nodes = jsonGraph.getNodes(); | ||||
|         trees = (Tree[]) new Tree[nodes]; | ||||
|         for (int i = 0; i < nodes; i++) { | ||||
|             trees[i] = new Tree(); | ||||
|         } | ||||
| 
 | ||||
|         int edgesFromInput = jsonGraph.getEdges(); | ||||
|         for (int i = 0; i < edgesFromInput; i++) { | ||||
|             int first = jsonGraph.getEdgeList() | ||||
|                 .get(i) | ||||
|                 .getFirst(); | ||||
|             int second = jsonGraph.getEdgeList() | ||||
|                 .get(i) | ||||
|                 .getSecond(); | ||||
|             int weight = jsonGraph.getEdgeList() | ||||
|                 .get(i) | ||||
|                 .getWeight(); | ||||
|             Edge edge = new Edge(first, second, weight); | ||||
|              | ||||
|             trees[first].addEdge(edge); | ||||
|             trees[second].addEdge(edge); | ||||
|             edges++; | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     public int getNodes() { | ||||
|         return nodes; | ||||
|     } | ||||
| 
 | ||||
|     public int getEdges() { | ||||
|         return edges; | ||||
|     } | ||||
| 
 | ||||
|     public Iterable<Edge> iterableTree(int i) { | ||||
|         return trees[i]; | ||||
|     } | ||||
| 
 | ||||
|     public Iterable<Edge> getAllEdges() { | ||||
|         Iterable<Edge> list = new Tree(); | ||||
|         for (int i = 0; i < nodes; i++) { | ||||
|             for (Edge edge : iterableTree(i)) { | ||||
|                 if (edge.getOtherNode(i) > i) { | ||||
|                     ((Tree) list).addEdge(edge); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return list; | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,65 @@ | ||||
| package com.baeldung.algorithms.boruvka; | ||||
| 
 | ||||
| import java.util.List; | ||||
| 
 | ||||
| public class Input { | ||||
|     private int nodes; | ||||
|     private int edges; | ||||
|     private List<E> edgeList; | ||||
| 
 | ||||
|     public int getNodes() { | ||||
|         return nodes; | ||||
|     } | ||||
| 
 | ||||
|     public void setNodes(int nodes) { | ||||
|         this.nodes = nodes; | ||||
|     } | ||||
| 
 | ||||
|     public int getEdges() { | ||||
|         return edges; | ||||
|     } | ||||
| 
 | ||||
|     public void setEdges(int edges) { | ||||
|         this.edges = edges; | ||||
|     } | ||||
| 
 | ||||
|     public List<E> getEdgeList() { | ||||
|         return edgeList; | ||||
|     } | ||||
| 
 | ||||
|     public void setEdgeList(List<E> edgeList) { | ||||
|         this.edgeList = edgeList; | ||||
|     } | ||||
| 
 | ||||
|     static class E { | ||||
|         private int first; | ||||
|         private int second; | ||||
|         private int weight; | ||||
| 
 | ||||
|         public int getFirst() { | ||||
|             return first; | ||||
|         } | ||||
| 
 | ||||
|         public void setFirst(int first) { | ||||
|             this.first = first; | ||||
|         } | ||||
| 
 | ||||
|         public int getSecond() { | ||||
|             return second; | ||||
|         } | ||||
| 
 | ||||
|         public void setSecond(int second) { | ||||
|             this.second = second; | ||||
|         } | ||||
| 
 | ||||
|         public int getWeight() { | ||||
|             return weight; | ||||
|         } | ||||
| 
 | ||||
|         public void setWeight(int weight) { | ||||
|             this.weight = weight; | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,63 @@ | ||||
| package com.baeldung.algorithms.boruvka; | ||||
| 
 | ||||
| import java.util.Iterator; | ||||
| 
 | ||||
| public class Tree implements Iterable<Edge> { | ||||
|     private Node root; | ||||
|     private int edgeCount; | ||||
| 
 | ||||
|     private static class Node { | ||||
|         private Edge edge; | ||||
|         private Node next; | ||||
| 
 | ||||
|         public String toString() { | ||||
|             String nextStr = next != null ? next.toString() : ""; | ||||
|             return edge.toString() + " | " + nextStr; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public Tree() { | ||||
|         root = null; | ||||
|         edgeCount = 0; | ||||
|     } | ||||
| 
 | ||||
|     public int getEdgeCount() { | ||||
|         return edgeCount; | ||||
|     } | ||||
| 
 | ||||
|     public void addEdge(Edge edge) { | ||||
|         Node oldRoot = root; | ||||
|         root = new Node(); | ||||
|         root.edge = edge; | ||||
|         root.next = oldRoot; | ||||
|         edgeCount++; | ||||
|     } | ||||
| 
 | ||||
|     public String toString() { | ||||
|         String rootStr = root != null ? root.toString() : ""; | ||||
|         return "Tree: " + rootStr + "Size: " + edgeCount; | ||||
|     } | ||||
| 
 | ||||
|     public Iterator<Edge> iterator() { | ||||
|         return new LinkedIterator(root); | ||||
|     } | ||||
| 
 | ||||
|     private class LinkedIterator implements Iterator<Edge> { | ||||
|         private Node current; | ||||
| 
 | ||||
|         public LinkedIterator(Node root) { | ||||
|             current = root; | ||||
|         } | ||||
| 
 | ||||
|         public boolean hasNext() { | ||||
|             return current != null; | ||||
|         } | ||||
| 
 | ||||
|         public Edge next() { | ||||
|             Edge edge = current.edge; | ||||
|             current = current.next; | ||||
|             return edge; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,48 @@ | ||||
| package com.baeldung.algorithms.boruvka; | ||||
| 
 | ||||
| import static org.junit.jupiter.api.Assertions.assertEquals; | ||||
| 
 | ||||
| import java.io.BufferedReader; | ||||
| import java.io.IOException; | ||||
| import java.io.InputStreamReader; | ||||
| 
 | ||||
| import org.junit.Before; | ||||
| import org.junit.Test; | ||||
| 
 | ||||
| import com.fasterxml.jackson.core.JsonParseException; | ||||
| import com.fasterxml.jackson.databind.JsonMappingException; | ||||
| import com.fasterxml.jackson.databind.ObjectMapper; | ||||
| 
 | ||||
| public class BoruvkaUnitTest { | ||||
| 
 | ||||
|     private Input input; | ||||
|     private static String INPUT_JSON = "/input.json"; | ||||
| 
 | ||||
|     @Before | ||||
|     public void convertInputJsonToObject() throws JsonParseException, JsonMappingException, IOException { | ||||
|         ObjectMapper mapper = new ObjectMapper(); | ||||
|         StringBuilder jsonStr = new StringBuilder(); | ||||
|         try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(BoruvkaMST.class.getResourceAsStream(INPUT_JSON)))) { | ||||
|             String line; | ||||
|             while ((line = bufferedReader.readLine()) != null) { | ||||
|                 jsonStr.append(line) | ||||
|                     .append("\n"); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         input = mapper.readValue(jsonStr.toString(), Input.class); | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void givenInputGraph_whenBoruvkaPerformed_thenMinimumSpanningTree() throws JsonParseException, JsonMappingException, IOException { | ||||
|         Graph graph = new Graph(input); | ||||
|         BoruvkaMST boruvkaMST = new BoruvkaMST(graph); | ||||
| 
 | ||||
|         Tree mst = (Tree) boruvkaMST.getMST(); | ||||
| 
 | ||||
|         assertEquals(30, boruvkaMST.getTotalWeight()); | ||||
|         assertEquals(4, mst.getEdgeCount()); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										41
									
								
								algorithms-miscellaneous-5/src/test/resources/input.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								algorithms-miscellaneous-5/src/test/resources/input.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,41 @@ | ||||
| { | ||||
| 	"nodes": 5, | ||||
| 	"edges": 7, | ||||
| 	"edgeList": [ | ||||
| 		{ | ||||
| 			"first": 0, | ||||
| 			"second": 1, | ||||
| 			"weight": 8 | ||||
| 		}, | ||||
| 		{ | ||||
| 			"first": 0, | ||||
| 			"second": 2, | ||||
| 			"weight": 5 | ||||
| 		}, | ||||
| 		{ | ||||
| 			"first": 1, | ||||
| 			"second": 2, | ||||
| 			"weight": 9 | ||||
| 		}, | ||||
| 		{ | ||||
| 			"first": 1, | ||||
| 			"second": 3, | ||||
| 			"weight": 11 | ||||
| 		}, | ||||
| 		{ | ||||
| 			"first": 2, | ||||
| 			"second": 3, | ||||
| 			"weight": 15 | ||||
| 		}, | ||||
| 		{ | ||||
| 			"first": 2, | ||||
| 			"second": 4, | ||||
| 			"weight": 10 | ||||
| 		}, | ||||
| 		{ | ||||
| 			"first": 3, | ||||
| 			"second": 4, | ||||
| 			"weight": 7 | ||||
| 		} | ||||
| 	] | ||||
| } | ||||
| @ -0,0 +1,57 @@ | ||||
| package com.baeldung.algorithms.suffixtree; | ||||
| 
 | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
| 
 | ||||
| public class Node { | ||||
|     private String text; | ||||
|     private List<Node> children; | ||||
|     private int position; | ||||
| 
 | ||||
|     public Node(String word, int position) { | ||||
|         this.text = word; | ||||
|         this.position = position; | ||||
|         this.children = new ArrayList<>(); | ||||
|     } | ||||
| 
 | ||||
|     public String getText() { | ||||
|         return text; | ||||
|     } | ||||
| 
 | ||||
|     public void setText(String text) { | ||||
|         this.text = text; | ||||
|     } | ||||
| 
 | ||||
|     public int getPosition() { | ||||
|         return position; | ||||
|     } | ||||
| 
 | ||||
|     public void setPosition(int position) { | ||||
|         this.position = position; | ||||
|     } | ||||
| 
 | ||||
|     public List<Node> getChildren() { | ||||
|         return children; | ||||
|     } | ||||
| 
 | ||||
|     public void setChildren(List<Node> children) { | ||||
|         this.children = children; | ||||
|     } | ||||
| 
 | ||||
|     public String printTree(String depthIndicator) { | ||||
|         String str = ""; | ||||
|         String positionStr = position > -1 ? "[" + String.valueOf(position) + "]" : ""; | ||||
|         str += depthIndicator + text + positionStr + "\n"; | ||||
| 
 | ||||
|         for (int i = 0; i < children.size(); i++) { | ||||
|             str += children.get(i) | ||||
|                 .printTree(depthIndicator + "\t"); | ||||
|         } | ||||
|         return str; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public String toString() { | ||||
|         return printTree(""); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,175 @@ | ||||
| package com.baeldung.algorithms.suffixtree; | ||||
| 
 | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
| import java.util.stream.Collectors; | ||||
| 
 | ||||
| import org.slf4j.Logger; | ||||
| import org.slf4j.LoggerFactory; | ||||
| 
 | ||||
| public class SuffixTree { | ||||
|     private static final Logger LOGGER = LoggerFactory.getLogger(SuffixTree.class); | ||||
|     private static final String WORD_TERMINATION = "$"; | ||||
|     private static final int POSITION_UNDEFINED = -1; | ||||
|     private Node root; | ||||
|     private String fullText; | ||||
| 
 | ||||
|     public SuffixTree(String text) { | ||||
|         root = new Node("", POSITION_UNDEFINED); | ||||
|         for (int i = 0; i < text.length(); i++) { | ||||
|             addSuffix(text.substring(i) + WORD_TERMINATION, i); | ||||
|         } | ||||
|         fullText = text; | ||||
|     } | ||||
| 
 | ||||
|     public List<String> searchText(String pattern) { | ||||
|         LOGGER.info("Searching for pattern \"{}\"", pattern); | ||||
|         List<String> result = new ArrayList<>(); | ||||
|         List<Node> nodes = getAllNodesInTraversePath(pattern, root, false); | ||||
| 
 | ||||
|         if (nodes.size() > 0) { | ||||
|             Node lastNode = nodes.get(nodes.size() - 1); | ||||
|             if (lastNode != null) { | ||||
|                 List<Integer> positions = getPositions(lastNode); | ||||
|                 positions = positions.stream() | ||||
|                     .sorted() | ||||
|                     .collect(Collectors.toList()); | ||||
|                 positions.forEach(m -> result.add((markPatternInText(m, pattern)))); | ||||
|             } | ||||
|         } | ||||
|         return result; | ||||
|     } | ||||
| 
 | ||||
|     private void addSuffix(String suffix, int position) { | ||||
|         LOGGER.info(">>>>>>>>>>>> Adding new suffix {}", suffix); | ||||
|         List<Node> nodes = getAllNodesInTraversePath(suffix, root, true); | ||||
|         if (nodes.size() == 0) { | ||||
|             addChildNode(root, suffix, position); | ||||
|             LOGGER.info("{}", printTree()); | ||||
|         } else { | ||||
|             Node lastNode = nodes.remove(nodes.size() - 1); | ||||
|             String newText = suffix; | ||||
|             if (nodes.size() > 0) { | ||||
|                 String existingSuffixUptoLastNode = nodes.stream() | ||||
|                     .map(a -> a.getText()) | ||||
|                     .reduce("", String::concat); | ||||
| 
 | ||||
|                 // Remove prefix from newText already included in parent | ||||
|                 newText = newText.substring(existingSuffixUptoLastNode.length()); | ||||
|             } | ||||
|             extendNode(lastNode, newText, position); | ||||
|             LOGGER.info("{}", printTree()); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private List<Integer> getPositions(Node node) { | ||||
|         List<Integer> positions = new ArrayList<>(); | ||||
|         if (node.getText() | ||||
|             .endsWith(WORD_TERMINATION)) { | ||||
|             positions.add(node.getPosition()); | ||||
|         } | ||||
|         for (int i = 0; i < node.getChildren() | ||||
|             .size(); i++) { | ||||
|             positions.addAll(getPositions(node.getChildren() | ||||
|                 .get(i))); | ||||
|         } | ||||
|         return positions; | ||||
|     } | ||||
| 
 | ||||
|     private String markPatternInText(Integer startPosition, String pattern) { | ||||
|         String matchingTextLHS = fullText.substring(0, startPosition); | ||||
|         String matchingText = fullText.substring(startPosition, startPosition + pattern.length()); | ||||
|         String matchingTextRHS = fullText.substring(startPosition + pattern.length()); | ||||
|         return matchingTextLHS + "[" + matchingText + "]" + matchingTextRHS; | ||||
|     } | ||||
| 
 | ||||
|     private void addChildNode(Node parentNode, String text, int position) { | ||||
|         parentNode.getChildren() | ||||
|             .add(new Node(text, position)); | ||||
|     } | ||||
| 
 | ||||
|     private void extendNode(Node node, String newText, int position) { | ||||
|         String currentText = node.getText(); | ||||
|         String commonPrefix = getLongestCommonPrefix(currentText, newText); | ||||
| 
 | ||||
|         if (commonPrefix != currentText) { | ||||
|             String parentText = currentText.substring(0, commonPrefix.length()); | ||||
|             String childText = currentText.substring(commonPrefix.length()); | ||||
|             splitNodeToParentAndChild(node, parentText, childText); | ||||
|         } | ||||
| 
 | ||||
|         String remainingText = newText.substring(commonPrefix.length()); | ||||
|         addChildNode(node, remainingText, position); | ||||
|     } | ||||
| 
 | ||||
|     private void splitNodeToParentAndChild(Node parentNode, String parentNewText, String childNewText) { | ||||
|         Node childNode = new Node(childNewText, parentNode.getPosition()); | ||||
| 
 | ||||
|         if (parentNode.getChildren() | ||||
|             .size() > 0) { | ||||
|             while (parentNode.getChildren() | ||||
|                 .size() > 0) { | ||||
|                 childNode.getChildren() | ||||
|                     .add(parentNode.getChildren() | ||||
|                         .remove(0)); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         parentNode.getChildren() | ||||
|             .add(childNode); | ||||
|         parentNode.setText(parentNewText); | ||||
|         parentNode.setPosition(POSITION_UNDEFINED); | ||||
|     } | ||||
| 
 | ||||
|     private String getLongestCommonPrefix(String str1, String str2) { | ||||
|         int compareLength = Math.min(str1.length(), str2.length()); | ||||
|         for (int i = 0; i < compareLength; i++) { | ||||
|             if (str1.charAt(i) != str2.charAt(i)) { | ||||
|                 return str1.substring(0, i); | ||||
|             } | ||||
|         } | ||||
|         return str1.substring(0, compareLength); | ||||
|     } | ||||
| 
 | ||||
|     private List<Node> getAllNodesInTraversePath(String pattern, Node startNode, boolean isAllowPartialMatch) { | ||||
|         List<Node> nodes = new ArrayList<>(); | ||||
|         for (int i = 0; i < startNode.getChildren() | ||||
|             .size(); i++) { | ||||
|             Node currentNode = startNode.getChildren() | ||||
|                 .get(i); | ||||
|             String nodeText = currentNode.getText(); | ||||
|             if (pattern.charAt(0) == nodeText.charAt(0)) { | ||||
|                 if (isAllowPartialMatch && pattern.length() <= nodeText.length()) { | ||||
|                     nodes.add(currentNode); | ||||
|                     return nodes; | ||||
|                 } | ||||
| 
 | ||||
|                 int compareLength = Math.min(nodeText.length(), pattern.length()); | ||||
|                 for (int j = 1; j < compareLength; j++) { | ||||
|                     if (pattern.charAt(j) != nodeText.charAt(j)) { | ||||
|                         if (isAllowPartialMatch) { | ||||
|                             nodes.add(currentNode); | ||||
|                         } | ||||
|                         return nodes; | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 nodes.add(currentNode); | ||||
|                 if (pattern.length() > compareLength) { | ||||
|                     List<Node> nodes2 = getAllNodesInTraversePath(pattern.substring(compareLength), currentNode, isAllowPartialMatch); | ||||
|                     if (nodes2.size() > 0) { | ||||
|                         nodes.addAll(nodes2); | ||||
|                     } else if (!isAllowPartialMatch) { | ||||
|                         nodes.add(null); | ||||
|                     } | ||||
|                 } | ||||
|                 return nodes; | ||||
|             } | ||||
|         } | ||||
|         return nodes; | ||||
|     } | ||||
| 
 | ||||
|     public String printTree() { | ||||
|         return root.printTree(""); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,77 @@ | ||||
| package com.baeldung.algorithms.suffixtree; | ||||
| 
 | ||||
| import java.util.List; | ||||
| 
 | ||||
| import org.junit.Assert; | ||||
| import org.junit.BeforeClass; | ||||
| import org.junit.Test; | ||||
| import org.slf4j.Logger; | ||||
| import org.slf4j.LoggerFactory; | ||||
| 
 | ||||
| public class SuffixTreeUnitTest { | ||||
| 
 | ||||
|     private static final Logger LOGGER = LoggerFactory.getLogger(SuffixTreeUnitTest.class); | ||||
| 
 | ||||
|     private static SuffixTree suffixTree; | ||||
| 
 | ||||
|     @BeforeClass | ||||
|     public static void setUp() { | ||||
|         suffixTree = new SuffixTree("havanabanana"); | ||||
|         printTree(); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void givenSuffixTree_whenSearchingForA_thenReturn6Matches() { | ||||
|         List<String> matches = suffixTree.searchText("a"); | ||||
|         matches.stream() | ||||
|             .forEach(m -> LOGGER.info(m)); | ||||
|         Assert.assertArrayEquals(new String[] { "h[a]vanabanana", "hav[a]nabanana", "havan[a]banana", "havanab[a]nana", "havanaban[a]na", "havanabanan[a]" }, matches.toArray()); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void givenSuffixTree_whenSearchingForNab_thenReturn1Match() { | ||||
|         List<String> matches = suffixTree.searchText("nab"); | ||||
|         matches.stream() | ||||
|             .forEach(m -> LOGGER.info(m)); | ||||
|         Assert.assertArrayEquals(new String[] { "hava[nab]anana" }, matches.toArray()); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void givenSuffixTree_whenSearchingForNag_thenReturnNoMatches() { | ||||
|         List<String> matches = suffixTree.searchText("nag"); | ||||
|         matches.stream() | ||||
|             .forEach(m -> LOGGER.info(m)); | ||||
|         Assert.assertArrayEquals(new String[] {}, matches.toArray()); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void givenSuffixTree_whenSearchingForBanana_thenReturn2Matches() { | ||||
|         List<String> matches = suffixTree.searchText("ana"); | ||||
|         matches.stream() | ||||
|             .forEach(m -> LOGGER.info(m)); | ||||
|         Assert.assertArrayEquals(new String[] { "hav[ana]banana", "havanab[ana]na", "havanaban[ana]" }, matches.toArray()); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void givenSuffixTree_whenSearchingForNa_thenReturn4Matches() { | ||||
|         List<String> matches = suffixTree.searchText("na"); | ||||
|         matches.stream() | ||||
|             .forEach(m -> LOGGER.info(m)); | ||||
|         Assert.assertArrayEquals(new String[] { "hava[na]banana", "havanaba[na]na", "havanabana[na]" }, matches.toArray()); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void givenSuffixTree_whenSearchingForX_thenReturnNoMatches() { | ||||
|         List<String> matches = suffixTree.searchText("x"); | ||||
|         matches.stream() | ||||
|             .forEach(m -> LOGGER.info(m)); | ||||
|         Assert.assertArrayEquals(new String[] {}, matches.toArray()); | ||||
|     } | ||||
| 
 | ||||
|     private static void printTree() { | ||||
|         suffixTree.printTree(); | ||||
| 
 | ||||
|         LOGGER.info("\n" + suffixTree.printTree()); | ||||
|         LOGGER.info("=============================================="); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										43
									
								
								apache-beam/pom.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								apache-beam/pom.xml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,43 @@ | ||||
| <project xmlns="http://maven.apache.org/POM/4.0.0" | ||||
|     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||||
|     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||||
|     <modelVersion>4.0.0</modelVersion> | ||||
| 
 | ||||
|     <parent> | ||||
|         <groupId>com.baeldung</groupId> | ||||
|         <artifactId>parent-modules</artifactId> | ||||
|         <version>1.0.0-SNAPSHOT</version> | ||||
|     </parent> | ||||
| 
 | ||||
|     <groupId>com.baeldung.apache</groupId> | ||||
|     <artifactId>apache-beam</artifactId> | ||||
|     <version>0.0.1-SNAPSHOT</version> | ||||
| 
 | ||||
|     <dependencies> | ||||
|         <dependency> | ||||
|             <groupId>org.apache.beam</groupId> | ||||
|             <artifactId>beam-sdks-java-core</artifactId> | ||||
|             <version>${beam.version}</version> | ||||
|         </dependency> | ||||
|         <!-- runtime scoped --> | ||||
|         <dependency> | ||||
|             <groupId>org.apache.beam</groupId> | ||||
|             <artifactId>beam-runners-direct-java</artifactId> | ||||
|             <version>${beam.version}</version> | ||||
|             <scope>runtime</scope> | ||||
|         </dependency> | ||||
|         <!-- test scoped --> | ||||
|         <dependency> | ||||
|             <groupId>org.assertj</groupId> | ||||
|             <artifactId>assertj-core</artifactId> | ||||
|             <version>${assertj.version}</version> | ||||
|             <scope>test</scope> | ||||
|         </dependency> | ||||
|     </dependencies> | ||||
| 
 | ||||
|     <properties> | ||||
|         <beam.version>2.19.0</beam.version> | ||||
|         <assertj.version>3.6.1</assertj.version> | ||||
|     </properties> | ||||
| 
 | ||||
| </project> | ||||
| @ -0,0 +1,71 @@ | ||||
| package com.baeldung.apache.beam.intro; | ||||
| 
 | ||||
| import java.util.Arrays; | ||||
| 
 | ||||
| import org.apache.beam.sdk.Pipeline; | ||||
| import org.apache.beam.sdk.io.TextIO; | ||||
| import org.apache.beam.sdk.options.PipelineOptions; | ||||
| import org.apache.beam.sdk.options.PipelineOptionsFactory; | ||||
| import org.apache.beam.sdk.transforms.Count; | ||||
| import org.apache.beam.sdk.transforms.Filter; | ||||
| import org.apache.beam.sdk.transforms.FlatMapElements; | ||||
| import org.apache.beam.sdk.transforms.MapElements; | ||||
| import org.apache.beam.sdk.values.KV; | ||||
| import org.apache.beam.sdk.values.PCollection; | ||||
| import org.apache.beam.sdk.values.TypeDescriptors; | ||||
| 
 | ||||
| public class WordCount { | ||||
|      | ||||
|     public static boolean wordCount(String inputFilePath, String outputFilePath) { | ||||
|         // We use default options | ||||
|         PipelineOptions options = PipelineOptionsFactory.create(); | ||||
|         // to create the pipeline | ||||
|         Pipeline p = Pipeline.create(options); | ||||
|         // Here is our workflow graph | ||||
|         PCollection<KV<String, Long>> wordCount = p | ||||
|             .apply("(1) Read all lines", TextIO.read().from(inputFilePath)) | ||||
|             .apply("(2) Flatmap to a list of words", FlatMapElements.into(TypeDescriptors.strings()) | ||||
|                 .via(line -> Arrays.asList(line.split("\\s")))) | ||||
|             .apply("(3) Lowercase all", MapElements.into(TypeDescriptors.strings()) | ||||
|                 .via(word -> word.toLowerCase())) | ||||
|             .apply("(4) Trim punctuations", MapElements.into(TypeDescriptors.strings()) | ||||
|                 .via(word -> trim(word))) | ||||
|             .apply("(5) Filter stopwords", Filter.by(word -> !isStopWord(word))) | ||||
|             .apply("(6) Count words", Count.perElement()); | ||||
|         // We convert the PCollection to String so that we can write it to file | ||||
|         wordCount.apply(MapElements.into(TypeDescriptors.strings()) | ||||
|                 .via(count -> count.getKey() + " --> " + count.getValue())) | ||||
|             .apply(TextIO.write().to(outputFilePath)); | ||||
|         // Finally we must run the pipeline, otherwise it's only a definition | ||||
|         p.run().waitUntilFinish();   | ||||
|         return true; | ||||
|     } | ||||
|      | ||||
|     public static boolean isStopWord(String word) { | ||||
|         String[] stopwords = {"am", "are", "is", "i", "you", "me", | ||||
|                                "he", "she", "they", "them", "was", | ||||
|                                "were", "from", "in", "of", "to", "be", | ||||
|                                "him", "her", "us", "and", "or"}; | ||||
|         for (String stopword : stopwords) { | ||||
|             if (stopword.compareTo(word) == 0) { | ||||
|                 return true; | ||||
|             } | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|      | ||||
|     public static String trim(String word) { | ||||
|         return word.replace("(","") | ||||
|             .replace(")", "") | ||||
|             .replace(",", "") | ||||
|             .replace(".", "") | ||||
|             .replace("\"", "") | ||||
|             .replace("'", "") | ||||
|             .replace(":", "") | ||||
|             .replace(";", "") | ||||
|             .replace("-", "") | ||||
|             .replace("?", "") | ||||
|             .replace("!", ""); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,19 @@ | ||||
| package com.baeldung.apache.beam.intro; | ||||
| 
 | ||||
| import static org.junit.Assert.assertTrue; | ||||
| 
 | ||||
| import org.junit.Ignore; | ||||
| import org.junit.Test; | ||||
| 
 | ||||
| import com.baeldung.apache.beam.intro.WordCount; | ||||
| 
 | ||||
| public class WordCountUnitTest { | ||||
|      | ||||
|     @Test | ||||
|     // @Ignore | ||||
|     public void givenInputFile_whenWordCountRuns_thenJobFinishWithoutError() { | ||||
|         boolean jobDone = WordCount.wordCount("src/test/resources/wordcount.txt", "target/output"); | ||||
|         assertTrue(jobDone); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										16
									
								
								apache-beam/src/test/resources/wordcount.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								apache-beam/src/test/resources/wordcount.txt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | ||||
| We've all heard the scare stories about North Korea: the homemade nuclear arsenal built while their people starve and then aimed imprecisely at the rest of the world, a  | ||||
| leader so deluded he makes L Ron Hubbard look like a man excessively overburdened with self-doubt and their deep-seated belief that foreign capitalists will invade at any  | ||||
| moment and steal all their bauxite. | ||||
| The popular portrayal of this Marxist nation is something like one of the more harrowing episodes of M*A*S*H, only with the cast of wacky characters replaced by twitchy,  | ||||
| heavily armed Stalinist meth addicts | ||||
| Cracked would like to take a moment to celebrate the good things about North Korea though, the things that the country's enemies prefer to suppress as part of their politically  | ||||
| motivated jealousy. Like how no different to you and me, there's nothing every North Korean likes more after an 18 hour shift at the phosphorus plant than a nice beer to go with  | ||||
| his dried fish ration. Ever attentive to its people's needs and in the twinkling of a decade, North Korea's leadership bought, disassembled, transported and rebuilt a British  | ||||
| brewery in order to discover and reproduce the secrets of beer and then brew the sweet nectar for its hardworking people, up to 18 bottles at a time. And with minimal fatalities.  | ||||
| When was the last time YOUR leader got a beer for YOU, American? (NB do not answer this question if you are Henry Louis Gates). | ||||
| Or how about the fried chicken restaurant that downtown Pyongyang boasts? Yes real chicken, fried and then delivered to your sleeping cube, with optional beer if you like! You  | ||||
| don't even have to remove the feathers or pull out the gizzard yourself. Mostly. Americans must eat their fried chicken from a bucket, like swine, sold by a company so secretive  | ||||
| that even the very blend of seasoning used is intentionally kept from them. And they call North Korea paranoid? | ||||
| And how many nations would entertain the syphilitic, bourgeois ramblings of Bill Clinton let alone permit him anywhere near their proud womenfolk? Only wise Kim Jong Il could see  | ||||
| past Bill's many, many imperfections and treat him with the pity and kindness he deserves, accepting his feeble pleas to pardon the American spies rightly convicted of photographing  | ||||
| the nation's sensitive beetroot fields. | ||||
| @ -1,3 +0,0 @@ | ||||
| ### Relevant Articles | ||||
| 
 | ||||
| - [Introduction to Apache CXF Aegis Data Binding](https://www.baeldung.com/aegis-data-binding-in-apache-cxf) | ||||
| @ -1,5 +0,0 @@ | ||||
| ## Apache FOP | ||||
| 
 | ||||
| This module contains articles about Apache FOP | ||||
| 
 | ||||
| ### Relevant Articles:  | ||||
| @ -1,4 +1,3 @@ | ||||
| ### Relevant Articles: | ||||
| 
 | ||||
| - [OData Protocol Guide](https://www.baeldung.com/odata) | ||||
| - [Intro to OData with Olingo](https://www.baeldung.com/olingo) | ||||
|  | ||||
| @ -8,4 +8,4 @@ This module contains articles about Apache POI | ||||
| - [Creating a MS PowerPoint Presentation in Java](https://www.baeldung.com/apache-poi-slideshow) | ||||
| - [Merge Cells in Excel Using Apache POI](https://www.baeldung.com/java-apache-poi-merge-cells) | ||||
| - [Get String Value of Excel Cell with Apache POI](https://www.baeldung.com/java-apache-poi-cell-string-value) | ||||
| - [Read Excel Cell Value Rather Than Formula With Apache POI](https://github.com/eugenp/tutorials/tree/master/apache-poi) | ||||
| - [Read Excel Cell Value Rather Than Formula With Apache POI](https://www.baeldung.com/apache-poi-read-cell-value-formula) | ||||
|  | ||||
| @ -5,7 +5,7 @@ spring.jpa.hibernate.ddl-auto=create | ||||
| logging.file=azure.log | ||||
| logging.level.root=info | ||||
| 
 | ||||
| spring.datasource.url=jdbc:h2:file:~/test | ||||
| spring.datasource.url=jdbc:h2:mem:azure-test-db | ||||
| spring.datasource.username=sa | ||||
| spring.datasource.password= | ||||
| 
 | ||||
|  | ||||
| @ -106,7 +106,7 @@ | ||||
|                             <arguments> | ||||
|                                 <argument>java</argument> | ||||
|                                 <argument>-jar</argument> | ||||
|                                 <argument>sample-blade-app.jar</argument> | ||||
|                                 <argument>blade.jar</argument> | ||||
|                             </arguments> | ||||
|                         </configuration> | ||||
|                     </execution> | ||||
|  | ||||
| @ -26,8 +26,8 @@ | ||||
|         </dependency> | ||||
|         <dependency> | ||||
|             <groupId>org.hamcrest</groupId> | ||||
|             <artifactId>hamcrest-core</artifactId> | ||||
|             <version>${org.hamcrest.version}</version> | ||||
|             <artifactId>hamcrest</artifactId> | ||||
|             <version>${hamcrest.version}</version> | ||||
|             <scope>test</scope> | ||||
|         </dependency> | ||||
|         <dependency> | ||||
|  | ||||
| @ -0,0 +1,26 @@ | ||||
| package com.baeldung.java14.patternmatchingforinstanceof; | ||||
| 
 | ||||
| public class PatternMatchingForInstanceOf { | ||||
| 
 | ||||
|     public void performAnimalOperations(Animal animal) { | ||||
|          if (animal instanceof Cat cat) { | ||||
|              cat.meow(); | ||||
|          } else if(animal instanceof Dog dog) { | ||||
|              dog.woof(); | ||||
|          } | ||||
|     } | ||||
| 
 | ||||
|     abstract class Animal { | ||||
|     } | ||||
| 
 | ||||
|     final class Cat extends Animal { | ||||
|         void meow() { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     final class Dog extends Animal { | ||||
|         void woof() { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,33 @@ | ||||
| package com.baeldung.java14.patternmatchingforinstanceof; | ||||
| 
 | ||||
| import static org.mockito.Mockito.mock; | ||||
| import static org.mockito.Mockito.verify; | ||||
| 
 | ||||
| import org.junit.jupiter.api.Test; | ||||
| 
 | ||||
| import com.baeldung.java14.patternmatchingforinstanceof.PatternMatchingForInstanceOf.Cat; | ||||
| import com.baeldung.java14.patternmatchingforinstanceof.PatternMatchingForInstanceOf.Dog; | ||||
| 
 | ||||
| class PatternMatchingForInstanceOfUnitTest { | ||||
| 
 | ||||
|     @Test | ||||
|     void givenAnAnimal_whenTypeIsCat_ThenCatGoesMeow() { | ||||
|         Cat animal = mock(Cat.class); | ||||
| 
 | ||||
|         PatternMatchingForInstanceOf instanceOf = new PatternMatchingForInstanceOf(); | ||||
|         instanceOf.performAnimalOperations(animal); | ||||
| 
 | ||||
|         verify(animal).meow(); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     void givenAnAnimal_whenTypeIsDog_ThenDogGoesWoof() { | ||||
|         Dog animal = mock(Dog.class); | ||||
| 
 | ||||
|         PatternMatchingForInstanceOf instanceOf = new PatternMatchingForInstanceOf(); | ||||
|         instanceOf.performAnimalOperations(animal); | ||||
| 
 | ||||
|         verify(animal).woof(); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -3,7 +3,7 @@ | ||||
| This module contains articles about Java 8 core features | ||||
| 
 | ||||
| ### Relevant Articles:  | ||||
| - [Anonymous Classes in Java](https://www.baeldung.com/java-anonymous-classes) | ||||
| 
 | ||||
| - [How to Delay Code Execution in Java](https://www.baeldung.com/java-delay-code-execution) | ||||
| - [Run a Java Application from the Command Line](https://www.baeldung.com/java-run-jar-with-arguments) | ||||
| - [Java 8 Stream skip() vs limit()](https://www.baeldung.com/java-stream-skip-vs-limit) | ||||
|  | ||||
| @ -48,25 +48,6 @@ | ||||
|                 <filtering>true</filtering> | ||||
|             </resource> | ||||
|         </resources> | ||||
| 
 | ||||
|         <plugins> | ||||
|             <plugin> | ||||
|                 <groupId>org.springframework.boot</groupId> | ||||
|                 <artifactId>spring-boot-maven-plugin</artifactId> | ||||
|                 <version>${spring-boot-maven-plugin.version}</version> | ||||
|                 <executions> | ||||
|                     <execution> | ||||
|                         <goals> | ||||
|                             <goal>repackage</goal> | ||||
|                         </goals> | ||||
|                         <configuration> | ||||
|                             <classifier>spring-boot</classifier> | ||||
|                             <mainClass>com.baeldung.executable.ExecutableMavenJar</mainClass> | ||||
|                         </configuration> | ||||
|                     </execution> | ||||
|                 </executions> | ||||
|             </plugin> | ||||
|         </plugins> | ||||
|     </build> | ||||
| 
 | ||||
|     <properties> | ||||
| @ -74,8 +55,6 @@ | ||||
|         <commons-collections4.version>4.1</commons-collections4.version> | ||||
|         <!-- testing --> | ||||
|         <assertj.version>3.6.1</assertj.version> | ||||
|         <!-- plugins --> | ||||
|         <spring-boot-maven-plugin.version>2.0.4.RELEASE</spring-boot-maven-plugin.version> | ||||
|     </properties> | ||||
| 
 | ||||
| </project> | ||||
|  | ||||
| @ -1,5 +0,0 @@ | ||||
| ## Core Java Arrays (Part 3) | ||||
| 
 | ||||
| This module contains articles about Java arrays | ||||
| 
 | ||||
| ## Relevant Articles | ||||
| @ -66,100 +66,6 @@ | ||||
|                 </executions> | ||||
|             </plugin> | ||||
| 
 | ||||
|             <plugin> | ||||
|                 <groupId>org.apache.maven.plugins</groupId> | ||||
|                 <artifactId>maven-jar-plugin</artifactId> | ||||
|                 <version>${maven-jar-plugin.version}</version> | ||||
|                 <configuration> | ||||
|                     <archive> | ||||
|                         <manifest> | ||||
|                             <addClasspath>true</addClasspath> | ||||
|                             <classpathPrefix>libs/</classpathPrefix> | ||||
|                             <mainClass>com.baeldung.executable.ExecutableMavenJar</mainClass> | ||||
|                         </manifest> | ||||
|                     </archive> | ||||
|                 </configuration> | ||||
|             </plugin> | ||||
| 
 | ||||
|             <plugin> | ||||
|                 <groupId>org.apache.maven.plugins</groupId> | ||||
|                 <artifactId>maven-assembly-plugin</artifactId> | ||||
|                 <executions> | ||||
|                     <execution> | ||||
|                         <phase>package</phase> | ||||
|                         <goals> | ||||
|                             <goal>single</goal> | ||||
|                         </goals> | ||||
|                         <configuration> | ||||
|                             <archiveBaseDirectory>${project.basedir}</archiveBaseDirectory> | ||||
|                             <archive> | ||||
|                                 <manifest> | ||||
|                                     <mainClass>com.baeldung.executable.ExecutableMavenJar</mainClass> | ||||
|                                 </manifest> | ||||
|                             </archive> | ||||
|                             <descriptorRefs> | ||||
|                                 <descriptorRef>jar-with-dependencies</descriptorRef> | ||||
|                             </descriptorRefs> | ||||
|                         </configuration> | ||||
|                     </execution> | ||||
|                 </executions> | ||||
|             </plugin> | ||||
| 
 | ||||
|             <plugin> | ||||
|                 <groupId>org.apache.maven.plugins</groupId> | ||||
|                 <artifactId>maven-shade-plugin</artifactId> | ||||
|                 <version>${maven-shade-plugin.version}</version> | ||||
|                 <executions> | ||||
|                     <execution> | ||||
|                         <goals> | ||||
|                             <goal>shade</goal> | ||||
|                         </goals> | ||||
|                         <configuration> | ||||
|                             <shadedArtifactAttached>true</shadedArtifactAttached> | ||||
|                             <transformers> | ||||
|                                 <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> | ||||
|                                     <mainClass>com.baeldung.executable.ExecutableMavenJar</mainClass> | ||||
|                                 </transformer> | ||||
|                             </transformers> | ||||
|                         </configuration> | ||||
|                     </execution> | ||||
|                 </executions> | ||||
|             </plugin> | ||||
| 
 | ||||
|             <plugin> | ||||
|                 <groupId>com.jolira</groupId> | ||||
|                 <artifactId>onejar-maven-plugin</artifactId> | ||||
|                 <version>${onejar-maven-plugin.version}</version> | ||||
|                 <executions> | ||||
|                     <execution> | ||||
|                         <configuration> | ||||
|                             <mainClass>com.baeldung.executable.ExecutableMavenJar</mainClass> | ||||
|                             <attachToBuild>true</attachToBuild> | ||||
|                             <filename>${project.build.finalName}-onejar.${project.packaging}</filename> | ||||
|                         </configuration> | ||||
|                         <goals> | ||||
|                             <goal>one-jar</goal> | ||||
|                         </goals> | ||||
|                     </execution> | ||||
|                 </executions> | ||||
|             </plugin> | ||||
| 
 | ||||
|             <plugin> | ||||
|                 <groupId>org.springframework.boot</groupId> | ||||
|                 <artifactId>spring-boot-maven-plugin</artifactId> | ||||
|                 <version>${spring-boot-maven-plugin.version}</version> | ||||
|                 <executions> | ||||
|                     <execution> | ||||
|                         <goals> | ||||
|                             <goal>repackage</goal> | ||||
|                         </goals> | ||||
|                         <configuration> | ||||
|                             <classifier>spring-boot</classifier> | ||||
|                             <mainClass>com.baeldung.executable.ExecutableMavenJar</mainClass> | ||||
|                         </configuration> | ||||
|                     </execution> | ||||
|                 </executions> | ||||
|             </plugin> | ||||
|              | ||||
|             <plugin> | ||||
|                 <groupId>org.codehaus.mojo</groupId> | ||||
| @ -250,110 +156,6 @@ | ||||
|             </build> | ||||
|         </profile> | ||||
| 
 | ||||
|         <!-- java instrumentation profiles to build jars --> | ||||
|         <profile> | ||||
|             <id>buildAgentLoader</id> | ||||
|             <build> | ||||
|                 <plugins> | ||||
|                     <plugin> | ||||
|                         <groupId>org.apache.maven.plugins</groupId> | ||||
|                         <artifactId>maven-jar-plugin</artifactId> | ||||
|                         <executions> | ||||
|                             <execution> | ||||
|                                 <phase>package</phase> | ||||
|                                 <goals> | ||||
|                                     <goal>jar</goal> | ||||
|                                 </goals> | ||||
|                                 <configuration> | ||||
|                                     <classifier>agentLoader</classifier> | ||||
|                                     <classesDirectory>target/classes</classesDirectory> | ||||
|                                     <archive> | ||||
|                                         <manifest> | ||||
|                                             <addClasspath>true</addClasspath> | ||||
|                                         </manifest> | ||||
|                                         <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> | ||||
|                                     </archive> | ||||
| 
 | ||||
|                                     <includes> | ||||
|                                         <include>com/baeldung/instrumentation/application/AgentLoader.class</include> | ||||
|                                         <include>com/baeldung/instrumentation/application/Launcher.class</include> | ||||
|                                     </includes> | ||||
|                                 </configuration> | ||||
|                             </execution> | ||||
|                         </executions> | ||||
|                     </plugin> | ||||
|                 </plugins> | ||||
|             </build> | ||||
|         </profile> | ||||
|         <profile> | ||||
|             <id>buildApplication</id> | ||||
|             <build> | ||||
|                 <plugins> | ||||
|                     <plugin> | ||||
|                         <groupId>org.apache.maven.plugins</groupId> | ||||
|                         <artifactId>maven-jar-plugin</artifactId> | ||||
|                         <executions> | ||||
|                             <execution> | ||||
|                                 <phase>package</phase> | ||||
|                                 <goals> | ||||
|                                     <goal>jar</goal> | ||||
|                                 </goals> | ||||
|                                 <configuration> | ||||
|                                     <classifier>application</classifier> | ||||
|                                     <classesDirectory>target/classes</classesDirectory> | ||||
|                                     <archive> | ||||
|                                         <manifest> | ||||
|                                             <addClasspath>true</addClasspath> | ||||
|                                         </manifest> | ||||
|                                         <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> | ||||
|                                     </archive> | ||||
| 
 | ||||
|                                     <includes> | ||||
|                                         <include>com/baeldung/instrumentation/application/MyAtm.class</include> | ||||
|                                         <include>com/baeldung/instrumentation/application/MyAtmApplication.class</include> | ||||
|                                         <include>com/baeldung/instrumentation/application/Launcher.class</include> | ||||
|                                     </includes> | ||||
|                                 </configuration> | ||||
|                             </execution> | ||||
|                         </executions> | ||||
|                     </plugin> | ||||
|                 </plugins> | ||||
|             </build> | ||||
|         </profile> | ||||
|         <profile> | ||||
|             <id>buildAgent</id> | ||||
|             <build> | ||||
|                 <plugins> | ||||
|                     <plugin> | ||||
|                         <groupId>org.apache.maven.plugins</groupId> | ||||
|                         <artifactId>maven-jar-plugin</artifactId> | ||||
|                         <executions> | ||||
|                             <execution> | ||||
|                                 <phase>package</phase> | ||||
|                                 <goals> | ||||
|                                     <goal>jar</goal> | ||||
|                                 </goals> | ||||
|                                 <configuration> | ||||
|                                     <classifier>agent</classifier> | ||||
|                                     <classesDirectory>target/classes</classesDirectory> | ||||
|                                     <archive> | ||||
|                                         <manifest> | ||||
|                                             <addClasspath>true</addClasspath> | ||||
|                                         </manifest> | ||||
|                                         <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> | ||||
|                                     </archive> | ||||
| 
 | ||||
|                                     <includes> | ||||
|                                         <include>com/baeldung/instrumentation/agent/AtmTransformer.class</include> | ||||
|                                         <include>com/baeldung/instrumentation/agent/MyInstrumentationAgent.class</include> | ||||
|                                     </includes> | ||||
|                                 </configuration> | ||||
|                             </execution> | ||||
|                         </executions> | ||||
|                     </plugin> | ||||
|                 </plugins> | ||||
|             </build> | ||||
|         </profile> | ||||
|     </profiles> | ||||
| 
 | ||||
|     <properties> | ||||
| @ -368,10 +170,6 @@ | ||||
| 
 | ||||
|         <!-- maven and spring plugins --> | ||||
|         <maven-javadoc-plugin.version>3.0.0-M1</maven-javadoc-plugin.version> | ||||
|         <maven-jar-plugin.version>3.0.2</maven-jar-plugin.version> | ||||
|         <onejar-maven-plugin.version>1.4.4</onejar-maven-plugin.version> | ||||
|         <maven-shade-plugin.version>3.1.1</maven-shade-plugin.version> | ||||
|         <spring-boot-maven-plugin.version>2.0.3.RELEASE</spring-boot-maven-plugin.version> | ||||
|         <exec-maven-plugin.version>1.6.0</exec-maven-plugin.version> | ||||
|         <source.version>1.8</source.version> | ||||
|         <target.version>1.8</target.version> | ||||
|  | ||||
| @ -15,7 +15,7 @@ import java.util.logging.Logger; | ||||
| 
 | ||||
| import static org.junit.Assert.fail; | ||||
| 
 | ||||
| public class PrimeNumbersUnitTest { | ||||
| public class PrimeNumbersUnitManualTest { | ||||
| 
 | ||||
|     private static Logger logger = Logger.getAnonymousLogger(); | ||||
| 
 | ||||
| @ -0,0 +1,13 @@ | ||||
| package com.baeldung.suppressed; | ||||
| 
 | ||||
| public class ExceptionalResource implements AutoCloseable { | ||||
|      | ||||
|     public void processSomething() { | ||||
|         throw new IllegalArgumentException("Thrown from processSomething()"); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void close() throws Exception { | ||||
|         throw new NullPointerException("Thrown from close()"); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,44 @@ | ||||
| package com.baeldung.suppressed; | ||||
| 
 | ||||
| import java.io.FileInputStream; | ||||
| import java.io.FileNotFoundException; | ||||
| import java.io.IOException; | ||||
| 
 | ||||
| public class SuppressedExceptionsDemo { | ||||
| 
 | ||||
|     public static void demoSuppressedException(String filePath) throws IOException { | ||||
|         FileInputStream fileIn = null; | ||||
|         try { | ||||
|             fileIn = new FileInputStream(filePath); | ||||
|         } catch (FileNotFoundException e) { | ||||
|             throw new IOException(e); | ||||
|         } finally { | ||||
|             fileIn.close(); | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     public static void demoAddSuppressedException(String filePath) throws IOException { | ||||
|         Throwable firstException = null; | ||||
|         FileInputStream fileIn = null; | ||||
|         try { | ||||
|             fileIn = new FileInputStream(filePath); | ||||
|         } catch (IOException e) { | ||||
|             firstException = e; | ||||
|         } finally { | ||||
|             try { | ||||
|                 fileIn.close(); | ||||
|             } catch (NullPointerException npe) { | ||||
|                 if (firstException != null) { | ||||
|                     npe.addSuppressed(firstException); | ||||
|                 } | ||||
|                 throw npe; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     public static void demoExceptionalResource() throws Exception { | ||||
|         try (ExceptionalResource exceptionalResource = new ExceptionalResource()) { | ||||
|             exceptionalResource.processSomething(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,42 @@ | ||||
| package com.baeldung.suppressed; | ||||
| 
 | ||||
| import static org.junit.Assert.assertEquals; | ||||
| import static org.junit.Assert.assertThat; | ||||
| 
 | ||||
| import java.io.FileNotFoundException; | ||||
| import java.io.IOException; | ||||
| 
 | ||||
| import org.junit.Test; | ||||
| import static org.hamcrest.CoreMatchers.instanceOf; | ||||
| 
 | ||||
| public class SuppressedExceptionsUnitTest { | ||||
| 
 | ||||
|     @Test(expected = NullPointerException.class) | ||||
|     public void givenNonExistentFileName_whenAttemptFileOpen_thenNullPointerException() throws IOException { | ||||
|         SuppressedExceptionsDemo.demoSuppressedException("/non-existent-path/non-existent-file.txt"); | ||||
|     } | ||||
|      | ||||
|     @Test | ||||
|     public void givenNonExistentFileName_whenAttemptFileOpenStoreSuppressed_thenSuppressedExceptionAvailable() { | ||||
|         try { | ||||
|             SuppressedExceptionsDemo.demoAddSuppressedException("/non-existent-path/non-existent-file.txt"); | ||||
|         } catch (Exception e) { | ||||
|             assertThat(e, instanceOf(NullPointerException.class)); | ||||
|             assertEquals(1, e.getSuppressed().length); | ||||
|             assertThat(e.getSuppressed()[0], instanceOf(FileNotFoundException.class)); | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     @Test | ||||
|     public void whenUsingExceptionalResource_thenSuppressedExceptionAvailable() { | ||||
|         try { | ||||
|             SuppressedExceptionsDemo.demoExceptionalResource(); | ||||
|         } catch (Exception e) { | ||||
|             assertThat(e, instanceOf(IllegalArgumentException.class)); | ||||
|             assertEquals("Thrown from processSomething()", e.getMessage()); | ||||
|             assertEquals(1, e.getSuppressed().length); | ||||
|             assertThat(e.getSuppressed()[0], instanceOf(NullPointerException.class)); | ||||
|             assertEquals("Thrown from close()", e.getSuppressed()[0].getMessage()); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -3,7 +3,7 @@ | ||||
| This module contains articles about core Java input and output (IO) | ||||
| 
 | ||||
| ### Relevant Articles:  | ||||
| - [Java – Read from File](https://www.baeldung.com/java-read-file) | ||||
| - [How to Read a File in Java](https://www.baeldung.com/reading-file-in-java) | ||||
| - [Read a File into an ArrayList](https://www.baeldung.com/java-file-to-arraylist) | ||||
| - [Java – Directory Size](https://www.baeldung.com/java-folder-size) | ||||
| - [File Size in Java](https://www.baeldung.com/java-file-size) | ||||
|  | ||||
| @ -11,5 +11,4 @@ This module contains articles about Java operators | ||||
| - [Java Compound Operators](https://www.baeldung.com/java-compound-operators) | ||||
| - [The XOR Operator in Java](https://www.baeldung.com/java-xor-operator) | ||||
| - [Java Bitwise Operators](https://www.baeldung.com/java-bitwise-operators) | ||||
| - [Bitwise & vs Logical && Operators](https://www.baeldung.com/bitwise-vs-logical-operators/) | ||||
| 
 | ||||
| - [Bitwise & vs Logical && Operators](https://www.baeldung.com/java-bitwise-vs-logical-and) | ||||
|  | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -0,0 +1,148 @@ | ||||
| package com.baeldung.lock; | ||||
| 
 | ||||
| import org.slf4j.Logger; | ||||
| import org.slf4j.LoggerFactory; | ||||
| 
 | ||||
| import java.io.FileInputStream; | ||||
| import java.io.FileOutputStream; | ||||
| import java.io.IOException; | ||||
| import java.io.RandomAccessFile; | ||||
| import java.nio.ByteBuffer; | ||||
| import java.nio.channels.FileChannel; | ||||
| import java.nio.channels.FileLock; | ||||
| import java.nio.channels.NonReadableChannelException; | ||||
| import java.nio.channels.NonWritableChannelException; | ||||
| import java.nio.charset.StandardCharsets; | ||||
| import java.nio.file.Files; | ||||
| import java.nio.file.Path; | ||||
| import java.nio.file.StandardOpenOption; | ||||
| 
 | ||||
| public class FileLocks { | ||||
| 
 | ||||
|     private static final Logger LOG = LoggerFactory.getLogger(FileLocks.class); | ||||
| 
 | ||||
|     // Write locks | ||||
| 
 | ||||
|     /** | ||||
|      * Trying to get an exclusive lock on a read-only FileChannel won't work. | ||||
|      */ | ||||
|     static void getExclusiveLockFromInputStream() throws IOException { | ||||
|         Path path = Files.createTempFile("foo", "txt"); | ||||
|         try (FileInputStream fis = new FileInputStream(path.toFile()); | ||||
|             FileLock lock = fis.getChannel() | ||||
|                 .lock()) { | ||||
|             LOG.debug("This won't happen"); | ||||
|         } catch (NonWritableChannelException e) { | ||||
|             LOG.error("The channel obtained through a FileInputStream isn't writable. You can't obtain an exclusive lock on it!"); | ||||
|             throw e; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Gets an exclusive lock from a RandomAccessFile. Works because the file is writable. | ||||
|      * @param from beginning of the locked region | ||||
|      * @param size how many bytes to lock | ||||
|      * @return A lock object representing the newly-acquired lock | ||||
|      * @throws IOException if there is a problem creating the temporary file | ||||
|      */ | ||||
|     static FileLock getExclusiveLockFromRandomAccessFile(long from, long size) throws IOException { | ||||
|         Path path = Files.createTempFile("foo", "txt"); | ||||
|         try (RandomAccessFile file = new RandomAccessFile(path.toFile(), "rw"); | ||||
|             FileLock lock = file.getChannel() | ||||
|                 .lock(from, size, false)) { | ||||
|             if (lock.isValid()) { | ||||
|                 LOG.debug("This is a valid exclusive lock"); | ||||
|                 return lock; | ||||
|             } | ||||
|             return null; | ||||
|         } catch (Exception e) { | ||||
|             LOG.error(e.getMessage()); | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Acquires an exclusive lock on a file region. | ||||
|      * @param from beginning of the locked region | ||||
|      * @param size how many bytes to lock | ||||
|      * @return A lock object representing the newly-acquired lock | ||||
|      * @throws IOException if there is a problem creating the temporary file | ||||
|      */ | ||||
|     static FileLock getExclusiveLockFromFileChannelOpen(long from, long size) throws IOException { | ||||
|         Path path = Files.createTempFile("foo", "txt"); | ||||
|         try (FileChannel channel = FileChannel.open(path, StandardOpenOption.APPEND); FileLock lock = channel.lock(from, size, false)) { | ||||
|             String text = "Hello, world."; | ||||
|             ByteBuffer buffer = ByteBuffer.allocate(text.length() + System.lineSeparator() | ||||
|                 .length()); | ||||
|             buffer.put((text + System.lineSeparator()).getBytes(StandardCharsets.UTF_8)); | ||||
|             buffer.flip(); | ||||
|             while (buffer.hasRemaining()) { | ||||
|                 channel.write(buffer, channel.size()); | ||||
|             } | ||||
|             LOG.debug("This was written to the file"); | ||||
|             Files.lines(path) | ||||
|                 .forEach(LOG::debug); | ||||
|             return lock; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // Read locks | ||||
| 
 | ||||
|     /** | ||||
|      * Trying to get a shared lock on a write-only FileChannel won't work. | ||||
|      */ | ||||
|     static void getReadLockFromOutputStream() throws IOException { | ||||
|         Path path = Files.createTempFile("foo", "txt"); | ||||
|         try (FileOutputStream fis = new FileOutputStream(path.toFile()); | ||||
|             FileLock lock = fis.getChannel() | ||||
|                 .lock(0, Long.MAX_VALUE, true)) { | ||||
|             LOG.debug("This won't happen"); | ||||
|         } catch (NonReadableChannelException e) { | ||||
|             LOG.error("The channel obtained through a FileOutputStream isn't readable. " + "You can't obtain an shared lock on it!"); | ||||
|             throw e; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Gets a lock from an <tt>InputStream</tt>. | ||||
|      * @param from beginning of the locked region | ||||
|      * @param size how many bytes to lock | ||||
|      * @return A lock object representing the newly-acquired lock | ||||
|      * @throws IOException if there is a problem creating the temporary file | ||||
|      */ | ||||
|     static FileLock getReadLockFromInputStream(long from, long size) throws IOException { | ||||
|         Path path = Files.createTempFile("foo", "txt"); | ||||
|         try (FileInputStream fis = new FileInputStream(path.toFile()); | ||||
|             FileLock lock = fis.getChannel() | ||||
|                 .lock(from, size, true)) { | ||||
|             if (lock.isValid()) { | ||||
|                 LOG.debug("This is a valid shared lock"); | ||||
|                 return lock; | ||||
|             } | ||||
|             return null; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Gets an exclusive lock from a RandomAccessFile. Works because the file is readable. | ||||
|      * @param from beginning of the locked region | ||||
|      * @param size how many bytes to lock | ||||
|      * @return A lock object representing the newly-acquired lock | ||||
|      * @throws IOException if there is a problem creating the temporary file | ||||
|      */ | ||||
|     static FileLock getReadLockFromRandomAccessFile(long from, long size) throws IOException { | ||||
|         Path path = Files.createTempFile("foo", "txt"); | ||||
|         try (RandomAccessFile file = new RandomAccessFile(path.toFile(), "r"); // could also be "rw", but "r" is sufficient for reading | ||||
|             FileLock lock = file.getChannel() | ||||
|                 .lock(from, size, true)) { | ||||
|             if (lock.isValid()) { | ||||
|                 LOG.debug("This is a valid shared lock"); | ||||
|                 return lock; | ||||
|             } | ||||
|         } catch (Exception e) { | ||||
|             LOG.error(e.getMessage()); | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,54 @@ | ||||
| package com.baeldung.lock; | ||||
| 
 | ||||
| import static org.junit.jupiter.api.Assertions.assertNotNull; | ||||
| import static org.junit.jupiter.api.Assertions.assertFalse; | ||||
| import static org.junit.jupiter.api.Assertions.assertThrows; | ||||
| import static org.junit.jupiter.api.Assertions.assertTrue; | ||||
| 
 | ||||
| import java.io.IOException; | ||||
| import java.nio.channels.FileLock; | ||||
| import java.nio.channels.NonReadableChannelException; | ||||
| import java.nio.channels.NonWritableChannelException; | ||||
| 
 | ||||
| import org.junit.jupiter.api.Test; | ||||
| 
 | ||||
| class FileLocksUnitTest { | ||||
| 
 | ||||
|     @Test | ||||
|     void givenAnInputStream_whenGetWriteLock_thenThrowNonWritableChannelException() { | ||||
|         assertThrows(NonWritableChannelException.class, () -> FileLocks.getExclusiveLockFromInputStream()); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     void givenARandomAccessFileWithReadWriteAccess_whenGetWriteLock_thenLock() throws IOException { | ||||
|         FileLock lock = FileLocks.getExclusiveLockFromRandomAccessFile(0, 10); | ||||
|         assertNotNull(lock); | ||||
|         assertFalse(lock.isShared()); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     void givenAPath_whenGetExclusiveLock_thenLock() throws IOException { | ||||
|         FileLock lock = FileLocks.getExclusiveLockFromFileChannelOpen(0, 10); | ||||
|         assertNotNull(lock); | ||||
|         assertFalse(lock.isShared()); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     void givenAFileOutputStream_whenGetSharedLock_thenThrowNonReadableChannelException() { | ||||
|         assertThrows(NonReadableChannelException.class, FileLocks::getReadLockFromOutputStream); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     void givenAnInputStream_whenGetSharedLock_thenLock() throws IOException { | ||||
|         FileLock lock = FileLocks.getReadLockFromInputStream(0, 10); | ||||
|         assertNotNull(lock); | ||||
|         assertTrue(lock.isShared()); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     void givenARandomAccessFile_whenGetSharedLock_thenLock() throws IOException { | ||||
|         FileLock lock = FileLocks.getReadLockFromRandomAccessFile(0, 10); | ||||
|         assertNotNull(lock); | ||||
|         assertTrue(lock.isShared()); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,28 @@ | ||||
| package com.baeldung.threaddump; | ||||
| 
 | ||||
| import java.io.IOException; | ||||
| import java.lang.management.ManagementFactory; | ||||
| import java.lang.management.ThreadInfo; | ||||
| import java.lang.management.ThreadMXBean; | ||||
| import java.nio.file.Files; | ||||
| import java.nio.file.Path; | ||||
| import java.nio.file.Paths; | ||||
| 
 | ||||
| public class ThreadDump { | ||||
|      | ||||
|     public static void main(String[] args) throws IOException { | ||||
|         threadDump(true, true); | ||||
|     } | ||||
|      | ||||
|     private static void threadDump(boolean lockedMonitors, boolean lockedSynchronizers) throws IOException { | ||||
|         Path threadDumpFile = Paths.get("ThreadDump.txt"); | ||||
|          | ||||
|         StringBuffer threadDump = new StringBuffer(System.lineSeparator()); | ||||
|         ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean(); | ||||
|         for(ThreadInfo threadInfo : threadMXBean.dumpAllThreads(lockedMonitors, lockedSynchronizers)) { | ||||
|             threadDump.append(threadInfo.toString()); | ||||
|         } | ||||
|         Files.write(threadDumpFile, threadDump.toString().getBytes()); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -25,6 +25,12 @@ | ||||
|             <artifactId>jmh-generator-annprocess</artifactId> | ||||
|             <version>${jmh-core.version}</version> | ||||
|         </dependency> | ||||
|         <dependency> | ||||
|             <groupId>org.assertj</groupId> | ||||
|             <artifactId>assertj-core</artifactId> | ||||
|             <version>3.15.0</version> | ||||
|             <scope>test</scope> | ||||
|         </dependency> | ||||
|     </dependencies> | ||||
| 
 | ||||
|     <build> | ||||
|  | ||||
| @ -0,0 +1,63 @@ | ||||
| package com.baeldung.replacetokens; | ||||
| 
 | ||||
| import java.util.function.Function; | ||||
| import java.util.regex.Matcher; | ||||
| import java.util.regex.Pattern; | ||||
| 
 | ||||
| public class ReplacingTokens { | ||||
|     public static final Pattern TITLE_CASE_PATTERN = Pattern.compile("(?<=^|[^A-Za-z])([A-Z][a-z]*)(?=[^A-Za-z]|$)"); | ||||
| 
 | ||||
|     /** | ||||
|      * Iterate over the title case tokens in the input and replace them with lowercase | ||||
|      * @param original the original string | ||||
|      * @return a string with words replaced with their lowercase equivalents | ||||
|      */ | ||||
|     public static String replaceTitleCaseWithLowerCase(String original) { | ||||
|         int lastIndex = 0; | ||||
|         StringBuilder output = new StringBuilder(); | ||||
|         Matcher matcher = TITLE_CASE_PATTERN.matcher(original); | ||||
|         while (matcher.find()) { | ||||
|             output.append(original, lastIndex, matcher.start()) | ||||
|                     .append(convert(matcher.group(1))); | ||||
| 
 | ||||
|             lastIndex = matcher.end(); | ||||
|         } | ||||
|         if (lastIndex < original.length()) { | ||||
|             output.append(original, lastIndex, original.length()); | ||||
|         } | ||||
|         return output.toString(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Convert a token found into its desired lowercase | ||||
|      * @param token the token to convert | ||||
|      * @return the converted token | ||||
|      */ | ||||
|     private static String convert(String token) { | ||||
|         return token.toLowerCase(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Replace all the tokens in an input using the algorithm provided for each | ||||
|      * @param original original string | ||||
|      * @param tokenPattern the pattern to match with | ||||
|      * @param converter the conversion to apply | ||||
|      * @return the substituted string | ||||
|      */ | ||||
|     public static String replaceTokens(String original, Pattern tokenPattern, | ||||
|                                        Function<Matcher, String> converter) { | ||||
|         int lastIndex = 0; | ||||
|         StringBuilder output = new StringBuilder(); | ||||
|         Matcher matcher = tokenPattern.matcher(original); | ||||
|         while (matcher.find()) { | ||||
|             output.append(original, lastIndex, matcher.start()) | ||||
|                     .append(converter.apply(matcher)); | ||||
| 
 | ||||
|             lastIndex = matcher.end(); | ||||
|         } | ||||
|         if (lastIndex < original.length()) { | ||||
|             output.append(original, lastIndex, original.length()); | ||||
|         } | ||||
|         return output.toString(); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,79 @@ | ||||
| package com.baeldung.replacetokens; | ||||
| 
 | ||||
| import org.junit.Test; | ||||
| 
 | ||||
| import java.util.ArrayList; | ||||
| import java.util.HashMap; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
| import java.util.regex.Matcher; | ||||
| import java.util.regex.Pattern; | ||||
| 
 | ||||
| import static com.baeldung.replacetokens.ReplacingTokens.TITLE_CASE_PATTERN; | ||||
| import static com.baeldung.replacetokens.ReplacingTokens.replaceTokens; | ||||
| import static org.assertj.core.api.Assertions.assertThat; | ||||
| 
 | ||||
| public class ReplacingTokensUnitTest { | ||||
|     private static final String EXAMPLE_INPUT = "First 3 Capital Words! then 10 TLAs, I Found"; | ||||
|     private static final String EXAMPLE_INPUT_PROCESSED = "first 3 capital words! then 10 TLAs, i found"; | ||||
| 
 | ||||
|     @Test | ||||
|     public void whenFindMatches_thenTitleWordsFound() { | ||||
|         Matcher matcher = TITLE_CASE_PATTERN.matcher(EXAMPLE_INPUT); | ||||
|         List<String> matches = new ArrayList<>(); | ||||
|         while (matcher.find()) { | ||||
|             matches.add(matcher.group(1)); | ||||
|         } | ||||
| 
 | ||||
|         assertThat(matches) | ||||
|           .containsExactly("First", "Capital", "Words", "I", "Found"); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void exploreMatches() { | ||||
|         Matcher matcher = TITLE_CASE_PATTERN.matcher(EXAMPLE_INPUT); | ||||
|         while (matcher.find()) { | ||||
|             System.out.println("Match: " + matcher.group(0)); | ||||
|             System.out.println("Start: " + matcher.start()); | ||||
|             System.out.println("End: " + matcher.end()); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void whenReplaceTokensWithLowerCase() { | ||||
|         assertThat(ReplacingTokens.replaceTitleCaseWithLowerCase(EXAMPLE_INPUT)) | ||||
|           .isEqualTo(EXAMPLE_INPUT_PROCESSED); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void whenReplaceTokensWithLowerCaseUsingGeneralPurpose() { | ||||
|         assertThat(replaceTokens("First 3 Capital Words! then 10 TLAs, I Found", | ||||
|           TITLE_CASE_PATTERN, | ||||
|           match -> match.group(1).toLowerCase())) | ||||
|           .isEqualTo("first 3 capital words! then 10 TLAs, i found"); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void escapeRegexCharacters() { | ||||
|         Pattern regexCharacters = Pattern.compile("[<(\\[{\\\\^\\-=$!|\\]})?*+.>]"); | ||||
| 
 | ||||
|         assertThat(replaceTokens("A regex character like [", | ||||
|           regexCharacters, | ||||
|           match -> "\\" + match.group())) | ||||
|           .isEqualTo("A regex character like \\["); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void replacePlaceholders() { | ||||
|         Pattern placeholderPattern = Pattern.compile("\\$\\{(?<placeholder>[A-Za-z0-9-_]+)}"); | ||||
| 
 | ||||
|         Map<String, String> placeholderValues = new HashMap<>(); | ||||
|         placeholderValues.put("name", "Bill"); | ||||
|         placeholderValues.put("company", "Baeldung"); | ||||
| 
 | ||||
|         assertThat(replaceTokens("Hi ${name} at ${company}", | ||||
|           placeholderPattern, | ||||
|           match -> placeholderValues.get(match.group("placeholder")))) | ||||
|           .isEqualTo("Hi Bill at Baeldung"); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										17
									
								
								core-java-modules/core-java-security-2/pom.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								core-java-modules/core-java-security-2/pom.xml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,17 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||||
|          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||||
|     <modelVersion>4.0.0</modelVersion> | ||||
|     <artifactId>core-java-security-2</artifactId> | ||||
|     <version>0.1.0-SNAPSHOT</version> | ||||
|     <name>core-java-security-2</name> | ||||
|     <packaging>jar</packaging> | ||||
| 
 | ||||
|     <parent> | ||||
|         <groupId>com.baeldung</groupId> | ||||
|         <artifactId>parent-java</artifactId> | ||||
|         <version>0.0.1-SNAPSHOT</version> | ||||
|         <relativePath>../../parent-java</relativePath> | ||||
|     </parent> | ||||
| 
 | ||||
| </project> | ||||
| @ -0,0 +1,24 @@ | ||||
| package com.baeldung.jaas; | ||||
| 
 | ||||
| import javax.security.auth.callback.*; | ||||
| import java.io.Console; | ||||
| import java.io.IOException; | ||||
| 
 | ||||
| public class ConsoleCallbackHandler implements CallbackHandler { | ||||
| 
 | ||||
|     @Override | ||||
|     public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { | ||||
|         Console console = System.console(); | ||||
|         for (Callback callback : callbacks) { | ||||
|             if (callback instanceof NameCallback) { | ||||
|                 NameCallback nameCallback = (NameCallback) callback; | ||||
|                 nameCallback.setName(console.readLine(nameCallback.getPrompt())); | ||||
|             } else if (callback instanceof PasswordCallback) { | ||||
|                 PasswordCallback passwordCallback = (PasswordCallback) callback; | ||||
|                 passwordCallback.setPassword(console.readPassword(passwordCallback.getPrompt())); | ||||
|             } else { | ||||
|                 throw new UnsupportedCallbackException(callback); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,13 @@ | ||||
| package com.baeldung.jaas; | ||||
| 
 | ||||
| import javax.security.auth.Subject; | ||||
| import javax.security.auth.login.LoginException; | ||||
| 
 | ||||
| public class JaasAuthentication { | ||||
| 
 | ||||
|     public static void main(String[] args) throws LoginException { | ||||
|         LoginService loginService = new LoginService(); | ||||
|         Subject subject = loginService.login(); | ||||
|         System.out.println(subject.getPrincipals().iterator().next() + " sucessfully logeed in"); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,17 @@ | ||||
| package com.baeldung.jaas; | ||||
| 
 | ||||
| import javax.security.auth.Subject; | ||||
| import javax.security.auth.login.LoginException; | ||||
| import java.security.PrivilegedAction; | ||||
| 
 | ||||
| public class JaasAuthorization { | ||||
| 
 | ||||
|     public static void main(String[] args) throws LoginException { | ||||
| 
 | ||||
|         LoginService loginService = new LoginService(); | ||||
|         Subject subject = loginService.login(); | ||||
| 
 | ||||
|         PrivilegedAction privilegedAction = new ResourceAction(); | ||||
|         Subject.doAsPrivileged(subject, privilegedAction, null); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,14 @@ | ||||
| package com.baeldung.jaas; | ||||
| 
 | ||||
| import javax.security.auth.Subject; | ||||
| import javax.security.auth.login.LoginContext; | ||||
| import javax.security.auth.login.LoginException; | ||||
| 
 | ||||
| public class LoginService { | ||||
| 
 | ||||
|     public Subject login() throws LoginException { | ||||
|         LoginContext loginContext = new LoginContext("jaasApplication", new ConsoleCallbackHandler()); | ||||
|         loginContext.login(); | ||||
|         return loginContext.getSubject(); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,15 @@ | ||||
| package com.baeldung.jaas; | ||||
| 
 | ||||
| import java.security.PrivilegedAction; | ||||
| 
 | ||||
| public class ResourceAction implements PrivilegedAction { | ||||
|     @Override | ||||
|     public Object run() { | ||||
|         SecurityManager sm = System.getSecurityManager(); | ||||
|         if (sm != null) { | ||||
|             sm.checkPermission(new ResourcePermission("test_resource")); | ||||
|         } | ||||
|         System.out.println("I have access to test_resource !"); | ||||
|         return null; | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,9 @@ | ||||
| package com.baeldung.jaas; | ||||
| 
 | ||||
| import java.security.BasicPermission; | ||||
| 
 | ||||
| public class ResourcePermission extends BasicPermission { | ||||
|     public ResourcePermission(String name) { | ||||
|         super(name); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,74 @@ | ||||
| package com.baeldung.jaas.loginmodule; | ||||
| 
 | ||||
| import com.sun.security.auth.UserPrincipal; | ||||
| 
 | ||||
| import javax.security.auth.Subject; | ||||
| import javax.security.auth.callback.*; | ||||
| import javax.security.auth.login.LoginException; | ||||
| import javax.security.auth.spi.LoginModule; | ||||
| import java.io.IOException; | ||||
| import java.security.Principal; | ||||
| import java.util.Map; | ||||
| 
 | ||||
| public class InMemoryLoginModule implements LoginModule { | ||||
| 
 | ||||
|     private static final String USERNAME = "testuser"; | ||||
|     private static final String PASSWORD = "testpassword"; | ||||
| 
 | ||||
|     private Subject subject; | ||||
|     private CallbackHandler callbackHandler; | ||||
|     private Map<String, ?> sharedState; | ||||
|     private Map<String, ?> options; | ||||
| 
 | ||||
|     private String username; | ||||
|     private boolean loginSucceeded = false; | ||||
|     private Principal userPrincipal; | ||||
| 
 | ||||
|     @Override | ||||
|     public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState, | ||||
|                            Map<String, ?> options) { | ||||
|         this.subject = subject; | ||||
|         this.callbackHandler = callbackHandler; | ||||
|         this.sharedState = sharedState; | ||||
|         this.options = options; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public boolean login() throws LoginException { | ||||
|         NameCallback nameCallback = new NameCallback("username: "); | ||||
|         PasswordCallback passwordCallback = new PasswordCallback("password: ", false); | ||||
|         try { | ||||
|             callbackHandler.handle(new Callback[]{nameCallback, passwordCallback}); | ||||
|             username = nameCallback.getName(); | ||||
|             String password = new String(passwordCallback.getPassword()); | ||||
|             if (USERNAME.equals(username) && PASSWORD.equals(password)) { | ||||
|                 loginSucceeded = true; | ||||
|             } | ||||
|         } catch (IOException | UnsupportedCallbackException e) { | ||||
|             throw new LoginException("Can't login"); | ||||
|         } | ||||
|         return loginSucceeded; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public boolean commit() throws LoginException { | ||||
|         if (!loginSucceeded) { | ||||
|             return false; | ||||
|         } | ||||
|         userPrincipal = new UserPrincipal(username); | ||||
|         subject.getPrincipals().add(userPrincipal); | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public boolean abort() throws LoginException { | ||||
|         logout(); | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public boolean logout() throws LoginException { | ||||
|         subject.getPrincipals().remove(userPrincipal); | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,3 @@ | ||||
| jaasApplication { | ||||
|    com.baeldung.jaas.loginmodule.InMemoryLoginModule required debug=true; | ||||
| }; | ||||
| @ -0,0 +1,14 @@ | ||||
| grant codebase "file:./target/core-java-security-2-0.1.0-SNAPSHOT.jar" { | ||||
|     permission javax.security.auth.AuthPermission "createLoginContext.jaasApplication"; | ||||
|     permission javax.security.auth.AuthPermission "doAsPrivileged"; | ||||
|     permission java.lang.RuntimePermission "readFileDescriptor"; | ||||
|     permission java.lang.RuntimePermission "writeFileDescriptor"; | ||||
| }; | ||||
| 
 | ||||
| grant codebase "file:./target/core-java-security-2-0.1.0-SNAPSHOT.jar" { | ||||
|     permission javax.security.auth.AuthPermission "modifyPrincipals"; | ||||
| }; | ||||
| 
 | ||||
| grant principal com.sun.security.auth.UserPrincipal "testuser" { | ||||
|     permission com.baeldung.jaas.ResourcePermission "test_resource"; | ||||
| }; | ||||
| @ -28,8 +28,8 @@ | ||||
|         </dependency> | ||||
|         <dependency> | ||||
|             <groupId>org.hamcrest</groupId> | ||||
|             <artifactId>hamcrest-library</artifactId> | ||||
|             <version>${org.hamcrest.version}</version> | ||||
|             <artifactId>hamcrest</artifactId> | ||||
|             <version>${hamcrest.version}</version> | ||||
|             <scope>test</scope> | ||||
|         </dependency> | ||||
|     </dependencies> | ||||
|  | ||||
| @ -44,8 +44,8 @@ | ||||
|         </dependency> | ||||
|         <dependency> | ||||
|             <groupId>org.hamcrest</groupId> | ||||
|             <artifactId>hamcrest-library</artifactId> | ||||
|             <version>${org.hamcrest.version}</version> | ||||
|             <artifactId>hamcrest</artifactId> | ||||
|             <version>${hamcrest.version}</version> | ||||
|             <scope>test</scope> | ||||
|         </dependency> | ||||
|     </dependencies> | ||||
|  | ||||
| @ -48,8 +48,8 @@ | ||||
|         </dependency> | ||||
|         <dependency> | ||||
|             <groupId>org.hamcrest</groupId> | ||||
|             <artifactId>hamcrest-library</artifactId> | ||||
|             <version>${org.hamcrest.version}</version> | ||||
|             <artifactId>hamcrest</artifactId> | ||||
|             <version>${hamcrest.version}</version> | ||||
|             <scope>test</scope> | ||||
|         </dependency> | ||||
|         <dependency> | ||||
|  | ||||
| @ -40,20 +40,6 @@ | ||||
|             </resource> | ||||
|         </resources> | ||||
|         <plugins> | ||||
|             <plugin> | ||||
|                 <groupId>org.apache.maven.plugins</groupId> | ||||
|                 <artifactId>maven-jar-plugin</artifactId> | ||||
|                 <version>${maven-jar-plugin.version}</version> | ||||
|                 <configuration> | ||||
|                     <archive> | ||||
|                         <manifest> | ||||
|                             <addClasspath>true</addClasspath> | ||||
|                             <classpathPrefix>libs/</classpathPrefix> | ||||
|                             <mainClass>com.baeldung.executable.ExecutableMavenJar</mainClass> | ||||
|                         </manifest> | ||||
|                     </archive> | ||||
|                 </configuration> | ||||
|             </plugin> | ||||
|             <plugin> | ||||
|                 <groupId>org.codehaus.mojo</groupId> | ||||
|                 <artifactId>exec-maven-plugin</artifactId> | ||||
| @ -115,7 +101,6 @@ | ||||
| 
 | ||||
|         <!-- maven plugins --> | ||||
|         <sun-tools.version>1.8.0</sun-tools.version> | ||||
|         <maven-jar-plugin.version>3.0.2</maven-jar-plugin.version> | ||||
|     </properties> | ||||
| 
 | ||||
| </project> | ||||
| @ -11,7 +11,7 @@ | ||||
| - [Introduction to Java Serialization](http://www.baeldung.com/java-serialization) | ||||
| - [Guide to UUID in Java](http://www.baeldung.com/java-uuid) | ||||
| - [Creating a Java Compiler Plugin](http://www.baeldung.com/java-build-compiler-plugin) | ||||
| - [Quick Guide to Java Stack](http://www.baeldung.com/java-stack) | ||||
| - [Quick Guide to the Java Stack](https://www.baeldung.com/java-stack) | ||||
| - [Compiling Java *.class Files with javac](http://www.baeldung.com/javac) | ||||
| - [Introduction to Javadoc](http://www.baeldung.com/javadoc) | ||||
| - [Guide to the Externalizable Interface in Java](http://www.baeldung.com/java-externalizable) | ||||
|  | ||||
| @ -90,101 +90,6 @@ | ||||
|                 </executions> | ||||
|             </plugin> | ||||
| 
 | ||||
|             <plugin> | ||||
|                 <groupId>org.apache.maven.plugins</groupId> | ||||
|                 <artifactId>maven-jar-plugin</artifactId> | ||||
|                 <version>${maven-jar-plugin.version}</version> | ||||
|                 <configuration> | ||||
|                     <archive> | ||||
|                         <manifest> | ||||
|                             <addClasspath>true</addClasspath> | ||||
|                             <classpathPrefix>libs/</classpathPrefix> | ||||
|                             <mainClass>com.baeldung.executable.ExecutableMavenJar</mainClass> | ||||
|                         </manifest> | ||||
|                     </archive> | ||||
|                 </configuration> | ||||
|             </plugin> | ||||
| 
 | ||||
|             <plugin> | ||||
|                 <groupId>org.apache.maven.plugins</groupId> | ||||
|                 <artifactId>maven-assembly-plugin</artifactId> | ||||
|                 <executions> | ||||
|                     <execution> | ||||
|                         <phase>package</phase> | ||||
|                         <goals> | ||||
|                             <goal>single</goal> | ||||
|                         </goals> | ||||
|                         <configuration> | ||||
|                             <archiveBaseDirectory>${project.basedir}</archiveBaseDirectory> | ||||
|                             <archive> | ||||
|                                 <manifest> | ||||
|                                     <mainClass>com.baeldung.executable.ExecutableMavenJar</mainClass> | ||||
|                                 </manifest> | ||||
|                             </archive> | ||||
|                             <descriptorRefs> | ||||
|                                 <descriptorRef>jar-with-dependencies</descriptorRef> | ||||
|                             </descriptorRefs> | ||||
|                         </configuration> | ||||
|                     </execution> | ||||
|                 </executions> | ||||
|             </plugin> | ||||
| 
 | ||||
|             <plugin> | ||||
|                 <groupId>org.apache.maven.plugins</groupId> | ||||
|                 <artifactId>maven-shade-plugin</artifactId> | ||||
|                 <version>${maven-shade-plugin.version}</version> | ||||
|                 <executions> | ||||
|                     <execution> | ||||
|                         <goals> | ||||
|                             <goal>shade</goal> | ||||
|                         </goals> | ||||
|                         <configuration> | ||||
|                             <shadedArtifactAttached>true</shadedArtifactAttached> | ||||
|                             <transformers> | ||||
|                                 <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> | ||||
|                                     <mainClass>com.baeldung.executable.ExecutableMavenJar</mainClass> | ||||
|                                 </transformer> | ||||
|                             </transformers> | ||||
|                         </configuration> | ||||
|                     </execution> | ||||
|                 </executions> | ||||
|             </plugin> | ||||
| 
 | ||||
|             <plugin> | ||||
|                 <groupId>com.jolira</groupId> | ||||
|                 <artifactId>onejar-maven-plugin</artifactId> | ||||
|                 <version>${onejar-maven-plugin.version}</version> | ||||
|                 <executions> | ||||
|                     <execution> | ||||
|                         <configuration> | ||||
|                             <mainClass>com.baeldung.executable.ExecutableMavenJar</mainClass> | ||||
|                             <attachToBuild>true</attachToBuild> | ||||
|                             <filename>${project.build.finalName}-onejar.${project.packaging}</filename> | ||||
|                         </configuration> | ||||
|                         <goals> | ||||
|                             <goal>one-jar</goal> | ||||
|                         </goals> | ||||
|                     </execution> | ||||
|                 </executions> | ||||
|             </plugin> | ||||
| 
 | ||||
|             <plugin> | ||||
|                 <groupId>org.springframework.boot</groupId> | ||||
|                 <artifactId>spring-boot-maven-plugin</artifactId> | ||||
|                 <version>${spring-boot-maven-plugin.version}</version> | ||||
|                 <executions> | ||||
|                     <execution> | ||||
|                         <goals> | ||||
|                             <goal>repackage</goal> | ||||
|                         </goals> | ||||
|                         <configuration> | ||||
|                             <classifier>spring-boot</classifier> | ||||
|                             <mainClass>com.baeldung.executable.ExecutableMavenJar</mainClass> | ||||
|                         </configuration> | ||||
|                     </execution> | ||||
|                 </executions> | ||||
|             </plugin> | ||||
| 
 | ||||
|             <plugin> | ||||
|                 <groupId>org.codehaus.mojo</groupId> | ||||
|                 <artifactId>exec-maven-plugin</artifactId> | ||||
| @ -273,111 +178,6 @@ | ||||
|                 </plugins> | ||||
|             </build> | ||||
|         </profile> | ||||
| 
 | ||||
|         <!-- java instrumentation profiles to build jars --> | ||||
|         <profile> | ||||
|             <id>buildAgentLoader</id> | ||||
|             <build> | ||||
|                 <plugins> | ||||
|                     <plugin> | ||||
|                         <groupId>org.apache.maven.plugins</groupId> | ||||
|                         <artifactId>maven-jar-plugin</artifactId> | ||||
|                         <executions> | ||||
|                             <execution> | ||||
|                                 <phase>package</phase> | ||||
|                                 <goals> | ||||
|                                     <goal>jar</goal> | ||||
|                                 </goals> | ||||
|                                 <configuration> | ||||
|                                     <classifier>agentLoader</classifier> | ||||
|                                     <classesDirectory>target/classes</classesDirectory> | ||||
|                                     <archive> | ||||
|                                         <manifest> | ||||
|                                             <addClasspath>true</addClasspath> | ||||
|                                         </manifest> | ||||
|                                         <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> | ||||
|                                     </archive> | ||||
| 
 | ||||
|                                     <includes> | ||||
|                                         <include>com/baeldung/instrumentation/application/AgentLoader.class</include> | ||||
|                                         <include>com/baeldung/instrumentation/application/Launcher.class</include> | ||||
|                                     </includes> | ||||
|                                 </configuration> | ||||
|                             </execution> | ||||
|                         </executions> | ||||
|                     </plugin> | ||||
|                 </plugins> | ||||
|             </build> | ||||
|         </profile> | ||||
|         <profile> | ||||
|             <id>buildApplication</id> | ||||
|             <build> | ||||
|                 <plugins> | ||||
|                     <plugin> | ||||
|                         <groupId>org.apache.maven.plugins</groupId> | ||||
|                         <artifactId>maven-jar-plugin</artifactId> | ||||
|                         <executions> | ||||
|                             <execution> | ||||
|                                 <phase>package</phase> | ||||
|                                 <goals> | ||||
|                                     <goal>jar</goal> | ||||
|                                 </goals> | ||||
|                                 <configuration> | ||||
|                                     <classifier>application</classifier> | ||||
|                                     <classesDirectory>target/classes</classesDirectory> | ||||
|                                     <archive> | ||||
|                                         <manifest> | ||||
|                                             <addClasspath>true</addClasspath> | ||||
|                                         </manifest> | ||||
|                                         <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> | ||||
|                                     </archive> | ||||
| 
 | ||||
|                                     <includes> | ||||
|                                         <include>com/baeldung/instrumentation/application/MyAtm.class</include> | ||||
|                                         <include>com/baeldung/instrumentation/application/MyAtmApplication.class</include> | ||||
|                                         <include>com/baeldung/instrumentation/application/Launcher.class</include> | ||||
|                                     </includes> | ||||
|                                 </configuration> | ||||
|                             </execution> | ||||
|                         </executions> | ||||
|                     </plugin> | ||||
|                 </plugins> | ||||
|             </build> | ||||
|         </profile> | ||||
|         <profile> | ||||
|             <id>buildAgent</id> | ||||
|             <build> | ||||
|                 <plugins> | ||||
|                     <plugin> | ||||
|                         <groupId>org.apache.maven.plugins</groupId> | ||||
|                         <artifactId>maven-jar-plugin</artifactId> | ||||
|                         <executions> | ||||
|                             <execution> | ||||
|                                 <phase>package</phase> | ||||
|                                 <goals> | ||||
|                                     <goal>jar</goal> | ||||
|                                 </goals> | ||||
|                                 <configuration> | ||||
|                                     <classifier>agent</classifier> | ||||
|                                     <classesDirectory>target/classes</classesDirectory> | ||||
|                                     <archive> | ||||
|                                         <manifest> | ||||
|                                             <addClasspath>true</addClasspath> | ||||
|                                         </manifest> | ||||
|                                         <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> | ||||
|                                     </archive> | ||||
| 
 | ||||
|                                     <includes> | ||||
|                                         <include>com/baeldung/instrumentation/agent/AtmTransformer.class</include> | ||||
|                                         <include>com/baeldung/instrumentation/agent/MyInstrumentationAgent.class</include> | ||||
|                                     </includes> | ||||
|                                 </configuration> | ||||
|                             </execution> | ||||
|                         </executions> | ||||
|                     </plugin> | ||||
|                 </plugins> | ||||
|             </build> | ||||
|         </profile> | ||||
|     </profiles> | ||||
| 
 | ||||
|     <properties> | ||||
| @ -392,10 +192,6 @@ | ||||
|         <javamoney.moneta.version>1.1</javamoney.moneta.version> | ||||
| 
 | ||||
|         <maven-javadoc-plugin.version>3.0.0-M1</maven-javadoc-plugin.version> | ||||
|         <maven-jar-plugin.version>3.0.2</maven-jar-plugin.version> | ||||
|         <onejar-maven-plugin.version>1.4.4</onejar-maven-plugin.version> | ||||
|         <maven-shade-plugin.version>3.1.1</maven-shade-plugin.version> | ||||
|         <spring-boot-maven-plugin.version>2.0.3.RELEASE</spring-boot-maven-plugin.version> | ||||
|         <exec-maven-plugin.version>1.6.0</exec-maven-plugin.version> | ||||
|         <source.version>1.8</source.version> | ||||
|         <target.version>1.8</target.version> | ||||
|  | ||||
| @ -1,123 +1,153 @@ | ||||
| package com.baeldung.stack; | ||||
| 
 | ||||
| import static org.hamcrest.CoreMatchers.equalTo; | ||||
| import static org.junit.Assert.*; | ||||
| import org.junit.Test; | ||||
| 
 | ||||
| import java.util.Arrays; | ||||
| import java.util.List; | ||||
| import java.util.ListIterator; | ||||
| import java.util.Stack; | ||||
| import java.util.stream.Collectors; | ||||
| 
 | ||||
| import org.junit.Test; | ||||
| import static org.hamcrest.CoreMatchers.equalTo; | ||||
| import static org.junit.Assert.assertEquals; | ||||
| import static org.junit.Assert.assertThat; | ||||
| import static org.junit.Assert.assertTrue; | ||||
| public class StackUnitTest { | ||||
| 
 | ||||
|     @Test | ||||
|     public void whenStackIsCreated_thenItHasSize0() { | ||||
|         Stack intStack = new Stack(); | ||||
|     public void whenStackIsCreated_thenItHasSizeZero() { | ||||
|         Stack<Integer> intStack = new Stack<>(); | ||||
| 
 | ||||
|         assertEquals(0, intStack.size()); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void givenEmptyStack_whenElementIsPushed_thenStackSizeisIncreased() { | ||||
|         Stack intStack = new Stack(); | ||||
|     public void whenElementIsPushed_thenStackSizeIsIncreased() { | ||||
|         Stack<Integer> intStack = new Stack<>(); | ||||
|         intStack.push(1); | ||||
| 
 | ||||
|         assertEquals(1, intStack.size()); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void givenEmptyStack_whenMultipleElementsArePushed_thenStackSizeisIncreased() { | ||||
|         Stack intStack = new Stack(); | ||||
|     public void whenMultipleElementsArePushed_thenStackSizeIsIncreased() { | ||||
|         Stack<Integer> intStack = new Stack<>(); | ||||
|         List<Integer> intList = Arrays.asList(1, 2, 3, 4, 5, 6, 7); | ||||
| 
 | ||||
|         boolean result = intStack.addAll(intList); | ||||
| 
 | ||||
|         assertTrue(result); | ||||
|         assertEquals(7, intList.size()); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void whenElementIsPoppedFromStack_thenElementIsRemovedAndSizeChanges() { | ||||
|         Stack<Integer> intStack = new Stack(); | ||||
|         Stack<Integer> intStack = new Stack<>(); | ||||
|         intStack.push(5); | ||||
|         intStack.pop(); | ||||
| 
 | ||||
|         Integer element = intStack.pop(); | ||||
| 
 | ||||
|         assertEquals(Integer.valueOf(5), element); | ||||
|         assertTrue(intStack.isEmpty()); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void whenElementIsPeeked_thenElementIsNotRemovedAndSizeDoesNotChange() { | ||||
|         Stack<Integer> intStack = new Stack(); | ||||
|         Stack<Integer> intStack = new Stack<>(); | ||||
|         intStack.push(5); | ||||
|         intStack.peek(); | ||||
| 
 | ||||
|         Integer element = intStack.peek(); | ||||
| 
 | ||||
|         assertEquals(Integer.valueOf(5), element); | ||||
|         assertEquals(1, intStack.search(5)); | ||||
|         assertEquals(1, intStack.size()); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void whenElementIsOnStack_thenSearchReturnsItsDistanceFromTheTop() { | ||||
|         Stack<Integer> intStack = new Stack(); | ||||
|         Stack<Integer> intStack = new Stack<>(); | ||||
|         intStack.push(5); | ||||
|         assertEquals(1, intStack.search(5)); | ||||
|         intStack.push(8); | ||||
| 
 | ||||
|         assertEquals(2, intStack.search(5)); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void whenElementIsOnStack_thenIndexOfReturnsItsIndex() { | ||||
|         Stack<Integer> intStack = new Stack(); | ||||
|         Stack<Integer> intStack = new Stack<>(); | ||||
|         intStack.push(5); | ||||
| 
 | ||||
|         int indexOf = intStack.indexOf(5); | ||||
| 
 | ||||
|         assertEquals(0, indexOf); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void whenMultipleElementsAreOnStack_thenIndexOfReturnsLastElementIndex() { | ||||
|         Stack<Integer> intStack = new Stack(); | ||||
|         Stack<Integer> intStack = new Stack<>(); | ||||
|         intStack.push(5); | ||||
|         intStack.push(5); | ||||
|         intStack.push(5); | ||||
| 
 | ||||
|         int lastIndexOf = intStack.lastIndexOf(5); | ||||
| 
 | ||||
|         assertEquals(2, lastIndexOf); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void givenElementOnStack_whenRemoveElementIsInvoked_thenElementIsRemoved() { | ||||
|         Stack<Integer> intStack = new Stack(); | ||||
|     public void whenRemoveElementIsInvoked_thenElementIsRemoved() { | ||||
|         Stack<Integer> intStack = new Stack<>(); | ||||
|         intStack.push(5); | ||||
|         intStack.push(5); | ||||
| 
 | ||||
|         intStack.removeElement(5); | ||||
| 
 | ||||
|         assertEquals(1, intStack.size()); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void givenElementOnStack_whenRemoveElementAtIsInvoked_thenElementIsRemoved() { | ||||
|         Stack<Integer> intStack = new Stack(); | ||||
|     public void whenRemoveElementAtIsInvoked_thenElementIsRemoved() { | ||||
|         Stack<Integer> intStack = new Stack<>(); | ||||
|         intStack.push(5); | ||||
|         intStack.push(7); | ||||
| 
 | ||||
|         intStack.removeElementAt(1); | ||||
| 
 | ||||
|         assertEquals(-1, intStack.search(7)); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void givenElementsOnStack_whenRemoveAllElementsIsInvoked_thenAllElementsAreRemoved() { | ||||
|         Stack<Integer> intStack = new Stack(); | ||||
|     public void whenRemoveAllElementsIsInvoked_thenAllElementsAreRemoved() { | ||||
|         Stack<Integer> intStack = new Stack<>(); | ||||
|         intStack.push(5); | ||||
|         intStack.push(7); | ||||
| 
 | ||||
|         intStack.removeAllElements(); | ||||
| 
 | ||||
|         assertTrue(intStack.isEmpty()); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void givenElementsOnStack_whenRemoveAllIsInvoked_thenAllElementsFromCollectionAreRemoved() { | ||||
|         Stack<Integer> intStack = new Stack(); | ||||
|         Stack<Integer> intStack = new Stack<>(); | ||||
|         List<Integer> intList = Arrays.asList(1, 2, 3, 4, 5, 6, 7); | ||||
|         intStack.addAll(intList); | ||||
|         intStack.add(500); | ||||
| 
 | ||||
|         intStack.removeAll(intList); | ||||
| 
 | ||||
|         assertEquals(1, intStack.size()); | ||||
|         assertEquals(1, intStack.search(500)); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void givenElementsOnStack_whenRemoveIfIsInvoked_thenAllElementsSatysfyingConditionAreRemoved() { | ||||
|         Stack<Integer> intStack = new Stack(); | ||||
|     public void whenRemoveIfIsInvoked_thenAllElementsSatysfyingConditionAreRemoved() { | ||||
|         Stack<Integer> intStack = new Stack<>(); | ||||
|         List<Integer> intList = Arrays.asList(1, 2, 3, 4, 5, 6, 7); | ||||
|         intStack.addAll(intList); | ||||
| 
 | ||||
|         intStack.removeIf(element -> element < 6); | ||||
| 
 | ||||
|         assertEquals(2, intStack.size()); | ||||
|     } | ||||
| 
 | ||||
| @ -126,12 +156,28 @@ public class StackUnitTest { | ||||
|         Stack<Integer> intStack = new Stack<>(); | ||||
|         List<Integer> intList = Arrays.asList(1, 2, 3, 4, 5, 6, 7); | ||||
|         intStack.addAll(intList); | ||||
| 
 | ||||
|         ListIterator<Integer> it = intStack.listIterator(); | ||||
|         Stack<Integer> result = new Stack(); | ||||
| 
 | ||||
|         Stack<Integer> result = new Stack<>(); | ||||
|         while(it.hasNext()) { | ||||
|             result.push(it.next()); | ||||
|         } | ||||
| 
 | ||||
|         assertThat(result, equalTo(intStack)); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void whenStackIsFiltered_allElementsNotSatisfyingFilterConditionAreDiscarded() { | ||||
|         Stack<Integer> intStack = new Stack<>(); | ||||
|         List<Integer> inputIntList = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 9, 10); | ||||
|         intStack.addAll(inputIntList); | ||||
| 
 | ||||
|         List<Integer> filtered = intStack | ||||
|                 .stream() | ||||
|                 .filter(element -> element <= 3) | ||||
|                 .collect(Collectors.toList()); | ||||
| 
 | ||||
|         assertEquals(3, filtered.size()); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| package com.baeldung; | ||||
| package com.baeldung.timer; | ||||
| 
 | ||||
| import org.junit.Test; | ||||
| import org.slf4j.Logger; | ||||
| @ -100,6 +100,7 @@ | ||||
|         <module>core-java-reflection</module> | ||||
| 
 | ||||
|         <module>core-java-security</module> | ||||
|         <module>core-java-security-2</module> | ||||
|         <module>core-java-streams</module> | ||||
|         <module>core-java-streams-2</module> | ||||
|         <module>core-java-streams-3</module> | ||||
|  | ||||
| @ -1,5 +0,0 @@ | ||||
| ## Core Kotlin | ||||
| 
 | ||||
| This module contains articles about core Kotlin. | ||||
| 
 | ||||
| 
 | ||||
| @ -5,4 +5,5 @@ This module contains articles about Kotlin core features. | ||||
| ### Relevant articles: | ||||
| - [Working with Dates in Kotlin](https://www.baeldung.com/kotlin-dates) | ||||
| - [Kotlin Ternary Conditional Operator](https://www.baeldung.com/kotlin-ternary-operator) | ||||
| - [Sequences in Kotlin](https://www.baeldung.com/kotlin/sequences) | ||||
| - [[<-- Prev]](/core-kotlin-modules/core-kotlin) | ||||
|  | ||||
| @ -13,4 +13,7 @@ This module contains articles about Kotlin core features. | ||||
| - [Implementing a Binary Tree in Kotlin](https://www.baeldung.com/kotlin-binary-tree) | ||||
| - [JUnit 5 for Kotlin Developers](https://www.baeldung.com/junit-5-kotlin) | ||||
| - [Converting Kotlin Data Class from JSON using GSON](https://www.baeldung.com/kotlin-json-convert-data-class) | ||||
| - [Fuel HTTP Library with Kotlin](https://www.baeldung.com/kotlin-fuel) | ||||
| - [Introduction to Kovenant Library for Kotlin](https://www.baeldung.com/kotlin-kovenant) | ||||
| - [Dependency Injection for Kotlin with Injekt](https://www.baeldung.com/kotlin-dependency-injection-with-injekt) | ||||
| - [[More --> ]](/core-kotlin-modules/core-kotlin-2) | ||||
|  | ||||
| @ -5,3 +5,4 @@ This module contains articles about Scala's core features | ||||
| ### Relevant Articles:  | ||||
| 
 | ||||
| - [Introduction to Scala](https://www.baeldung.com/scala-intro) | ||||
| - [Regular Expressions in Scala](https://www.baeldung.com/scala/regular-expressions) | ||||
|  | ||||
| @ -0,0 +1,82 @@ | ||||
| package com.baeldung.scala | ||||
| 
 | ||||
| import org.junit.Assert.assertEquals | ||||
| import org.junit.Test | ||||
| 
 | ||||
| 
 | ||||
| class HigherOrderFunctionsExamplesUnitTest { | ||||
| 
 | ||||
|   @Test | ||||
|   def whenCallingMapWithAnonymousFunction_thenTransformationIsApplied() = { | ||||
|     val expected = Seq("sir Alex Ferguson", "sir Bobby Charlton", "sir Frank Lampard") | ||||
| 
 | ||||
|     val names = Seq("Alex Ferguson", "Bobby Charlton", "Frank Lampard") | ||||
|     val sirNames = names.map(name => "sir " + name) | ||||
| 
 | ||||
|     assertEquals(expected, sirNames) | ||||
|   } | ||||
| 
 | ||||
|   @Test | ||||
|   def whenCallingMapWithDefined_thenTransformationIsApplied() = { | ||||
|     val expected = Seq("sir Alex Ferguson", "sir Bobby Charlton", "sir Frank Lampard") | ||||
| 
 | ||||
|     val names = Seq("Alex Ferguson", "Bobby Charlton", "Frank Lampard") | ||||
| 
 | ||||
|     def prefixWithSir(name: String) = "sir " + name | ||||
|     val sirNames = names.map(prefixWithSir) | ||||
| 
 | ||||
|     assertEquals(expected, sirNames) | ||||
|   } | ||||
| 
 | ||||
|   @Test | ||||
|   def whenCallingFilter_thenUnecessaryElementsAreRemoved() = { | ||||
|     val expected = Seq("John O'Shea", "John Hartson") | ||||
| 
 | ||||
|     val names = Seq("John O'Shea", "Aiden McGeady", "John Hartson") | ||||
|     val johns = names.filter(name => name.matches("^John .*")) | ||||
| 
 | ||||
|     assertEquals(expected, johns) | ||||
|   } | ||||
| 
 | ||||
|   @Test | ||||
|   def whenCallingReduce_thenProperSumIsCalculated() = { | ||||
|     val expected = 2750 | ||||
| 
 | ||||
|     val earnings = Seq(1000, 1300, 450) | ||||
|     val sumEarnings = earnings.reduce((acc, x) => acc + x) | ||||
| 
 | ||||
|     assertEquals(expected, sumEarnings) | ||||
|   } | ||||
| 
 | ||||
|   @Test | ||||
|   def whenCallingFold_thenNumberOfWordsShouldBeCalculated() = { | ||||
|     val expected = 6 | ||||
| 
 | ||||
|     val strings = Seq("bunch of words", "just me", "it") | ||||
|     val sumEarnings = strings.foldLeft(0)((acc, x) => acc + x.split(" ").size) | ||||
| 
 | ||||
|     assertEquals(expected, sumEarnings) | ||||
|   } | ||||
| 
 | ||||
|   @Test | ||||
|   def whenCallingOwnHigherOrderFunction_thenProperFunctionIsReturned() = { | ||||
|     def mathOperation(name: String): (Int, Int) => Int = (x: Int, y: Int) => { | ||||
|       name match { | ||||
|         case "addition" => x + y | ||||
|         case "multiplication" => x * y | ||||
|         case "division" => x/y | ||||
|         case "subtraction" => x - y | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     def add: (Int, Int) => Int = mathOperation("addition") | ||||
|     def mul: (Int, Int) => Int = mathOperation("multiplication") | ||||
|     def div: (Int, Int) => Int = mathOperation("division") | ||||
|     def sub: (Int, Int) => Int = mathOperation("subtraction") | ||||
| 
 | ||||
|     assertEquals(15, add(10, 5)) | ||||
|     assertEquals(50, mul(10, 5)) | ||||
|     assertEquals(2, div(10, 5)) | ||||
|     assertEquals(5, sub(10, 5)) | ||||
|   } | ||||
| } | ||||
| @ -1,4 +1,4 @@ | ||||
| package com.baeldung.scala | ||||
| package com.baeldung.scala.regex | ||||
| 
 | ||||
| import org.junit.Test | ||||
| import org.junit.Assert.assertEquals | ||||
| @ -1,4 +1,4 @@ | ||||
| package com.baeldung.algorithms.balancedbinarytree; | ||||
| package com.baeldung.avltree; | ||||
| 
 | ||||
| public class AVLTree { | ||||
| 
 | ||||
| @ -1,4 +1,4 @@ | ||||
| package com.baeldung.algorithms.balancedbinarytree; | ||||
| package com.baeldung.avltree; | ||||
| 
 | ||||
| import org.junit.Assert; | ||||
| import org.junit.Test; | ||||
							
								
								
									
										1
									
								
								ddd-modules/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								ddd-modules/README.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | ||||
| ## Relevant Articles | ||||
							
								
								
									
										53
									
								
								ddd-modules/infrastructure/pom.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								ddd-modules/infrastructure/pom.xml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,53 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||||
|          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||||
|     <modelVersion>4.0.0</modelVersion> | ||||
|     <groupId>com.baeldung.dddmodules.infrastructure</groupId> | ||||
|     <artifactId>infrastructure</artifactId> | ||||
|     <version>1.0</version> | ||||
| 
 | ||||
|     <packaging>jar</packaging> | ||||
| 
 | ||||
|     <parent> | ||||
|         <groupId>com.baeldung.dddmodules</groupId> | ||||
|         <artifactId>dddmodules</artifactId> | ||||
|         <version>1.0</version> | ||||
|     </parent> | ||||
| 
 | ||||
|     <dependencies> | ||||
|         <dependency> | ||||
|             <groupId>com.baeldung.dddmodules.shippingcontext</groupId> | ||||
|             <artifactId>shippingcontext</artifactId> | ||||
|             <version>${appmodules.version}</version> | ||||
|         </dependency> | ||||
|         <dependency> | ||||
|             <groupId>com.baeldung.dddmodules.ordercontext</groupId> | ||||
|             <artifactId>ordercontext</artifactId> | ||||
|             <version>${appmodules.version}</version> | ||||
|         </dependency> | ||||
|         <dependency> | ||||
|             <groupId>com.baeldung.dddmodules.sharedkernel</groupId> | ||||
|             <artifactId>sharedkernel</artifactId> | ||||
|             <version>${appmodules.version}</version> | ||||
|         </dependency> | ||||
|     </dependencies> | ||||
| 
 | ||||
|     <build> | ||||
|         <plugins> | ||||
|             <plugin> | ||||
|                 <groupId>org.apache.maven.plugins</groupId> | ||||
|                 <artifactId>maven-compiler-plugin</artifactId> | ||||
|                 <configuration> | ||||
|                     <source>${source.version}</source> | ||||
|                     <target>${target.version}</target> | ||||
|                 </configuration> | ||||
|             </plugin> | ||||
|         </plugins> | ||||
|     </build> | ||||
| 
 | ||||
|     <properties> | ||||
|         <source.version>9</source.version> | ||||
|         <target.version>9</target.version> | ||||
|     </properties> | ||||
| 
 | ||||
| </project> | ||||
| @ -0,0 +1,79 @@ | ||||
| package com.baeldung.dddmodules.infrastructure.db; | ||||
| 
 | ||||
| import com.baeldung.dddmodules.ordercontext.model.CustomerOrder; | ||||
| import com.baeldung.dddmodules.ordercontext.repository.CustomerOrderRepository; | ||||
| import com.baeldung.dddmodules.shippingcontext.model.PackageItem; | ||||
| import com.baeldung.dddmodules.shippingcontext.model.ShippableOrder; | ||||
| import com.baeldung.dddmodules.shippingcontext.repository.ShippingOrderRepository; | ||||
| 
 | ||||
| import java.util.HashMap; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
| import java.util.Optional; | ||||
| import java.util.stream.Collectors; | ||||
| 
 | ||||
| public class InMemoryOrderStore implements CustomerOrderRepository, ShippingOrderRepository { | ||||
|     private Map<Integer, PersistenceOrder> ordersDb = new HashMap<>(); | ||||
|     private volatile static InMemoryOrderStore instance = new InMemoryOrderStore(); | ||||
| 
 | ||||
|     @Override | ||||
|     public void saveCustomerOrder(CustomerOrder order) { | ||||
|         this.ordersDb.put(order.getOrderId(), new PersistenceOrder(order.getOrderId(), | ||||
|           order.getPaymentMethod(), | ||||
|           order.getAddress(), | ||||
|           order | ||||
|             .getOrderItems() | ||||
|             .stream() | ||||
|             .map(orderItem -> | ||||
|               new PersistenceOrder.OrderItem(orderItem.getProductId(), | ||||
|                 orderItem.getQuantity(), | ||||
|                 orderItem.getUnitWeight(), | ||||
|                 orderItem.getUnitPrice())) | ||||
|             .collect(Collectors.toList()) | ||||
|         )); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public Optional<ShippableOrder> findShippableOrder(int orderId) { | ||||
|         if (!this.ordersDb.containsKey(orderId)) return Optional.empty(); | ||||
|         PersistenceOrder orderRecord = this.ordersDb.get(orderId); | ||||
|         return Optional.of( | ||||
|           new ShippableOrder(orderRecord.orderId, orderRecord.orderItems | ||||
|             .stream().map(orderItem -> new PackageItem(orderItem.productId, | ||||
|               orderItem.itemWeight, | ||||
|               orderItem.quantity * orderItem.unitPrice) | ||||
|             ).collect(Collectors.toList()))); | ||||
|     } | ||||
| 
 | ||||
|     public static InMemoryOrderStore provider() { | ||||
|         return instance; | ||||
|     } | ||||
| 
 | ||||
|     public static class PersistenceOrder { | ||||
|         public int orderId; | ||||
|         public String paymentMethod; | ||||
|         public String address; | ||||
|         public List<OrderItem> orderItems; | ||||
| 
 | ||||
|         public PersistenceOrder(int orderId, String paymentMethod, String address, List<OrderItem> orderItems) { | ||||
|             this.orderId = orderId; | ||||
|             this.paymentMethod = paymentMethod; | ||||
|             this.address = address; | ||||
|             this.orderItems = orderItems; | ||||
|         } | ||||
| 
 | ||||
|         public static class OrderItem { | ||||
|             public int productId; | ||||
|             public float unitPrice; | ||||
|             public float itemWeight; | ||||
|             public int quantity; | ||||
| 
 | ||||
|             public OrderItem(int productId, int quantity, float unitWeight, float unitPrice) { | ||||
|                 this.itemWeight = unitWeight; | ||||
|                 this.quantity = quantity; | ||||
|                 this.unitPrice = unitPrice; | ||||
|                 this.productId = productId; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,39 @@ | ||||
| package com.baeldung.dddmodules.infrastructure.events; | ||||
| 
 | ||||
| import com.baeldung.dddmodules.sharedkernel.events.ApplicationEvent; | ||||
| import com.baeldung.dddmodules.sharedkernel.events.EventBus; | ||||
| import com.baeldung.dddmodules.sharedkernel.events.EventSubscriber; | ||||
| 
 | ||||
| import java.util.Map; | ||||
| import java.util.Set; | ||||
| import java.util.concurrent.ConcurrentHashMap; | ||||
| import java.util.concurrent.CopyOnWriteArraySet; | ||||
| 
 | ||||
| public class SimpleEventBus implements EventBus { | ||||
|     private final Map<String, Set<EventSubscriber>> subscribers = new ConcurrentHashMap<>(); | ||||
| 
 | ||||
|     @Override | ||||
|     public <E extends ApplicationEvent> void publish(E event) { | ||||
|         if (subscribers.containsKey(event.getType())) { | ||||
|             subscribers.get(event.getType()) | ||||
|               .forEach(subscriber -> subscriber.onEvent(event)); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public <E extends ApplicationEvent> void subscribe(String eventType, EventSubscriber subscriber) { | ||||
|         Set<EventSubscriber> eventSubscribers = subscribers.get(eventType); | ||||
|         if (eventSubscribers == null) { | ||||
|             eventSubscribers = new CopyOnWriteArraySet<>(); | ||||
|             subscribers.put(eventType, eventSubscribers); | ||||
|         } | ||||
|         eventSubscribers.add(subscriber); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public <E extends ApplicationEvent> void unsubscribe(String eventType, EventSubscriber subscriber) { | ||||
|         if (subscribers.containsKey(eventType)) { | ||||
|             subscribers.get(eventType).remove(subscriber); | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										11
									
								
								ddd-modules/infrastructure/src/main/java/module-info.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								ddd-modules/infrastructure/src/main/java/module-info.java
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | ||||
| module com.baeldung.dddmodules.infrastructure { | ||||
|     requires transitive com.baeldung.dddmodules.sharedkernel; | ||||
|     requires transitive com.baeldung.dddmodules.ordercontext; | ||||
|     requires transitive com.baeldung.dddmodules.shippingcontext; | ||||
|     provides com.baeldung.dddmodules.sharedkernel.events.EventBus | ||||
|       with com.baeldung.dddmodules.infrastructure.events.SimpleEventBus; | ||||
|     provides com.baeldung.dddmodules.ordercontext.repository.CustomerOrderRepository | ||||
|       with com.baeldung.dddmodules.infrastructure.db.InMemoryOrderStore; | ||||
|     provides com.baeldung.dddmodules.shippingcontext.repository.ShippingOrderRepository | ||||
|       with com.baeldung.dddmodules.infrastructure.db.InMemoryOrderStore; | ||||
| } | ||||
							
								
								
									
										51
									
								
								ddd-modules/mainapp/pom.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								ddd-modules/mainapp/pom.xml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,51 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||||
|          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||||
|     <modelVersion>4.0.0</modelVersion> | ||||
|     <groupId>com.baeldung.dddmodules.mainapp</groupId> | ||||
|     <artifactId>mainapp</artifactId> | ||||
|     <version>1.0</version> | ||||
|     <packaging>jar</packaging> | ||||
| 
 | ||||
|     <parent> | ||||
|         <groupId>com.baeldung.dddmodules</groupId> | ||||
|         <artifactId>dddmodules</artifactId> | ||||
|         <version>1.0</version> | ||||
|     </parent> | ||||
| 
 | ||||
|     <dependencies> | ||||
|         <dependency> | ||||
|             <groupId>com.baeldung.dddmodules.infrastructure</groupId> | ||||
|             <artifactId>infrastructure</artifactId> | ||||
|             <version>${appmodules.version}</version> | ||||
|         </dependency> | ||||
|     </dependencies> | ||||
| 
 | ||||
|     <build> | ||||
|         <plugins> | ||||
|             <plugin> | ||||
|                 <groupId>org.apache.maven.plugins</groupId> | ||||
|                 <artifactId>maven-surefire-plugin</artifactId> | ||||
|                 <version>2.16</version> | ||||
|                 <configuration> | ||||
|                     <enableAssertions>true</enableAssertions> | ||||
|                 </configuration> | ||||
|             </plugin> | ||||
|             <plugin> | ||||
|                 <groupId>org.apache.maven.plugins</groupId> | ||||
|                 <artifactId>maven-compiler-plugin</artifactId> | ||||
|                 <version>${compiler.plugin.version}</version> | ||||
|                 <configuration> | ||||
|                     <source>${source.version}</source> | ||||
|                     <target>${target.version}</target> | ||||
|                 </configuration> | ||||
|             </plugin> | ||||
|         </plugins> | ||||
|     </build> | ||||
| 
 | ||||
|     <properties> | ||||
|         <source.version>9</source.version> | ||||
|         <target.version>9</target.version> | ||||
|     </properties> | ||||
| 
 | ||||
| </project> | ||||
| @ -0,0 +1,54 @@ | ||||
| package com.baeldung.dddmodules.mainapp; | ||||
| 
 | ||||
| import com.baeldung.dddmodules.ordercontext.model.CustomerOrder; | ||||
| import com.baeldung.dddmodules.ordercontext.model.OrderItem; | ||||
| import com.baeldung.dddmodules.ordercontext.repository.CustomerOrderRepository; | ||||
| import com.baeldung.dddmodules.ordercontext.service.OrderService; | ||||
| import com.baeldung.dddmodules.sharedkernel.events.EventBus; | ||||
| import com.baeldung.dddmodules.shippingcontext.repository.ShippingOrderRepository; | ||||
| import com.baeldung.dddmodules.shippingcontext.service.ShippingService; | ||||
| 
 | ||||
| import java.util.*; | ||||
| 
 | ||||
| public class Application { | ||||
| 
 | ||||
|     public static void main(String args[]) { | ||||
|         Map<Class<?>, Object> container = createContainer(); | ||||
|         OrderService orderService = (OrderService) container.get(OrderService.class); | ||||
|         ShippingService shippingService = (ShippingService) container.get(ShippingService.class); | ||||
|         shippingService.listenToOrderEvents(); | ||||
| 
 | ||||
|         CustomerOrder customerOrder = new CustomerOrder(); | ||||
|         int orderId = 1; | ||||
|         customerOrder.setOrderId(orderId); | ||||
|         List<OrderItem> orderItems = new ArrayList<OrderItem>(); | ||||
|         orderItems.add(new OrderItem(1, 2, 3, 1)); | ||||
|         orderItems.add(new OrderItem(2, 1, 1, 1)); | ||||
|         orderItems.add(new OrderItem(3, 4, 11, 21)); | ||||
|         customerOrder.setOrderItems(orderItems); | ||||
|         customerOrder.setPaymentMethod("PayPal"); | ||||
|         customerOrder.setAddress("Full address here"); | ||||
|         orderService.placeOrder(customerOrder); | ||||
| 
 | ||||
|         if (orderId == shippingService.getParcelByOrderId(orderId).get().getOrderId()) { | ||||
|             System.out.println("Order has been processed and shipped successfully"); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public static Map<Class<?>, Object> createContainer() { | ||||
|         EventBus eventBus = ServiceLoader.load(EventBus.class).findFirst().get(); | ||||
|         CustomerOrderRepository customerOrderRepository = ServiceLoader.load(CustomerOrderRepository.class).findFirst().get(); | ||||
|         ShippingOrderRepository shippingOrderRepository = ServiceLoader.load(ShippingOrderRepository.class).findFirst().get(); | ||||
|         ShippingService shippingService = ServiceLoader.load(ShippingService.class).findFirst().get(); | ||||
|         shippingService.setEventBus(eventBus); | ||||
|         shippingService.setOrderRepository(shippingOrderRepository); | ||||
|         OrderService orderService = ServiceLoader.load(OrderService.class).findFirst().get(); | ||||
|         orderService.setEventBus(eventBus); | ||||
|         orderService.setOrderRepository(customerOrderRepository); | ||||
|         HashMap<Class<?>, Object> container = new HashMap<>(); | ||||
|         container.put(OrderService.class, orderService); | ||||
|         container.put(ShippingService.class, shippingService); | ||||
|         return container; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										8
									
								
								ddd-modules/mainapp/src/main/java/module-info.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								ddd-modules/mainapp/src/main/java/module-info.java
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | ||||
| module com.baeldung.dddmodules.mainapp { | ||||
|     uses com.baeldung.dddmodules.sharedkernel.events.EventBus; | ||||
|     uses com.baeldung.dddmodules.ordercontext.service.OrderService; | ||||
|     uses com.baeldung.dddmodules.ordercontext.repository.CustomerOrderRepository; | ||||
|     uses com.baeldung.dddmodules.shippingcontext.repository.ShippingOrderRepository; | ||||
|     uses com.baeldung.dddmodules.shippingcontext.service.ShippingService; | ||||
|     requires transitive com.baeldung.dddmodules.infrastructure; | ||||
| } | ||||
							
								
								
									
										44
									
								
								ddd-modules/ordercontext/pom.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								ddd-modules/ordercontext/pom.xml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,44 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||||
|          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||||
|     <modelVersion>4.0.0</modelVersion> | ||||
|     <groupId>com.baeldung.dddmodules.ordercontext</groupId> | ||||
|     <artifactId>ordercontext</artifactId> | ||||
|     <version>1.0</version> | ||||
|     <packaging>jar</packaging> | ||||
| 
 | ||||
|     <parent> | ||||
|         <groupId>com.baeldung.dddmodules</groupId> | ||||
|         <artifactId>dddmodules</artifactId> | ||||
|         <version>1.0</version> | ||||
|     </parent> | ||||
| 
 | ||||
|     <dependencies> | ||||
|         <dependency> | ||||
|             <groupId>com.baeldung.dddmodules.sharedkernel</groupId> | ||||
|             <artifactId>sharedkernel</artifactId> | ||||
|             <version>${appmodules.version}</version> | ||||
|         </dependency> | ||||
|     </dependencies> | ||||
| 
 | ||||
|     <build> | ||||
|         <plugins> | ||||
|             <plugin> | ||||
|                 <groupId>org.apache.maven.plugins</groupId> | ||||
|                 <artifactId>maven-compiler-plugin</artifactId> | ||||
|                 <configuration> | ||||
|                     <source>${source.version}</source> | ||||
|                     <target>${target.version}</target> | ||||
|                 </configuration> | ||||
|             </plugin> | ||||
|         </plugins> | ||||
|     </build> | ||||
| 
 | ||||
|     <properties> | ||||
|         <source.version>9</source.version> | ||||
|         <target.version>9</target.version> | ||||
|         <entitymodule.version>1.0</entitymodule.version> | ||||
|         <daomodule.version>1.0</daomodule.version> | ||||
|     </properties> | ||||
| 
 | ||||
| </project> | ||||
| @ -0,0 +1,51 @@ | ||||
| package com.baeldung.dddmodules.ordercontext.model; | ||||
| 
 | ||||
| import java.util.List; | ||||
| 
 | ||||
| public class CustomerOrder { | ||||
|     private int orderId; | ||||
|     private String paymentMethod; | ||||
|     private String address; | ||||
|     private List<OrderItem> orderItems; | ||||
| 
 | ||||
|     public CustomerOrder() { | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     public float calculateTotalPrice() { | ||||
|         return orderItems.stream().map(OrderItem::getTotalPrice) | ||||
|           .reduce(0F, Float::sum); | ||||
|     } | ||||
| 
 | ||||
|     public void setOrderItems(List<OrderItem> orderItems) { | ||||
|         this.orderItems = orderItems; | ||||
|     } | ||||
| 
 | ||||
|     public int getOrderId() { | ||||
|         return orderId; | ||||
|     } | ||||
| 
 | ||||
|     public List<OrderItem> getOrderItems() { | ||||
|         return orderItems; | ||||
|     } | ||||
| 
 | ||||
|     public void setOrderId(int orderId) { | ||||
|         this.orderId = orderId; | ||||
|     } | ||||
| 
 | ||||
|     public String getPaymentMethod() { | ||||
|         return paymentMethod; | ||||
|     } | ||||
| 
 | ||||
|     public void setPaymentMethod(String paymentMethod) { | ||||
|         this.paymentMethod = paymentMethod; | ||||
|     } | ||||
| 
 | ||||
|     public String getAddress() { | ||||
|         return address; | ||||
|     } | ||||
| 
 | ||||
|     public void setAddress(String address) { | ||||
|         this.address = address; | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,51 @@ | ||||
| package com.baeldung.dddmodules.ordercontext.model; | ||||
| 
 | ||||
| public class OrderItem { | ||||
|     private int productId; | ||||
|     private int quantity; | ||||
|     private float unitPrice; | ||||
|     private float unitWeight; | ||||
| 
 | ||||
|     public OrderItem(int productId, int quantity, float unitPrice, float unitWeight) { | ||||
|         this.productId = productId; | ||||
|         this.quantity = quantity; | ||||
|         this.unitPrice = unitPrice; | ||||
|         this.unitWeight = unitWeight; | ||||
|     } | ||||
| 
 | ||||
|     public int getProductId() { | ||||
|         return productId; | ||||
|     } | ||||
| 
 | ||||
|     public void setProductId(int productId) { | ||||
|         this.productId = productId; | ||||
|     } | ||||
| 
 | ||||
|     public int getQuantity() { | ||||
|         return quantity; | ||||
|     } | ||||
| 
 | ||||
|     public void setQuantity(int quantity) { | ||||
|         this.quantity = quantity; | ||||
|     } | ||||
| 
 | ||||
|     public float getTotalPrice() { | ||||
|         return this.quantity * this.unitPrice; | ||||
|     } | ||||
| 
 | ||||
|     public void setUnitPrice(float unitPrice) { | ||||
|         this.unitPrice = unitPrice; | ||||
|     } | ||||
| 
 | ||||
|     public float getUnitWeight() { | ||||
|         return unitWeight; | ||||
|     } | ||||
| 
 | ||||
|     public float getUnitPrice() { | ||||
|         return unitPrice; | ||||
|     } | ||||
| 
 | ||||
|     public void setUnitWeight(float unitWeight) { | ||||
|         this.unitWeight = unitWeight; | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,7 @@ | ||||
| package com.baeldung.dddmodules.ordercontext.repository; | ||||
| 
 | ||||
| import com.baeldung.dddmodules.ordercontext.model.CustomerOrder; | ||||
| 
 | ||||
| public interface CustomerOrderRepository { | ||||
|     void saveCustomerOrder(CustomerOrder order); | ||||
| } | ||||
| @ -0,0 +1,44 @@ | ||||
| package com.baeldung.dddmodules.ordercontext.service; | ||||
| 
 | ||||
| import com.baeldung.dddmodules.ordercontext.model.CustomerOrder; | ||||
| import com.baeldung.dddmodules.ordercontext.repository.CustomerOrderRepository; | ||||
| import com.baeldung.dddmodules.sharedkernel.events.ApplicationEvent; | ||||
| import com.baeldung.dddmodules.sharedkernel.events.EventBus; | ||||
| 
 | ||||
| import java.util.HashMap; | ||||
| import java.util.Map; | ||||
| 
 | ||||
| public class CustomerOrderService implements OrderService { | ||||
|     public static final String EVENT_ORDER_READY_FOR_SHIPMENT = "OrderReadyForShipmentEvent"; | ||||
| 
 | ||||
|     private CustomerOrderRepository orderRepository; | ||||
|     private EventBus eventBus; | ||||
| 
 | ||||
|     @Override | ||||
|     public void placeOrder(CustomerOrder order) { | ||||
|         this.orderRepository.saveCustomerOrder(order); | ||||
|         Map<String, String> payload = new HashMap<>(); | ||||
|         payload.put("order_id", String.valueOf(order.getOrderId())); | ||||
|         ApplicationEvent event = new ApplicationEvent(payload) { | ||||
|             @Override | ||||
|             public String getType() { | ||||
|                 return EVENT_ORDER_READY_FOR_SHIPMENT; | ||||
|             } | ||||
|         }; | ||||
|         this.eventBus.publish(event); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public EventBus getEventBus() { | ||||
|         return eventBus; | ||||
|     } | ||||
| 
 | ||||
|     public void setOrderRepository(CustomerOrderRepository orderRepository) { | ||||
|         this.orderRepository = orderRepository; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void setEventBus(EventBus eventBus) { | ||||
|         this.eventBus = eventBus; | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,11 @@ | ||||
| package com.baeldung.dddmodules.ordercontext.service; | ||||
| 
 | ||||
| import com.baeldung.dddmodules.ordercontext.model.CustomerOrder; | ||||
| import com.baeldung.dddmodules.ordercontext.repository.CustomerOrderRepository; | ||||
| import com.baeldung.dddmodules.sharedkernel.service.ApplicationService; | ||||
| 
 | ||||
| public interface OrderService extends ApplicationService { | ||||
|     void placeOrder(CustomerOrder order); | ||||
| 
 | ||||
|     void setOrderRepository(CustomerOrderRepository orderRepository); | ||||
| } | ||||
							
								
								
									
										8
									
								
								ddd-modules/ordercontext/src/main/java/module-info.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								ddd-modules/ordercontext/src/main/java/module-info.java
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | ||||
| module com.baeldung.dddmodules.ordercontext { | ||||
|     requires com.baeldung.dddmodules.sharedkernel; | ||||
|     exports com.baeldung.dddmodules.ordercontext.service; | ||||
|     exports com.baeldung.dddmodules.ordercontext.model; | ||||
|     exports com.baeldung.dddmodules.ordercontext.repository; | ||||
|     provides com.baeldung.dddmodules.ordercontext.service.OrderService | ||||
|       with com.baeldung.dddmodules.ordercontext.service.CustomerOrderService; | ||||
| } | ||||
							
								
								
									
										68
									
								
								ddd-modules/pom.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								ddd-modules/pom.xml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,68 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||||
|          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||||
|     <modelVersion>4.0.0</modelVersion> | ||||
|     <groupId>com.baeldung.dddmodules</groupId> | ||||
|     <artifactId>dddmodules</artifactId> | ||||
|     <version>1.0</version> | ||||
|     <name>ddd-modules</name> | ||||
|     <packaging>pom</packaging> | ||||
| 
 | ||||
|     <parent> | ||||
|         <groupId>com.baeldung</groupId> | ||||
|         <artifactId>parent-modules</artifactId> | ||||
|         <version>1.0.0-SNAPSHOT</version> | ||||
|         <relativePath>../</relativePath> | ||||
|     </parent> | ||||
| 
 | ||||
|     <modules> | ||||
|         <module>sharedkernel</module> | ||||
|         <module>infrastructure</module> | ||||
|         <module>shippingcontext</module> | ||||
|         <module>ordercontext</module> | ||||
|         <module>mainapp</module> | ||||
|     </modules> | ||||
| 
 | ||||
|     <dependencyManagement> | ||||
|         <dependencies> | ||||
|             <dependency> | ||||
|                 <groupId>junit</groupId> | ||||
|                 <artifactId>junit</artifactId> | ||||
|                 <version>${junit.version}</version> | ||||
|                 <scope>test</scope> | ||||
|             </dependency> | ||||
|             <dependency> | ||||
|                 <groupId>org.assertj</groupId> | ||||
|                 <artifactId>assertj-core</artifactId> | ||||
|                 <version>${assertj-core.version}</version> | ||||
|                 <scope>test</scope> | ||||
|             </dependency> | ||||
|         </dependencies> | ||||
|     </dependencyManagement> | ||||
| 
 | ||||
|     <build> | ||||
|         <pluginManagement> | ||||
|             <plugins> | ||||
|                 <plugin> | ||||
|                     <groupId>org.apache.maven.plugins</groupId> | ||||
|                     <artifactId>maven-compiler-plugin</artifactId> | ||||
|                     <version>${compiler.plugin.version}</version> | ||||
|                     <configuration> | ||||
|                         <source>${source.version}</source> | ||||
|                         <target>${target.version}</target> | ||||
|                     </configuration> | ||||
|                 </plugin> | ||||
|             </plugins> | ||||
|         </pluginManagement> | ||||
|     </build> | ||||
| 
 | ||||
|     <properties> | ||||
|         <compiler.plugin.version>3.8.1</compiler.plugin.version> | ||||
|         <source.version>9</source.version> | ||||
|         <target.version>9</target.version> | ||||
|         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | ||||
|         <assertj-core.version>3.12.2</assertj-core.version> | ||||
|         <appmodules.version>1.0</appmodules.version> | ||||
|     </properties> | ||||
| 
 | ||||
| </project> | ||||
							
								
								
									
										34
									
								
								ddd-modules/sharedkernel/pom.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								ddd-modules/sharedkernel/pom.xml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,34 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||||
|          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||||
|     <modelVersion>4.0.0</modelVersion> | ||||
|     <groupId>com.baeldung.dddmodules.sharedkernel</groupId> | ||||
|     <artifactId>sharedkernel</artifactId> | ||||
|     <version>1.0</version> | ||||
|     <packaging>jar</packaging> | ||||
| 
 | ||||
|     <parent> | ||||
|         <groupId>com.baeldung.dddmodules</groupId> | ||||
|         <artifactId>dddmodules</artifactId> | ||||
|         <version>1.0</version> | ||||
|     </parent> | ||||
| 
 | ||||
|     <build> | ||||
|         <plugins> | ||||
|             <plugin> | ||||
|                 <groupId>org.apache.maven.plugins</groupId> | ||||
|                 <artifactId>maven-compiler-plugin</artifactId> | ||||
|                 <configuration> | ||||
|                     <source>${source.version}</source> | ||||
|                     <target>${target.version}</target> | ||||
|                 </configuration> | ||||
|             </plugin> | ||||
|         </plugins> | ||||
|     </build> | ||||
| 
 | ||||
|     <properties> | ||||
|         <source.version>9</source.version> | ||||
|         <target.version>9</target.version> | ||||
|     </properties> | ||||
| 
 | ||||
| </project> | ||||
| @ -0,0 +1,21 @@ | ||||
| package com.baeldung.dddmodules.sharedkernel.events; | ||||
| 
 | ||||
| import java.util.Map; | ||||
| 
 | ||||
| public abstract class ApplicationEvent { | ||||
|     protected Map<String, String> payload; | ||||
| 
 | ||||
|     public abstract String getType(); | ||||
| 
 | ||||
|     public String getPayloadValue(String key) { | ||||
|         if (this.payload.containsKey(key)) { | ||||
|             return this.payload.get(key); | ||||
|         } | ||||
|         return ""; | ||||
|     } | ||||
| 
 | ||||
|     public ApplicationEvent(Map<String, String> payload) { | ||||
|         this.payload = payload; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -0,0 +1,9 @@ | ||||
| package com.baeldung.dddmodules.sharedkernel.events; | ||||
| 
 | ||||
| public interface EventBus { | ||||
|     <E extends ApplicationEvent> void publish(E event); | ||||
| 
 | ||||
|     <E extends ApplicationEvent> void subscribe(String eventType, EventSubscriber subscriber); | ||||
| 
 | ||||
|     <E extends ApplicationEvent> void unsubscribe(String eventType, EventSubscriber subscriber); | ||||
| } | ||||
| @ -0,0 +1,5 @@ | ||||
| package com.baeldung.dddmodules.sharedkernel.events; | ||||
| 
 | ||||
| public interface EventSubscriber { | ||||
|     <E extends ApplicationEvent> void onEvent(E event); | ||||
| } | ||||
| @ -0,0 +1,33 @@ | ||||
| package com.baeldung.dddmodules.sharedkernel.service; | ||||
| 
 | ||||
| import com.baeldung.dddmodules.sharedkernel.events.ApplicationEvent; | ||||
| import com.baeldung.dddmodules.sharedkernel.events.EventBus; | ||||
| import com.baeldung.dddmodules.sharedkernel.events.EventSubscriber; | ||||
| 
 | ||||
| public interface ApplicationService { | ||||
| 
 | ||||
|     default <E extends ApplicationEvent> void publishEvent(E event) { | ||||
|         EventBus eventBus = getEventBus(); | ||||
|         if (eventBus != null) { | ||||
|             eventBus.publish(event); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     default <E extends ApplicationEvent> void subscribe(String eventType, EventSubscriber subscriber) { | ||||
|         EventBus eventBus = getEventBus(); | ||||
|         if (eventBus != null) { | ||||
|             eventBus.subscribe(eventType, subscriber); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     default <E extends ApplicationEvent> void unsubscribe(String eventType, EventSubscriber subscriber) { | ||||
|         EventBus eventBus = getEventBus(); | ||||
|         if (eventBus != null) { | ||||
|             eventBus.unsubscribe(eventType, subscriber); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     EventBus getEventBus(); | ||||
| 
 | ||||
|     void setEventBus(EventBus eventBus); | ||||
| } | ||||
							
								
								
									
										4
									
								
								ddd-modules/sharedkernel/src/main/java/module-info.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								ddd-modules/sharedkernel/src/main/java/module-info.java
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,4 @@ | ||||
| module com.baeldung.dddmodules.sharedkernel { | ||||
|     exports com.baeldung.dddmodules.sharedkernel.events; | ||||
|     exports com.baeldung.dddmodules.sharedkernel.service; | ||||
| } | ||||
							
								
								
									
										42
									
								
								ddd-modules/shippingcontext/pom.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								ddd-modules/shippingcontext/pom.xml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,42 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||||
|          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||||
|     <modelVersion>4.0.0</modelVersion> | ||||
|     <groupId>com.baeldung.dddmodules.shippingcontext</groupId> | ||||
|     <artifactId>shippingcontext</artifactId> | ||||
|     <version>1.0</version> | ||||
|     <packaging>jar</packaging> | ||||
| 
 | ||||
|     <parent> | ||||
|         <groupId>com.baeldung.dddmodules</groupId> | ||||
|         <artifactId>dddmodules</artifactId> | ||||
|         <version>1.0</version> | ||||
|     </parent> | ||||
| 
 | ||||
|     <dependencies> | ||||
|         <dependency> | ||||
|             <groupId>com.baeldung.dddmodules.sharedkernel</groupId> | ||||
|             <artifactId>sharedkernel</artifactId> | ||||
|             <version>${appmodules.version}</version> | ||||
|         </dependency> | ||||
|     </dependencies> | ||||
| 
 | ||||
|     <build> | ||||
|         <plugins> | ||||
|             <plugin> | ||||
|                 <groupId>org.apache.maven.plugins</groupId> | ||||
|                 <artifactId>maven-compiler-plugin</artifactId> | ||||
|                 <configuration> | ||||
|                     <source>${source.version}</source> | ||||
|                     <target>${target.version}</target> | ||||
|                 </configuration> | ||||
|             </plugin> | ||||
|         </plugins> | ||||
|     </build> | ||||
| 
 | ||||
|     <properties> | ||||
|         <source.version>9</source.version> | ||||
|         <target.version>9</target.version> | ||||
|     </properties> | ||||
| 
 | ||||
| </project> | ||||
| @ -0,0 +1,37 @@ | ||||
| package com.baeldung.dddmodules.shippingcontext.model; | ||||
| 
 | ||||
| public class PackageItem { | ||||
|     private int productId; | ||||
|     private float weight; | ||||
|     private float estimatedValue; | ||||
| 
 | ||||
|     public PackageItem(int productId, float weight, float estimatedValue) { | ||||
|         this.productId = productId; | ||||
|         this.weight = weight; | ||||
|         this.estimatedValue = estimatedValue; | ||||
|     } | ||||
| 
 | ||||
|     public int getProductId() { | ||||
|         return productId; | ||||
|     } | ||||
| 
 | ||||
|     public void setProductId(int productId) { | ||||
|         this.productId = productId; | ||||
|     } | ||||
| 
 | ||||
|     public float getWeight() { | ||||
|         return weight; | ||||
|     } | ||||
| 
 | ||||
|     public void setWeight(float weight) { | ||||
|         this.weight = weight; | ||||
|     } | ||||
| 
 | ||||
|     public float getEstimatedValue() { | ||||
|         return estimatedValue; | ||||
|     } | ||||
| 
 | ||||
|     public void setEstimatedValue(float estimatedValue) { | ||||
|         this.estimatedValue = estimatedValue; | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,54 @@ | ||||
| package com.baeldung.dddmodules.shippingcontext.model; | ||||
| 
 | ||||
| import java.util.List; | ||||
| 
 | ||||
| public class Parcel { | ||||
|     private int orderId; | ||||
|     private String address; | ||||
|     private String trackingId; | ||||
|     private List<PackageItem> packageItems; | ||||
| 
 | ||||
|     public Parcel(int orderId, String address, List<PackageItem> packageItems) { | ||||
|         this.orderId = orderId; | ||||
|         this.address = address; | ||||
|         this.packageItems = packageItems; | ||||
|     } | ||||
| 
 | ||||
|     public float calculateTotalWeight() { | ||||
|         return packageItems.stream().map(PackageItem::getWeight) | ||||
|           .reduce(0F, Float::sum); | ||||
|     } | ||||
| 
 | ||||
|     public boolean isTaxable() { | ||||
|         return calculateEstimatedValue() > 100; | ||||
|     } | ||||
| 
 | ||||
|     public float calculateEstimatedValue() { | ||||
|         return packageItems.stream().map(PackageItem::getWeight) | ||||
|           .reduce(0F, Float::sum); | ||||
|     } | ||||
| 
 | ||||
|     public int getOrderId() { | ||||
|         return orderId; | ||||
|     } | ||||
| 
 | ||||
|     public void setOrderId(int orderId) { | ||||
|         this.orderId = orderId; | ||||
|     } | ||||
| 
 | ||||
|     public String getTrackingId() { | ||||
|         return trackingId; | ||||
|     } | ||||
| 
 | ||||
|     public void setTrackingId(String trackingId) { | ||||
|         this.trackingId = trackingId; | ||||
|     } | ||||
| 
 | ||||
|     public String getAddress() { | ||||
|         return address; | ||||
|     } | ||||
| 
 | ||||
|     public void setAddress(String address) { | ||||
|         this.address = address; | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,38 @@ | ||||
| package com.baeldung.dddmodules.shippingcontext.model; | ||||
| 
 | ||||
| import java.util.List; | ||||
| 
 | ||||
| public class ShippableOrder { | ||||
|     private int orderId; | ||||
|     private String address; | ||||
|     private List<PackageItem> packageItems; | ||||
| 
 | ||||
|     public ShippableOrder(int orderId, List<PackageItem> packageItems) { | ||||
|         this.orderId = orderId; | ||||
|         this.packageItems = packageItems; | ||||
|     } | ||||
| 
 | ||||
|     public int getOrderId() { | ||||
|         return orderId; | ||||
|     } | ||||
| 
 | ||||
|     public void setOrderId(int orderId) { | ||||
|         this.orderId = orderId; | ||||
|     } | ||||
| 
 | ||||
|     public List<PackageItem> getPackageItems() { | ||||
|         return packageItems; | ||||
|     } | ||||
| 
 | ||||
|     public void setPackageItems(List<PackageItem> packageItems) { | ||||
|         this.packageItems = packageItems; | ||||
|     } | ||||
| 
 | ||||
|     public String getAddress() { | ||||
|         return address; | ||||
|     } | ||||
| 
 | ||||
|     public void setAddress(String address) { | ||||
|         this.address = address; | ||||
|     } | ||||
| } | ||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user