mirror of
https://github.com/tiennm99/java-design-patterns.git
synced 2026-05-20 18:24:15 +00:00
deps: Refactor dependencies (#3224)
* remove spring dep move junit, logging, mockito under dep mgmt * upgrade anti-corruption-layer deps * async method invocation * balking, bloc * bridge to bytecode * caching * callback - cqrs * component - health check * hexagonal - metadata mapping * rest of the patterns * remove checkstyle, take spotless into use
This commit is contained in:
@@ -28,16 +28,15 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The Version Number pattern helps to resolve concurrency conflicts in applications.
|
||||
* Usually these conflicts arise in database operations, when multiple clients are trying
|
||||
* to update the same record simultaneously.
|
||||
* Resolving such conflicts requires determining whether an object has changed.
|
||||
* For this reason we need a version number that is incremented with each change
|
||||
* to the underlying data, e.g. database. The version number can be used by repositories
|
||||
* to check for external changes and to report concurrency issues to the users.
|
||||
* The Version Number pattern helps to resolve concurrency conflicts in applications. Usually these
|
||||
* conflicts arise in database operations, when multiple clients are trying to update the same
|
||||
* record simultaneously. Resolving such conflicts requires determining whether an object has
|
||||
* changed. For this reason we need a version number that is incremented with each change to the
|
||||
* underlying data, e.g. database. The version number can be used by repositories to check for
|
||||
* external changes and to report concurrency issues to the users.
|
||||
*
|
||||
* <p>In this example we show how Alice and Bob will try to update the {@link Book}
|
||||
* and save it simultaneously to {@link BookRepository}, which represents a typical database.
|
||||
* <p>In this example we show how Alice and Bob will try to update the {@link Book} and save it
|
||||
* simultaneously to {@link BookRepository}, which represents a typical database.
|
||||
*
|
||||
* <p>As in real databases, each client operates with copy of the data instead of original data
|
||||
* passed by reference, that's why we are using {@link Book} copy-constructor here.
|
||||
@@ -50,10 +49,8 @@ public class App {
|
||||
*
|
||||
* @param args command line args
|
||||
*/
|
||||
public static void main(String[] args) throws
|
||||
BookDuplicateException,
|
||||
BookNotFoundException,
|
||||
VersionMismatchException {
|
||||
public static void main(String[] args)
|
||||
throws BookDuplicateException, BookNotFoundException, VersionMismatchException {
|
||||
var bookId = 1;
|
||||
|
||||
var bookRepository = new BookRepository();
|
||||
|
||||
@@ -27,9 +27,7 @@ package com.iluwatar.versionnumber;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* Model class for Book entity.
|
||||
*/
|
||||
/** Model class for Book entity. */
|
||||
@Getter
|
||||
@Setter
|
||||
public class Book {
|
||||
@@ -40,9 +38,7 @@ public class Book {
|
||||
|
||||
public Book() {}
|
||||
|
||||
/**
|
||||
* We need this copy constructor to copy book representation in {@link BookRepository}.
|
||||
*/
|
||||
/** We need this copy constructor to copy book representation in {@link BookRepository}. */
|
||||
public Book(Book book) {
|
||||
this.id = book.id;
|
||||
this.title = book.title;
|
||||
|
||||
@@ -24,9 +24,7 @@
|
||||
*/
|
||||
package com.iluwatar.versionnumber;
|
||||
|
||||
/**
|
||||
* When someone has tried to add a book which repository already have.
|
||||
*/
|
||||
/** When someone has tried to add a book which repository already have. */
|
||||
public class BookDuplicateException extends Exception {
|
||||
public BookDuplicateException(String message) {
|
||||
super(message);
|
||||
|
||||
@@ -24,9 +24,7 @@
|
||||
*/
|
||||
package com.iluwatar.versionnumber;
|
||||
|
||||
/**
|
||||
* Client has tried to make an operation with book which repository does not have.
|
||||
*/
|
||||
/** Client has tried to make an operation with book which repository does not have. */
|
||||
public class BookNotFoundException extends Exception {
|
||||
public BookNotFoundException(String message) {
|
||||
super(message);
|
||||
|
||||
@@ -27,18 +27,17 @@ package com.iluwatar.versionnumber;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* This repository represents simplified database.
|
||||
* As a typical database do, repository operates with copies of object.
|
||||
* So client and repo has different copies of book, which can lead to concurrency conflicts
|
||||
* as much as in real databases.
|
||||
* This repository represents simplified database. As a typical database do, repository operates
|
||||
* with copies of object. So client and repo has different copies of book, which can lead to
|
||||
* concurrency conflicts as much as in real databases.
|
||||
*/
|
||||
public class BookRepository {
|
||||
private final ConcurrentHashMap<Long, Book> collection = new ConcurrentHashMap<>();
|
||||
private final Object lock = new Object();
|
||||
|
||||
/**
|
||||
* Adds book to collection.
|
||||
* Actually we are putting copy of book (saving a book by value, not by reference);
|
||||
* Adds book to collection. Actually we are putting copy of book (saving a book by value, not by
|
||||
* reference);
|
||||
*/
|
||||
public void add(Book book) throws BookDuplicateException {
|
||||
if (collection.containsKey(book.getId())) {
|
||||
@@ -49,9 +48,7 @@ public class BookRepository {
|
||||
collection.put(book.getId(), new Book(book));
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates book in collection only if client has modified the latest version of the book.
|
||||
*/
|
||||
/** Updates book in collection only if client has modified the latest version of the book. */
|
||||
public void update(Book book) throws BookNotFoundException, VersionMismatchException {
|
||||
if (!collection.containsKey(book.getId())) {
|
||||
throw new BookNotFoundException("Not found book with id: " + book.getId());
|
||||
@@ -62,9 +59,10 @@ public class BookRepository {
|
||||
var latestBook = collection.get(book.getId());
|
||||
if (book.getVersion() != latestBook.getVersion()) {
|
||||
throw new VersionMismatchException(
|
||||
"Tried to update stale version " + book.getVersion()
|
||||
+ " while actual version is " + latestBook.getVersion()
|
||||
);
|
||||
"Tried to update stale version "
|
||||
+ book.getVersion()
|
||||
+ " while actual version is "
|
||||
+ latestBook.getVersion());
|
||||
}
|
||||
|
||||
// update version, including client representation - modify by reference here
|
||||
@@ -76,8 +74,8 @@ public class BookRepository {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns book representation to the client.
|
||||
* Representation means we are returning copy of the book.
|
||||
* Returns book representation to the client. Representation means we are returning copy of the
|
||||
* book.
|
||||
*/
|
||||
public Book get(long bookId) throws BookNotFoundException {
|
||||
if (!collection.containsKey(bookId)) {
|
||||
|
||||
+1
-3
@@ -24,9 +24,7 @@
|
||||
*/
|
||||
package com.iluwatar.versionnumber;
|
||||
|
||||
/**
|
||||
* Client has tried to update a stale version of the book.
|
||||
*/
|
||||
/** Client has tried to update a stale version of the book. */
|
||||
public class VersionMismatchException extends Exception {
|
||||
public VersionMismatchException(String message) {
|
||||
super(message);
|
||||
|
||||
Reference in New Issue
Block a user