Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,44 @@
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
replay_pid*

.idea
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
.kotlin

### IntelliJ IDEA ###
.idea/modules.xml
.idea/jarRepositories.xml
.idea/compiler.xml
.idea/libraries/
*.iws
*.iml
*.ipr

### Eclipse ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache

### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/

### VS Code ###
.vscode/

### Mac OS ###
.DS_Store
17 changes: 17 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.nerosoft</groupId>
<artifactId>Mediator</artifactId>
<version>1.0.0</version>

<properties>
<maven.compiler.source>25</maven.compiler.source>
<maven.compiler.target>25</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

</project>
12 changes: 12 additions & 0 deletions src/main/java/com/nerosoft/mediator/Command.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.nerosoft.mediator;

import com.nerosoft.mediator.internal.Message;
import com.nerosoft.mediator.internal.Validatable;

/**
* Represents a command that can be sent to the mediator.
* A command is an instruction to perform a specific action, and it typically does not expect a response.
* Commands are used to change the state of the system or to trigger some behavior.
*/
public interface Command extends Message, Validatable {
}
10 changes: 10 additions & 0 deletions src/main/java/com/nerosoft/mediator/Event.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.nerosoft.mediator;

import com.nerosoft.mediator.internal.Message;

/**
* Represents an event that can be published to the mediator.
* An event is a notification of something that has happened, and it typically does not expect a response.
*/
public interface Event extends Message {
}
4 changes: 4 additions & 0 deletions src/main/java/com/nerosoft/mediator/Handler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package com.nerosoft.mediator;

public interface Handler {
}
41 changes: 41 additions & 0 deletions src/main/java/com/nerosoft/mediator/Mediator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.nerosoft.mediator;

/**
* Defines the Mediator interface for handling commands, queries, and events.
* The Mediator pattern promotes loose coupling between components by centralizing communication.
* This interface can be implemented to create a concrete mediator that manages the interactions between various components in the system.
*/
public interface Mediator {

/**
* Sends a command to the appropriate handler.
* @param command the command to be sent
* @param <T> the type of the command
*/
<T extends Command> void send(T command);

/**
* Executes a query and returns the result.
* @param query the query to be executed
* @param <T> the type of the query
* @param <R> the type of the result
* @return the result of the query
*/
<T extends Query<R>, R> R execute(T query);

/**
* Executes a query and provides the result to the specified response handler.
* @param query the query to be executed
* @param response the response handler
* @param <T> the type of the query
* @param <R> the type of the result
*/
<T extends Query<R>, R> void execute(T query, R response);

/**
* Publishes an event to all interested handlers.
* @param event the event to be published
* @param <T> the type of the event
*/
<T extends Event> void publish(T event);
}
24 changes: 24 additions & 0 deletions src/main/java/com/nerosoft/mediator/Middleware.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.nerosoft.mediator;

import com.nerosoft.mediator.internal.Message;
import com.nerosoft.mediator.internal.MiddlewareDelegate;

/**
* Represents a middleware that can be used in the mediator pipeline.
* Middleware can be used to perform additional processing on messages before they are handled by their respective handlers.
* This can include tasks such as logging, validation, authentication,
* or any other cross-cutting concerns that you want to apply to messages as they pass through the mediator.
* Middleware can be added to the mediator pipeline to intercept messages and perform actions before or after the main handling logic is executed.
* This allows you to separate concerns and keep your handlers focused on their specific tasks, while still allowing for additional processing to be applied to messages in a consistent and reusable way.
*/
@FunctionalInterface
public interface Middleware {

/**
* Executes the middleware logic for the given message and then invokes the next middleware or handler in the chain.
* @param message the message to be processed by the middleware
* @param next the delegate to invoke the next middleware or handler in the chain
* @return the result of the next middleware or handler
*/
Object handle(Message message, MiddlewareDelegate next);
}
23 changes: 23 additions & 0 deletions src/main/java/com/nerosoft/mediator/PipelinedMediator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.nerosoft.mediator;

public class PipelinedMediator implements Mediator {
@Override
public <T extends Command> void send(T command) {

}

@Override
public <T extends Query<R>, R> R execute(T query) {
return null;
}

@Override
public <T extends Query<R>, R> void execute(T query, R response) {

}

@Override
public <T extends Event> void publish(T event) {

}
}
13 changes: 13 additions & 0 deletions src/main/java/com/nerosoft/mediator/Query.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.nerosoft.mediator;

import com.nerosoft.mediator.internal.Message;
import com.nerosoft.mediator.internal.Validatable;

/**
* Represents a query that can be sent to the mediator.
* A query is a request for data or information, and it typically expects a response of type R.
*
* @param <R> the type of the response expected from the query.
*/
public interface Query<R> extends Message, Validatable {
}
20 changes: 20 additions & 0 deletions src/main/java/com/nerosoft/mediator/Validator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.nerosoft.mediator;

import com.nerosoft.mediator.internal.Message;
import com.nerosoft.mediator.internal.Validatable;
import com.nerosoft.mediator.validation.ValidationResult;

/**
* Defines a contract for validating messages before they are processed by the mediator.
* Implementations of this interface can be used to ensure that messages meet certain criteria or constraints before they are handled by the appropriate handlers in the mediator pattern.
* @param <T> the type of message to be validated. Only messages that extend the Validatable class can be validated using this interface, ensuring that the validation logic is specific to the types of messages being processed in the mediator pattern.
*/
public interface Validator<T extends Validatable & Message> {

/**
* Validates the given message and returns a ValidationResult indicating whether the validation was successful or if there were any errors.
* @param message the message to be validated
* @return the result of the validation, including any error messages if the validation failed
*/
ValidationResult validate(T message);
}
4 changes: 4 additions & 0 deletions src/main/java/com/nerosoft/mediator/internal/Message.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package com.nerosoft.mediator.internal;

public interface Message {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.nerosoft.mediator.internal;

/**
* The next invocation of the middleware chain.
* To invoke the next middleware or handler in the chain, call the invoke() method on this delegate.
* This delegate is passed to each middleware and handler in the chain, allowing them to control when the next middleware is invoked.
* Middleware and handlers can choose to invoke the next middleware immediately,
* or they can perform some processing before invoking the next middleware.
* This allows for flexible control over the flow of the middleware chain,
* enabling middleware to perform tasks such as logging, validation, authentication, or any other cross-cutting concerns before the main handling logic is executed.
* By using this delegate, middleware and handlers can ensure that the next middleware in the chain is invoked at the appropriate time,
* allowing for a consistent and reusable way to apply additional processing to messages as they pass through the mediator.
*/
@FunctionalInterface
public interface MiddlewareDelegate {
/**
* Invokes the next middleware or handler in the chain.
* @return the result of the next middleware or handler
*/
Object invoke();
}
9 changes: 9 additions & 0 deletions src/main/java/com/nerosoft/mediator/internal/Validatable.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.nerosoft.mediator.internal;

/**
* Represents a marker interface for objects that can be validated.
* This interface is used to indicate that a class has validation logic associated with it, and it can be used in conjunction with the Validator interface to perform validation on instances of classes that implement Validatable.
* By implementing this interface, a class can be recognized as being subject to validation rules, allowing for a consistent approach to validating objects within the mediator pattern.
*/
public interface Validatable {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package com.nerosoft.mediator.validation;

import java.util.List;

/**
* Represents an exception that is thrown when validation fails in the mediator pattern.
* This exception encapsulates the details of the validation failure,
* including a list of error messages that describe the reasons for the failure.
* The ValidationException class extends RuntimeException,
* allowing it to be thrown without the need for explicit handling in the code that performs validation.
* By providing a dedicated exception for validation failures,
* it allows for better error handling and improved code readability when dealing with validation logic in the mediator pattern.
* The ValidationException class also provides a method to retrieve the ValidationResult associated with the exception,
* allowing for easy access to the details of the validation failure when catching the exception.
* Overall, this class serves as a clear and consistent way to represent validation failures in the mediator pattern,
* promoting better error handling and improved code readability when dealing with validation logic in the application.
*/
public class ValidationException extends RuntimeException {
private final transient ValidationResult result;

/**
* Creates a new ValidationException with the specified list of error messages.
* @param errors the list of error messages describing the validation failure
*/
private ValidationException(List<String> errors) {
super("Validation failed: " + String.join(", ", errors));
this.result = ValidationResult.failure(errors);
}

/**
* Creates a new ValidationException with the specified list of error messages.
* @param message the error message describing the validation failure
*/
public ValidationException(String message) {
super(message);
this.result = ValidationResult.failure(message);
}

/**
* Gets the ValidationResult associated with this exception, which contains the details of the validation failure, including any error messages.
* @return the ValidationResult associated with this exception
*/
public ValidationResult getResult() {
return result;
}

/**
* Gets the list of error messages describing the validation failure.
* @return the list of error messages describing the validation failure
*/
public List<String> getErrors() {
return result.getErrors();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package com.nerosoft.mediator.validation;

import java.util.List;

/**
* Defines the result of a validation operation, which can be either successful or failed with a list of error messages.
* This class provides static factory methods to create success or failure results, and it allows checking the status of the validation and retrieving any error messages if the validation failed.
* The ValidationResult class is designed to be immutable and thread-safe, making it suitable for use in concurrent environments where multiple threads may be performing validation operations simultaneously.
* By encapsulating the validation result in a dedicated class, it promotes a clear and consistent way to handle validation outcomes throughout the application, allowing for better error handling and improved code readability when dealing with validation logic in the mediator pattern.
*/
public final class ValidationResult {
private static final ValidationResult SUCCESS = new ValidationResult(List.of());

private final List<String> errors;

public ValidationResult(List<String> errors) {
this.errors = errors;
}

public static ValidationResult success() {
return SUCCESS;
}

public static ValidationResult failure(List<String> errors) {
return new ValidationResult(errors);
}

public static ValidationResult failure(String message) {
return new ValidationResult(List.of(message));
}

public List<String> getErrors() {
return errors;
}

public boolean isSuccess() {
return errors.isEmpty();
}

public boolean isFailure() {
return !isSuccess();
}

@Override
public String toString() {
return isSuccess()? "ValidationResult{success}" : "ValidationResult{failure, errors=" + errors + "}";
}
}
Loading