Merge branch 'eugenp:master' into master
This commit is contained in:
		
						commit
						9892d9ba83
					
				| @ -1,7 +1,5 @@ | ||||
| package com.baeldung.algorithms.dfs; | ||||
| 
 | ||||
| import java.util.LinkedList; | ||||
| import java.util.Queue; | ||||
| import java.util.Stack; | ||||
| 
 | ||||
| public class BinaryTree { | ||||
| @ -124,69 +122,43 @@ public class BinaryTree { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public void traverseLevelOrder() { | ||||
|         if (root == null) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         Queue<Node> nodes = new LinkedList<>(); | ||||
|         nodes.add(root); | ||||
| 
 | ||||
|         while (!nodes.isEmpty()) { | ||||
| 
 | ||||
|             Node node = nodes.remove(); | ||||
| 
 | ||||
|             System.out.print(" " + node.value); | ||||
| 
 | ||||
|             if (node.left != null) { | ||||
|                 nodes.add(node.left); | ||||
|             } | ||||
| 
 | ||||
|             if (node.left != null) { | ||||
|                 nodes.add(node.right); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|      | ||||
|     public void traverseInOrderWithoutRecursion() { | ||||
|         Stack<Node> stack = new Stack<Node>(); | ||||
|         Stack<Node> stack = new Stack<>(); | ||||
|         Node current = root; | ||||
|         stack.push(root); | ||||
|         while(! stack.isEmpty()) { | ||||
|             while(current.left != null) { | ||||
|                 current = current.left;                 | ||||
|                 stack.push(current);                 | ||||
|             } | ||||
|             current = stack.pop(); | ||||
|             visit(current.value); | ||||
|             if(current.right != null) { | ||||
|                 current = current.right;                 | ||||
| 
 | ||||
|         while (current != null || !stack.isEmpty()) { | ||||
|             while (current != null) { | ||||
|                 stack.push(current); | ||||
|                 current = current.left; | ||||
|             } | ||||
| 
 | ||||
|             Node top = stack.pop(); | ||||
|             visit(top.value); | ||||
|             current = top.right; | ||||
|         } | ||||
|     } | ||||
|      | ||||
| 
 | ||||
|     public void traversePreOrderWithoutRecursion() { | ||||
|         Stack<Node> stack = new Stack<Node>(); | ||||
|         Node current = root; | ||||
|         Stack<Node> stack = new Stack<>(); | ||||
|         Node current; | ||||
|         stack.push(root); | ||||
|         while(! stack.isEmpty()) { | ||||
|             current = stack.pop(); | ||||
|             visit(current.value); | ||||
|              | ||||
| 
 | ||||
|             if(current.right != null) | ||||
|                 stack.push(current.right); | ||||
|                  | ||||
| 
 | ||||
|             if(current.left != null) | ||||
|                 stack.push(current.left); | ||||
|         }         | ||||
|         } | ||||
|     } | ||||
|      | ||||
| 
 | ||||
|     public void traversePostOrderWithoutRecursion() { | ||||
|         Stack<Node> stack = new Stack<Node>(); | ||||
|         Stack<Node> stack = new Stack<>(); | ||||
|         Node prev = root; | ||||
|         Node current = root; | ||||
|         Node current; | ||||
|         stack.push(root); | ||||
| 
 | ||||
|         while (!stack.isEmpty()) { | ||||
| @ -206,14 +178,14 @@ public class BinaryTree { | ||||
|                     stack.push(current.left); | ||||
|                 } | ||||
|             } | ||||
|         }    | ||||
|     }     | ||||
|      | ||||
|     private void visit(int value) { | ||||
|         System.out.print(" " + value);         | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     class Node { | ||||
| 
 | ||||
|     private void visit(int value) { | ||||
|         System.out.print(" " + value); | ||||
|     } | ||||
| 
 | ||||
|     static class Node { | ||||
|         int value; | ||||
|         Node left; | ||||
|         Node right; | ||||
|  | ||||
| @ -1,11 +1,11 @@ | ||||
| package com.baeldung.algorithms.dfs; | ||||
| 
 | ||||
| import org.junit.Test; | ||||
| 
 | ||||
| import static org.junit.Assert.assertEquals; | ||||
| import static org.junit.Assert.assertFalse; | ||||
| import static org.junit.Assert.assertTrue; | ||||
| 
 | ||||
| import org.junit.Test; | ||||
| 
 | ||||
| public class BinaryTreeUnitTest { | ||||
| 
 | ||||
|     @Test | ||||
| @ -13,7 +13,7 @@ public class BinaryTreeUnitTest { | ||||
| 
 | ||||
|         BinaryTree bt = createBinaryTree(); | ||||
| 
 | ||||
|         assertTrue(!bt.isEmpty()); | ||||
|         assertFalse(bt.isEmpty()); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
| @ -111,14 +111,6 @@ public class BinaryTreeUnitTest { | ||||
|         bt.traversePostOrderWithoutRecursion(); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void givenABinaryTree_WhenTraversingLevelOrder_ThenPrintValues() { | ||||
| 
 | ||||
|         BinaryTree bt = createBinaryTree(); | ||||
| 
 | ||||
|         bt.traverseLevelOrder(); | ||||
|     } | ||||
| 
 | ||||
|     private BinaryTree createBinaryTree() { | ||||
|         BinaryTree bt = new BinaryTree(); | ||||
| 
 | ||||
|  | ||||
| @ -83,4 +83,4 @@ | ||||
|         <olingo.version>2.0.11</olingo.version> | ||||
|     </properties> | ||||
| 
 | ||||
| </project> | ||||
| </project> | ||||
| @ -9,4 +9,6 @@ This module contains articles about Apache POI. | ||||
| - [Numeric Format Using POI](https://www.baeldung.com/apache-poi-numeric-format) | ||||
| - [Microsoft Word Processing in Java with Apache POI](https://www.baeldung.com/java-microsoft-word-with-apache-poi) | ||||
| - [Creating a MS PowerPoint Presentation in Java](https://www.baeldung.com/apache-poi-slideshow) | ||||
| - [Finding the Last Row in an Excel Spreadsheet From Java](https://www.baeldung.com/java-excel-find-last-row) | ||||
| - [Setting Formulas in Excel with Apache POI](https://www.baeldung.com/java-apache-poi-set-formulas) | ||||
| - More articles: [[<-- prev]](../apache-poi) | ||||
|  | ||||
| @ -22,7 +22,7 @@ | ||||
|     </dependencies> | ||||
| 
 | ||||
|     <properties> | ||||
|         <poi.version>5.0.0</poi.version> | ||||
|         <poi.version>5.2.0</poi.version> | ||||
|     </properties> | ||||
| 
 | ||||
| </project> | ||||
|  | ||||
| @ -1,26 +1,25 @@ | ||||
| package com.baeldung.poi.excel.setformula; | ||||
| 
 | ||||
| import org.apache.poi.xssf.usermodel.XSSFCell; | ||||
| import org.apache.poi.xssf.usermodel.XSSFFormulaEvaluator; | ||||
| import org.apache.poi.xssf.usermodel.XSSFSheet; | ||||
| import org.apache.poi.xssf.usermodel.XSSFWorkbook; | ||||
| 
 | ||||
| import java.io.File; | ||||
| import java.io.FileOutputStream; | ||||
| import java.io.IOException; | ||||
| 
 | ||||
| public class ExcelFormula { | ||||
|     public double setFormula(String fileLocation, XSSFWorkbook wb, String formula) throws IOException { | ||||
|         XSSFSheet sheet = wb.getSheetAt(0); | ||||
|         int lastCellNum = sheet.getRow(0).getLastCellNum(); | ||||
|         XSSFCell formulaCell = sheet.getRow(0).createCell(lastCellNum); | ||||
|         formulaCell.setCellFormula(formula); | ||||
|         XSSFFormulaEvaluator formulaEvaluator = wb.getCreationHelper().createFormulaEvaluator(); | ||||
|         formulaEvaluator.evaluateFormulaCell(formulaCell); | ||||
|         FileOutputStream fileOut = new FileOutputStream(new File(fileLocation)); | ||||
|         wb.write(fileOut); | ||||
|         wb.close(); | ||||
|         fileOut.close(); | ||||
|         return formulaCell.getNumericCellValue(); | ||||
|     } | ||||
| } | ||||
| package com.baeldung.poi.excel.setformula; | ||||
| 
 | ||||
| import org.apache.poi.xssf.usermodel.XSSFCell; | ||||
| import org.apache.poi.xssf.usermodel.XSSFFormulaEvaluator; | ||||
| import org.apache.poi.xssf.usermodel.XSSFSheet; | ||||
| import org.apache.poi.xssf.usermodel.XSSFWorkbook; | ||||
| 
 | ||||
| import java.io.FileOutputStream; | ||||
| import java.io.IOException; | ||||
| 
 | ||||
| public class ExcelFormula { | ||||
|     public double setFormula(String fileLocation, XSSFWorkbook wb, String formula) throws IOException { | ||||
|         XSSFSheet sheet = wb.getSheetAt(0); | ||||
|         int lastCellNum = sheet.getRow(0).getLastCellNum(); | ||||
|         XSSFCell formulaCell = sheet.getRow(0).createCell(lastCellNum); | ||||
|         formulaCell.setCellFormula(formula); | ||||
|         XSSFFormulaEvaluator formulaEvaluator = wb.getCreationHelper().createFormulaEvaluator(); | ||||
|         formulaEvaluator.evaluateFormulaCell(formulaCell); | ||||
|         FileOutputStream fileOut = new FileOutputStream(fileLocation); | ||||
|         wb.write(fileOut); | ||||
|         wb.close(); | ||||
|         fileOut.close(); | ||||
|         return formulaCell.getNumericCellValue(); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,67 @@ | ||||
| package com.baeldung.poi.excel.lastrow; | ||||
| 
 | ||||
| import org.apache.poi.ss.usermodel.Row; | ||||
| import org.apache.poi.ss.usermodel.Sheet; | ||||
| import org.apache.poi.ss.usermodel.Workbook; | ||||
| import org.apache.poi.xssf.usermodel.XSSFWorkbook; | ||||
| import org.junit.Before; | ||||
| import org.junit.Test; | ||||
| 
 | ||||
| import java.io.IOException; | ||||
| import java.net.URISyntaxException; | ||||
| import java.nio.file.Paths; | ||||
| 
 | ||||
| import static org.junit.jupiter.api.Assertions.*; | ||||
| 
 | ||||
| public class LastRowUnitTest { | ||||
|     private static final String FILE_NAME = "lastRowTest.xlsx"; | ||||
|     private String fileLocation; | ||||
| 
 | ||||
|     @Before | ||||
|     public void setup() throws URISyntaxException { | ||||
|         fileLocation = Paths.get(ClassLoader.getSystemResource(FILE_NAME).toURI()).toString(); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void givenExampleGrid_whenGetRow_thenReturnRowObjectIfModified() throws IOException { | ||||
|         Workbook workbook = new XSSFWorkbook(fileLocation); | ||||
|         Sheet sheet = workbook.getSheetAt(0); | ||||
| 
 | ||||
|         assertEquals(7, sheet.getLastRowNum()); | ||||
|         assertEquals(6, sheet.getPhysicalNumberOfRows()); | ||||
| 
 | ||||
|         assertNotNull(sheet.getRow(0)); | ||||
|         assertNotNull(sheet.getRow(1)); | ||||
|         assertNotNull(sheet.getRow(2)); | ||||
|         assertNotNull(sheet.getRow(3)); | ||||
|         assertNull(sheet.getRow(4)); | ||||
|         assertNull(sheet.getRow(5)); | ||||
|         assertNotNull(sheet.getRow(6)); | ||||
|         assertNotNull(sheet.getRow(7)); | ||||
|         assertNull(sheet.getRow(8)); | ||||
| 
 | ||||
|         assertSame(sheet.getRow(7), getLastRowFromSheet(sheet)); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void givenEmptySheet_whenGetRow_thenReturnNull() throws IOException { | ||||
|         Workbook workbook = new XSSFWorkbook(fileLocation); | ||||
|         Sheet sheet = workbook.getSheetAt(1); | ||||
| 
 | ||||
|         assertEquals(-1, sheet.getLastRowNum()); | ||||
|         assertEquals(0, sheet.getPhysicalNumberOfRows()); | ||||
| 
 | ||||
|         assertNull(sheet.getRow(0)); | ||||
| 
 | ||||
|         assertSame(sheet.getRow(0), getLastRowFromSheet(sheet)); | ||||
|     } | ||||
| 
 | ||||
|     public static Row getLastRowFromSheet(Sheet sheet) { | ||||
|         Row lastRow = null; | ||||
|         int lastRowNum = sheet.getLastRowNum(); | ||||
|         if (lastRowNum >= 0) { | ||||
|             lastRow = sheet.getRow(lastRowNum); | ||||
|         } | ||||
|         return lastRow; | ||||
|     } | ||||
| } | ||||
| @ -3,18 +3,19 @@ package com.baeldung.poi.excel.setformula; | ||||
| import org.apache.poi.ss.util.CellReference; | ||||
| import org.apache.poi.xssf.usermodel.XSSFSheet; | ||||
| import org.apache.poi.xssf.usermodel.XSSFWorkbook; | ||||
| import org.junit.Assert; | ||||
| import org.junit.jupiter.api.BeforeEach; | ||||
| import org.junit.jupiter.api.Test; | ||||
| 
 | ||||
| import java.io.File; | ||||
| import java.io.FileInputStream; | ||||
| import java.io.IOException; | ||||
| import java.net.URISyntaxException; | ||||
| import java.nio.file.Paths; | ||||
| 
 | ||||
| import static org.junit.jupiter.api.Assertions.assertEquals; | ||||
| 
 | ||||
| class ExcelFormulaUnitTest { | ||||
|     private static String FILE_NAME = "com/baeldung/poi/excel/setformula/SetFormulaTest.xlsx"; | ||||
|     private static final String FILE_NAME = "com/baeldung/poi/excel/setformula/SetFormulaTest.xlsx"; | ||||
| 
 | ||||
|     private String fileLocation; | ||||
|     private ExcelFormula excelFormula; | ||||
| 
 | ||||
| @ -26,7 +27,7 @@ class ExcelFormulaUnitTest { | ||||
| 
 | ||||
|     @Test | ||||
|     void givenExcelData_whenSetFormula_thenSuccess() throws IOException { | ||||
|         FileInputStream inputStream = new FileInputStream(new File(fileLocation)); | ||||
|         FileInputStream inputStream = new FileInputStream(fileLocation); | ||||
|         XSSFWorkbook wb = new XSSFWorkbook(inputStream); | ||||
|         XSSFSheet sheet = wb.getSheetAt(0); | ||||
|         double resultColumnA = 0; | ||||
| @ -46,6 +47,6 @@ class ExcelFormulaUnitTest { | ||||
| 
 | ||||
|         double resultValue = excelFormula.setFormula(fileLocation, wb, sumFormulaForColumnA + "-" + sumFormulaForColumnB); | ||||
| 
 | ||||
|         Assert.assertEquals(resultColumnA - resultColumnB, resultValue, 0d); | ||||
|         assertEquals(resultColumnA - resultColumnB, resultValue, 0d); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										
											BIN
										
									
								
								apache-poi-2/src/test/resources/lastRowTest.xlsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								apache-poi-2/src/test/resources/lastRowTest.xlsx
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| @ -8,7 +8,6 @@ This module contains articles about Apache POI. | ||||
| - [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://www.baeldung.com/apache-poi-read-cell-value-formula) | ||||
| - [Setting Formulas in Excel with Apache POI](https://www.baeldung.com/java-apache-poi-set-formulas) | ||||
| - [Insert a Row in Excel Using Apache POI](https://www.baeldung.com/apache-poi-insert-excel-row) | ||||
| - [Multiline Text in Excel Cell Using Apache POI](https://www.baeldung.com/apache-poi-write-multiline-text) | ||||
| - [Set Background Color of a Cell with Apache POI](https://www.baeldung.com/apache-poi-background-color) | ||||
|  | ||||
| @ -1,128 +0,0 @@ | ||||
| package com.baeldung.poi.excel; | ||||
| 
 | ||||
| import java.io.File; | ||||
| import java.io.FileInputStream; | ||||
| import java.io.IOException; | ||||
| 
 | ||||
| import org.apache.poi.ss.usermodel.Cell; | ||||
| import org.apache.poi.ss.usermodel.CellType; | ||||
| import org.apache.poi.ss.usermodel.DateUtil; | ||||
| import org.apache.poi.ss.usermodel.Row; | ||||
| import org.apache.poi.ss.usermodel.Sheet; | ||||
| import org.apache.poi.ss.usermodel.Workbook; | ||||
| import org.apache.poi.xssf.usermodel.XSSFWorkbook; | ||||
| 
 | ||||
| public class ExcelUtility { | ||||
| <<<<<<< HEAD | ||||
|     private static final String ENDLINE = System.getProperty("line.separator"); | ||||
| 
 | ||||
|     public static String readExcel(String filePath) throws IOException { | ||||
|         File file = new File(filePath); | ||||
|         FileInputStream inputStream = null; | ||||
|         StringBuilder toReturn = new StringBuilder(); | ||||
|         try { | ||||
|             inputStream = new FileInputStream(file); | ||||
|             Workbook baeuldungWorkBook = new XSSFWorkbook(inputStream); | ||||
|             for (Sheet sheet : baeuldungWorkBook) { | ||||
|                 toReturn.append("--------------------------------------------------------------------") | ||||
|                     .append(ENDLINE); | ||||
|                 toReturn.append("Worksheet :") | ||||
|                     .append(sheet.getSheetName()) | ||||
|                     .append(ENDLINE); | ||||
|                 toReturn.append("--------------------------------------------------------------------") | ||||
|                     .append(ENDLINE); | ||||
|                 int firstRow = sheet.getFirstRowNum(); | ||||
|                 int lastRow = sheet.getLastRowNum(); | ||||
|                 for (int index = firstRow + 1; index <= lastRow; index++) { | ||||
|                     Row row = sheet.getRow(index); | ||||
|                     toReturn.append("|| "); | ||||
|                     for (int cellIndex = row.getFirstCellNum(); cellIndex < row.getLastCellNum(); cellIndex++) { | ||||
|                         Cell cell = row.getCell(cellIndex, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK); | ||||
|                         printCellValue(cell, toReturn); | ||||
|                     } | ||||
|                     toReturn.append(" ||") | ||||
|                         .append(ENDLINE); | ||||
|                 } | ||||
|             } | ||||
|             inputStream.close(); | ||||
| 
 | ||||
|         } catch (IOException e) { | ||||
|             throw e; | ||||
|         } | ||||
|         return toReturn.toString(); | ||||
|     } | ||||
| 
 | ||||
|     public static void printCellValue(Cell cell, StringBuilder toReturn) { | ||||
|         CellType cellType = cell.getCellType() | ||||
|             .equals(CellType.FORMULA) ? cell.getCachedFormulaResultType() : cell.getCellType(); | ||||
|         if (cellType.equals(CellType.STRING)) { | ||||
|             toReturn.append(cell.getStringCellValue()) | ||||
|                 .append(" | "); | ||||
|         } | ||||
|         if (cellType.equals(CellType.NUMERIC)) { | ||||
|             if (DateUtil.isCellDateFormatted(cell)) { | ||||
|                 toReturn.append(cell.getDateCellValue()) | ||||
|                     .append(" | "); | ||||
|             } else { | ||||
|                 toReturn.append(cell.getNumericCellValue()) | ||||
|                     .append(" | "); | ||||
|             } | ||||
|         } | ||||
|         if (cellType.equals(CellType.BOOLEAN)) { | ||||
|             toReturn.append(cell.getBooleanCellValue()) | ||||
|                 .append(" | "); | ||||
|         } | ||||
|     } | ||||
| ======= | ||||
| 	private static final String ENDLINE = System.getProperty("line.separator"); | ||||
| 
 | ||||
| 	public static String readExcel(String filePath) throws IOException { | ||||
| 		File file = new File(filePath); | ||||
| 		FileInputStream inputStream = null; | ||||
| 		StringBuilder toReturn = new StringBuilder(); | ||||
| 		try { | ||||
| 			inputStream = new FileInputStream(file); | ||||
| 			Workbook baeuldungWorkBook = new XSSFWorkbook(inputStream); | ||||
| 			for (Sheet sheet : baeuldungWorkBook) { | ||||
| 				toReturn.append("--------------------------------------------------------------------").append(ENDLINE); | ||||
| 				toReturn.append("Worksheet :").append(sheet.getSheetName()).append(ENDLINE); | ||||
| 				toReturn.append("--------------------------------------------------------------------").append(ENDLINE); | ||||
| 				int firstRow = sheet.getFirstRowNum(); | ||||
| 				int lastRow = sheet.getLastRowNum(); | ||||
| 				for (int index = firstRow + 1; index <= lastRow; index++) { | ||||
| 					Row row = sheet.getRow(index); | ||||
| 					toReturn.append("|| "); | ||||
| 					for (int cellIndex = row.getFirstCellNum(); cellIndex < row.getLastCellNum(); cellIndex++) { | ||||
| 						Cell cell = row.getCell(cellIndex, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK); | ||||
| 						printCellValue(cell, toReturn); | ||||
| 					} | ||||
| 					toReturn.append(" ||").append(ENDLINE); | ||||
| 				} | ||||
| 			} | ||||
| 			inputStream.close(); | ||||
| 
 | ||||
| 		} catch (IOException e) { | ||||
| 			throw e; | ||||
| 		} | ||||
| 		return toReturn.toString(); | ||||
| 	} | ||||
| 
 | ||||
| 	public static void printCellValue(Cell cell, StringBuilder toReturn) { | ||||
| 		CellType cellType = cell.getCellType().equals(CellType.FORMULA) ? cell.getCachedFormulaResultType() | ||||
| 				: cell.getCellType(); | ||||
| 		if (cellType.equals(CellType.STRING)) { | ||||
| 			toReturn.append(cell.getStringCellValue()).append(" | "); | ||||
| 		} | ||||
| 		if (cellType.equals(CellType.NUMERIC)) { | ||||
| 			if (DateUtil.isCellDateFormatted(cell)) { | ||||
| 				toReturn.append(cell.getDateCellValue()).append(" | "); | ||||
| 			} else { | ||||
| 				toReturn.append(cell.getNumericCellValue()).append(" | "); | ||||
| 			} | ||||
| 		} | ||||
| 		if (cellType.equals(CellType.BOOLEAN)) { | ||||
| 			toReturn.append(cell.getBooleanCellValue()).append(" | "); | ||||
| 		} | ||||
| 	} | ||||
| >>>>>>> master | ||||
| } | ||||
| @ -1,112 +0,0 @@ | ||||
| package com.baeldung.poi.excel; | ||||
| 
 | ||||
| import static org.junit.Assert.assertEquals; | ||||
| import static org.junit.jupiter.api.Assertions.assertThrows; | ||||
| 
 | ||||
| import java.io.IOException; | ||||
| import java.net.URISyntaxException; | ||||
| import java.nio.file.Paths; | ||||
| import java.text.ParseException; | ||||
| import java.text.SimpleDateFormat; | ||||
| 
 | ||||
| import org.junit.Before; | ||||
| import org.junit.Test; | ||||
| 
 | ||||
| public class ExcelUtilityUnitTest { | ||||
| <<<<<<< HEAD | ||||
|     private static final String FILE_NAME = "baeldung.xlsx"; | ||||
|     private String fileLocation; | ||||
|     private static final String ENDLINE = System.getProperty("line.separator"); | ||||
|     private StringBuilder output; | ||||
| 
 | ||||
|     @Before | ||||
|     public void setupUnitTest() throws IOException, URISyntaxException, ParseException { | ||||
|         output = new StringBuilder(); | ||||
|         output.append("--------------------------------------------------------------------") | ||||
|             .append(ENDLINE); | ||||
|         output.append("Worksheet :Sheet1") | ||||
|             .append(ENDLINE); | ||||
|         output.append("--------------------------------------------------------------------") | ||||
|             .append(ENDLINE); | ||||
|         output.append("|| Name1 | Surname1 | 3.55696564113E11 | ") | ||||
|             .append(new SimpleDateFormat("dd/MM/yyyy").parse("4/11/2021") | ||||
|                 .toString()) | ||||
|             .append(" | ‡ |  ||") | ||||
|             .append(ENDLINE); | ||||
|         output.append("|| Name2 | Surname2 | 5.646513512E9 | ") | ||||
|             .append(new SimpleDateFormat("dd/MM/yyyy").parse("4/12/2021") | ||||
|                 .toString()) | ||||
|             .append(" | false |  ||") | ||||
|             .append(ENDLINE); | ||||
|         output.append("|| Name3 | Surname3 | 3.55696564113E11 | ") | ||||
|             .append(new SimpleDateFormat("dd/MM/yyyy").parse("4/11/2021") | ||||
|                 .toString()) | ||||
|             .append(" | 7.17039641738E11 |  ||") | ||||
|             .append(ENDLINE); | ||||
|         output.append("--------------------------------------------------------------------") | ||||
|             .append(ENDLINE); | ||||
|         output.append("Worksheet :Sheet2") | ||||
|             .append(ENDLINE); | ||||
|         output.append("--------------------------------------------------------------------") | ||||
|             .append(ENDLINE); | ||||
|         output.append("|| Name4 | Surname4 | 3.55675623232E11 | 13/04/2021 |  ||") | ||||
|             .append(ENDLINE); | ||||
| 
 | ||||
|         fileLocation = Paths.get(ClassLoader.getSystemResource(FILE_NAME) | ||||
|             .toURI()) | ||||
|             .toString(); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void givenStringPath_whenReadExcel_thenReturnStringValue() throws IOException { | ||||
|         assertEquals(output.toString(), ExcelUtility.readExcel(fileLocation)); | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void givenStringPath_whenReadExcel_thenThrowException() { | ||||
|         assertThrows(IOException.class, () -> { | ||||
|             ExcelUtility.readExcel("baeldung"); | ||||
|         }); | ||||
|     } | ||||
| ======= | ||||
| 	private static final String FILE_NAME = "baeldung.xlsx"; | ||||
| 	private String fileLocation; | ||||
| 	private static final String ENDLINE = System.getProperty("line.separator"); | ||||
| 	private StringBuilder output; | ||||
| 
 | ||||
| 	@Before | ||||
| 	public void setupUnitTest() throws IOException, URISyntaxException, ParseException { | ||||
| 		output = new StringBuilder(); | ||||
| 		output.append("--------------------------------------------------------------------").append(ENDLINE); | ||||
| 		output.append("Worksheet :Sheet1").append(ENDLINE); | ||||
| 		output.append("--------------------------------------------------------------------").append(ENDLINE); | ||||
| 		output.append("|| Name1 | Surname1 | 3.55696564113E11 | ").append(new SimpleDateFormat("dd/MM/yyyy").parse("4/11/2021").toString()).append(" | ‡ |  ||") | ||||
| 				.append(ENDLINE); | ||||
| 		output.append("|| Name2 | Surname2 | 5.646513512E9 | ").append(new SimpleDateFormat("dd/MM/yyyy").parse("4/12/2021").toString()).append(" | false |  ||") | ||||
| 				.append(ENDLINE); | ||||
| 		output.append("|| Name3 | Surname3 | 3.55696564113E11 | ").append(new SimpleDateFormat("dd/MM/yyyy").parse("4/11/2021").toString()).append(" | 7.17039641738E11 |  ||") | ||||
| 				.append(ENDLINE); | ||||
| 		output.append("--------------------------------------------------------------------").append(ENDLINE); | ||||
| 		output.append("Worksheet :Sheet2").append(ENDLINE); | ||||
| 		output.append("--------------------------------------------------------------------").append(ENDLINE); | ||||
| 		output.append("|| Name4 | Surname4 | 3.55675623232E11 | 13/04/2021 |  ||").append(ENDLINE); | ||||
| 
 | ||||
| 		fileLocation = Paths.get(ClassLoader.getSystemResource(FILE_NAME).toURI()).toString(); | ||||
| 	} | ||||
| 
 | ||||
| 	@Test | ||||
| 	public void givenStringPath_whenReadExcel_thenReturnStringValue() throws IOException { | ||||
| 		assertEquals(output.toString(), ExcelUtility.readExcel(fileLocation)); | ||||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| 	@Test | ||||
| 	public void givenStringPath_whenReadExcel_thenThrowException() { | ||||
| 		assertThrows(IOException.class, () -> { | ||||
| 			ExcelUtility.readExcel("baeldung"); | ||||
| 		}); | ||||
| 	} | ||||
| >>>>>>> master | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										34
									
								
								apache-tomcat/pom.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								apache-tomcat/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</groupId> | ||||
|     <artifactId>apache-tomcat</artifactId> | ||||
|     <version>1.0.0-SNAPSHOT</version> | ||||
|     <name>apache-tomcat</name> | ||||
|     <packaging>pom</packaging> | ||||
| 
 | ||||
|     <parent> | ||||
|         <groupId>com.baeldung</groupId> | ||||
|         <artifactId>parent-modules</artifactId> | ||||
|         <version>1.0.0-SNAPSHOT</version> | ||||
|     </parent> | ||||
| 
 | ||||
|     <modules> | ||||
|         <module>sso</module> | ||||
|     </modules> | ||||
| 
 | ||||
|     <build> | ||||
|         <defaultGoal>install</defaultGoal> | ||||
|         <pluginManagement> | ||||
|             <plugins> | ||||
|                 <plugin> | ||||
|                     <groupId>org.codehaus.mojo</groupId> | ||||
|                     <artifactId>exec-maven-plugin</artifactId> | ||||
|                 </plugin> | ||||
|             </plugins> | ||||
|         </pluginManagement> | ||||
|     </build> | ||||
| </project> | ||||
							
								
								
									
										24
									
								
								apache-tomcat/sso/.dockerignore
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								apache-tomcat/sso/.dockerignore
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,24 @@ | ||||
| **/.classpath | ||||
| **/.dockerignore | ||||
| **/.env | ||||
| **/.git | ||||
| **/.gitignore | ||||
| **/.project | ||||
| **/.settings | ||||
| **/.toolstarget | ||||
| **/.vs | ||||
| **/.vscode | ||||
| **/*.*proj.user | ||||
| **/*.dbmdl | ||||
| **/*.jfm | ||||
| **/bin | ||||
| **/charts | ||||
| **/docker-compose* | ||||
| **/compose* | ||||
| **/Dockerfile* | ||||
| **/node_modules | ||||
| **/npm-debug.log | ||||
| **/obj | ||||
| **/secrets.dev.yaml | ||||
| **/values.dev.yaml | ||||
| README.md | ||||
							
								
								
									
										7
									
								
								apache-tomcat/sso/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								apache-tomcat/sso/README.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | ||||
| ### Related articles | ||||
| 
 | ||||
| - [SSO with Apache Tomcat](https://www.baeldung.com/apache-tomcat-sso) | ||||
| 
 | ||||
| ### Launch Example using Docker | ||||
| 
 | ||||
| $ docker-compose up | ||||
							
								
								
									
										11
									
								
								apache-tomcat/sso/docker-compose.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								apache-tomcat/sso/docker-compose.yml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | ||||
| version: '3.4' | ||||
| 
 | ||||
| services: | ||||
|   tomcatsso: | ||||
|     image: tomcat:10-jdk17-openjdk-slim-buster | ||||
|     volumes: | ||||
|       - ./res/conf:/usr/local/tomcat/conf | ||||
|       - ./webapps:/usr/local/tomcat/webapps | ||||
|     ports: | ||||
|       - 8080:8080 | ||||
|     command: ["catalina.sh", "run"] | ||||
							
								
								
									
										18
									
								
								apache-tomcat/sso/pom.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								apache-tomcat/sso/pom.xml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,18 @@ | ||||
| <?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.apache_tomcat</groupId> | ||||
|     <artifactId>sso</artifactId> | ||||
|     <version>1.0.0-SNAPSHOT</version> | ||||
|     <packaging>pom</packaging> | ||||
| 
 | ||||
|     <parent> | ||||
|         <groupId>com.baeldung</groupId> | ||||
|         <artifactId>apache-tomcat</artifactId> | ||||
|         <version>1.0.0-SNAPSHOT</version> | ||||
|     </parent> | ||||
| 
 | ||||
| </project> | ||||
							
								
								
									
										264
									
								
								apache-tomcat/sso/res/conf/catalina.policy
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										264
									
								
								apache-tomcat/sso/res/conf/catalina.policy
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,264 @@ | ||||
| // Licensed to the Apache Software Foundation (ASF) under one or more | ||||
| // contributor license agreements.  See the NOTICE file distributed with | ||||
| // this work for additional information regarding copyright ownership. | ||||
| // The ASF licenses this file to You under the Apache License, Version 2.0 | ||||
| // (the "License"); you may not use this file except in compliance with | ||||
| // the License.  You may obtain a copy of the License at | ||||
| // | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| // See the License for the specific language governing permissions and | ||||
| // limitations under the License. | ||||
| 
 | ||||
| // ============================================================================ | ||||
| // catalina.policy - Security Policy Permissions for Tomcat | ||||
| // | ||||
| // This file contains a default set of security policies to be enforced (by the | ||||
| // JVM) when Catalina is executed with the "-security" option.  In addition | ||||
| // to the permissions granted here, the following additional permissions are | ||||
| // granted to each web application: | ||||
| // | ||||
| // * Read access to the web application's document root directory | ||||
| // * Read, write and delete access to the web application's working directory | ||||
| // ============================================================================ | ||||
| 
 | ||||
| 
 | ||||
| // ========== SYSTEM CODE PERMISSIONS ========================================= | ||||
| 
 | ||||
| 
 | ||||
| // These permissions apply to javac | ||||
| grant codeBase "file:${java.home}/lib/-" { | ||||
|         permission java.security.AllPermission; | ||||
| }; | ||||
| 
 | ||||
| // These permissions apply to all shared system extensions | ||||
| grant codeBase "file:${java.home}/jre/lib/ext/-" { | ||||
|         permission java.security.AllPermission; | ||||
| }; | ||||
| 
 | ||||
| // These permissions apply to javac when ${java.home} points at $JAVA_HOME/jre | ||||
| grant codeBase "file:${java.home}/../lib/-" { | ||||
|         permission java.security.AllPermission; | ||||
| }; | ||||
| 
 | ||||
| // These permissions apply to all shared system extensions when | ||||
| // ${java.home} points at $JAVA_HOME/jre | ||||
| grant codeBase "file:${java.home}/lib/ext/-" { | ||||
|         permission java.security.AllPermission; | ||||
| }; | ||||
| 
 | ||||
| // This permission is required when using javac to compile JSPs on Java 9 | ||||
| // onwards | ||||
| //grant codeBase "jrt:/jdk.compiler" { | ||||
| //        permission java.security.AllPermission; | ||||
| //}; | ||||
| 
 | ||||
| 
 | ||||
| // ========== CATALINA CODE PERMISSIONS ======================================= | ||||
| 
 | ||||
| // These permissions apply to the daemon code | ||||
| grant codeBase "file:${catalina.home}/bin/commons-daemon.jar" { | ||||
|         permission java.security.AllPermission; | ||||
| }; | ||||
| 
 | ||||
| // These permissions apply to the logging API | ||||
| // Note: If tomcat-juli.jar is in ${catalina.base} and not in ${catalina.home}, | ||||
| // update this section accordingly. | ||||
| //  grant codeBase "file:${catalina.base}/bin/tomcat-juli.jar" {..} | ||||
| grant codeBase "file:${catalina.home}/bin/tomcat-juli.jar" { | ||||
|         permission java.io.FilePermission | ||||
|          "${java.home}${file.separator}lib${file.separator}logging.properties", "read"; | ||||
| 
 | ||||
|         permission java.io.FilePermission | ||||
|          "${catalina.base}${file.separator}conf${file.separator}logging.properties", "read"; | ||||
|         permission java.io.FilePermission | ||||
|          "${catalina.base}${file.separator}logs", "read, write"; | ||||
|         permission java.io.FilePermission | ||||
|          "${catalina.base}${file.separator}logs${file.separator}*", "read, write, delete"; | ||||
| 
 | ||||
|         permission java.lang.RuntimePermission "shutdownHooks"; | ||||
|         permission java.lang.RuntimePermission "getClassLoader"; | ||||
|         permission java.lang.RuntimePermission "setContextClassLoader"; | ||||
| 
 | ||||
|         permission java.lang.management.ManagementPermission "monitor"; | ||||
| 
 | ||||
|         permission java.util.logging.LoggingPermission "control"; | ||||
| 
 | ||||
|         permission java.util.PropertyPermission "java.util.logging.config.class", "read"; | ||||
|         permission java.util.PropertyPermission "java.util.logging.config.file", "read"; | ||||
|         permission java.util.PropertyPermission "org.apache.juli.AsyncMaxRecordCount", "read"; | ||||
|         permission java.util.PropertyPermission "org.apache.juli.AsyncOverflowDropType", "read"; | ||||
|         permission java.util.PropertyPermission "org.apache.juli.ClassLoaderLogManager.debug", "read"; | ||||
|         permission java.util.PropertyPermission "catalina.base", "read"; | ||||
| 
 | ||||
|         // Note: To enable per context logging configuration, permit read access to | ||||
|         // the appropriate file. Be sure that the logging configuration is | ||||
|         // secure before enabling such access. | ||||
|         // E.g. for the examples web application (uncomment and unwrap | ||||
|         // the following to be on a single line): | ||||
|         // permission java.io.FilePermission "${catalina.base}${file.separator} | ||||
|         //  webapps${file.separator}examples${file.separator}WEB-INF | ||||
|         //  ${file.separator}classes${file.separator}logging.properties", "read"; | ||||
| }; | ||||
| 
 | ||||
| // These permissions apply to the server startup code | ||||
| grant codeBase "file:${catalina.home}/bin/bootstrap.jar" { | ||||
|         permission java.security.AllPermission; | ||||
| }; | ||||
| 
 | ||||
| // These permissions apply to the servlet API classes | ||||
| // and those that are shared across all class loaders | ||||
| // located in the "lib" directory | ||||
| grant codeBase "file:${catalina.home}/lib/-" { | ||||
|         permission java.security.AllPermission; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| // If using a per instance lib directory, i.e. ${catalina.base}/lib, | ||||
| // then the following permission will need to be uncommented | ||||
| // grant codeBase "file:${catalina.base}/lib/-" { | ||||
| //         permission java.security.AllPermission; | ||||
| // }; | ||||
| 
 | ||||
| 
 | ||||
| // ========== WEB APPLICATION PERMISSIONS ===================================== | ||||
| 
 | ||||
| 
 | ||||
| // These permissions are granted by default to all web applications | ||||
| // In addition, a web application will be given a read FilePermission | ||||
| // for all files and directories in its document root. | ||||
| grant { | ||||
|     // Required for JNDI lookup of named JDBC DataSource's and | ||||
|     // javamail named MimePart DataSource used to send mail | ||||
|     permission java.util.PropertyPermission "java.home", "read"; | ||||
|     permission java.util.PropertyPermission "java.naming.*", "read"; | ||||
|     permission java.util.PropertyPermission "javax.sql.*", "read"; | ||||
| 
 | ||||
|     // OS Specific properties to allow read access | ||||
|     permission java.util.PropertyPermission "os.name", "read"; | ||||
|     permission java.util.PropertyPermission "os.version", "read"; | ||||
|     permission java.util.PropertyPermission "os.arch", "read"; | ||||
|     permission java.util.PropertyPermission "file.separator", "read"; | ||||
|     permission java.util.PropertyPermission "path.separator", "read"; | ||||
|     permission java.util.PropertyPermission "line.separator", "read"; | ||||
| 
 | ||||
|     // JVM properties to allow read access | ||||
|     permission java.util.PropertyPermission "java.version", "read"; | ||||
|     permission java.util.PropertyPermission "java.vendor", "read"; | ||||
|     permission java.util.PropertyPermission "java.vendor.url", "read"; | ||||
|     permission java.util.PropertyPermission "java.class.version", "read"; | ||||
|     permission java.util.PropertyPermission "java.specification.version", "read"; | ||||
|     permission java.util.PropertyPermission "java.specification.vendor", "read"; | ||||
|     permission java.util.PropertyPermission "java.specification.name", "read"; | ||||
| 
 | ||||
|     permission java.util.PropertyPermission "java.vm.specification.version", "read"; | ||||
|     permission java.util.PropertyPermission "java.vm.specification.vendor", "read"; | ||||
|     permission java.util.PropertyPermission "java.vm.specification.name", "read"; | ||||
|     permission java.util.PropertyPermission "java.vm.version", "read"; | ||||
|     permission java.util.PropertyPermission "java.vm.vendor", "read"; | ||||
|     permission java.util.PropertyPermission "java.vm.name", "read"; | ||||
| 
 | ||||
|     // Required for OpenJMX | ||||
|     permission java.lang.RuntimePermission "getAttribute"; | ||||
| 
 | ||||
|     // Allow read of JAXP compliant XML parser debug | ||||
|     permission java.util.PropertyPermission "jaxp.debug", "read"; | ||||
| 
 | ||||
|     // All JSPs need to be able to read this package | ||||
|     permission java.lang.RuntimePermission "accessClassInPackage.org.apache.tomcat"; | ||||
| 
 | ||||
|     // Precompiled JSPs need access to these packages. | ||||
|     permission java.lang.RuntimePermission "accessClassInPackage.org.apache.jasper.el"; | ||||
|     permission java.lang.RuntimePermission "accessClassInPackage.org.apache.jasper.runtime"; | ||||
|     permission java.lang.RuntimePermission | ||||
|      "accessClassInPackage.org.apache.jasper.runtime.*"; | ||||
| 
 | ||||
|     // Applications using WebSocket need to be able to access these packages | ||||
|     permission java.lang.RuntimePermission "accessClassInPackage.org.apache.tomcat.websocket"; | ||||
|     permission java.lang.RuntimePermission "accessClassInPackage.org.apache.tomcat.websocket.server"; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| // The Manager application needs access to the following packages to support the | ||||
| // session display functionality. It also requires the custom Tomcat | ||||
| // DeployXmlPermission to enable the use of META-INF/context.xml | ||||
| // These settings support the following configurations: | ||||
| // - default CATALINA_HOME == CATALINA_BASE | ||||
| // - CATALINA_HOME != CATALINA_BASE, per instance Manager in CATALINA_BASE | ||||
| // - CATALINA_HOME != CATALINA_BASE, shared Manager in CATALINA_HOME | ||||
| grant codeBase "file:${catalina.base}/webapps/manager/-" { | ||||
|     permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina"; | ||||
|     permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina.ha.session"; | ||||
|     permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina.manager"; | ||||
|     permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina.manager.util"; | ||||
|     permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina.util"; | ||||
|     permission org.apache.catalina.security.DeployXmlPermission "manager"; | ||||
| }; | ||||
| grant codeBase "file:${catalina.home}/webapps/manager/-" { | ||||
|     permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina"; | ||||
|     permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina.ha.session"; | ||||
|     permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina.manager"; | ||||
|     permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina.manager.util"; | ||||
|     permission java.lang.RuntimePermission "accessClassInPackage.org.apache.catalina.util"; | ||||
|     permission org.apache.catalina.security.DeployXmlPermission "manager"; | ||||
| }; | ||||
| 
 | ||||
| // The Host Manager application needs the custom Tomcat DeployXmlPermission to | ||||
| // enable the use of META-INF/context.xml | ||||
| // These settings support the following configurations: | ||||
| // - default CATALINA_HOME == CATALINA_BASE | ||||
| // - CATALINA_HOME != CATALINA_BASE, per instance Host Manager in CATALINA_BASE | ||||
| // - CATALINA_HOME != CATALINA_BASE, shared Host Manager in CATALINA_HOME | ||||
| grant codeBase "file:${catalina.base}/webapps/host-manager/-" { | ||||
|     permission org.apache.catalina.security.DeployXmlPermission "host-manager"; | ||||
| }; | ||||
| grant codeBase "file:${catalina.home}/webapps/host-manager/-" { | ||||
|     permission org.apache.catalina.security.DeployXmlPermission "host-manager"; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| // You can assign additional permissions to particular web applications by | ||||
| // adding additional "grant" entries here, based on the code base for that | ||||
| // application, /WEB-INF/classes/, or /WEB-INF/lib/ jar files. | ||||
| // | ||||
| // Different permissions can be granted to JSP pages, classes loaded from | ||||
| // the /WEB-INF/classes/ directory, all jar files in the /WEB-INF/lib/ | ||||
| // directory, or even to individual jar files in the /WEB-INF/lib/ directory. | ||||
| // | ||||
| // For instance, assume that the standard "examples" application | ||||
| // included a JDBC driver that needed to establish a network connection to the | ||||
| // corresponding database and used the scrape taglib to get the weather from | ||||
| // the NOAA web server.  You might create a "grant" entries like this: | ||||
| // | ||||
| // The permissions granted to the context root directory apply to JSP pages. | ||||
| // grant codeBase "file:${catalina.base}/webapps/examples/-" { | ||||
| //      permission java.net.SocketPermission "dbhost.mycompany.com:5432", "connect"; | ||||
| //      permission java.net.SocketPermission "*.noaa.gov:80", "connect"; | ||||
| // }; | ||||
| // | ||||
| // The permissions granted to the context WEB-INF/classes directory | ||||
| // grant codeBase "file:${catalina.base}/webapps/examples/WEB-INF/classes/-" { | ||||
| // }; | ||||
| // | ||||
| // The permission granted to your JDBC driver | ||||
| // grant codeBase "jar:file:${catalina.base}/webapps/examples/WEB-INF/lib/driver.jar!/-" { | ||||
| //      permission java.net.SocketPermission "dbhost.mycompany.com:5432", "connect"; | ||||
| // }; | ||||
| // The permission granted to the scrape taglib | ||||
| // grant codeBase "jar:file:${catalina.base}/webapps/examples/WEB-INF/lib/scrape.jar!/-" { | ||||
| //      permission java.net.SocketPermission "*.noaa.gov:80", "connect"; | ||||
| // }; | ||||
| 
 | ||||
| // To grant permissions for web applications using packed WAR files, use the | ||||
| // Tomcat specific WAR url scheme. | ||||
| // | ||||
| // The permissions granted to the entire web application | ||||
| // grant codeBase "war:file:${catalina.base}/webapps/examples.war*/-" { | ||||
| // }; | ||||
| // | ||||
| // The permissions granted to a specific JAR | ||||
| // grant codeBase "war:file:${catalina.base}/webapps/examples.war*/WEB-INF/lib/foo.jar" { | ||||
| // }; | ||||
							
								
								
									
										208
									
								
								apache-tomcat/sso/res/conf/catalina.properties
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										208
									
								
								apache-tomcat/sso/res/conf/catalina.properties
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,208 @@ | ||||
| # Licensed to the Apache Software Foundation (ASF) under one or more | ||||
| # contributor license agreements.  See the NOTICE file distributed with | ||||
| # this work for additional information regarding copyright ownership. | ||||
| # The ASF licenses this file to You under the Apache License, Version 2.0 | ||||
| # (the "License"); you may not use this file except in compliance with | ||||
| # the License.  You may obtain a copy of the License at | ||||
| # | ||||
| #     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| # | ||||
| # Unless required by applicable law or agreed to in writing, software | ||||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| # See the License for the specific language governing permissions and | ||||
| # limitations under the License. | ||||
| 
 | ||||
| # | ||||
| # List of comma-separated packages that start with or equal this string | ||||
| # will cause a security exception to be thrown when | ||||
| # passed to checkPackageAccess unless the | ||||
| # corresponding RuntimePermission ("accessClassInPackage."+package) has | ||||
| # been granted. | ||||
| package.access=sun.,org.apache.catalina.,org.apache.coyote.,org.apache.jasper.,org.apache.tomcat. | ||||
| # | ||||
| # List of comma-separated packages that start with or equal this string | ||||
| # will cause a security exception to be thrown when | ||||
| # passed to checkPackageDefinition unless the | ||||
| # corresponding RuntimePermission ("defineClassInPackage."+package) has | ||||
| # been granted. | ||||
| # | ||||
| # by default, no packages are restricted for definition, and none of | ||||
| # the class loaders supplied with the JDK call checkPackageDefinition. | ||||
| # | ||||
| package.definition=sun.,java.,org.apache.catalina.,org.apache.coyote.,\ | ||||
| org.apache.jasper.,org.apache.naming.,org.apache.tomcat. | ||||
| 
 | ||||
| # | ||||
| # | ||||
| # List of comma-separated paths defining the contents of the "common" | ||||
| # classloader. Prefixes should be used to define what is the repository type. | ||||
| # Path may be relative to the CATALINA_HOME or CATALINA_BASE path or absolute. | ||||
| # If left as blank,the JVM system loader will be used as Catalina's "common" | ||||
| # loader. | ||||
| # Examples: | ||||
| #     "foo": Add this folder as a class repository | ||||
| #     "foo/*.jar": Add all the JARs of the specified folder as class | ||||
| #                  repositories | ||||
| #     "foo/bar.jar": Add bar.jar as a class repository | ||||
| # | ||||
| # Note: Values are enclosed in double quotes ("...") in case either the | ||||
| #       ${catalina.base} path or the ${catalina.home} path contains a comma. | ||||
| #       Because double quotes are used for quoting, the double quote character | ||||
| #       may not appear in a path. | ||||
| common.loader="${catalina.base}/lib","${catalina.base}/lib/*.jar","${catalina.home}/lib","${catalina.home}/lib/*.jar" | ||||
| 
 | ||||
| # | ||||
| # List of comma-separated paths defining the contents of the "server" | ||||
| # classloader. Prefixes should be used to define what is the repository type. | ||||
| # Path may be relative to the CATALINA_HOME or CATALINA_BASE path or absolute. | ||||
| # If left as blank, the "common" loader will be used as Catalina's "server" | ||||
| # loader. | ||||
| # Examples: | ||||
| #     "foo": Add this folder as a class repository | ||||
| #     "foo/*.jar": Add all the JARs of the specified folder as class | ||||
| #                  repositories | ||||
| #     "foo/bar.jar": Add bar.jar as a class repository | ||||
| # | ||||
| # Note: Values may be enclosed in double quotes ("...") in case either the | ||||
| #       ${catalina.base} path or the ${catalina.home} path contains a comma. | ||||
| #       Because double quotes are used for quoting, the double quote character | ||||
| #       may not appear in a path. | ||||
| server.loader= | ||||
| 
 | ||||
| # | ||||
| # List of comma-separated paths defining the contents of the "shared" | ||||
| # classloader. Prefixes should be used to define what is the repository type. | ||||
| # Path may be relative to the CATALINA_BASE path or absolute. If left as blank, | ||||
| # the "common" loader will be used as Catalina's "shared" loader. | ||||
| # Examples: | ||||
| #     "foo": Add this folder as a class repository | ||||
| #     "foo/*.jar": Add all the JARs of the specified folder as class | ||||
| #                  repositories | ||||
| #     "foo/bar.jar": Add bar.jar as a class repository | ||||
| # Please note that for single jars, e.g. bar.jar, you need the URL form | ||||
| # starting with file:. | ||||
| # | ||||
| # Note: Values may be enclosed in double quotes ("...") in case either the | ||||
| #       ${catalina.base} path or the ${catalina.home} path contains a comma. | ||||
| #       Because double quotes are used for quoting, the double quote character | ||||
| #       may not appear in a path. | ||||
| shared.loader= | ||||
| 
 | ||||
| # Default list of JAR files that should not be scanned using the JarScanner | ||||
| # functionality. This is typically used to scan JARs for configuration | ||||
| # information. JARs that do not contain such information may be excluded from | ||||
| # the scan to speed up the scanning process. This is the default list. JARs on | ||||
| # this list are excluded from all scans. The list must be a comma separated list | ||||
| # of JAR file names. | ||||
| # The list of JARs to skip may be over-ridden at a Context level for individual | ||||
| # scan types by configuring a JarScanner with a nested JarScanFilter. | ||||
| # The JARs listed below include: | ||||
| # - Tomcat Bootstrap JARs | ||||
| # - Tomcat API JARs | ||||
| # - Catalina JARs | ||||
| # - Jasper JARs | ||||
| # - Tomcat JARs | ||||
| # - Common non-Tomcat JARs | ||||
| # - Test JARs (JUnit, Cobertura and dependencies) | ||||
| tomcat.util.scan.StandardJarScanFilter.jarsToSkip=\ | ||||
| annotations-api.jar,\ | ||||
| ant-junit*.jar,\ | ||||
| ant-launcher.jar,\ | ||||
| ant.jar,\ | ||||
| asm-*.jar,\ | ||||
| aspectj*.jar,\ | ||||
| bootstrap.jar,\ | ||||
| catalina-ant.jar,\ | ||||
| catalina-ha.jar,\ | ||||
| catalina-ssi.jar,\ | ||||
| catalina-storeconfig.jar,\ | ||||
| catalina-tribes.jar,\ | ||||
| catalina.jar,\ | ||||
| cglib-*.jar,\ | ||||
| cobertura-*.jar,\ | ||||
| commons-beanutils*.jar,\ | ||||
| commons-codec*.jar,\ | ||||
| commons-collections*.jar,\ | ||||
| commons-daemon.jar,\ | ||||
| commons-dbcp*.jar,\ | ||||
| commons-digester*.jar,\ | ||||
| commons-fileupload*.jar,\ | ||||
| commons-httpclient*.jar,\ | ||||
| commons-io*.jar,\ | ||||
| commons-lang*.jar,\ | ||||
| commons-logging*.jar,\ | ||||
| commons-math*.jar,\ | ||||
| commons-pool*.jar,\ | ||||
| derby-*.jar,\ | ||||
| dom4j-*.jar,\ | ||||
| easymock-*.jar,\ | ||||
| ecj-*.jar,\ | ||||
| el-api.jar,\ | ||||
| geronimo-spec-jaxrpc*.jar,\ | ||||
| h2*.jar,\ | ||||
| hamcrest-*.jar,\ | ||||
| hibernate*.jar,\ | ||||
| httpclient*.jar,\ | ||||
| icu4j-*.jar,\ | ||||
| jakartaee-migration-*.jar,\ | ||||
| jasper-el.jar,\ | ||||
| jasper.jar,\ | ||||
| jaspic-api.jar,\ | ||||
| jaxb-*.jar,\ | ||||
| jaxen-*.jar,\ | ||||
| jdom-*.jar,\ | ||||
| jetty-*.jar,\ | ||||
| jmx-tools.jar,\ | ||||
| jmx.jar,\ | ||||
| jsp-api.jar,\ | ||||
| jstl.jar,\ | ||||
| jta*.jar,\ | ||||
| junit-*.jar,\ | ||||
| junit.jar,\ | ||||
| log4j*.jar,\ | ||||
| mail*.jar,\ | ||||
| objenesis-*.jar,\ | ||||
| oraclepki.jar,\ | ||||
| oro-*.jar,\ | ||||
| servlet-api-*.jar,\ | ||||
| servlet-api.jar,\ | ||||
| slf4j*.jar,\ | ||||
| taglibs-standard-spec-*.jar,\ | ||||
| tagsoup-*.jar,\ | ||||
| tomcat-api.jar,\ | ||||
| tomcat-coyote.jar,\ | ||||
| tomcat-dbcp.jar,\ | ||||
| tomcat-i18n-*.jar,\ | ||||
| tomcat-jdbc.jar,\ | ||||
| tomcat-jni.jar,\ | ||||
| tomcat-juli-adapters.jar,\ | ||||
| tomcat-juli.jar,\ | ||||
| tomcat-util-scan.jar,\ | ||||
| tomcat-util.jar,\ | ||||
| tomcat-websocket.jar,\ | ||||
| tools.jar,\ | ||||
| websocket-api.jar,\ | ||||
| wsdl4j*.jar,\ | ||||
| xercesImpl.jar,\ | ||||
| xml-apis.jar,\ | ||||
| xmlParserAPIs-*.jar,\ | ||||
| xmlParserAPIs.jar,\ | ||||
| xom-*.jar | ||||
| 
 | ||||
| # Default list of JAR files that should be scanned that overrides the default | ||||
| # jarsToSkip list above. This is typically used to include a specific JAR that | ||||
| # has been excluded by a broad file name pattern in the jarsToSkip list. | ||||
| # The list of JARs to scan may be over-ridden at a Context level for individual | ||||
| # scan types by configuring a JarScanner with a nested JarScanFilter. | ||||
| tomcat.util.scan.StandardJarScanFilter.jarsToScan=\ | ||||
| log4j-taglib*.jar,\ | ||||
| log4j-web*.jar,\ | ||||
| log4javascript*.jar,\ | ||||
| slf4j-taglib*.jar | ||||
| 
 | ||||
| # String cache configuration. | ||||
| tomcat.util.buf.StringCache.byte.enabled=true | ||||
| #tomcat.util.buf.StringCache.char.enabled=true | ||||
| #tomcat.util.buf.StringCache.trainThreshold=500000 | ||||
| #tomcat.util.buf.StringCache.cacheSize=5000 | ||||
							
								
								
									
										31
									
								
								apache-tomcat/sso/res/conf/context.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								apache-tomcat/sso/res/conf/context.xml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,31 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <!-- | ||||
|   Licensed to the Apache Software Foundation (ASF) under one or more | ||||
|   contributor license agreements.  See the NOTICE file distributed with | ||||
|   this work for additional information regarding copyright ownership. | ||||
|   The ASF licenses this file to You under the Apache License, Version 2.0 | ||||
|   (the "License"); you may not use this file except in compliance with | ||||
|   the License.  You may obtain a copy of the License at | ||||
| 
 | ||||
|       http://www.apache.org/licenses/LICENSE-2.0 | ||||
| 
 | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
| --> | ||||
| <!-- The contents of this file will be loaded for each web application --> | ||||
| <Context> | ||||
| 
 | ||||
|     <!-- Default set of monitored resources. If one of these changes, the    --> | ||||
|     <!-- web application will be reloaded.                                   --> | ||||
|     <WatchedResource>WEB-INF/web.xml</WatchedResource> | ||||
|     <WatchedResource>WEB-INF/tomcat-web.xml</WatchedResource> | ||||
|     <WatchedResource>${catalina.base}/conf/web.xml</WatchedResource> | ||||
| 
 | ||||
|     <!-- Uncomment this to enable session persistence across Tomcat restarts --> | ||||
|     <!-- | ||||
|     <Manager pathname="SESSIONS.ser" /> | ||||
|     --> | ||||
| </Context> | ||||
							
								
								
									
										23
									
								
								apache-tomcat/sso/res/conf/jaspic-providers.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								apache-tomcat/sso/res/conf/jaspic-providers.xml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,23 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <!-- | ||||
|   Licensed to the Apache Software Foundation (ASF) under one or more | ||||
|   contributor license agreements.  See the NOTICE file distributed with | ||||
|   this work for additional information regarding copyright ownership. | ||||
|   The ASF licenses this file to You under the Apache License, Version 2.0 | ||||
|   (the "License"); you may not use this file except in compliance with | ||||
|   the License.  You may obtain a copy of the License at | ||||
| 
 | ||||
|       http://www.apache.org/licenses/LICENSE-2.0 | ||||
| 
 | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
| --> | ||||
| <jaspic-providers xmlns="http://tomcat.apache.org/xml" | ||||
|                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||||
|                   xsi:schemaLocation="http://tomcat.apache.org/xml jaspic-providers.xsd" | ||||
|                   version="1.0"> | ||||
|   <!-- No JASPIC providers configured by default --> | ||||
| </jaspic-providers> | ||||
							
								
								
									
										53
									
								
								apache-tomcat/sso/res/conf/jaspic-providers.xsd
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								apache-tomcat/sso/res/conf/jaspic-providers.xsd
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,53 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <!-- | ||||
|   Licensed to the Apache Software Foundation (ASF) under one or more | ||||
|   contributor license agreements.  See the NOTICE file distributed with | ||||
|   this work for additional information regarding copyright ownership. | ||||
|   The ASF licenses this file to You under the Apache License, Version 2.0 | ||||
|   (the "License"); you may not use this file except in compliance with | ||||
|   the License.  You may obtain a copy of the License at | ||||
| 
 | ||||
|       http://www.apache.org/licenses/LICENSE-2.0 | ||||
| 
 | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
| --> | ||||
| <xs:schema xmlns="http://www.w3.org/2001/XMLSchema" | ||||
|            targetNamespace="http://tomcat.apache.org/xml" | ||||
|            xmlns:jaspic="http://tomcat.apache.org/xml" | ||||
|            xmlns:xs="http://www.w3.org/2001/XMLSchema" | ||||
|            elementFormDefault="qualified" | ||||
|            attributeFormDefault="unqualified" | ||||
|            version="1.0"> | ||||
|   <xs:element name="jaspic-providers"> | ||||
|     <xs:complexType> | ||||
|       <xs:sequence> | ||||
|         <xs:element name="provider" minOccurs="0" maxOccurs="unbounded"> | ||||
|           <xs:complexType> | ||||
|             <xs:sequence> | ||||
|               <xs:element name="property" minOccurs="0" maxOccurs="unbounded"> | ||||
|                 <xs:complexType> | ||||
|                   <xs:attribute name="name" use="required" type="jaspic:propertyname" /> | ||||
|                   <xs:attribute name="value" use="required" type="xs:string" /> | ||||
|                 </xs:complexType> | ||||
|               </xs:element> | ||||
|             </xs:sequence> | ||||
|             <xs:attribute name="className" type="xs:string" /> | ||||
|             <xs:attribute name="layer" type="xs:string" /> | ||||
|             <xs:attribute name="appContext" type="xs:string" /> | ||||
|             <xs:attribute name="description" type="xs:string" /> | ||||
|           </xs:complexType> | ||||
|         </xs:element> | ||||
|       </xs:sequence> | ||||
|       <xs:attribute name="version" type="xs:string" /> | ||||
|     </xs:complexType> | ||||
|   </xs:element> | ||||
|   <xs:simpleType name="propertyname"> | ||||
|     <xs:restriction base="xs:string"> | ||||
|       <xs:minLength value="1"/> | ||||
|     </xs:restriction> | ||||
|   </xs:simpleType> | ||||
| </xs:schema> | ||||
							
								
								
									
										90
									
								
								apache-tomcat/sso/res/conf/logging.properties
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								apache-tomcat/sso/res/conf/logging.properties
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,90 @@ | ||||
| # Licensed to the Apache Software Foundation (ASF) under one or more | ||||
| # contributor license agreements.  See the NOTICE file distributed with | ||||
| # this work for additional information regarding copyright ownership. | ||||
| # The ASF licenses this file to You under the Apache License, Version 2.0 | ||||
| # (the "License"); you may not use this file except in compliance with | ||||
| # the License.  You may obtain a copy of the License at | ||||
| # | ||||
| #     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| # | ||||
| # Unless required by applicable law or agreed to in writing, software | ||||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| # See the License for the specific language governing permissions and | ||||
| # limitations under the License. | ||||
| 
 | ||||
| handlers = 1catalina.org.apache.juli.AsyncFileHandler, 2localhost.org.apache.juli.AsyncFileHandler, 3manager.org.apache.juli.AsyncFileHandler, 4host-manager.org.apache.juli.AsyncFileHandler, java.util.logging.ConsoleHandler | ||||
| 
 | ||||
| .handlers = 1catalina.org.apache.juli.AsyncFileHandler, java.util.logging.ConsoleHandler | ||||
| 
 | ||||
| ############################################################ | ||||
| # Handler specific properties. | ||||
| # Describes specific configuration info for Handlers. | ||||
| ############################################################ | ||||
| 
 | ||||
| 1catalina.org.apache.juli.AsyncFileHandler.level = ALL | ||||
| 1catalina.org.apache.juli.AsyncFileHandler.directory = ${catalina.base}/logs | ||||
| 1catalina.org.apache.juli.AsyncFileHandler.prefix = catalina. | ||||
| 1catalina.org.apache.juli.AsyncFileHandler.maxDays = 90 | ||||
| 1catalina.org.apache.juli.AsyncFileHandler.encoding = UTF-8 | ||||
| 
 | ||||
| 2localhost.org.apache.juli.AsyncFileHandler.level = FINE | ||||
| 2localhost.org.apache.juli.AsyncFileHandler.directory = ${catalina.base}/logs | ||||
| 2localhost.org.apache.juli.AsyncFileHandler.prefix = localhost. | ||||
| 2localhost.org.apache.juli.AsyncFileHandler.maxDays = 90 | ||||
| 2localhost.org.apache.juli.AsyncFileHandler.encoding = UTF-8 | ||||
| 
 | ||||
| 3manager.org.apache.juli.AsyncFileHandler.level = FINE | ||||
| 3manager.org.apache.juli.AsyncFileHandler.directory = ${catalina.base}/logs | ||||
| 3manager.org.apache.juli.AsyncFileHandler.prefix = manager. | ||||
| 3manager.org.apache.juli.AsyncFileHandler.maxDays = 90 | ||||
| 3manager.org.apache.juli.AsyncFileHandler.encoding = UTF-8 | ||||
| 
 | ||||
| 4host-manager.org.apache.juli.AsyncFileHandler.level = FINE | ||||
| 4host-manager.org.apache.juli.AsyncFileHandler.directory = ${catalina.base}/logs | ||||
| 4host-manager.org.apache.juli.AsyncFileHandler.prefix = host-manager. | ||||
| 4host-manager.org.apache.juli.AsyncFileHandler.maxDays = 90 | ||||
| 4host-manager.org.apache.juli.AsyncFileHandler.encoding = UTF-8 | ||||
| 
 | ||||
| java.util.logging.ConsoleHandler.level = FINE | ||||
| java.util.logging.ConsoleHandler.formatter = org.apache.juli.OneLineFormatter | ||||
| java.util.logging.ConsoleHandler.encoding = UTF-8 | ||||
| 
 | ||||
| org.apache.catalina.authenticator.level = FINE | ||||
| org.apache.catalina.authenticator.formatter = org.apache.juli.OneLineFormatter | ||||
| org.apache.catalina.authenticator.encoding = UTF-8 | ||||
| 
 | ||||
| org.apache.catalina.Realm.level = FINE | ||||
| org.apache.catalina.Realm.formatter = org.apache.juli.OneLineFormatter | ||||
| org.apache.catalina.Realm.encoding = UTF-8 | ||||
| 
 | ||||
| org.apache.catalina.realm.level = FINE | ||||
| org.apache.catalina.realm.formatter = org.apache.juli.OneLineFormatter | ||||
| org.apache.catalina.realm.encoding = UTF-8 | ||||
| 
 | ||||
| ############################################################ | ||||
| # Facility specific properties. | ||||
| # Provides extra control for each logger. | ||||
| ############################################################ | ||||
| 
 | ||||
| org.apache.catalina.core.ContainerBase.[Catalina].[localhost].level = ALL | ||||
| org.apache.catalina.core.ContainerBase.[Catalina].[localhost].handlers = 2localhost.org.apache.juli.AsyncFileHandler | ||||
| 
 | ||||
| org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager].level = INFO | ||||
| org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager].handlers = 3manager.org.apache.juli.AsyncFileHandler | ||||
| 
 | ||||
| org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/host-manager].level = INFO | ||||
| org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/host-manager].handlers = 4host-manager.org.apache.juli.AsyncFileHandler | ||||
| 
 | ||||
| # For example, set the org.apache.catalina.util.LifecycleBase logger to log | ||||
| # each component that extends LifecycleBase changing state: | ||||
| # org.apache.catalina.util.LifecycleBase.level = FINE | ||||
| 
 | ||||
| # To see debug messages in TldLocationsCache, uncomment the following line: | ||||
| #org.apache.jasper.compiler.TldLocationsCache.level = FINE | ||||
| 
 | ||||
| # To see debug messages for HTTP/2 handling, uncomment the following line: | ||||
| #org.apache.coyote.http2.level = FINE | ||||
| 
 | ||||
| # To see debug messages for WebSocket handling, uncomment the following line: | ||||
| #org.apache.tomcat.websocket.level = FINE | ||||
							
								
								
									
										151
									
								
								apache-tomcat/sso/res/conf/server.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										151
									
								
								apache-tomcat/sso/res/conf/server.xml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,151 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <!-- | ||||
|   Licensed to the Apache Software Foundation (ASF) under one or more | ||||
|   contributor license agreements.  See the NOTICE file distributed with | ||||
|   this work for additional information regarding copyright ownership. | ||||
|   The ASF licenses this file to You under the Apache License, Version 2.0 | ||||
|   (the "License"); you may not use this file except in compliance with | ||||
|   the License.  You may obtain a copy of the License at | ||||
| 
 | ||||
|       http://www.apache.org/licenses/LICENSE-2.0 | ||||
| 
 | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
| --> | ||||
| <!-- Note:  A "Server" is not itself a "Container", so you may not | ||||
|      define subcomponents such as "Valves" at this level. | ||||
|      Documentation at /docs/config/server.html | ||||
|  --> | ||||
| <Server port="8005" shutdown="SHUTDOWN"> | ||||
|   <Listener className="org.apache.catalina.startup.VersionLoggerListener" /> | ||||
|   <!-- Security listener. Documentation at /docs/config/listeners.html | ||||
|   <Listener className="org.apache.catalina.security.SecurityListener" /> | ||||
|   --> | ||||
|   <!-- APR library loader. Documentation at /docs/apr.html --> | ||||
|   <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" /> | ||||
|   <!-- Prevent memory leaks due to use of particular java/javax APIs--> | ||||
|   <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" /> | ||||
|   <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" /> | ||||
|   <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" /> | ||||
| 
 | ||||
|   <!-- Global JNDI resources | ||||
|        Documentation at /docs/jndi-resources-howto.html | ||||
|   --> | ||||
|   <GlobalNamingResources> | ||||
|     <!-- Editable user database that can also be used by | ||||
|          UserDatabaseRealm to authenticate users | ||||
|     --> | ||||
|     <Resource name="UserDatabase" auth="Container" | ||||
|               type="org.apache.catalina.UserDatabase" | ||||
|               description="User database that can be updated and saved" | ||||
|               factory="org.apache.catalina.users.MemoryUserDatabaseFactory" | ||||
|               pathname="conf/tomcat-users.xml" /> | ||||
|   </GlobalNamingResources> | ||||
| 
 | ||||
|   <!-- A "Service" is a collection of one or more "Connectors" that share | ||||
|        a single "Container" Note:  A "Service" is not itself a "Container", | ||||
|        so you may not define subcomponents such as "Valves" at this level. | ||||
|        Documentation at /docs/config/service.html | ||||
|    --> | ||||
|   <Service name="Catalina"> | ||||
| 
 | ||||
|     <!--The connectors can use a shared executor, you can define one or more named thread pools--> | ||||
|     <!-- | ||||
|     <Executor name="tomcatThreadPool" namePrefix="catalina-exec-" | ||||
|         maxThreads="150" minSpareThreads="4"/> | ||||
|     --> | ||||
| 
 | ||||
| 
 | ||||
|     <!-- A "Connector" represents an endpoint by which requests are received | ||||
|          and responses are returned. Documentation at : | ||||
|          HTTP Connector: /docs/config/http.html | ||||
|          AJP  Connector: /docs/config/ajp.html | ||||
|          Define a non-SSL/TLS HTTP/1.1 Connector on port 8080 | ||||
|     --> | ||||
|     <Connector port="8080" protocol="HTTP/1.1" | ||||
|                connectionTimeout="20000" | ||||
|                redirectPort="8443" /> | ||||
|     <!-- A "Connector" using the shared thread pool--> | ||||
|     <!-- | ||||
|     <Connector executor="tomcatThreadPool" | ||||
|                port="8080" protocol="HTTP/1.1" | ||||
|                connectionTimeout="20000" | ||||
|                redirectPort="8443" /> | ||||
|     --> | ||||
|     <!-- Define an SSL/TLS HTTP/1.1 Connector on port 8443 with HTTP/2 | ||||
|          This connector uses the NIO implementation. The default | ||||
|          SSLImplementation will depend on the presence of the APR/native | ||||
|          library and the useOpenSSL attribute of the AprLifecycleListener. | ||||
|          Either JSSE or OpenSSL style configuration may be used regardless of | ||||
|          the SSLImplementation selected. JSSE style configuration is used below. | ||||
|     --> | ||||
|     <!-- | ||||
|     <Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol" | ||||
|                maxThreads="150" SSLEnabled="true"> | ||||
|         <UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" /> | ||||
|         <SSLHostConfig> | ||||
|             <Certificate certificateKeystoreFile="conf/localhost-rsa.jks" | ||||
|                          type="RSA" /> | ||||
|         </SSLHostConfig> | ||||
|     </Connector> | ||||
|     --> | ||||
| 
 | ||||
|     <!-- Define an AJP 1.3 Connector on port 8009 --> | ||||
|     <!-- | ||||
|     <Connector protocol="AJP/1.3" | ||||
|                address="::1" | ||||
|                port="8009" | ||||
|                redirectPort="8443" /> | ||||
|     --> | ||||
| 
 | ||||
|     <!-- An Engine represents the entry point (within Catalina) that processes | ||||
|          every request.  The Engine implementation for Tomcat stand alone | ||||
|          analyzes the HTTP headers included with the request, and passes them | ||||
|          on to the appropriate Host (virtual host). | ||||
|          Documentation at /docs/config/engine.html --> | ||||
| 
 | ||||
|     <!-- You should set jvmRoute to support load-balancing via AJP ie : | ||||
|     <Engine name="Catalina" defaultHost="localhost" jvmRoute="jvm1"> | ||||
|     --> | ||||
|     <Engine name="Catalina" defaultHost="localhost"> | ||||
| 
 | ||||
|       <!--For clustering, please take a look at documentation at: | ||||
|           /docs/cluster-howto.html  (simple how to) | ||||
|           /docs/config/cluster.html (reference documentation) --> | ||||
|       <!-- | ||||
|       <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/> | ||||
|       --> | ||||
| 
 | ||||
|       <!-- Use the LockOutRealm to prevent attempts to guess user passwords | ||||
|            via a brute-force attack --> | ||||
|       <Realm className="org.apache.catalina.realm.LockOutRealm"> | ||||
|         <!-- This Realm uses the UserDatabase configured in the global JNDI | ||||
|              resources under the key "UserDatabase".  Any edits | ||||
|              that are performed against this UserDatabase are immediately | ||||
|              available for use by the Realm.  --> | ||||
|         <Realm className="org.apache.catalina.realm.UserDatabaseRealm" | ||||
|                resourceName="UserDatabase"/> | ||||
|       </Realm> | ||||
| 
 | ||||
|       <Host name="localhost"  appBase="webapps" | ||||
|             unpackWARs="true" autoDeploy="true"> | ||||
| 
 | ||||
|         <!-- SingleSignOn valve, share authentication between web applications | ||||
|              Documentation at: /docs/config/valve.html --> | ||||
|         <Valve className="org.apache.catalina.authenticator.SingleSignOn" /> | ||||
|          | ||||
| 
 | ||||
|         <!-- Access log processes all example. | ||||
|              Documentation at: /docs/config/valve.html | ||||
|              Note: The pattern used is equivalent to using pattern="common" --> | ||||
|         <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" | ||||
|                prefix="localhost_access_log" suffix=".txt" | ||||
|                pattern="%h %l %u %t "%r" %s %b" /> | ||||
| 
 | ||||
|       </Host> | ||||
|     </Engine> | ||||
|   </Service> | ||||
| </Server> | ||||
							
								
								
									
										59
									
								
								apache-tomcat/sso/res/conf/tomcat-users.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								apache-tomcat/sso/res/conf/tomcat-users.xml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,59 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <!-- | ||||
|   Licensed to the Apache Software Foundation (ASF) under one or more | ||||
|   contributor license agreements.  See the NOTICE file distributed with | ||||
|   this work for additional information regarding copyright ownership. | ||||
|   The ASF licenses this file to You under the Apache License, Version 2.0 | ||||
|   (the "License"); you may not use this file except in compliance with | ||||
|   the License.  You may obtain a copy of the License at | ||||
| 
 | ||||
|       http://www.apache.org/licenses/LICENSE-2.0 | ||||
| 
 | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
| --> | ||||
| <tomcat-users xmlns="http://tomcat.apache.org/xml" | ||||
|               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||||
|               xsi:schemaLocation="http://tomcat.apache.org/xml tomcat-users.xsd" | ||||
|               version="1.0"> | ||||
| <!-- | ||||
|   By default, no user is included in the "manager-gui" role required | ||||
|   to operate the "/manager/html" web application.  If you wish to use this app, | ||||
|   you must define such a user - the username and password are arbitrary. | ||||
| 
 | ||||
|   Built-in Tomcat manager roles: | ||||
|     - manager-gui    - allows access to the HTML GUI and the status pages | ||||
|     - manager-script - allows access to the HTTP API and the status pages | ||||
|     - manager-jmx    - allows access to the JMX proxy and the status pages | ||||
|     - manager-status - allows access to the status pages only | ||||
| 
 | ||||
|   The users below are wrapped in a comment and are therefore ignored. If you | ||||
|   wish to configure one or more of these users for use with the manager web | ||||
|   application, do not forget to remove the <!.. ..> that surrounds them. You | ||||
|   will also need to set the passwords to something appropriate. | ||||
| --> | ||||
| <!-- | ||||
|   <user username="admin" password="<must-be-changed>" roles="manager-gui"/> | ||||
|   <user username="robot" password="<must-be-changed>" roles="manager-script"/> | ||||
| --> | ||||
| <!-- | ||||
|   The sample user and role entries below are intended for use with the | ||||
|   examples web application. They are wrapped in a comment and thus are ignored | ||||
|   when reading this file. If you wish to configure these users for use with the | ||||
|   examples web application, do not forget to remove the <!.. ..> that surrounds | ||||
|   them. You will also need to set the passwords to something appropriate. | ||||
| --> | ||||
| <!-- | ||||
|   <role rolename="tomcat"/> | ||||
|   <role rolename="role1"/> | ||||
|   <user username="tomcat" password="<must-be-changed>" roles="tomcat"/> | ||||
|   <user username="both" password="<must-be-changed>" roles="tomcat,role1"/> | ||||
|   <user username="role1" password="<must-be-changed>" roles="role1"/> | ||||
| --> | ||||
|   <role rolename="admin"/> | ||||
|   <user username="demo" password="demo" roles="admin"/> | ||||
| 
 | ||||
| </tomcat-users> | ||||
							
								
								
									
										59
									
								
								apache-tomcat/sso/res/conf/tomcat-users.xsd
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								apache-tomcat/sso/res/conf/tomcat-users.xsd
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,59 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <!-- | ||||
|   Licensed to the Apache Software Foundation (ASF) under one or more | ||||
|   contributor license agreements.  See the NOTICE file distributed with | ||||
|   this work for additional information regarding copyright ownership. | ||||
|   The ASF licenses this file to You under the Apache License, Version 2.0 | ||||
|   (the "License"); you may not use this file except in compliance with | ||||
|   the License.  You may obtain a copy of the License at | ||||
| 
 | ||||
|       http://www.apache.org/licenses/LICENSE-2.0 | ||||
| 
 | ||||
|   Unless required by applicable law or agreed to in writing, software | ||||
|   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|   See the License for the specific language governing permissions and | ||||
|   limitations under the License. | ||||
| --> | ||||
| <xs:schema xmlns="http://www.w3.org/2001/XMLSchema" | ||||
|            targetNamespace="http://tomcat.apache.org/xml" | ||||
|            xmlns:users="http://tomcat.apache.org/xml" | ||||
|            xmlns:xs="http://www.w3.org/2001/XMLSchema" | ||||
|            elementFormDefault="qualified" | ||||
|            attributeFormDefault="unqualified" | ||||
|            version="1.0"> | ||||
|   <xs:element name="tomcat-users"> | ||||
|     <xs:complexType> | ||||
|       <xs:choice minOccurs="0" maxOccurs="unbounded"> | ||||
|         <xs:element name="role"> | ||||
|           <xs:complexType> | ||||
|             <xs:attribute name="rolename" use="required" type="users:entityname" /> | ||||
|             <xs:attribute name="description" type="xs:string" /> | ||||
|           </xs:complexType> | ||||
|         </xs:element> | ||||
|         <xs:element name="group"> | ||||
|           <xs:complexType> | ||||
|             <xs:attribute name="groupname" use="required" type="users:entityname" /> | ||||
|             <xs:attribute name="description" type="xs:string" /> | ||||
|             <xs:attribute name="roles" type="xs:string" /> | ||||
|           </xs:complexType> | ||||
|         </xs:element> | ||||
|         <xs:element name="user"> | ||||
|           <xs:complexType> | ||||
|             <xs:attribute name="username" use="required" type="users:entityname" /> | ||||
|             <xs:attribute name="fullname" type="xs:string" /> | ||||
|             <xs:attribute name="password" type="xs:string" /> | ||||
|             <xs:attribute name="roles" type="xs:string" /> | ||||
|             <xs:attribute name="groups" type="xs:string" /> | ||||
|           </xs:complexType> | ||||
|         </xs:element> | ||||
|       </xs:choice> | ||||
|       <xs:attribute name="version" type="xs:string" /> | ||||
|     </xs:complexType> | ||||
|   </xs:element> | ||||
|   <xs:simpleType name="entityname"> | ||||
|     <xs:restriction base="xs:string"> | ||||
|       <xs:minLength value="1"/> | ||||
|     </xs:restriction> | ||||
|   </xs:simpleType> | ||||
| </xs:schema> | ||||
							
								
								
									
										4742
									
								
								apache-tomcat/sso/res/conf/web.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4742
									
								
								apache-tomcat/sso/res/conf/web.xml
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										50
									
								
								apache-tomcat/sso/webapps/ping/WEB-INF/web.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								apache-tomcat/sso/webapps/ping/WEB-INF/web.xml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,50 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <web-app | ||||
|   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||||
|   xmlns="http://java.sun.com/xml/ns/javaee" | ||||
|   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_4_0.xsd" | ||||
|   id="ping" | ||||
|   version="3.0"> | ||||
|     <display-name>Ping</display-name> | ||||
| 
 | ||||
|     <security-constraint> | ||||
|         <display-name>Ping Login Auth</display-name> | ||||
|         <web-resource-collection> | ||||
|             <web-resource-name>PingRestrictedAccess</web-resource-name> | ||||
|             <url-pattern>/private/*</url-pattern>      | ||||
|         </web-resource-collection> | ||||
|         <auth-constraint> | ||||
|             <role-name>admin</role-name>         | ||||
|         </auth-constraint> | ||||
|         <user-data-constraint> | ||||
|             <transport-guarantee>NONE</transport-guarantee>      | ||||
|         </user-data-constraint> | ||||
|     </security-constraint> | ||||
| 
 | ||||
|     <security-role> | ||||
|         <role-name>admin</role-name> | ||||
|     </security-role> | ||||
| 
 | ||||
|     <login-config> | ||||
|         <auth-method>FORM</auth-method> | ||||
|         <form-login-config> | ||||
|             <form-login-page>/logging.html</form-login-page> | ||||
|             <form-error-page>/logging_error.html</form-error-page>        | ||||
|         </form-login-config> | ||||
|     </login-config> | ||||
| 
 | ||||
|     <filter> | ||||
|         <filter-name>PingExpiresFilter</filter-name> | ||||
|         <filter-class>org.apache.catalina.filters.ExpiresFilter</filter-class> | ||||
|         <init-param> | ||||
|             <param-name>ExpiresByType text/html</param-name> | ||||
|             <param-value>access plus 0 seconds</param-value> | ||||
|         </init-param> | ||||
|     </filter> | ||||
| 
 | ||||
|     <filter-mapping> | ||||
|         <filter-name>PingExpiresFilter</filter-name> | ||||
|         <url-pattern>/private/*</url-pattern> | ||||
|         <dispatcher>REQUEST</dispatcher> | ||||
|     </filter-mapping> | ||||
| </web-app> | ||||
							
								
								
									
										9
									
								
								apache-tomcat/sso/webapps/ping/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								apache-tomcat/sso/webapps/ping/index.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | ||||
| <!DOCTYPE html> | ||||
| <html> | ||||
| <head> | ||||
|     <title>Ping</title> | ||||
| </head> | ||||
| <body> | ||||
|     <a href="private/index.html">Start pinging</a>     | ||||
| </body> | ||||
| </html> | ||||
							
								
								
									
										26
									
								
								apache-tomcat/sso/webapps/ping/logging.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								apache-tomcat/sso/webapps/ping/logging.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,26 @@ | ||||
| <!DOCTYPE html> | ||||
| <html> | ||||
| <head> | ||||
|     <title>Ping - Login</title> | ||||
| </head> | ||||
| <body> | ||||
|     <form method="post" action="j_security_check"> | ||||
|         <table > | ||||
|             <tr> | ||||
|                 <td>User name: </td> | ||||
|                 <td><input type="text" name="j_username"  | ||||
|                            size="20"/></td> | ||||
|             </tr> | ||||
|             <tr> | ||||
|                 <td>Password: </td> | ||||
|                 <td><input type="password" name="j_password"  | ||||
|                            size="20"/></td> | ||||
|             </tr> | ||||
|         </table> | ||||
|         <p></p> | ||||
|         <input type="submit" value="Submit"/> | ||||
|           | ||||
|         <input type="reset" value="Reset"/> | ||||
|     </form> | ||||
| </body> | ||||
| </html> | ||||
							
								
								
									
										10
									
								
								apache-tomcat/sso/webapps/ping/logging_error.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								apache-tomcat/sso/webapps/ping/logging_error.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | ||||
| <!DOCTYPE html> | ||||
| <html> | ||||
| <head> | ||||
|     <title>Ping</title> | ||||
| </head> | ||||
| <body> | ||||
|     Error logging in! | ||||
|     <a href="index.html">Try again</a> | ||||
| </body> | ||||
| </html> | ||||
							
								
								
									
										9
									
								
								apache-tomcat/sso/webapps/ping/private/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								apache-tomcat/sso/webapps/ping/private/index.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | ||||
| <!DOCTYPE html> | ||||
| <html> | ||||
| <head> | ||||
|     <title>Ping - Pinging</title> | ||||
| </head> | ||||
| <body> | ||||
|     <a href="/pong/private/index.html">Pong!</a> | ||||
| </body> | ||||
| </html> | ||||
							
								
								
									
										47
									
								
								apache-tomcat/sso/webapps/pong/WEB-INF/web.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								apache-tomcat/sso/webapps/pong/WEB-INF/web.xml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,47 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> | ||||
|   <display-name>Pong</display-name> | ||||
|   <welcome-file-list> | ||||
|     <welcome-file>index.html</welcome-file> | ||||
|   </welcome-file-list> | ||||
| 
 | ||||
| 
 | ||||
|     <security-constraint> | ||||
|         <display-name>Pong Login Auth</display-name> | ||||
|         <web-resource-collection> | ||||
|             <web-resource-name>PongRestrictedAccess</web-resource-name> | ||||
|             <url-pattern>/private/*</url-pattern>      | ||||
|         </web-resource-collection> | ||||
|         <auth-constraint> | ||||
|             <role-name>admin</role-name>         | ||||
|         </auth-constraint> | ||||
|         <user-data-constraint> | ||||
|             <transport-guarantee>NONE</transport-guarantee>      | ||||
|         </user-data-constraint> | ||||
|     </security-constraint> | ||||
| 
 | ||||
|     <security-role> | ||||
|         <role-name>admin</role-name> | ||||
|     </security-role> | ||||
| 
 | ||||
| 
 | ||||
|     <login-config> | ||||
|         <auth-method>DIGEST</auth-method> | ||||
|     </login-config> | ||||
| 
 | ||||
|     <filter> | ||||
|         <filter-name>PongExpiresFilter</filter-name> | ||||
|         <filter-class>org.apache.catalina.filters.ExpiresFilter</filter-class> | ||||
|         <init-param> | ||||
|             <param-name>ExpiresByType text/html</param-name> | ||||
|             <param-value>access plus 0 seconds</param-value> | ||||
|         </init-param> | ||||
|     </filter> | ||||
| 
 | ||||
|     <filter-mapping> | ||||
|         <filter-name>PongExpiresFilter</filter-name> | ||||
|         <url-pattern>/private/*</url-pattern> | ||||
|         <dispatcher>REQUEST</dispatcher> | ||||
|     </filter-mapping> | ||||
| 
 | ||||
| </web-app> | ||||
							
								
								
									
										9
									
								
								apache-tomcat/sso/webapps/pong/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								apache-tomcat/sso/webapps/pong/index.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | ||||
| <!DOCTYPE html> | ||||
| <html> | ||||
| <head> | ||||
|     <title>Pong</title> | ||||
| </head> | ||||
| <body> | ||||
|     <a href="private/index.html">Start ponging</a>     | ||||
| </body> | ||||
| </html> | ||||
							
								
								
									
										9
									
								
								apache-tomcat/sso/webapps/pong/private/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								apache-tomcat/sso/webapps/pong/private/index.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | ||||
| <!DOCTYPE html> | ||||
| <html> | ||||
| <head> | ||||
|     <title>Pong - Ponging</title> | ||||
| </head> | ||||
| <body> | ||||
|     <a href="/ping/private/index.html">Ping!</a> | ||||
| </body> | ||||
| </html> | ||||
| @ -8,4 +8,6 @@ This module contains articles about Java 8 core features | ||||
| - [Java 8 Stream skip() vs limit()](https://www.baeldung.com/java-stream-skip-vs-limit) | ||||
| - [Guide to Java BiFunction Interface](https://www.baeldung.com/java-bifunction-interface) | ||||
| - [Interface With Default Methods vs Abstract Class](https://www.baeldung.com/java-interface-default-method-vs-abstract-class) | ||||
| - [Convert Between Byte Array and UUID in Java](https://www.baeldung.com/java-byte-array-to-uuid) | ||||
| - [Create a Simple “Rock-Paper-Scissors” Game in Java](https://www.baeldung.com/java-rock-paper-scissors) | ||||
| - [[<-- Prev]](/core-java-modules/core-java-8) | ||||
|  | ||||
| @ -1,17 +1,24 @@ | ||||
| package com.baeldung.game; | ||||
| 
 | ||||
| import java.util.HashMap; | ||||
| import java.util.Map; | ||||
| import java.util.Random; | ||||
| import java.util.Scanner; | ||||
| import java.util.*; | ||||
| 
 | ||||
| class RockPaperScissorsGame { | ||||
| 
 | ||||
|     private static Map<Integer, String> movesMap = new HashMap<Integer, String>() {{ | ||||
|         put(0, "rock"); | ||||
|         put(1, "paper"); | ||||
|         put(2, "scissors"); | ||||
|     }}; | ||||
|     enum Move { | ||||
|         ROCK("rock"), | ||||
|         PAPER("paper"), | ||||
|         SCISSORS("scissors"); | ||||
| 
 | ||||
|         private String value; | ||||
| 
 | ||||
|         Move(String value) { | ||||
|             this.value = value; | ||||
|         } | ||||
| 
 | ||||
|         public String getValue() { | ||||
|             return value; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public static void main(String[] args) { | ||||
|         Scanner scanner = new Scanner(System.in); | ||||
| @ -31,7 +38,7 @@ class RockPaperScissorsGame { | ||||
|                 break; | ||||
|             } | ||||
| 
 | ||||
|             if (!movesMap.containsValue(playerMove)) { | ||||
|             if (Arrays.stream(Move.values()).noneMatch(x -> x.getValue().equals(playerMove))) { | ||||
|                 System.out.println("Your move isn't valid!"); | ||||
|                 continue; | ||||
|             } | ||||
| @ -51,15 +58,15 @@ class RockPaperScissorsGame { | ||||
|     } | ||||
| 
 | ||||
|     private static boolean isPlayerWin(String playerMove, String computerMove) { | ||||
|         return playerMove.equals("rock") && computerMove.equals("scissors") | ||||
|                 || (playerMove.equals("scissors") && computerMove.equals("paper")) | ||||
|                 || (playerMove.equals("paper") && computerMove.equals("rock")); | ||||
|         return playerMove.equals(Move.ROCK.value) && computerMove.equals(Move.SCISSORS.value) | ||||
|                 || (playerMove.equals(Move.SCISSORS.value) && computerMove.equals(Move.PAPER.value)) | ||||
|                 || (playerMove.equals(Move.PAPER.value) && computerMove.equals(Move.ROCK.value)); | ||||
|     } | ||||
| 
 | ||||
|     private static String getComputerMove() { | ||||
|         Random random = new Random(); | ||||
|         int randomNumber = random.nextInt(3); | ||||
|         String computerMove = movesMap.get(randomNumber); | ||||
|         String computerMove = Move.values()[randomNumber].getValue(); | ||||
|         System.out.println("Computer move: " + computerMove); | ||||
|         return computerMove; | ||||
|     } | ||||
|  | ||||
| @ -22,6 +22,6 @@ class RandomDatesUnitTest { | ||||
|         LocalDate end = LocalDate.now(); | ||||
| 
 | ||||
|         LocalDate random = RandomDates.between(start, end); | ||||
|         assertThat(random).isAfter(start).isBefore(end); | ||||
|         assertThat(random).isAfterOrEqualTo(start).isBefore(end); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -34,6 +34,28 @@ | ||||
|         </dependency> | ||||
|     </dependencies> | ||||
| 
 | ||||
|     <build> | ||||
|         <finalName>core-java-9-new-features</finalName> | ||||
|         <plugins> | ||||
|             <plugin> | ||||
|                 <groupId>org.apache.maven.plugins</groupId> | ||||
|                 <artifactId>maven-compiler-plugin</artifactId> | ||||
|                 <version>${maven-compiler-plugin.version}</version> | ||||
|                 <configuration> | ||||
|                     <source>${maven.compiler.source}</source> | ||||
|                     <target>${maven.compiler.target}</target> | ||||
|                 </configuration> | ||||
|             </plugin> | ||||
|         </plugins> | ||||
|     </build> | ||||
| 
 | ||||
|     <pluginRepositories> | ||||
|         <pluginRepository> | ||||
|             <id>apache.snapshots</id> | ||||
|             <url>https://repository.apache.org/snapshots/</url> | ||||
|         </pluginRepository> | ||||
|     </pluginRepositories> | ||||
| 
 | ||||
|     <profiles> | ||||
|         <profile> | ||||
|             <id>incubator-features</id> | ||||
| @ -126,28 +148,6 @@ | ||||
|         </profile> | ||||
|     </profiles> | ||||
| 
 | ||||
|     <build> | ||||
|         <finalName>core-java-9-new-features</finalName> | ||||
|         <plugins> | ||||
|             <plugin> | ||||
|                 <groupId>org.apache.maven.plugins</groupId> | ||||
|                 <artifactId>maven-compiler-plugin</artifactId> | ||||
|                 <version>${maven-compiler-plugin.version}</version> | ||||
|                 <configuration> | ||||
|                     <source>${maven.compiler.source}</source> | ||||
|                     <target>${maven.compiler.target}</target> | ||||
|                 </configuration> | ||||
|             </plugin> | ||||
|         </plugins> | ||||
|     </build> | ||||
| 
 | ||||
|     <pluginRepositories> | ||||
|         <pluginRepository> | ||||
|             <id>apache.snapshots</id> | ||||
|             <url>https://repository.apache.org/snapshots/</url> | ||||
|         </pluginRepository> | ||||
|     </pluginRepositories> | ||||
| 
 | ||||
|     <properties> | ||||
|         <rxjava.version>3.0.0</rxjava.version> | ||||
|         <awaitility.version>4.0.2</awaitility.version> | ||||
|  | ||||
| @ -7,3 +7,4 @@ | ||||
| - [ArrayList vs. LinkedList vs. HashMap in Java](https://www.baeldung.com/java-arraylist-vs-linkedlist-vs-hashmap) | ||||
| - [Java Deque vs. Stack](https://www.baeldung.com/java-deque-vs-stack) | ||||
| - [Collection.toArray(new T[0]) or .toArray(new T[size])](https://www.baeldung.com/java-collection-toarray-methods) | ||||
| - [Create an Empty Map in Java](https://www.baeldung.com/java-create-empty-map) | ||||
|  | ||||
| @ -6,3 +6,5 @@ This module contains articles about Map data structures in Java. | ||||
| - [Using a Custom Class as a Key in a Java HashMap](https://www.baeldung.com/java-custom-class-map-key) | ||||
| - [Nested HashMaps Examples in Java](https://www.baeldung.com/java-nested-hashmaps) | ||||
| - [Java HashMap With Different Value Types](https://www.baeldung.com/java-hashmap-different-value-types) | ||||
| - [Difference Between Map and HashMap in Java](https://www.baeldung.com/java-map-vs-hashmap) | ||||
| - [How to Create a New Entry in a Map](https://www.baeldung.com/java-map-new-entry) | ||||
|  | ||||
| @ -15,6 +15,16 @@ | ||||
|     </parent> | ||||
| 
 | ||||
|     <dependencies> | ||||
|         <dependency> | ||||
|             <groupId>org.apache.commons</groupId> | ||||
|             <artifactId>commons-collections4</artifactId> | ||||
|             <version>${commons-collections4.version}</version> | ||||
|         </dependency> | ||||
|         <dependency> | ||||
|             <groupId>com.google.guava</groupId> | ||||
|             <artifactId>guava</artifactId> | ||||
|             <version>${guava.version}</version> | ||||
|         </dependency> | ||||
|         <dependency> | ||||
|             <groupId>junit</groupId> | ||||
|             <artifactId>junit</artifactId> | ||||
| @ -37,12 +47,23 @@ | ||||
|                 </plugin> | ||||
|             </plugins> | ||||
|         </pluginManagement> | ||||
|         <plugins> | ||||
|             <plugin> | ||||
|                 <groupId>org.apache.maven.plugins</groupId> | ||||
|                 <artifactId>maven-compiler-plugin</artifactId> | ||||
|                 <version>${maven-compiler-plugin.version}</version> | ||||
|                 <configuration> | ||||
|                     <source>${maven.compiler.source}</source> | ||||
|                     <target>${maven.compiler.target}</target> | ||||
|                 </configuration> | ||||
|             </plugin> | ||||
|         </plugins> | ||||
|     </build> | ||||
| 
 | ||||
|     <properties> | ||||
|         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | ||||
|         <maven.compiler.source>1.8</maven.compiler.source> | ||||
|         <maven.compiler.target>1.8</maven.compiler.target> | ||||
|         <maven.compiler.source>1.9</maven.compiler.source> | ||||
|         <maven.compiler.target>1.9</maven.compiler.target> | ||||
|     </properties> | ||||
| 
 | ||||
| </project> | ||||
| @ -0,0 +1,53 @@ | ||||
| package com.baeldung.entries; | ||||
| 
 | ||||
| import java.util.Map; | ||||
| import java.util.Objects; | ||||
| import java.util.StringJoiner; | ||||
| 
 | ||||
| public class SimpleCustomKeyValue<K, V> implements Map.Entry<K, V> { | ||||
| 
 | ||||
|     private final K key; | ||||
|     private V value; | ||||
| 
 | ||||
|     public SimpleCustomKeyValue(K key, V value) { | ||||
|         this.key = key; | ||||
|         this.value = value; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public K getKey() { | ||||
|         return key; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public V getValue() { | ||||
|         return value; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public V setValue(V value) { | ||||
|         return this.value = value; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public boolean equals(Object o) { | ||||
|         if (this == o) { | ||||
|             return true; | ||||
|         } | ||||
|         if (o == null || getClass() != o.getClass()) { | ||||
|             return false; | ||||
|         } | ||||
|         SimpleCustomKeyValue<?, ?> that = (SimpleCustomKeyValue<?, ?>) o; | ||||
|         return Objects.equals(key, that.key) && Objects.equals(value, that.value); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public int hashCode() { | ||||
|         return Objects.hash(key, value); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public String toString() { | ||||
|         return new StringJoiner(", ", SimpleCustomKeyValue.class.getSimpleName() + "[", "]").add("key=" + key).add("value=" + value).toString(); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,113 @@ | ||||
| package com.baeldung.entries; | ||||
| 
 | ||||
| import com.google.common.collect.Maps; | ||||
| import org.apache.commons.collections4.KeyValue; | ||||
| import org.apache.commons.collections4.keyvalue.DefaultMapEntry; | ||||
| import org.apache.commons.collections4.keyvalue.UnmodifiableMapEntry; | ||||
| import org.junit.jupiter.api.Test; | ||||
| 
 | ||||
| import java.util.AbstractMap; | ||||
| import java.util.Map; | ||||
| import java.util.stream.Stream; | ||||
| 
 | ||||
| import static org.assertj.core.api.Assertions.assertThat; | ||||
| import static org.assertj.core.api.Assertions.tuple; | ||||
| 
 | ||||
| public class EntriesExampleUnitTest { | ||||
| 
 | ||||
|     @Test | ||||
|     public void givenEntries_whenVerifying_thenShouldContainKeyValues() { | ||||
|         AbstractMap.SimpleEntry<String, String> firstEntry = new AbstractMap.SimpleEntry<>("key1", "value1"); | ||||
|         AbstractMap.SimpleEntry<String, String> secondEntry = new AbstractMap.SimpleEntry<>("key2", "value2"); | ||||
|         AbstractMap.SimpleEntry<String, String> thirdEntry = new AbstractMap.SimpleEntry<>(firstEntry); | ||||
|         thirdEntry.setValue("a different value"); | ||||
| 
 | ||||
|         assertThat(Stream.of(firstEntry, secondEntry, thirdEntry)) | ||||
|           .extracting("key", "value") | ||||
|           .containsExactly( | ||||
|             tuple("key1", "value1"), | ||||
|             tuple("key2", "value2"), | ||||
|             tuple("key1", "a different value")); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void givenImmutableEntries_whenVerifying_thenShouldContainKeyValues() { | ||||
|         AbstractMap.SimpleImmutableEntry<String, String> firstEntry = new AbstractMap.SimpleImmutableEntry<>("key1", "value1"); | ||||
|         AbstractMap.SimpleImmutableEntry<String, String> secondEntry = new AbstractMap.SimpleImmutableEntry<>("key2", "value2"); | ||||
|         AbstractMap.SimpleImmutableEntry<String, String> thirdEntry = new AbstractMap.SimpleImmutableEntry<>(firstEntry); | ||||
| 
 | ||||
|         assertThat(Stream.of(firstEntry, secondEntry, thirdEntry)) | ||||
|           .extracting("key", "value") | ||||
|           .containsExactly( | ||||
|             tuple("key1", "value1"), | ||||
|             tuple("key2", "value2"), | ||||
|             tuple("key1", "value1")); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void givenImmutableEntryUsingJava9_whenVerifying_thenShouldContainKeyValues() { | ||||
|         Map.Entry<String, String> entry = Map.entry("key", "value"); | ||||
| 
 | ||||
|         assertThat(entry.getKey()) | ||||
|           .isEqualTo("key"); | ||||
|         assertThat(entry.getValue()) | ||||
|           .isEqualTo("value"); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     @Test | ||||
|     public void givenEntriesWithApacheCommons_whenVerifying_thenShouldContainKeyValues() { | ||||
|         Map.Entry<String, String> firstEntry = new DefaultMapEntry<>("key1", "value1"); | ||||
|         KeyValue<String, String> secondEntry = new DefaultMapEntry<>("key2", "value2"); | ||||
| 
 | ||||
|         KeyValue<String, String> thirdEntry = new DefaultMapEntry<>(firstEntry); | ||||
|         KeyValue<String, String> fourthEntry = new DefaultMapEntry<>(secondEntry); | ||||
| 
 | ||||
|         firstEntry.setValue("a different value"); | ||||
| 
 | ||||
|         assertThat(firstEntry) | ||||
|           .extracting("key", "value") | ||||
|           .containsExactly("key1", "a different value"); | ||||
| 
 | ||||
|         assertThat(Stream.of(secondEntry, thirdEntry, fourthEntry)) | ||||
|           .extracting("key", "value") | ||||
|           .containsExactly( | ||||
|             tuple("key2", "value2"), | ||||
|             tuple("key1", "value1"), | ||||
|             tuple("key2", "value2")); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void givenImmutableEntriesWithApacheCommons_whenVerifying_thenShouldContainKeyValues() { | ||||
|         Map.Entry<String, String> firstEntry = new UnmodifiableMapEntry<>("key1", "value1"); | ||||
|         KeyValue<String, String> secondEntry = new UnmodifiableMapEntry<>("key2", "value2"); | ||||
| 
 | ||||
|         KeyValue<String, String> thirdEntry = new UnmodifiableMapEntry<>(firstEntry); | ||||
|         KeyValue<String, String> fourthEntry = new UnmodifiableMapEntry<>(secondEntry); | ||||
| 
 | ||||
|         assertThat(firstEntry) | ||||
|           .extracting("key", "value") | ||||
|           .containsExactly("key1", "value1"); | ||||
| 
 | ||||
|         assertThat(Stream.of(secondEntry, thirdEntry, fourthEntry)) | ||||
|           .extracting("key", "value") | ||||
|           .containsExactly( | ||||
|             tuple("key2", "value2"), | ||||
|             tuple("key1", "value1"), | ||||
|             tuple("key2", "value2")); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     @Test | ||||
|     public void givenImmutableEntriesWithGuava_whenVerifying_thenShouldContainKeyValues() { | ||||
|         Map.Entry<String, String> firstEntry = Maps.immutableEntry("key1", "value1"); | ||||
|         Map.Entry<String, String> secondEntry = Maps.immutableEntry("key2", "value2"); | ||||
| 
 | ||||
|         assertThat(Stream.of(firstEntry, secondEntry)) | ||||
|           .extracting("key", "value") | ||||
|           .containsExactly( | ||||
|             tuple("key1", "value1"), | ||||
|             tuple("key2", "value2")); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,31 @@ | ||||
| package com.baeldung.entries; | ||||
| 
 | ||||
| import com.google.common.collect.ImmutableMap; | ||||
| import org.junit.jupiter.api.Test; | ||||
| 
 | ||||
| import java.util.Map; | ||||
| import java.util.stream.Stream; | ||||
| 
 | ||||
| import static org.assertj.core.api.Assertions.assertThat; | ||||
| import static org.assertj.core.api.Assertions.tuple; | ||||
| 
 | ||||
| class SimpleCustomKeyValueUnitTest { | ||||
| 
 | ||||
| 
 | ||||
|     @Test | ||||
|     public void givenModifiableEntries_whenVerifying_thenShouldContainKeyValues() { | ||||
|         Map.Entry<String, String> firstEntry = new SimpleCustomKeyValue<>("key1", "value1"); | ||||
| 
 | ||||
|         Map.Entry<String, String> secondEntry = new SimpleCustomKeyValue<>("key2", "value2"); | ||||
|         secondEntry.setValue("different value"); | ||||
| 
 | ||||
|         Map<String, String> map = Map.ofEntries(firstEntry, secondEntry); | ||||
| 
 | ||||
|         assertThat(map) | ||||
|           .isEqualTo(ImmutableMap.<String,String>builder() | ||||
|             .put("key1", "value1") | ||||
|             .put("key2", "different value") | ||||
|             .build()); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -12,3 +12,4 @@ This module contains articles about the Java Set collection | ||||
| - [Set Operations in Java](https://www.baeldung.com/java-set-operations) | ||||
| - [Copying Sets in Java](https://www.baeldung.com/java-copy-sets) | ||||
| - [Immutable Set in Java](https://www.baeldung.com/java-immutable-set) | ||||
| - [Find the Difference Between Two Sets](https://www.baeldung.com/java-difference-between-sets) | ||||
|  | ||||
| @ -0,0 +1,28 @@ | ||||
| package com.baeldung.set; | ||||
| 
 | ||||
| import java.util.HashMap; | ||||
| import java.util.Map; | ||||
| import java.util.Set; | ||||
| import java.util.stream.Collectors; | ||||
| 
 | ||||
| public class SetDiff { | ||||
| 
 | ||||
|     public static <T> Set<T> findSymmetricDiff(Set<T> set1, Set<T> set2) { | ||||
|         Map<T, Integer> map = new HashMap<>(); | ||||
|         set1.forEach(e -> putKey(map, e)); | ||||
|         set2.forEach(e -> putKey(map, e)); | ||||
|         return map.entrySet().stream() | ||||
|             .filter(e -> e.getValue() == 1) | ||||
|             .map(Map.Entry::getKey) | ||||
|             .collect(Collectors.toSet()); | ||||
|     } | ||||
| 
 | ||||
|     private static <T> void putKey(Map<T, Integer> map, T key) { | ||||
|         if (map.containsKey(key)) { | ||||
|             map.replace(key, Integer.MAX_VALUE); | ||||
|         } else { | ||||
|             map.put(key, 1); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,61 @@ | ||||
| package com.baeldung.set; | ||||
| 
 | ||||
| import com.google.common.collect.Sets; | ||||
| import org.apache.commons.collections4.CollectionUtils; | ||||
| import org.apache.commons.collections4.SetUtils; | ||||
| import org.junit.Test; | ||||
| 
 | ||||
| import java.util.HashSet; | ||||
| import java.util.Set; | ||||
| import java.util.stream.Collectors; | ||||
| import java.util.stream.Stream; | ||||
| 
 | ||||
| import static org.assertj.core.api.Assertions.assertThat; | ||||
| 
 | ||||
| public class SetDiffUnitTest { | ||||
|     private final static Set<String> immutableSet1 = Set.of("Kotlin", "Java", "Rust", "Python", "C++"); | ||||
|     private final static Set<String> immutableSet2 = Set.of("Kotlin", "Java", "Rust", "Ruby", "C#"); | ||||
|     private final static Set<String> expectedOnlyInSet1 = Set.of("Python", "C++"); | ||||
|     private final static Set<String> expectedDiff = Set.of("Python", "C++", "Ruby", "C#"); | ||||
| 
 | ||||
|     @Test | ||||
|     public void givenAnotherSet_whenRemoveAll_shouldGetDiff() { | ||||
|         Set<String> set1 = Stream.of("Kotlin", "Java", "Rust", "Python", "C++").collect(Collectors.toSet()); | ||||
|         Set<String> set2 = Stream.of("Kotlin", "Java", "Rust", "Ruby", "C#").collect(Collectors.toSet()); | ||||
|         Set<String> expectedOnlyInSet1 = Set.of("Python", "C++"); | ||||
|         set1.removeAll(set2); | ||||
|         assertThat(set1).isEqualTo(expectedOnlyInSet1); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void givenAnotherSet_whenUsingStreamFilter_shouldGet() { | ||||
|         Set<String> actualOnlyInSet1 = immutableSet1.stream().filter(e -> !immutableSet2.contains(e)).collect(Collectors.toSet()); | ||||
|         assertThat(actualOnlyInSet1).isEqualTo(expectedOnlyInSet1); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void givenAnotherSet_whenCallingGuavaMethod_shouldGetDiff() { | ||||
|         Set<String> actualOnlyInSet1 = Sets.difference(immutableSet1, immutableSet2); | ||||
|         assertThat(actualOnlyInSet1).isEqualTo(expectedOnlyInSet1); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void givenAnotherSet_whenCallingCommonsMethod_shouldGetDiff() { | ||||
|         Set<String> actualOnlyInSet1 = new HashSet<>(CollectionUtils.removeAll(immutableSet1, immutableSet2)); | ||||
|         assertThat(actualOnlyInSet1).isEqualTo(expectedOnlyInSet1); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     @Test | ||||
|     public void givenTwoSets_whenCallingFindDisjunction_shouldGetDisjunction() { | ||||
|         Set<String> actualDiff = SetDiff.findSymmetricDiff(immutableSet1, immutableSet2); | ||||
|         assertThat(actualDiff).isEqualTo(expectedDiff); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void givenTwoSets_whenCallingCommonsMethod_shouldGetDisjunction() { | ||||
|         Set<String> actualDiff = SetUtils.disjunction(immutableSet1, immutableSet2); | ||||
|         assertThat(actualDiff).isEqualTo(expectedDiff); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -4,3 +4,5 @@ | ||||
| - [Bad Practices With Synchronization](https://www.baeldung.com/java-synchronization-bad-practices) | ||||
| - [Start Two Threads at the Exact Same Time in Java](https://www.baeldung.com/java-start-two-threads-at-same-time) | ||||
| - [Volatile Variables and Thread Safety](https://www.baeldung.com/java-volatile-variables-thread-safety) | ||||
| - [Producer-Consumer Problem With Example in Java](https://www.baeldung.com/java-producer-consumer-problem) | ||||
| - [Acquire a Lock by a Key in Java](https://www.baeldung.com/java-acquire-lock-by-key) | ||||
|  | ||||
| @ -0,0 +1,43 @@ | ||||
| package com.baeldung.lockbykey; | ||||
| 
 | ||||
| /** | ||||
|  * This class shows examples of how you should use the lock | ||||
|  * | ||||
|  */ | ||||
| public class ExampleUsage { | ||||
|      | ||||
|     void doWithSimpleExclusiveLock(String key) { | ||||
|         SimpleExclusiveLockByKey simpleExclusiveLockByKey = new SimpleExclusiveLockByKey(); | ||||
|         if (simpleExclusiveLockByKey.tryLock(key)) { | ||||
|             try { | ||||
|                 // do stuff | ||||
|             } finally { | ||||
|                 // it is very important to unlock in the finally block to avoid locking keys forever | ||||
|                 simpleExclusiveLockByKey.unlock(key); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     // A concrete example can be found in the unit tests | ||||
|     void doWithLock(String key) { | ||||
|         LockByKey lockByKey = new LockByKey(); | ||||
|         lockByKey.lock(key); | ||||
|         try { | ||||
|             // do stuff | ||||
|         } finally { | ||||
|             lockByKey.unlock(key); | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     // It works exactly the same as with locks | ||||
|     void doWithSemaphore(String key) { | ||||
|         SimultaneousEntriesLockByKey lockByKey = new SimultaneousEntriesLockByKey(); | ||||
|         lockByKey.lock(key); | ||||
|         try { | ||||
|             // do stuff | ||||
|         } finally { | ||||
|             lockByKey.unlock(key); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,41 @@ | ||||
| package com.baeldung.lockbykey; | ||||
| 
 | ||||
| import java.util.concurrent.ConcurrentHashMap; | ||||
| import java.util.concurrent.atomic.AtomicInteger; | ||||
| import java.util.concurrent.locks.Lock; | ||||
| import java.util.concurrent.locks.ReentrantLock; | ||||
| 
 | ||||
| public class LockByKey { | ||||
|      | ||||
|     private static class LockWrapper { | ||||
|         private final Lock lock = new ReentrantLock(); | ||||
|         private final AtomicInteger numberOfThreadsInQueue = new AtomicInteger(1); | ||||
|          | ||||
|         private LockWrapper addThreadInQueue() { | ||||
|             numberOfThreadsInQueue.incrementAndGet();  | ||||
|             return this; | ||||
|         } | ||||
|          | ||||
|         private int removeThreadFromQueue() { | ||||
|             return numberOfThreadsInQueue.decrementAndGet();  | ||||
|         } | ||||
|          | ||||
|     } | ||||
|      | ||||
|     private static ConcurrentHashMap<String, LockWrapper> locks = new ConcurrentHashMap<String, LockWrapper>(); | ||||
|      | ||||
|     public void lock(String key) { | ||||
|         LockWrapper lockWrapper = locks.compute(key, (k, v) -> v == null ? new LockWrapper() : v.addThreadInQueue()); | ||||
|         lockWrapper.lock.lock(); | ||||
|     } | ||||
|      | ||||
|     public void unlock(String key) { | ||||
|         LockWrapper lockWrapper = locks.get(key); | ||||
|         lockWrapper.lock.unlock(); | ||||
|         if (lockWrapper.removeThreadFromQueue() == 0) {  | ||||
|             // NB : We pass in the specific value to remove to handle the case where another thread would queue right before the removal | ||||
|             locks.remove(key, lockWrapper); | ||||
|         } | ||||
|     } | ||||
|      | ||||
| } | ||||
| @ -0,0 +1,18 @@ | ||||
| package com.baeldung.lockbykey; | ||||
| 
 | ||||
| import java.util.Set; | ||||
| import java.util.concurrent.ConcurrentHashMap; | ||||
| 
 | ||||
| public class SimpleExclusiveLockByKey { | ||||
| 
 | ||||
|     private static Set<String> usedKeys= ConcurrentHashMap.newKeySet(); | ||||
|      | ||||
|     public boolean tryLock(String key) { | ||||
|         return usedKeys.add(key); | ||||
|     } | ||||
|      | ||||
|     public void unlock(String key) { | ||||
|         usedKeys.remove(key); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,25 @@ | ||||
| package com.baeldung.lockbykey; | ||||
| 
 | ||||
| import java.util.concurrent.ConcurrentHashMap; | ||||
| import java.util.concurrent.Semaphore; | ||||
| 
 | ||||
| public class SimultaneousEntriesLockByKey { | ||||
| 
 | ||||
|     private static final int ALLOWED_THREADS = 2; | ||||
|      | ||||
|     private static ConcurrentHashMap<String, Semaphore> semaphores = new ConcurrentHashMap<String, Semaphore>(); | ||||
|      | ||||
|     public void lock(String key) { | ||||
|         Semaphore semaphore = semaphores.compute(key, (k, v) -> v == null ? new Semaphore(ALLOWED_THREADS) : v); | ||||
|         semaphore.acquireUninterruptibly(); | ||||
|     } | ||||
|      | ||||
|     public void unlock(String key) { | ||||
|         Semaphore semaphore = semaphores.get(key); | ||||
|         semaphore.release(); | ||||
|         if (semaphore.availablePermits() == ALLOWED_THREADS) {  | ||||
|             semaphores.remove(key, semaphore); | ||||
|         }   | ||||
|     } | ||||
|      | ||||
| } | ||||
| @ -0,0 +1,51 @@ | ||||
| package com.baeldung.producerconsumer; | ||||
| 
 | ||||
| public class Consumer implements Runnable { | ||||
|     private final DataQueue dataQueue; | ||||
|     private volatile boolean runFlag; | ||||
| 
 | ||||
|     public Consumer(DataQueue dataQueue) { | ||||
|         this.dataQueue = dataQueue; | ||||
|         runFlag = true; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void run() { | ||||
|         consume(); | ||||
|     } | ||||
| 
 | ||||
|     public void consume() { | ||||
|         while (runFlag) { | ||||
|             Message message; | ||||
|             if (dataQueue.isEmpty()) { | ||||
|                 try { | ||||
|                     dataQueue.waitOnEmpty(); | ||||
|                 } catch (InterruptedException e) { | ||||
|                     e.printStackTrace(); | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
|             if (!runFlag) { | ||||
|                 break; | ||||
|             } | ||||
|             message = dataQueue.remove(); | ||||
|             dataQueue.notifyAllForFull(); | ||||
|             useMessage(message); | ||||
|         } | ||||
|         System.out.println("Consumer Stopped"); | ||||
|     } | ||||
| 
 | ||||
|     private void useMessage(Message message) { | ||||
|         if (message != null) { | ||||
|             System.out.printf("[%s] Consuming Message. Id: %d, Data: %f\n", Thread.currentThread().getName(), message.getId(), message.getData()); | ||||
| 
 | ||||
|             //Sleeping on random time to make it realistic | ||||
|             ThreadUtil.sleep((long) (message.getData() * 100)); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public void stop() { | ||||
|         runFlag = false; | ||||
|         dataQueue.notifyAllForEmpty(); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,59 @@ | ||||
| package com.baeldung.producerconsumer; | ||||
| 
 | ||||
| import java.util.LinkedList; | ||||
| import java.util.Queue; | ||||
| 
 | ||||
| public class DataQueue { | ||||
|     private final Queue<Message> queue = new LinkedList<>(); | ||||
|     private final int maxSize; | ||||
|     private final Object FULL_QUEUE = new Object(); | ||||
|     private final Object EMPTY_QUEUE = new Object(); | ||||
| 
 | ||||
|     DataQueue(int maxSize) { | ||||
|         this.maxSize = maxSize; | ||||
|     } | ||||
| 
 | ||||
|     public boolean isFull() { | ||||
|         return queue.size() == maxSize; | ||||
|     } | ||||
| 
 | ||||
|     public boolean isEmpty() { | ||||
|         return queue.isEmpty(); | ||||
|     } | ||||
| 
 | ||||
|     public void waitOnFull() throws InterruptedException { | ||||
|         synchronized (FULL_QUEUE) { | ||||
|             FULL_QUEUE.wait(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public void waitOnEmpty() throws InterruptedException { | ||||
|         synchronized (EMPTY_QUEUE) { | ||||
|             EMPTY_QUEUE.wait(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public void notifyAllForFull() { | ||||
|         synchronized (FULL_QUEUE) { | ||||
|             FULL_QUEUE.notifyAll(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public void notifyAllForEmpty() { | ||||
|         synchronized (EMPTY_QUEUE) { | ||||
|             EMPTY_QUEUE.notifyAll(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public void add(Message message) { | ||||
|         synchronized (queue) { | ||||
|             queue.add(message); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public Message remove() { | ||||
|         synchronized (queue) { | ||||
|             return queue.poll(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,27 @@ | ||||
| package com.baeldung.producerconsumer; | ||||
| 
 | ||||
| public class Message { | ||||
|     private int id; | ||||
|     private double data; | ||||
| 
 | ||||
|     public Message(int id, double data) { | ||||
|         this.id = id; | ||||
|         this.data = data; | ||||
|     } | ||||
| 
 | ||||
|     public int getId() { | ||||
|         return id; | ||||
|     } | ||||
| 
 | ||||
|     public void setId(int id) { | ||||
|         this.id = id; | ||||
|     } | ||||
| 
 | ||||
|     public double getData() { | ||||
|         return data; | ||||
|     } | ||||
| 
 | ||||
|     public void setData(double data) { | ||||
|         this.data = data; | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,53 @@ | ||||
| package com.baeldung.producerconsumer; | ||||
| 
 | ||||
| public class Producer implements Runnable { | ||||
|     private final DataQueue dataQueue; | ||||
|     private volatile boolean runFlag; | ||||
| 
 | ||||
|     private static int idSequence = 0; | ||||
| 
 | ||||
|     public Producer(DataQueue dataQueue) { | ||||
|         this.dataQueue = dataQueue; | ||||
|         runFlag = true; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void run() { | ||||
|         produce(); | ||||
|     } | ||||
| 
 | ||||
|     public void produce() { | ||||
|         while (runFlag) { | ||||
|             Message message = generateMessage(); | ||||
|             while (dataQueue.isFull()) { | ||||
|                 try { | ||||
|                     dataQueue.waitOnFull(); | ||||
|                 } catch (InterruptedException e) { | ||||
|                     e.printStackTrace(); | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
|             if (!runFlag) { | ||||
|                 break; | ||||
|             } | ||||
|             dataQueue.add(message); | ||||
|             dataQueue.notifyAllForEmpty(); | ||||
|         } | ||||
|         System.out.println("Producer Stopped"); | ||||
|     } | ||||
| 
 | ||||
|     private Message generateMessage() { | ||||
|         Message message = new Message(++idSequence, Math.random()); | ||||
|         System.out.printf("[%s] Generated Message. Id: %d, Data: %f\n", Thread.currentThread().getName(), message.getId(), message.getData()); | ||||
| 
 | ||||
|         //Sleeping on random time to make it realistic | ||||
|         ThreadUtil.sleep((long) (message.getData() * 100)); | ||||
| 
 | ||||
|         return message; | ||||
|     } | ||||
| 
 | ||||
|     public void stop() { | ||||
|         runFlag = false; | ||||
|         dataQueue.notifyAllForFull(); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,69 @@ | ||||
| package com.baeldung.producerconsumer; | ||||
| 
 | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
| 
 | ||||
| import static com.baeldung.producerconsumer.ThreadUtil.*; | ||||
| 
 | ||||
| public class ProducerConsumerDemonstrator { | ||||
|     private static final int MAX_QUEUE_CAPACITY = 5; | ||||
| 
 | ||||
|     public static void demoSingleProducerAndSingleConsumer() { | ||||
|         DataQueue dataQueue = new DataQueue(MAX_QUEUE_CAPACITY); | ||||
| 
 | ||||
|         Producer producer = new Producer(dataQueue); | ||||
|         Thread producerThread = new Thread(producer); | ||||
| 
 | ||||
|         Consumer consumer = new Consumer(dataQueue); | ||||
|         Thread consumerThread = new Thread(consumer); | ||||
| 
 | ||||
|         producerThread.start(); | ||||
|         consumerThread.start(); | ||||
| 
 | ||||
|         List<Thread> threads = new ArrayList<>(); | ||||
|         threads.add(producerThread); | ||||
|         threads.add(consumerThread); | ||||
| 
 | ||||
|         // let threads run for two seconds | ||||
|         sleep(2000); | ||||
| 
 | ||||
|         // Stop threads | ||||
|         producer.stop(); | ||||
|         consumer.stop(); | ||||
| 
 | ||||
|         waitForAllThreadsToComplete(threads); | ||||
|     } | ||||
| 
 | ||||
|     public static void demoMultipleProducersAndMultipleConsumers() { | ||||
|         DataQueue dataQueue = new DataQueue(MAX_QUEUE_CAPACITY); | ||||
|         int producerCount = 3; | ||||
|         int consumerCount = 3; | ||||
|         List<Thread> threads = new ArrayList<>(); | ||||
|         Producer producer = new Producer(dataQueue); | ||||
|         for(int i = 0; i < producerCount; i++) { | ||||
|             Thread producerThread = new Thread(producer); | ||||
|             producerThread.start(); | ||||
|             threads.add(producerThread); | ||||
|         } | ||||
|         Consumer consumer = new Consumer(dataQueue); | ||||
|         for(int i = 0; i < consumerCount; i++) { | ||||
|             Thread consumerThread = new Thread(consumer); | ||||
|             consumerThread.start(); | ||||
|             threads.add(consumerThread); | ||||
|         } | ||||
| 
 | ||||
|         // let threads run for two seconds | ||||
|         sleep(2000); | ||||
| 
 | ||||
|         // Stop threads | ||||
|         producer.stop(); | ||||
|         consumer.stop(); | ||||
| 
 | ||||
|         waitForAllThreadsToComplete(threads); | ||||
|     } | ||||
| 
 | ||||
|     public static void main(String[] args) { | ||||
|         demoSingleProducerAndSingleConsumer(); | ||||
|         demoMultipleProducersAndMultipleConsumers(); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,60 @@ | ||||
| package com.baeldung.producerconsumer; | ||||
| 
 | ||||
| import java.util.concurrent.BlockingQueue; | ||||
| import java.util.concurrent.LinkedBlockingDeque; | ||||
| 
 | ||||
| import static com.baeldung.producerconsumer.ThreadUtil.sleep; | ||||
| 
 | ||||
| public class SimpleProducerConsumerDemonstrator { | ||||
|     BlockingQueue<Double> blockingQueue = new LinkedBlockingDeque<>(5); | ||||
| 
 | ||||
|     private void produce() { | ||||
|         while (true) { | ||||
|             double value = generateValue(); | ||||
|             try { | ||||
|                 blockingQueue.put(value); | ||||
|             } catch (InterruptedException e) { | ||||
|                 e.printStackTrace(); | ||||
|                 break; | ||||
|             } | ||||
|             System.out.printf("[%s] Value produced: %f\n", Thread.currentThread().getName(), value); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private void consume() { | ||||
|         while (true) { | ||||
|             Double value; | ||||
|             try { | ||||
|                 value = blockingQueue.take(); | ||||
|             } catch (InterruptedException e) { | ||||
|                 e.printStackTrace(); | ||||
|                 break; | ||||
|             } | ||||
|             // Consume value | ||||
|             System.out.printf("[%s] Value consumed: %f\n", Thread.currentThread().getName(), value); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private double generateValue() { | ||||
|         return Math.random(); | ||||
|     } | ||||
| 
 | ||||
|     private void runProducerConsumer() { | ||||
|         for (int i = 0; i < 2; i++) { | ||||
|             Thread producerThread = new Thread(this::produce); | ||||
|             producerThread.start(); | ||||
|         } | ||||
| 
 | ||||
|         for (int i = 0; i < 3; i++) { | ||||
|             Thread consumerThread = new Thread(this::consume); | ||||
|             consumerThread.start(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public static void main(String[] args) { | ||||
|         SimpleProducerConsumerDemonstrator simpleProducerConsumerDemonstrator = new SimpleProducerConsumerDemonstrator(); | ||||
|         simpleProducerConsumerDemonstrator.runProducerConsumer(); | ||||
|         sleep(2000); | ||||
|         System.exit(0); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,24 @@ | ||||
| package com.baeldung.producerconsumer; | ||||
| 
 | ||||
| import java.util.List; | ||||
| 
 | ||||
| public class ThreadUtil { | ||||
|     public static void waitForAllThreadsToComplete(List<Thread> threads) { | ||||
|         for(Thread thread: threads) { | ||||
|             try { | ||||
|                 thread.join(); | ||||
|             } catch (InterruptedException e) { | ||||
|                 e.printStackTrace(); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public static void sleep(long interval) { | ||||
|         try { | ||||
|             // Wait for some time to demonstrate threads | ||||
|             Thread.sleep(interval); | ||||
|         } catch (InterruptedException e) { | ||||
|             e.printStackTrace(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,106 @@ | ||||
| package com.baeldung.lockbykey; | ||||
| 
 | ||||
| import static org.junit.jupiter.api.Assertions.assertFalse; | ||||
| import static org.junit.jupiter.api.Assertions.assertTrue; | ||||
| 
 | ||||
| import java.util.concurrent.atomic.AtomicBoolean; | ||||
| 
 | ||||
| import org.junit.jupiter.api.Test; | ||||
| 
 | ||||
| public class LockByKeyUnitTest { | ||||
|      | ||||
|     @Test | ||||
|     void givenNoLockedKey_WhenLock_ThenSuccess() throws InterruptedException { | ||||
|         AtomicBoolean threadWasExecuted = new AtomicBoolean(false); | ||||
|         Thread thread = new Thread(() -> { | ||||
|             String key = "key"; | ||||
|             LockByKey lockByKey = new LockByKey(); | ||||
|             lockByKey.lock(key); | ||||
|             try { | ||||
|                threadWasExecuted.set(true); | ||||
|             } finally { | ||||
|                 lockByKey.unlock(key); | ||||
|             } | ||||
|         }); | ||||
|         try { | ||||
|             thread.start(); | ||||
|             Thread.sleep(100); | ||||
|         } finally { | ||||
|             assertTrue(threadWasExecuted.get()); | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     @Test | ||||
|     void givenLockedKey_WhenLock_ThenFailure() throws InterruptedException { | ||||
|         String key = "key"; | ||||
|         LockByKey lockByKey = new LockByKey(); | ||||
|         lockByKey.lock(key); | ||||
|         AtomicBoolean anotherThreadWasExecuted = new AtomicBoolean(false); | ||||
|         Thread threadLockingOnAnotherKey = new Thread(() -> { | ||||
|             LockByKey otherLockByKey = new LockByKey(); | ||||
|             otherLockByKey.lock(key); | ||||
|             try { | ||||
|                 anotherThreadWasExecuted.set(true); | ||||
|             } finally { | ||||
|                 otherLockByKey.unlock(key); | ||||
|             } | ||||
|         }); | ||||
|         try { | ||||
|             threadLockingOnAnotherKey.start(); | ||||
|             Thread.sleep(100); | ||||
|         } finally { | ||||
|             assertFalse(anotherThreadWasExecuted.get()); | ||||
|             lockByKey.unlock(key); | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     @Test | ||||
|     void givenAnotherKeyLocked_WhenLock_ThenSuccess() throws InterruptedException { | ||||
|         String key = "key"; | ||||
|         LockByKey lockByKey = new LockByKey(); | ||||
|         lockByKey.lock(key); | ||||
|         AtomicBoolean anotherThreadWasExecuted = new AtomicBoolean(false); | ||||
|         Thread threadLockingOnAnotherKey = new Thread(() -> { | ||||
|             String anotherKey = "anotherKey"; | ||||
|             LockByKey otherLockByKey = new LockByKey(); | ||||
|             otherLockByKey.lock(anotherKey); | ||||
|             try { | ||||
|                 anotherThreadWasExecuted.set(true); | ||||
|             } finally { | ||||
|                 otherLockByKey.unlock(anotherKey); | ||||
|             } | ||||
|         }); | ||||
|         try { | ||||
|             threadLockingOnAnotherKey.start(); | ||||
|             Thread.sleep(100); | ||||
|         } finally { | ||||
|             assertTrue(anotherThreadWasExecuted.get()); | ||||
|             lockByKey.unlock(key); | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     @Test | ||||
|     void givenUnlockedKey_WhenLock_ThenSuccess() throws InterruptedException { | ||||
|         String key = "key"; | ||||
|         LockByKey lockByKey = new LockByKey(); | ||||
|         lockByKey.lock(key); | ||||
|         AtomicBoolean anotherThreadWasExecuted = new AtomicBoolean(false); | ||||
|         Thread threadLockingOnAnotherKey = new Thread(() -> { | ||||
|             LockByKey otherLockByKey = new LockByKey(); | ||||
|             otherLockByKey.lock(key); | ||||
|             try { | ||||
|                 anotherThreadWasExecuted.set(true); | ||||
|             } finally { | ||||
|                 otherLockByKey.unlock(key); | ||||
|             } | ||||
|         }); | ||||
|         try { | ||||
|             lockByKey.unlock(key); | ||||
|             threadLockingOnAnotherKey.start(); | ||||
|             Thread.sleep(100); | ||||
|         } finally { | ||||
|             assertTrue(anotherThreadWasExecuted.get()); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,51 @@ | ||||
| package com.baeldung.lockbykey; | ||||
| 
 | ||||
| import static org.junit.jupiter.api.Assertions.assertFalse; | ||||
| import static org.junit.jupiter.api.Assertions.assertTrue; | ||||
| 
 | ||||
| import java.lang.reflect.Field; | ||||
| import java.util.concurrent.ConcurrentHashMap; | ||||
| 
 | ||||
| import org.junit.jupiter.api.BeforeEach; | ||||
| import org.junit.jupiter.api.Test; | ||||
| 
 | ||||
| public class SimpleExclusiveLockByKeyUnitTest { | ||||
|      | ||||
|     @BeforeEach | ||||
|     void cleanUpLocks() throws Exception { | ||||
|         Field field = SimpleExclusiveLockByKey.class.getDeclaredField("usedKeys"); | ||||
|         field.setAccessible(true); | ||||
|         field.set(null, ConcurrentHashMap.newKeySet()); | ||||
|     } | ||||
|      | ||||
|     @Test | ||||
|     void givenNoLockedKey_WhenTryLock_ThenSuccess() { | ||||
|         SimpleExclusiveLockByKey lockByKey = new SimpleExclusiveLockByKey(); | ||||
|         assertTrue(lockByKey.tryLock("key")); | ||||
|     } | ||||
|      | ||||
|     @Test | ||||
|     void givenLockedKey_WhenTryLock_ThenFailure() { | ||||
|         String key = "key"; | ||||
|         SimpleExclusiveLockByKey lockByKey = new SimpleExclusiveLockByKey(); | ||||
|         lockByKey.tryLock(key); | ||||
|         assertFalse(lockByKey.tryLock(key)); | ||||
|     } | ||||
|      | ||||
|     @Test | ||||
|     void givenAnotherKeyLocked_WhenTryLock_ThenSuccess() { | ||||
|         SimpleExclusiveLockByKey lockByKey = new SimpleExclusiveLockByKey(); | ||||
|         lockByKey.tryLock("other"); | ||||
|         assertTrue(lockByKey.tryLock("key")); | ||||
|     } | ||||
|      | ||||
|     @Test | ||||
|     void givenUnlockedKey_WhenTryLock_ThenSuccess() { | ||||
|         String key = "key"; | ||||
|         SimpleExclusiveLockByKey lockByKey = new SimpleExclusiveLockByKey(); | ||||
|         lockByKey.tryLock(key); | ||||
|         lockByKey.unlock(key); | ||||
|         assertTrue(lockByKey.tryLock(key)); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,146 @@ | ||||
| package com.baeldung.lockbykey; | ||||
| 
 | ||||
| import static org.junit.jupiter.api.Assertions.assertFalse; | ||||
| import static org.junit.jupiter.api.Assertions.assertTrue; | ||||
| 
 | ||||
| import java.util.concurrent.atomic.AtomicBoolean; | ||||
| 
 | ||||
| import org.junit.jupiter.api.Test; | ||||
| 
 | ||||
| public class SimultaneousEntriesLockByKeyUnitTest { | ||||
| 
 | ||||
|     @Test | ||||
|     void givenNoKeyUsed_WhenLock_ThenSuccess() throws InterruptedException { | ||||
|         AtomicBoolean threadWasExecuted = new AtomicBoolean(false); | ||||
|         Thread thread = new Thread(() -> { | ||||
|             String key = "key"; | ||||
|             SimultaneousEntriesLockByKey lockByKey = new SimultaneousEntriesLockByKey(); | ||||
|             lockByKey.lock(key); | ||||
|             try { | ||||
|                threadWasExecuted.set(true); | ||||
|             } finally { | ||||
|                 lockByKey.unlock(key); | ||||
|             } | ||||
|         }); | ||||
|         try { | ||||
|             thread.start(); | ||||
|             Thread.sleep(100); | ||||
|         } finally { | ||||
|             assertTrue(threadWasExecuted.get()); | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     @Test | ||||
|     void givenKeyLockedWithRemainingPermits_WhenLock_ThenSuccess() throws InterruptedException { | ||||
|         String key = "key"; | ||||
|         SimultaneousEntriesLockByKey lockByKey = new SimultaneousEntriesLockByKey(); | ||||
|         lockByKey.lock(key); | ||||
|         AtomicBoolean anotherThreadWasExecuted = new AtomicBoolean(false); | ||||
|         Thread threadLockingOnAnotherKey = new Thread(() -> { | ||||
|             SimultaneousEntriesLockByKey otherLockByKeyWithSemaphore = new SimultaneousEntriesLockByKey(); | ||||
|             otherLockByKeyWithSemaphore.lock(key); | ||||
|             try { | ||||
|                 anotherThreadWasExecuted.set(true); | ||||
|             } finally { | ||||
|                 otherLockByKeyWithSemaphore.unlock(key); | ||||
|             } | ||||
|         }); | ||||
|         try { | ||||
|             threadLockingOnAnotherKey.start(); | ||||
|             Thread.sleep(100); | ||||
|         } finally { | ||||
|             assertTrue(anotherThreadWasExecuted.get()); | ||||
|             lockByKey.unlock(key); | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     @Test | ||||
|     void givenKeyLockedWithNoRemainingPermits_WhenLock_ThenFailure() throws InterruptedException { | ||||
|         String key = "key"; | ||||
|         SimultaneousEntriesLockByKey lockByKey = new SimultaneousEntriesLockByKey(); | ||||
|         lockByKey.lock(key); | ||||
|         AtomicBoolean anotherThreadWasExecuted = new AtomicBoolean(false); | ||||
|         Thread threadLockingOnAnotherKey1 = new Thread(() -> { | ||||
|             SimultaneousEntriesLockByKey otherLockByKeyWithSemaphore = new SimultaneousEntriesLockByKey(); | ||||
|             otherLockByKeyWithSemaphore.lock(key); | ||||
|             try { | ||||
|                 Thread.sleep(200); // make sure this thread will release the lock after the assertion | ||||
|             } catch (InterruptedException e) { | ||||
|                  | ||||
|             } finally { | ||||
|                 otherLockByKeyWithSemaphore.unlock(key); | ||||
|             } | ||||
|         }); | ||||
|         Thread threadLockingOnAnotherKey2 = new Thread(() -> { | ||||
|             SimultaneousEntriesLockByKey otherLockByKey = new SimultaneousEntriesLockByKey(); | ||||
|             try { | ||||
|                 Thread.sleep(50); // make sure thread1 will acquire the key first | ||||
|             } catch (InterruptedException e) { | ||||
|             } | ||||
|             otherLockByKey.lock(key); | ||||
|             try { | ||||
|                 anotherThreadWasExecuted.set(true); | ||||
|             } finally { | ||||
|                 otherLockByKey.unlock(key); | ||||
|             } | ||||
|         }); | ||||
|         try { | ||||
|             threadLockingOnAnotherKey1.start(); | ||||
|             threadLockingOnAnotherKey2.start(); | ||||
|             Thread.sleep(100); | ||||
|         } finally { | ||||
|             assertFalse(anotherThreadWasExecuted.get()); | ||||
|             lockByKey.unlock(key); | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     @Test | ||||
|     void givenAnotherKeyLocked_WhenLock_ThenSuccess() throws InterruptedException { | ||||
|         String key = "key"; | ||||
|         SimultaneousEntriesLockByKey lockByKey = new SimultaneousEntriesLockByKey(); | ||||
|         lockByKey.lock(key); | ||||
|         AtomicBoolean anotherThreadWasExecuted = new AtomicBoolean(false); | ||||
|         Thread threadLockingOnAnotherKey = new Thread(() -> { | ||||
|             String anotherKey = "anotherKey"; | ||||
|             SimultaneousEntriesLockByKey otherLockByKey = new SimultaneousEntriesLockByKey(); | ||||
|             otherLockByKey.lock(anotherKey); | ||||
|             try { | ||||
|                 anotherThreadWasExecuted.set(true); | ||||
|             } finally { | ||||
|                 otherLockByKey.unlock(anotherKey); | ||||
|             } | ||||
|         }); | ||||
|         try { | ||||
|             threadLockingOnAnotherKey.start(); | ||||
|             Thread.sleep(100); | ||||
|         } finally { | ||||
|             assertTrue(anotherThreadWasExecuted.get()); | ||||
|             lockByKey.unlock(key); | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     @Test | ||||
|     void givenUnlockedKey_WhenLock_ThenSuccess() throws InterruptedException { | ||||
|         String key = "key"; | ||||
|         SimultaneousEntriesLockByKey lockByKey = new SimultaneousEntriesLockByKey(); | ||||
|         lockByKey.lock(key); | ||||
|         AtomicBoolean anotherThreadWasExecuted = new AtomicBoolean(false); | ||||
|         Thread threadLockingOnAnotherKey = new Thread(() -> { | ||||
|             SimultaneousEntriesLockByKey otherLockByKey = new SimultaneousEntriesLockByKey(); | ||||
|             otherLockByKey.lock(key); | ||||
|             try { | ||||
|                 anotherThreadWasExecuted.set(true); | ||||
|             } finally { | ||||
|                 otherLockByKey.unlock(key); | ||||
|             } | ||||
|         }); | ||||
|         try { | ||||
|             lockByKey.unlock(key); | ||||
|             threadLockingOnAnotherKey.start(); | ||||
|             Thread.sleep(100); | ||||
|         } finally { | ||||
|             assertTrue(anotherThreadWasExecuted.get()); | ||||
|         } | ||||
|     } | ||||
|      | ||||
| } | ||||
| @ -24,4 +24,4 @@ | ||||
|         </resources> | ||||
|     </build> | ||||
| 
 | ||||
| </project> | ||||
| </project> | ||||
| @ -25,7 +25,6 @@ | ||||
|             <artifactId>commons-lang3</artifactId> | ||||
|             <version>${commons-lang3.version}</version> | ||||
|         </dependency> | ||||
| 
 | ||||
|         <dependency> | ||||
|             <groupId>com.darwinsys</groupId> | ||||
|             <artifactId>hirondelle-date4j</artifactId> | ||||
|  | ||||
| @ -11,4 +11,5 @@ This module contains articles about date operations in Java. | ||||
| - [How to determine day of week by passing specific date in Java?](https://www.baeldung.com/java-get-day-of-week) | ||||
| - [Finding Leap Years in Java](https://www.baeldung.com/java-leap-year) | ||||
| - [Getting the Week Number From Any Date](https://www.baeldung.com/java-get-week-number) | ||||
| - [Subtract Days from a Date in Java](https://www.baeldung.com/java-subtract-days-from-date) | ||||
| - [[<-- Prev]](/core-java-modules/core-java-date-operations-1) | ||||
|  | ||||
| @ -0,0 +1,49 @@ | ||||
| package com.baeldung.subtractdays; | ||||
| 
 | ||||
| import static org.junit.Assert.assertEquals; | ||||
| 
 | ||||
| import java.text.SimpleDateFormat; | ||||
| import java.time.LocalDate; | ||||
| import java.util.Calendar; | ||||
| import java.util.Date; | ||||
| import java.util.GregorianCalendar; | ||||
| 
 | ||||
| import org.joda.time.DateTime; | ||||
| import org.junit.Test; | ||||
| 
 | ||||
| public class SubtractDaysFromDateUnitTest { | ||||
| 
 | ||||
|     @Test | ||||
|     public void givenLocalDateTime_whenSubtractingFiveDays_dateIsChangedCorrectly() { | ||||
|         LocalDate localDateTime = LocalDate.of(2022, 4, 20); | ||||
| 
 | ||||
|         localDateTime = localDateTime.minusDays(5); | ||||
| 
 | ||||
|         assertEquals(15, localDateTime.getDayOfMonth()); | ||||
|         assertEquals(4, localDateTime.getMonthValue()); | ||||
|         assertEquals(2022, localDateTime.getYear()); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void givenCalendarDate_whenSubtractingFiveDays_dateIsChangedCorrectly() { | ||||
|         Calendar calendar = Calendar.getInstance(); | ||||
|         calendar.set(2022, Calendar.APRIL, 20); | ||||
| 
 | ||||
|         calendar.add(Calendar.DATE, -5); | ||||
| 
 | ||||
|         assertEquals(15, calendar.get(Calendar.DAY_OF_MONTH)); | ||||
|         assertEquals(Calendar.APRIL, calendar.get(Calendar.MONTH)); | ||||
|         assertEquals(2022, calendar.get(Calendar.YEAR)); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void givenJodaDateTime_whenSubtractingFiveDays_dateIsChangedCorrectly() { | ||||
|         DateTime dateTime = new DateTime(2022, 4, 20, 12, 0, 0); | ||||
| 
 | ||||
|         dateTime = dateTime.minusDays(5); | ||||
| 
 | ||||
|         assertEquals(15, dateTime.getDayOfMonth()); | ||||
|         assertEquals(4, dateTime.getMonthOfYear()); | ||||
|         assertEquals(2022, dateTime.getYear()); | ||||
|     } | ||||
| } | ||||
| @ -12,3 +12,4 @@ This module contains articles about parsing and formatting Java date and time ob | ||||
| - [Convert between String and Timestamp](https://www.baeldung.com/java-string-to-timestamp) | ||||
| - [Convert String to Date in Java](http://www.baeldung.com/java-string-to-date) | ||||
| - [Format a Milliseconds Duration to HH:MM:SS](https://www.baeldung.com/java-ms-to-hhmmss) | ||||
| - [Format Instant to String in Java](https://www.baeldung.com/java-instant-to-string) | ||||
|  | ||||
| @ -0,0 +1,54 @@ | ||||
| package com.baeldung.formatinstant; | ||||
| 
 | ||||
| import static org.assertj.core.api.Assertions.assertThat; | ||||
| 
 | ||||
| import java.time.Instant; | ||||
| import java.time.ZoneId; | ||||
| import java.time.format.DateTimeFormatter; | ||||
| import java.time.temporal.UnsupportedTemporalTypeException; | ||||
| 
 | ||||
| import org.joda.time.format.DateTimeFormat; | ||||
| import org.junit.Test; | ||||
| 
 | ||||
| public class FormatInstantUnitTest { | ||||
|      | ||||
|     private static final String PATTERN_FORMAT = "dd.MM.yyyy"; | ||||
| 
 | ||||
|     @Test | ||||
|     public void givenInstant_whenUsingDateTimeFormatter_thenFormat() { | ||||
|         DateTimeFormatter formatter = DateTimeFormatter.ofPattern(PATTERN_FORMAT) | ||||
|             .withZone(ZoneId.systemDefault()); | ||||
| 
 | ||||
|         Instant instant = Instant.parse("2022-02-15T18:35:24.00Z"); | ||||
|         String formattedInstant = formatter.format(instant); | ||||
| 
 | ||||
|         assertThat(formattedInstant).isEqualTo("15.02.2022"); | ||||
|     } | ||||
| 
 | ||||
|     @Test(expected = UnsupportedTemporalTypeException.class) | ||||
|     public void givenInstant_whenNotSpecifyingTimeZone_thenThrowException() { | ||||
|         DateTimeFormatter formatter = DateTimeFormatter.ofPattern(PATTERN_FORMAT); | ||||
| 
 | ||||
|         Instant instant = Instant.now(); | ||||
|         formatter.format(instant); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void givenInstant_whenUsingToString_thenFormat() { | ||||
|         Instant instant = Instant.ofEpochMilli(1641828224000L); | ||||
|         String formattedInstant = instant.toString(); | ||||
| 
 | ||||
|         assertThat(formattedInstant).isEqualTo("2022-01-10T15:23:44Z"); | ||||
|     } | ||||
|      | ||||
|     @Test | ||||
|     public void givenInstant_whenUsingJodaTime_thenFormat() { | ||||
|         org.joda.time.Instant instant = new org.joda.time.Instant("2022-03-20T10:11:12"); | ||||
|          | ||||
|         String formattedInstant = DateTimeFormat.forPattern(PATTERN_FORMAT) | ||||
|             .print(instant); | ||||
| 
 | ||||
|         assertThat(formattedInstant).isEqualTo("20.03.2022"); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -7,7 +7,12 @@ import static org.junit.jupiter.api.Assertions.assertTrue; | ||||
| 
 | ||||
| import org.junit.jupiter.api.Test; | ||||
| 
 | ||||
| public class IllegalMonitorStateExceptionUnitTest { | ||||
| /** | ||||
|  * Needs to be run manually in order to demonstrate the IllegalMonitorStateException scenarios. | ||||
|  * | ||||
|  * There are some intermittent test failures in Jenkins that require further investigation. | ||||
|  */ | ||||
| public class IllegalMonitorStateExceptionManualTest { | ||||
| 
 | ||||
|     @Test | ||||
|     void whenSyncSenderAndSyncReceiverAreUsed_thenIllegalMonitorExceptionShouldNotBeThrown() throws InterruptedException { | ||||
| @ -1,3 +1,5 @@ | ||||
| ### Relevant Articles: | ||||
| 
 | ||||
| - [Java ArrayIndexOutOfBoundsException](https://www.baeldung.com/java-arrayindexoutofboundsexception) | ||||
| - [Java Missing Return Statement](https://www.baeldung.com/java-missing-return-statement) | ||||
| - [Convert long to int Type in Java](https://www.baeldung.com/java-convert-long-to-int) | ||||
|  | ||||
| @ -7,4 +7,6 @@ This module contains articles about core Java input and output (IO) | ||||
| - [Java File Separator vs File Path Separator](https://www.baeldung.com/java-file-vs-file-path-separator) | ||||
| - [Simulate touch Command in Java](https://www.baeldung.com/java-simulate-touch-command) | ||||
| - [SequenceInputStream Class in Java](https://www.baeldung.com/java-sequenceinputstream) | ||||
| - [Read a File Into a Map in Java](https://www.baeldung.com/java-read-file-into-map) | ||||
| - [Read User Input Until a Condition is Met](https://www.baeldung.com/java-read-input-until-condition) | ||||
| - [[<-- Prev]](/core-java-modules/core-java-io-3) | ||||
|  | ||||
| @ -0,0 +1,83 @@ | ||||
| package com.baeldung.filetomap; | ||||
| 
 | ||||
| import java.io.BufferedReader; | ||||
| import java.io.FileReader; | ||||
| import java.io.IOException; | ||||
| import java.nio.file.Files; | ||||
| import java.nio.file.Paths; | ||||
| import java.util.HashMap; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
| import java.util.stream.Collectors; | ||||
| import java.util.stream.Stream; | ||||
| 
 | ||||
| public class FileToHashMap { | ||||
| 
 | ||||
|     enum DupKeyOption { | ||||
|         OVERWRITE, DISCARD | ||||
|     } | ||||
| 
 | ||||
|     public static Map<String, String> byBufferedReader(String filePath, DupKeyOption dupKeyOption) { | ||||
|         HashMap<String, String> map = new HashMap<>(); | ||||
|         String line; | ||||
|         try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) { | ||||
|             while ((line = reader.readLine()) != null) { | ||||
|                 String[] keyValuePair = line.split(":", 2); | ||||
|                 if (keyValuePair.length > 1) { | ||||
|                     String key = keyValuePair[0]; | ||||
|                     String value = keyValuePair[1]; | ||||
|                     if (DupKeyOption.OVERWRITE == dupKeyOption) { | ||||
|                         map.put(key, value); | ||||
|                     } else if (DupKeyOption.DISCARD == dupKeyOption) { | ||||
|                         map.putIfAbsent(key, value); | ||||
|                     } | ||||
|                 } else { | ||||
|                     System.out.println("No Key:Value found in line, ignoring: " + line); | ||||
|                 } | ||||
|             } | ||||
|         } catch (IOException e) { | ||||
|             e.printStackTrace(); | ||||
|         } | ||||
|         return map; | ||||
|     } | ||||
| 
 | ||||
|     public static Map<String, String> byStream(String filePath, DupKeyOption dupKeyOption) { | ||||
|         Map<String, String> map = new HashMap<>(); | ||||
|         try (Stream<String> lines = Files.lines(Paths.get(filePath))) { | ||||
|             lines.filter(line -> line.contains(":")) | ||||
|                 .forEach(line -> { | ||||
|                     String[] keyValuePair = line.split(":", 2); | ||||
|                     String key = keyValuePair[0]; | ||||
|                     String value = keyValuePair[1]; | ||||
|                     if (DupKeyOption.OVERWRITE == dupKeyOption) { | ||||
|                         map.put(key, value); | ||||
|                     } else if (DupKeyOption.DISCARD == dupKeyOption) { | ||||
|                         map.putIfAbsent(key, value); | ||||
|                     } | ||||
|                 }); | ||||
|         } catch (IOException e) { | ||||
|             e.printStackTrace(); | ||||
|         } | ||||
|         return map; | ||||
|     } | ||||
| 
 | ||||
|     public static Map<String, List<String>> aggregateByKeys(String filePath) { | ||||
|         Map<String, List<String>> map = new HashMap<>(); | ||||
|         try (Stream<String> lines = Files.lines(Paths.get(filePath))) { | ||||
|             lines.filter(line -> line.contains(":")) | ||||
|                 .forEach(line -> { | ||||
|                     String[] keyValuePair = line.split(":", 2); | ||||
|                     String key = keyValuePair[0]; | ||||
|                     String value = keyValuePair[1]; | ||||
|                     if (map.containsKey(key)) { | ||||
|                         map.get(key).add(value); | ||||
|                     } else { | ||||
|                         map.put(key, Stream.of(value).collect(Collectors.toList())); | ||||
|                     } | ||||
|                 }); | ||||
|         } catch (IOException e) { | ||||
|             e.printStackTrace(); | ||||
|         } | ||||
|         return map; | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,27 @@ | ||||
| package com.baeldung.userinput; | ||||
| 
 | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
| import java.util.Scanner; | ||||
| 
 | ||||
| public class UserInputHandler { | ||||
| 
 | ||||
|     public static List<String> readUserInput() { | ||||
|         List<String> userData = new ArrayList<>(); | ||||
|         System.out.println("Please enter your data below: (send 'bye' to exit) "); | ||||
|         Scanner input = new Scanner(System.in); | ||||
|         while (true) { | ||||
|             String line = input.nextLine(); | ||||
|             if ("bye".equalsIgnoreCase(line)) { | ||||
|                 break; | ||||
|             } | ||||
|             userData.add(line); | ||||
|         } | ||||
|         return userData; | ||||
|     } | ||||
| 
 | ||||
|     public static void main(String[] args) { | ||||
|         List<String> userData = readUserInput(); | ||||
|         System.out.printf("User Input Data:\n%s", String.join("\n", userData)); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,66 @@ | ||||
| package com.baeldung.filetomap; | ||||
| 
 | ||||
| import org.junit.Before; | ||||
| import org.junit.Test; | ||||
| 
 | ||||
| import java.net.URISyntaxException; | ||||
| import java.nio.file.Paths; | ||||
| import java.util.Arrays; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
| import java.util.stream.Collectors; | ||||
| import java.util.stream.Stream; | ||||
| 
 | ||||
| import static org.assertj.core.api.Assertions.assertThat; | ||||
| 
 | ||||
| public class FileToHashMapUnitTest { | ||||
| 
 | ||||
|     private String filePath; | ||||
| 
 | ||||
|     private static final Map<String, String> EXPECTED_MAP_DISCARD = Stream.of(new String[][]{ | ||||
|         {"title", "The Lord of the Rings: The Return of the King"}, | ||||
|         {"director", "Peter Jackson"}, | ||||
|         {"actor", "Sean Astin"} | ||||
|     }).collect(Collectors.toMap(data -> data[0], data -> data[1])); | ||||
| 
 | ||||
|     private static final Map<String, String> EXPECTED_MAP_OVERWRITE = Stream.of(new String[][]{ | ||||
|         {"title", "The Lord of the Rings: The Return of the King"}, | ||||
|         {"director", "Peter Jackson"}, | ||||
|         {"actor", "Ian McKellen"} | ||||
|     }).collect(Collectors.toMap(data -> data[0], data -> data[1])); | ||||
| 
 | ||||
|     private static final Map<String, List<String>> EXPECTED_MAP_AGGREGATE = Stream.of(new String[][]{ | ||||
|         {"title", "The Lord of the Rings: The Return of the King"}, | ||||
|         {"director", "Peter Jackson"}, | ||||
|         {"actor", "Sean Astin", "Ian McKellen"} | ||||
|     }).collect(Collectors.toMap(arr -> arr[0], arr -> Arrays.asList(Arrays.copyOfRange(arr, 1, arr.length)))); | ||||
| 
 | ||||
|     @Before | ||||
|     public void setPath() throws URISyntaxException { | ||||
|         if (filePath == null) { | ||||
|             filePath = Paths.get(ClassLoader.getSystemResource("filetomap/theLordOfRings.txt").toURI()).toString(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void givenInputFile_whenInvokeByBufferedReaderPriorToJava8_shouldGetExpectedMap() { | ||||
|         Map<String, String> mapOverwrite = FileToHashMap.byBufferedReader(filePath, FileToHashMap.DupKeyOption.OVERWRITE); | ||||
|         Map<String, String> mapDiscard = FileToHashMap.byBufferedReader(filePath, FileToHashMap.DupKeyOption.DISCARD); | ||||
|         assertThat(mapOverwrite).isEqualTo(EXPECTED_MAP_OVERWRITE); | ||||
|         assertThat(mapDiscard).isEqualTo(EXPECTED_MAP_DISCARD); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void givenInputFile_whenInvokeByStream_shouldGetExpectedMap() { | ||||
|         Map<String, String> mapOverwrite = FileToHashMap.byStream(filePath, FileToHashMap.DupKeyOption.OVERWRITE); | ||||
|         Map<String, String> mapDiscard = FileToHashMap.byStream(filePath, FileToHashMap.DupKeyOption.DISCARD); | ||||
|         assertThat(mapOverwrite).isEqualTo(EXPECTED_MAP_OVERWRITE); | ||||
|         assertThat(mapDiscard).isEqualTo(EXPECTED_MAP_DISCARD); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void givenInputFile_whenInvokeAggregateByKeys_shouldGetExpectedMap() { | ||||
|         Map<String, List<String>> mapAgg = FileToHashMap.aggregateByKeys(filePath); | ||||
|         assertThat(mapAgg).isEqualTo(EXPECTED_MAP_AGGREGATE); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,36 @@ | ||||
| package com.baeldung.userinput; | ||||
| 
 | ||||
| 
 | ||||
| import org.junit.Test; | ||||
| 
 | ||||
| import java.io.ByteArrayInputStream; | ||||
| import java.io.InputStream; | ||||
| import java.util.Arrays; | ||||
| import java.util.List; | ||||
| import java.util.stream.Collectors; | ||||
| 
 | ||||
| import static org.assertj.core.api.Assertions.assertThat; | ||||
| 
 | ||||
| public class UserInputHandlerUnitTest { | ||||
| 
 | ||||
|     @Test | ||||
|     public void givenDataInSystemIn_whenCallingReadUserInputMethod_thenHaveUserInputData() { | ||||
|         String[] inputLines = new String[]{ | ||||
|             "The first line.", | ||||
|             "The second line.", | ||||
|             "The last line.", | ||||
|             "bye", | ||||
|             "anything after 'bye' will be ignored" | ||||
|         }; | ||||
|         String[] expectedLines = Arrays.copyOf(inputLines, inputLines.length - 2); | ||||
|         List<String> expected = Arrays.stream(expectedLines).collect(Collectors.toList()); | ||||
|         InputStream stdin = System.in; | ||||
|         try { | ||||
|             System.setIn(new ByteArrayInputStream(String.join("\n", inputLines).getBytes())); | ||||
|             List<String> actual = UserInputHandler.readUserInput(); | ||||
|             assertThat(actual).isEqualTo(expected); | ||||
|         } finally { | ||||
|             System.setIn(stdin); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,6 @@ | ||||
| title:The Lord of the Rings: The Return of the King | ||||
| director:Peter Jackson | ||||
| actor:Sean Astin | ||||
| actor:Ian McKellen | ||||
| Gandalf and Aragorn lead the World of Men against Sauron's | ||||
| army to draw his gaze from Frodo and Sam as they approach Mount Doom with the One Ring. | ||||
| @ -259,7 +259,7 @@ | ||||
|                 </plugins> | ||||
|             </build> | ||||
|         </profile> | ||||
|         | ||||
| 
 | ||||
|     </profiles> | ||||
| 
 | ||||
|     <properties> | ||||
|  | ||||
| @ -64,13 +64,6 @@ | ||||
|         </dependency> | ||||
|     </dependencies> | ||||
| 
 | ||||
|     <properties> | ||||
|         <javaassist.version>3.27.0-GA</javaassist.version> | ||||
|         <sun.tools.version>1.8.0</sun.tools.version> | ||||
|         <jol-core.version>0.10</jol-core.version> | ||||
|         <asm.version>8.0.1</asm.version> | ||||
|         <bcel.version>6.5.0</bcel.version> | ||||
|     </properties> | ||||
|     <profiles> | ||||
|         <!-- java instrumentation profiles to build jars --> | ||||
|         <profile> | ||||
| @ -181,4 +174,12 @@ | ||||
|         </profile> | ||||
|     </profiles> | ||||
| 
 | ||||
|     <properties> | ||||
|         <javaassist.version>3.27.0-GA</javaassist.version> | ||||
|         <sun.tools.version>1.8.0</sun.tools.version> | ||||
|         <jol-core.version>0.10</jol-core.version> | ||||
|         <asm.version>8.0.1</asm.version> | ||||
|         <bcel.version>6.5.0</bcel.version> | ||||
|     </properties> | ||||
| 
 | ||||
| </project> | ||||
| @ -10,3 +10,4 @@ This module contains articles about core features in the Java language | ||||
| - [Tiered Compilation in JVM](https://www.baeldung.com/jvm-tiered-compilation) | ||||
| - [Fixing the “Declared package does not match the expected package” Error](https://www.baeldung.com/java-declared-expected-package-error) | ||||
| - [Chaining Constructors in Java](https://www.baeldung.com/java-chain-constructors) | ||||
| - [Difference Between POJO, JavaBeans, DTO and VO](https://www.baeldung.com/java-pojo-javabeans-dto-vo) | ||||
|  | ||||
| @ -0,0 +1,48 @@ | ||||
| package com.baeldung.employee; | ||||
| 
 | ||||
| import java.io.Serializable; | ||||
| import java.time.LocalDate; | ||||
| 
 | ||||
| public class EmployeeBean implements Serializable { | ||||
| 
 | ||||
|     private static final long serialVersionUID = -3760445487636086034L; | ||||
| 
 | ||||
|     private String firstName; | ||||
|     private String lastName; | ||||
|     private LocalDate startDate; | ||||
| 
 | ||||
|     public EmployeeBean() { | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     public EmployeeBean(String firstName, String lastName, LocalDate startDate) { | ||||
|         this.firstName = firstName; | ||||
|         this.lastName = lastName; | ||||
|         this.startDate = startDate; | ||||
|     } | ||||
| 
 | ||||
|     public String getFirstName() { | ||||
|         return firstName; | ||||
|     } | ||||
| 
 | ||||
|     public void setFirstName(String firstName) { | ||||
|         this.firstName = firstName; | ||||
|     } | ||||
| 
 | ||||
|     public String getLastName() { | ||||
|         return lastName; | ||||
|     } | ||||
| 
 | ||||
|     public void setLastName(String lastName) { | ||||
|         this.lastName = lastName; | ||||
|     } | ||||
| 
 | ||||
|     public LocalDate getStartDate() { | ||||
|         return startDate; | ||||
|     } | ||||
| 
 | ||||
|     public void setStartDate(LocalDate startDate) { | ||||
|         this.startDate = startDate; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,34 @@ | ||||
| package com.baeldung.employee; | ||||
| 
 | ||||
| import java.time.LocalDate; | ||||
| 
 | ||||
| public class EmployeeDTO { | ||||
| 
 | ||||
|     private String firstName; | ||||
|     private String lastName; | ||||
|     private LocalDate startDate; | ||||
| 
 | ||||
|     public String getFirstName() { | ||||
|         return firstName; | ||||
|     } | ||||
| 
 | ||||
|     public void setFirstName(String firstName) { | ||||
|         this.firstName = firstName; | ||||
|     } | ||||
| 
 | ||||
|     public String getLastName() { | ||||
|         return lastName; | ||||
|     } | ||||
| 
 | ||||
|     public void setLastName(String lastName) { | ||||
|         this.lastName = lastName; | ||||
|     } | ||||
| 
 | ||||
|     public LocalDate getStartDate() { | ||||
|         return startDate; | ||||
|     } | ||||
| 
 | ||||
|     public void setStartDate(LocalDate startDate) { | ||||
|         this.startDate = startDate; | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,49 @@ | ||||
| package com.baeldung.employee; | ||||
| 
 | ||||
| import java.time.LocalDate; | ||||
| import java.util.Objects; | ||||
| 
 | ||||
| public class EmployeePOJO { | ||||
| 
 | ||||
|     private String firstName; | ||||
|     private String lastName; | ||||
|     private LocalDate startDate; | ||||
| 
 | ||||
|     public EmployeePOJO(String firstName, String lastName, LocalDate startDate) { | ||||
|         this.firstName = firstName; | ||||
|         this.lastName = lastName; | ||||
|         this.startDate = startDate; | ||||
|     } | ||||
| 
 | ||||
|     public String name() { | ||||
|         return this.firstName + " " + this.lastName; | ||||
|     } | ||||
| 
 | ||||
|     public LocalDate getStart() { | ||||
|         return this.startDate; | ||||
|     } | ||||
| 
 | ||||
|     public String getFirstName() { | ||||
|         return firstName; | ||||
|     } | ||||
| 
 | ||||
|     public void setFirstName(String firstName) { | ||||
|         this.firstName = firstName; | ||||
|     } | ||||
| 
 | ||||
|     public String getLastName() { | ||||
|         return lastName; | ||||
|     } | ||||
| 
 | ||||
|     public void setLastName(String lastName) { | ||||
|         this.lastName = lastName; | ||||
|     } | ||||
| 
 | ||||
|     public LocalDate getStartDate() { | ||||
|         return startDate; | ||||
|     } | ||||
| 
 | ||||
|     public void setStartDate(LocalDate startDate) { | ||||
|         this.startDate = startDate; | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,40 @@ | ||||
| package com.baeldung.employee; | ||||
| 
 | ||||
| import java.time.LocalDate; | ||||
| import java.util.Objects; | ||||
| 
 | ||||
| public class EmployeeVO { | ||||
|     private String firstName; | ||||
|     private String lastName; | ||||
|     private LocalDate startDate; | ||||
| 
 | ||||
|     public EmployeeVO(String firstName, String lastName, LocalDate startDate) { | ||||
|         this.firstName = firstName; | ||||
|         this.lastName = lastName; | ||||
|         this.startDate = startDate; | ||||
|     } | ||||
| 
 | ||||
|     public String getFirstName() { | ||||
|         return firstName; | ||||
|     } | ||||
| 
 | ||||
|     public String getLastName() { | ||||
|         return lastName; | ||||
|     } | ||||
| 
 | ||||
|     public LocalDate getStartDate() { | ||||
|         return startDate; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public boolean equals(Object obj) { | ||||
|         return Objects.equals(firstName, this.firstName) | ||||
|             && Objects.equals(lastName, this.lastName) | ||||
|             && Objects.equals(startDate, this.startDate); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public int hashCode() { | ||||
|         return Objects.hash(firstName, lastName, startDate); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,60 @@ | ||||
| package com.baeldung.implementsvsextends; | ||||
| 
 | ||||
| import com.baeldung.implementsvsextends.media.model.AudioMedia; | ||||
| import com.baeldung.implementsvsextends.media.model.Media; | ||||
| import com.baeldung.implementsvsextends.media.model.VideoMedia; | ||||
| import com.baeldung.implementsvsextends.media.player.impl.AudioMediaPlayer; | ||||
| import com.baeldung.implementsvsextends.media.player.impl.CustomMediaPlayer; | ||||
| import com.baeldung.implementsvsextends.media.player.impl.MultiMediaPlayer; | ||||
| import com.baeldung.implementsvsextends.media.player.impl.VideoMediaPlayer; | ||||
| 
 | ||||
| public class Main { | ||||
| 
 | ||||
|     public static void main(String[] args) { | ||||
| 
 | ||||
|         Media media = new Media(); | ||||
|         media.setId(001); | ||||
|         media.setTitle("Media1"); | ||||
|         media.setArtist("Artist001"); | ||||
| 
 | ||||
|         AudioMedia audioMedia = new AudioMedia(); | ||||
|         audioMedia.setId(101); | ||||
|         audioMedia.setTitle("Audio1"); | ||||
|         audioMedia.setArtist("Artist101"); | ||||
|         audioMedia.setBitrate(3500); | ||||
|         audioMedia.setFrequency("256kbps"); | ||||
| 
 | ||||
|         VideoMedia videoMedia = new VideoMedia(); | ||||
|         videoMedia.setId(201); | ||||
|         videoMedia.setTitle("Video1"); | ||||
|         videoMedia.setArtist("Artist201"); | ||||
|         videoMedia.setResolution("1024x768"); | ||||
|         videoMedia.setAspectRatio("16:9"); | ||||
| 
 | ||||
|         System.out.println(media); | ||||
|         System.out.println(audioMedia); | ||||
|         System.out.println(videoMedia); | ||||
| 
 | ||||
|         AudioMediaPlayer audioMediaPlayer = new AudioMediaPlayer(); | ||||
|         audioMediaPlayer.play(); | ||||
|         audioMediaPlayer.pause(); | ||||
| 
 | ||||
|         VideoMediaPlayer videoMediaPlayer = new VideoMediaPlayer(); | ||||
|         videoMediaPlayer.play(); | ||||
|         videoMediaPlayer.pause(); | ||||
| 
 | ||||
|         MultiMediaPlayer multiMediaPlayer = new MultiMediaPlayer(); | ||||
|         multiMediaPlayer.play(); | ||||
|         multiMediaPlayer.pause(); | ||||
|         multiMediaPlayer.seek(); | ||||
|         multiMediaPlayer.fastForward(); | ||||
| 
 | ||||
|         CustomMediaPlayer customMediaPlayer = new CustomMediaPlayer(); | ||||
|         customMediaPlayer.play(); | ||||
|         customMediaPlayer.pause(); | ||||
|         customMediaPlayer.setId(301); | ||||
|         customMediaPlayer.setTitle("Custom1"); | ||||
|         customMediaPlayer.setArtist("Artist301"); | ||||
|         System.out.println(customMediaPlayer); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,41 @@ | ||||
| package com.baeldung.implementsvsextends.media.model; | ||||
| 
 | ||||
| public class AudioMedia extends Media { | ||||
| 
 | ||||
|     private int bitrate; | ||||
| 
 | ||||
|     private String frequency; | ||||
| 
 | ||||
|     @Override | ||||
|     public void printTitle() { | ||||
|         System.out.println("AudioMedia Title"); | ||||
|     } | ||||
| 
 | ||||
|     public int getBitrate() { | ||||
|         return bitrate; | ||||
|     } | ||||
| 
 | ||||
|     public void setBitrate(int bitrate) { | ||||
|         this.bitrate = bitrate; | ||||
|     } | ||||
| 
 | ||||
|     public String getFrequency() { | ||||
|         return frequency; | ||||
|     } | ||||
| 
 | ||||
|     public void setFrequency(String frequency) { | ||||
|         this.frequency = frequency; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     @Override | ||||
|     public String toString() { | ||||
|         return "AudioMedia{" + | ||||
|                 "id=" + this.getId() + | ||||
|                 ", title='" + this.getTitle() + '\'' + | ||||
|                 ", artist='" + this.getArtist() + '\'' + | ||||
|                 ", bitrate=" + bitrate + | ||||
|                 ", frequency='" + frequency + '\'' + | ||||
|                 "} "; | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,47 @@ | ||||
| package com.baeldung.implementsvsextends.media.model; | ||||
| 
 | ||||
| public class Media { | ||||
| 
 | ||||
|     private int id; | ||||
| 
 | ||||
|     private String title; | ||||
| 
 | ||||
|     private String artist; | ||||
| 
 | ||||
|     public void printTitle() { | ||||
|         System.out.println("Media Title"); | ||||
|     } | ||||
| 
 | ||||
|     public int getId() { | ||||
|         return id; | ||||
|     } | ||||
| 
 | ||||
|     public void setId(int id) { | ||||
|         this.id = id; | ||||
|     } | ||||
| 
 | ||||
|     public String getTitle() { | ||||
|         return title; | ||||
|     } | ||||
| 
 | ||||
|     public void setTitle(String title) { | ||||
|         this.title = title; | ||||
|     } | ||||
| 
 | ||||
|     public String getArtist() { | ||||
|         return artist; | ||||
|     } | ||||
| 
 | ||||
|     public void setArtist(String artist) { | ||||
|         this.artist = artist; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public String toString() { | ||||
|         return "Media{" + | ||||
|                 "id=" + id + | ||||
|                 ", title='" + title + '\'' + | ||||
|                 ", artist='" + artist + '\'' + | ||||
|                 '}'; | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,35 @@ | ||||
| package com.baeldung.implementsvsextends.media.model; | ||||
| 
 | ||||
| public class VideoMedia extends Media { | ||||
| 
 | ||||
|     private String resolution; | ||||
| 
 | ||||
|     private String aspectRatio; | ||||
| 
 | ||||
|     public String getResolution() { | ||||
|         return resolution; | ||||
|     } | ||||
| 
 | ||||
|     public void setResolution(String resolution) { | ||||
|         this.resolution = resolution; | ||||
|     } | ||||
| 
 | ||||
|     public String getAspectRatio() { | ||||
|         return aspectRatio; | ||||
|     } | ||||
| 
 | ||||
|     public void setAspectRatio(String aspectRatio) { | ||||
|         this.aspectRatio = aspectRatio; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public String toString() { | ||||
|         return "VideoMedia{" + | ||||
|                 "id=" + this.getId() + | ||||
|                 ", title='" + this.getTitle() + '\'' + | ||||
|                 ", artist='" + this.getArtist() + '\'' + | ||||
|                 "resolution='" + resolution + '\'' + | ||||
|                 ", aspectRatio='" + aspectRatio + '\'' + | ||||
|                 "} "; | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,8 @@ | ||||
| package com.baeldung.implementsvsextends.media.player; | ||||
| 
 | ||||
| public interface AdvancedPlayerOptions { | ||||
| 
 | ||||
|     void seek(); | ||||
| 
 | ||||
|     void fastForward(); | ||||
| } | ||||
| @ -0,0 +1,8 @@ | ||||
| package com.baeldung.implementsvsextends.media.player; | ||||
| 
 | ||||
| public interface MediaPlayer { | ||||
| 
 | ||||
|     void play(); | ||||
| 
 | ||||
|     void pause(); | ||||
| } | ||||
| @ -0,0 +1,16 @@ | ||||
| package com.baeldung.implementsvsextends.media.player.impl; | ||||
| 
 | ||||
| import com.baeldung.implementsvsextends.media.player.MediaPlayer; | ||||
| 
 | ||||
| public class AudioMediaPlayer implements MediaPlayer { | ||||
| 
 | ||||
|     @Override | ||||
|     public void play() { | ||||
|         System.out.println("AudioMediaPlayer is Playing"); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void pause() { | ||||
|         System.out.println("AudioMediaPlayer is Paused"); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,17 @@ | ||||
| package com.baeldung.implementsvsextends.media.player.impl; | ||||
| 
 | ||||
| import com.baeldung.implementsvsextends.media.model.Media; | ||||
| import com.baeldung.implementsvsextends.media.player.MediaPlayer; | ||||
| 
 | ||||
| public class CustomMediaPlayer extends Media implements MediaPlayer { | ||||
| 
 | ||||
|     @Override | ||||
|     public void play() { | ||||
|         System.out.println("CustomMediaPlayer is Playing"); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void pause() { | ||||
|         System.out.println("CustomMediaPlayer is Paused"); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,27 @@ | ||||
| package com.baeldung.implementsvsextends.media.player.impl; | ||||
| 
 | ||||
| import com.baeldung.implementsvsextends.media.player.AdvancedPlayerOptions; | ||||
| import com.baeldung.implementsvsextends.media.player.MediaPlayer; | ||||
| 
 | ||||
| public class MultiMediaPlayer implements MediaPlayer, AdvancedPlayerOptions { | ||||
| 
 | ||||
|     @Override | ||||
|     public void play() { | ||||
|         System.out.println("MultiMediaPlayer is Playing"); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void pause() { | ||||
|         System.out.println("MultiMediaPlayer is Paused"); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void seek() { | ||||
|         System.out.println("MultiMediaPlayer is being seeked"); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void fastForward() { | ||||
|         System.out.println("MultiMediaPlayer is being fast forwarded"); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,16 @@ | ||||
| package com.baeldung.implementsvsextends.media.player.impl; | ||||
| 
 | ||||
| import com.baeldung.implementsvsextends.media.player.MediaPlayer; | ||||
| 
 | ||||
| public class VideoMediaPlayer implements MediaPlayer { | ||||
| 
 | ||||
|     @Override | ||||
|     public void play() { | ||||
|         System.out.println("VideoMediaPlayer is Playing"); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void pause() { | ||||
|         System.out.println("VideoMediaPlayer is Paused"); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,14 @@ | ||||
| package com.baeldung.implementsvsextends.media.model; | ||||
| 
 | ||||
| import org.hamcrest.CoreMatchers; | ||||
| import org.junit.Assert; | ||||
| import org.junit.Test; | ||||
| 
 | ||||
| public class AudioMediaUnitTest { | ||||
| 
 | ||||
|     @Test | ||||
|     public void givenAudioMediaInstance_whenCheckedType_thenIsInstanceOfMedia() { | ||||
|         AudioMedia audioMedia = new AudioMedia(); | ||||
|         Assert.assertThat(audioMedia, CoreMatchers.<AudioMedia>instanceOf(Media.class)); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,14 @@ | ||||
| package com.baeldung.implementsvsextends.media.model; | ||||
| 
 | ||||
| import org.hamcrest.CoreMatchers; | ||||
| import org.junit.Assert; | ||||
| import org.junit.Test; | ||||
| 
 | ||||
| public class VideoMediaUnitTest { | ||||
| 
 | ||||
|     @Test | ||||
|     public void givenVideoMediaInstance_whenCheckedType_thenIsInstanceOfMedia() { | ||||
|         VideoMedia videoMedia = new VideoMedia(); | ||||
|         Assert.assertThat(videoMedia, CoreMatchers.<VideoMedia>instanceOf(Media.class)); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,41 @@ | ||||
| package com.baeldung.implementsvsextends.media.player.impl; | ||||
| 
 | ||||
| import org.junit.Assert; | ||||
| import org.junit.jupiter.api.AfterEach; | ||||
| import org.junit.jupiter.api.BeforeEach; | ||||
| import org.junit.jupiter.api.Test; | ||||
| 
 | ||||
| import java.io.ByteArrayOutputStream; | ||||
| import java.io.PrintStream; | ||||
| 
 | ||||
| public class AudioMediaPlayerUnitTest { | ||||
| 
 | ||||
|     private final PrintStream standardOut = System.out; | ||||
|     private final ByteArrayOutputStream outputStreamCaptor = new ByteArrayOutputStream(); | ||||
| 
 | ||||
|     @BeforeEach | ||||
|     public void setUp() { | ||||
|         System.setOut(new PrintStream(outputStreamCaptor)); | ||||
|     } | ||||
| 
 | ||||
|     @AfterEach | ||||
|     public void tearDown() { | ||||
|         System.setOut(standardOut); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void givenAudioMediaPlayer_whenPlay_thenPrintsPlayingString() { | ||||
|         AudioMediaPlayer audioMediaPlayer = new AudioMediaPlayer(); | ||||
|         audioMediaPlayer.play(); | ||||
|         Assert.assertEquals("AudioMediaPlayer is Playing", outputStreamCaptor.toString() | ||||
|                 .trim()); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void givenAudioMediaPlayer_whenPause_thenPrintsPausedString() { | ||||
|         AudioMediaPlayer audioMediaPlayer = new AudioMediaPlayer(); | ||||
|         audioMediaPlayer.pause(); | ||||
|         Assert.assertEquals("AudioMediaPlayer is Paused", outputStreamCaptor.toString() | ||||
|                 .trim()); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,58 @@ | ||||
| package com.baeldung.implementsvsextends.media.player.impl; | ||||
| 
 | ||||
| import org.junit.Assert; | ||||
| import org.junit.jupiter.api.AfterEach; | ||||
| import org.junit.jupiter.api.BeforeEach; | ||||
| import org.junit.jupiter.api.Test; | ||||
| 
 | ||||
| import java.io.ByteArrayOutputStream; | ||||
| import java.io.PrintStream; | ||||
| 
 | ||||
| public class MultiMediaPlayerUnitTest { | ||||
| 
 | ||||
|     private final PrintStream standardOut = System.out; | ||||
|     private final ByteArrayOutputStream outputStreamCaptor = new ByteArrayOutputStream(); | ||||
| 
 | ||||
|     @BeforeEach | ||||
|     public void setUp() { | ||||
|         System.setOut(new PrintStream(outputStreamCaptor)); | ||||
|     } | ||||
| 
 | ||||
|     @AfterEach | ||||
|     public void tearDown() { | ||||
|         System.setOut(standardOut); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void givenMultiMediaPlayer_whenPlay_thenPrintsPlayingString() { | ||||
|         MultiMediaPlayer multiMediaPlayer = new MultiMediaPlayer(); | ||||
|         multiMediaPlayer.play(); | ||||
|         Assert.assertEquals("MultiMediaPlayer is Playing", outputStreamCaptor.toString() | ||||
|                 .trim()); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void givenMultiMediaPlayer_whenPause_thenPrintsPausedString() { | ||||
|         MultiMediaPlayer multiMediaPlayer = new MultiMediaPlayer(); | ||||
|         multiMediaPlayer.pause(); | ||||
|         Assert.assertEquals("MultiMediaPlayer is Paused", outputStreamCaptor.toString() | ||||
|                 .trim()); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void givenMultiMediaPlayer_whenSeek_thenPrintsPausedString() { | ||||
|         MultiMediaPlayer multiMediaPlayer = new MultiMediaPlayer(); | ||||
|         multiMediaPlayer.seek(); | ||||
|         Assert.assertEquals("MultiMediaPlayer is being seeked", outputStreamCaptor.toString() | ||||
|                 .trim()); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void givenMultiMediaPlayer_whenFastForward_thenPrintsPausedString() { | ||||
|         MultiMediaPlayer multiMediaPlayer = new MultiMediaPlayer(); | ||||
|         multiMediaPlayer.fastForward(); | ||||
|         Assert.assertEquals("MultiMediaPlayer is being fast forwarded", | ||||
|                 outputStreamCaptor.toString() | ||||
|                 .trim()); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,41 @@ | ||||
| package com.baeldung.implementsvsextends.media.player.impl; | ||||
| 
 | ||||
| import org.junit.Assert; | ||||
| import org.junit.jupiter.api.AfterEach; | ||||
| import org.junit.jupiter.api.BeforeEach; | ||||
| import org.junit.jupiter.api.Test; | ||||
| 
 | ||||
| import java.io.ByteArrayOutputStream; | ||||
| import java.io.PrintStream; | ||||
| 
 | ||||
| public class VideoMediaPlayerUnitTest { | ||||
| 
 | ||||
|     private final PrintStream standardOut = System.out; | ||||
|     private final ByteArrayOutputStream outputStreamCaptor = new ByteArrayOutputStream(); | ||||
| 
 | ||||
|     @BeforeEach | ||||
|     public void setUp() { | ||||
|         System.setOut(new PrintStream(outputStreamCaptor)); | ||||
|     } | ||||
| 
 | ||||
|     @AfterEach | ||||
|     public void tearDown() { | ||||
|         System.setOut(standardOut); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void givenVideoMediaPlayer_whenPlay_thenPrintsPlayingString() { | ||||
|         VideoMediaPlayer videoMediaPlayer = new VideoMediaPlayer(); | ||||
|         videoMediaPlayer.play(); | ||||
|         Assert.assertEquals("VideoMediaPlayer is Playing", outputStreamCaptor.toString() | ||||
|                 .trim()); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void givenVideoMediaPlayer_whenPause_thenPrintsPausedString() { | ||||
|         VideoMediaPlayer videoMediaPlayer = new VideoMediaPlayer(); | ||||
|         videoMediaPlayer.pause(); | ||||
|         Assert.assertEquals("VideoMediaPlayer is Paused", outputStreamCaptor.toString() | ||||
|                 .trim()); | ||||
|     } | ||||
| } | ||||
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