[BAEL-3601] - Fix code review comments.
This commit is contained in:
@@ -8,5 +8,4 @@ This module contains articles about core Java non-blocking input and output (IO)
|
|||||||
- [Create a Symbolic Link with Java](https://www.baeldung.com/java-symlink)
|
- [Create a Symbolic Link with Java](https://www.baeldung.com/java-symlink)
|
||||||
- [Introduction to the Java NIO Selector](https://www.baeldung.com/java-nio-selector)
|
- [Introduction to the Java NIO Selector](https://www.baeldung.com/java-nio-selector)
|
||||||
- [Using Java MappedByteBuffer](https://www.baeldung.com/java-mapped-byte-buffer)
|
- [Using Java MappedByteBuffer](https://www.baeldung.com/java-mapped-byte-buffer)
|
||||||
- [How to Lock a File in Java](https://www.baeldung.com/how-to-lock-a-file-in-java)
|
- [[<-- Prev]](/core-java-modules/core-java-nio)
|
||||||
- [[<-- Prev]](/core-java-modules/core-java-nio)
|
|
||||||
|
|||||||
+107
-207
File diff suppressed because it is too large
Load Diff
@@ -1,87 +0,0 @@
|
|||||||
package com.baeldung.lock;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertNotNull;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.channels.FileLock;
|
|
||||||
import java.nio.channels.NonReadableChannelException;
|
|
||||||
import java.nio.channels.NonWritableChannelException;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
class FileLocksTest {
|
|
||||||
|
|
||||||
// Exclusive locks
|
|
||||||
/**
|
|
||||||
* Getting an exclusive (write) lock on the entire file.
|
|
||||||
* Fails when getting the lock from a FileChannel obtained through a FileInputStream.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
void givenAnInputStream_whenGetWriteLock_throwNonWritableChannelException() {
|
|
||||||
assertThrows(NonWritableChannelException.class,
|
|
||||||
() -> FileLocks.getExclusiveLockFromInputStream());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Getting an exclusive lock from a RandomAccessFile
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
void givenARandomAccessFileWithReadWriteAccess_whenGetWriteLock_lock() throws IOException {
|
|
||||||
FileLock lock = FileLocks.getExclusiveLockFromRandomAccessFile(0, 10);
|
|
||||||
assertNotNull(lock);
|
|
||||||
assertFalse(lock.isShared());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Getting an exclusive lock from FileChannel::open
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
void givenAPath_whenGetExclusiveLock_lock() throws IOException {
|
|
||||||
FileLock lock = FileLocks.getExclusiveLockFromFileChannelOpen(0, 10);
|
|
||||||
assertNotNull(lock);
|
|
||||||
assertFalse(lock.isShared());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Shared locks
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Getting a shared (read) lock on the entire file.
|
|
||||||
* Fails when getting the lock from a FileChannel obtained through a FileOutputStream.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
void givenAFileOutputStream_whenGetSharedLock_throwNonReadableChannelException() {
|
|
||||||
assertThrows(NonReadableChannelException.class,
|
|
||||||
() -> FileLocks.getReadLockFromOutputStream(0, 10));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Getting a shared (read) lock works fine when getting the lock from a FileChannel obtained through a FileInputStream.
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
void givenAnInputStream_whenGetSharedLock_lock() throws IOException {
|
|
||||||
FileLock lock = FileLocks.getReadLockFromInputStream(0, 10);
|
|
||||||
assertNotNull(lock);
|
|
||||||
assertTrue(lock.isShared());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Getting a shared lock from a RandomAccessFile
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
void givenARandomAccessFile_whenGetSharedLock_lock() throws IOException {
|
|
||||||
FileLock lock = FileLocks.getReadLockFromRandomAccessFile(0, 10);
|
|
||||||
assertNotNull(lock);
|
|
||||||
assertTrue(lock.isShared());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
+48
@@ -0,0 +1,48 @@
|
|||||||
|
package com.baeldung.lock;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.channels.FileLock;
|
||||||
|
import java.nio.channels.NonReadableChannelException;
|
||||||
|
import java.nio.channels.NonWritableChannelException;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
class FileLocksUnitTest {
|
||||||
|
|
||||||
|
@Test void givenAnInputStream_whenGetWriteLock_throwNonWritableChannelException() {
|
||||||
|
assertThrows(NonWritableChannelException.class, () -> FileLocks.getExclusiveLockFromInputStream());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test void givenARandomAccessFileWithReadWriteAccess_whenGetWriteLock_lock() throws IOException {
|
||||||
|
FileLock lock = FileLocks.getExclusiveLockFromRandomAccessFile(0, 10);
|
||||||
|
assertNotNull(lock);
|
||||||
|
assertFalse(lock.isShared());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test void givenAPath_whenGetExclusiveLock_lock() throws IOException {
|
||||||
|
FileLock lock = FileLocks.getExclusiveLockFromFileChannelOpen(0, 10);
|
||||||
|
assertNotNull(lock);
|
||||||
|
assertFalse(lock.isShared());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test void givenAFileOutputStream_whenGetSharedLock_throwNonReadableChannelException() {
|
||||||
|
assertThrows(NonReadableChannelException.class, FileLocks::getReadLockFromOutputStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test void givenAnInputStream_whenGetSharedLock_lock() throws IOException {
|
||||||
|
FileLock lock = FileLocks.getReadLockFromInputStream(0, 10);
|
||||||
|
assertNotNull(lock);
|
||||||
|
assertTrue(lock.isShared());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test void givenARandomAccessFile_whenGetSharedLock_lock() throws IOException {
|
||||||
|
FileLock lock = FileLocks.getReadLockFromRandomAccessFile(0, 10);
|
||||||
|
assertNotNull(lock);
|
||||||
|
assertTrue(lock.isShared());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
### Relevant Articles:
|
### Relevant Articles:
|
||||||
- [Service Locator Pattern](https://www.baeldung.com/java-service-locator-pattern)
|
- [Service Locator Pattern](https://www.baeldung.com/java-service-locator-pattern)
|
||||||
- [The DAO Pattern in Java](https://www.baeldung.com/java-dao-pattern)
|
- [The DAO Pattern in Java](https://www.baeldung.com/java-dao-pattern)
|
||||||
- [A Practical Example of Hexagonal Architecture in Java](https://www.baeldung.com/java-hexagonal-pattern)
|
|
||||||
|
|||||||
-45
@@ -1,45 +0,0 @@
|
|||||||
package com.baeldung.hexagonal;
|
|
||||||
|
|
||||||
import com.baeldung.hexagonal.adapters.DisplayInConsoleAdapter;
|
|
||||||
import com.baeldung.hexagonal.adapters.InMemoryMessageStore;
|
|
||||||
import com.baeldung.hexagonal.application.ChatManager;
|
|
||||||
import com.baeldung.hexagonal.domain.ChatUser;
|
|
||||||
import com.baeldung.hexagonal.domain.IDisplayMessages;
|
|
||||||
|
|
||||||
import java.util.ArrayDeque;
|
|
||||||
import java.util.Scanner;
|
|
||||||
|
|
||||||
public class ChatApplication {
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
Scanner console = new Scanner(System.in);
|
|
||||||
|
|
||||||
System.out.print("Enter username of user 1: ");
|
|
||||||
ChatUser user1 = new ChatUser(console.nextLine());
|
|
||||||
|
|
||||||
System.out.printf("Enter username of user 2: ");
|
|
||||||
ChatUser user2 = new ChatUser(console.nextLine());
|
|
||||||
|
|
||||||
System.out.println("Chat will end when any user uses the word bye in a message.");
|
|
||||||
|
|
||||||
InMemoryMessageStore messageStore = new InMemoryMessageStore(new ArrayDeque<>(10));
|
|
||||||
IDisplayMessages messageDisplayer = new DisplayInConsoleAdapter(messageStore);
|
|
||||||
ChatManager chatManager = new ChatManager(messageStore, messageDisplayer);
|
|
||||||
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
System.out.printf("From %s to %s : ", user1, user2);
|
|
||||||
String message = console.nextLine();
|
|
||||||
if (message.toLowerCase().contains("bye")) {
|
|
||||||
chatManager.sendMessage(user1, user2, message);
|
|
||||||
System.out.println("Chat recap:");
|
|
||||||
messageDisplayer.displayMessages();
|
|
||||||
System.exit(0);
|
|
||||||
}
|
|
||||||
chatManager.sendMessage(user1, user2, message);
|
|
||||||
ChatUser temp = user1;
|
|
||||||
user1 = user2;
|
|
||||||
user2 = temp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-36
@@ -1,36 +0,0 @@
|
|||||||
package com.baeldung.hexagonal.adapters;
|
|
||||||
|
|
||||||
import com.baeldung.hexagonal.domain.ChatMessage;
|
|
||||||
import com.baeldung.hexagonal.domain.IDisplayMessages;
|
|
||||||
import com.baeldung.hexagonal.domain.IStoreMessages;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A Utility adapter to display the chat messages in the console
|
|
||||||
*/
|
|
||||||
public class DisplayInConsoleAdapter implements IDisplayMessages {
|
|
||||||
|
|
||||||
IStoreMessages messageStore;
|
|
||||||
|
|
||||||
public DisplayInConsoleAdapter(IStoreMessages messageStore) {
|
|
||||||
this.messageStore = messageStore;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void clearScreen() {
|
|
||||||
System.out.print("\033[H\033[2J");
|
|
||||||
System.out.flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void displayMessages() {
|
|
||||||
clearScreen();
|
|
||||||
for (ChatMessage message: messageStore.getMessages(10)) {
|
|
||||||
System.out.printf(
|
|
||||||
"%tF %tT [%s to %s]: %s %n",
|
|
||||||
message.getTimeSent(),
|
|
||||||
message.getTimeSent(),
|
|
||||||
message.getFrom(),
|
|
||||||
message.getTo(),
|
|
||||||
message.getContents());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-37
@@ -1,37 +0,0 @@
|
|||||||
package com.baeldung.hexagonal.adapters;
|
|
||||||
|
|
||||||
import com.baeldung.hexagonal.domain.ChatMessage;
|
|
||||||
import com.baeldung.hexagonal.domain.IStoreMessages;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.Queue;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* We're storing the messages in memory. We could later opt to switch to an implementation that stores messages in a
|
|
||||||
* database.
|
|
||||||
*/
|
|
||||||
public class InMemoryMessageStore implements IStoreMessages {
|
|
||||||
|
|
||||||
private Queue<ChatMessage> messages;
|
|
||||||
|
|
||||||
public InMemoryMessageStore(Queue<ChatMessage> messages) {
|
|
||||||
this.messages = messages;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void storeMessage(ChatMessage message) {
|
|
||||||
this.messages.add(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Collection<ChatMessage> getMessages(long maxNbMessages) {// @formatter:off
|
|
||||||
return messages.stream()
|
|
||||||
.sorted((m1, m2) -> m2.getTimeSent().compareTo(m1.getTimeSent()))
|
|
||||||
.limit(maxNbMessages)
|
|
||||||
.sorted(Comparator.comparing(ChatMessage::getTimeSent))
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
// @formatter:on
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-27
@@ -1,27 +0,0 @@
|
|||||||
package com.baeldung.hexagonal.application;
|
|
||||||
|
|
||||||
import com.baeldung.hexagonal.domain.*;
|
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
|
|
||||||
public class ChatManager implements ISendMessage {
|
|
||||||
|
|
||||||
// The domain doesn't need to know where messages will be stored
|
|
||||||
private IStoreMessages messageStore;
|
|
||||||
|
|
||||||
// The domain doesn't need to know how messages will be displayed
|
|
||||||
private IDisplayMessages messageDisplayer;
|
|
||||||
|
|
||||||
public ChatManager(IStoreMessages messageStore, IDisplayMessages displayMessages) {
|
|
||||||
this.messageStore = messageStore;
|
|
||||||
this.messageDisplayer = displayMessages;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sendMessage(ChatUser from, ChatUser to, String message) {
|
|
||||||
ChatMessage chatMessage = new ChatMessage(LocalDateTime.now(), from, to, message);
|
|
||||||
this.messageStore.storeMessage(chatMessage);
|
|
||||||
this.messageDisplayer.displayMessages();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
-34
@@ -1,34 +0,0 @@
|
|||||||
package com.baeldung.hexagonal.domain;
|
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
|
|
||||||
public class ChatMessage {
|
|
||||||
private LocalDateTime timeSent;
|
|
||||||
private ChatUser from;
|
|
||||||
private ChatUser to;
|
|
||||||
private String contents;
|
|
||||||
|
|
||||||
public LocalDateTime getTimeSent() {
|
|
||||||
return timeSent;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ChatUser getFrom() {
|
|
||||||
return from;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ChatUser getTo() {
|
|
||||||
return to;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getContents() {
|
|
||||||
return contents;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ChatMessage(LocalDateTime timeSent, ChatUser from, ChatUser to, String contents) {
|
|
||||||
this.timeSent = timeSent;
|
|
||||||
this.from = from;
|
|
||||||
this.to = to;
|
|
||||||
this.contents = contents;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
-14
@@ -1,14 +0,0 @@
|
|||||||
package com.baeldung.hexagonal.domain;
|
|
||||||
|
|
||||||
public class ChatUser {
|
|
||||||
private String name;
|
|
||||||
|
|
||||||
public ChatUser(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-8
@@ -1,8 +0,0 @@
|
|||||||
package com.baeldung.hexagonal.domain;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An external system displays the messages sent by users.
|
|
||||||
*/
|
|
||||||
public interface IDisplayMessages {
|
|
||||||
void displayMessages();
|
|
||||||
}
|
|
||||||
-8
@@ -1,8 +0,0 @@
|
|||||||
package com.baeldung.hexagonal.domain;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A user sends a message (application's use case)
|
|
||||||
*/
|
|
||||||
public interface ISendMessage {
|
|
||||||
void sendMessage(ChatUser from, ChatUser to, String message);
|
|
||||||
}
|
|
||||||
-14
@@ -1,14 +0,0 @@
|
|||||||
package com.baeldung.hexagonal.domain;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An external system (infrastructure) stores a message
|
|
||||||
*/
|
|
||||||
public interface IStoreMessages {
|
|
||||||
|
|
||||||
void storeMessage(ChatMessage message);
|
|
||||||
|
|
||||||
Collection<ChatMessage> getMessages(long maxNbMessages);
|
|
||||||
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user