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);
|
||||
}
|
||||
}
|
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
|
||||
|
||||
}
|
|
@ -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>
|
|
@ -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
|
|
@ -0,0 +1,7 @@
|
|||
### Related articles
|
||||
|
||||
- [SSO with Apache Tomcat](https://www.baeldung.com/apache-tomcat-sso)
|
||||
|
||||
### Launch Example using Docker
|
||||
|
||||
$ docker-compose up
|
|
@ -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"]
|
|
@ -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>
|
|
@ -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" {
|
||||
// };
|
|
@ -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
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
File diff suppressed because it is too large
Load Diff
|
@ -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>
|
|
@ -0,0 +1,9 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Ping</title>
|
||||
</head>
|
||||
<body>
|
||||
<a href="private/index.html">Start pinging</a>
|
||||
</body>
|
||||
</html>
|
|
@ -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>
|
|
@ -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>
|
|
@ -0,0 +1,9 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Ping - Pinging</title>
|
||||
</head>
|
||||
<body>
|
||||
<a href="/pong/private/index.html">Pong!</a>
|
||||
</body>
|
||||
</html>
|
|
@ -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>
|
|
@ -0,0 +1,9 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Pong</title>
|
||||
</head>
|
||||
<body>
|
||||
<a href="private/index.html">Start ponging</a>
|
||||
</body>
|
||||
</html>
|
|
@ -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…
Reference in New Issue