All Projects → sizovs → Pipelinr

sizovs / Pipelinr

Licence: mit
PipelinR is a lightweight command processing pipeline ❍ ⇢ ❍ ⇢ ❍ for your Java awesome app.

Programming Languages

java
68154 projects - #9 most used programming language
kotlin
9241 projects

Projects that are alternatives of or similar to Pipelinr

Micro Company
Rest-full, Hipermedia-based distributed application. Spring boot & cloud. Angular. CQRS. Eventsourcing. Axonframework. Microservices. Docker. CloudFoundry
Stars: ✭ 307 (+129.1%)
Mutual labels:  spring, architecture, cqrs
All Things Cqrs
Comprehensive guide to a couple of possible ways of synchronizing two states with Spring tools. Synchronization is shown by separating command and queries in a simple CQRS application.
Stars: ✭ 474 (+253.73%)
Mutual labels:  spring, cqrs
Bunny
BunnyJS - Lightweight native (vanilla) JavaScript (JS) and ECMAScript 6 (ES6) browser library, package of small stand-alone components without dependencies: FormData, upload, image preview, HTML5 validation, Autocomplete, Dropdown, Calendar, Datepicker, Ajax, Datatable, Pagination, URL, Template engine, Element positioning, smooth scrolling, routing, inversion of control and more. Simple syntax and architecture. Next generation jQuery and front-end framework. Documentation and examples available.
Stars: ✭ 473 (+252.99%)
Mutual labels:  library, architecture
Modular Monolith With Ddd
Full Modular Monolith application with Domain-Driven Design approach.
Stars: ✭ 6,210 (+4534.33%)
Mutual labels:  architecture, cqrs
eshopzero
.Net Microservice Application
Stars: ✭ 27 (-79.85%)
Mutual labels:  cqrs, architecture
Bouncylayout
Make. It. Bounce.
Stars: ✭ 4,035 (+2911.19%)
Mutual labels:  spring, library
Equinoxproject
Full ASP.NET Core 5 application with DDD, CQRS and Event Sourcing concepts
Stars: ✭ 5,120 (+3720.9%)
Mutual labels:  architecture, cqrs
Kingly
Zero-cost state-machine library for robust, testable and portable user interfaces (most machines compile ~1-2KB)
Stars: ✭ 147 (+9.7%)
Mutual labels:  library, architecture
Onboarding
A list of resources we at flyeralarm use to get new developers up and running
Stars: ✭ 648 (+383.58%)
Mutual labels:  architecture, cqrs
Acwa book ru
Книга "Архитектура сложных веб-приложений. С примерами на Laravel"
Stars: ✭ 886 (+561.19%)
Mutual labels:  architecture, cqrs
Thirtyinch
a MVP library for Android favoring a stateful Presenter
Stars: ✭ 1,052 (+685.07%)
Mutual labels:  library, architecture
Sureness
A simple and efficient open-source security framework that focus on protection of restful api.
Stars: ✭ 254 (+89.55%)
Mutual labels:  spring, library
Biking2
This is the source code of http://biking.michael-simons.eu
Stars: ✭ 162 (+20.9%)
Mutual labels:  spring, architecture
Kratos
A modular-designed and easy-to-use microservices framework in Go.
Stars: ✭ 15,844 (+11723.88%)
Mutual labels:  library, architecture
Forcelayout
Forcelayout is library for android. You can drawing graph with spring-like attractive forces. Inspired by force layout in D3.js.
Stars: ✭ 108 (-19.4%)
Mutual labels:  spring, library
Almin
Client-side DDD/CQRS for JavaScript.
Stars: ✭ 477 (+255.97%)
Mutual labels:  library, cqrs
Run Aspnetcore Cqrs
Real world Enterprise CRM application example of ASP.NET Core + Angular web application. Implemented CQRS Design Pattern for ASP.NET Core + Angular reference application, demonstrating a layered application architecture with DDD best practices. Download 100+ page eBook PDF from here ->
Stars: ✭ 152 (+13.43%)
Mutual labels:  architecture, cqrs
Stepper Touch
Stepper Touch for Android based on MaterialUp submission
Stars: ✭ 621 (+363.43%)
Mutual labels:  spring, library
Dev Stuff
😎 Programming stuff for everyone. Collection of articles, videos about architecture, Domain Driven Design, microservices, testing etc.
Stars: ✭ 105 (-21.64%)
Mutual labels:  architecture, cqrs
Awesome Backend Architecture
后端开发常用技术框架、数据库、开源中间件、微服务、系统架构集合。
Stars: ✭ 114 (-14.93%)
Mutual labels:  spring, architecture

PipelinR

Build Status Test Coverage codebeat badge

Download

PipelinR is a lightweight command processing pipeline ❍ ⇢ ❍ ⇢ ❍ for your awesome Java app.

PipelinR has been battle-proven on production, as a service layer in some cool FinTech apps. PipelinR has helped teams switch from a giant service classes handling all use cases to small handlers following single responsibility principle. It's similar to a popular MediatR library for .NET.

💡 Join Effective Java Software Design course to learn more about building great Java enterprise applications.

Table of contents

How to use

PipelinR has no dependencies. All you need is a single 15KB library:

Maven:

<dependency>
  <groupId>an.awesome</groupId>
  <artifactId>pipelinr</artifactId>
  <version>0.5</version>
</dependency>

<repositories>
  <repository>
    <id>central</id>
    <name>bintray</name>
    <url>https://jcenter.bintray.com</url>
  </repository>
</repositories>

Gradle:

repositories {
    jcenter()
}

dependencies {
    compile 'an.awesome:pipelinr:0.5'
}

Java version required: 1.8+.

Commands

Commands is a request that can return a value. The Ping command below returns a string:

class Ping implements Command<String> {

    public final String host;
    
    public Ping(String host) {
        this.host = host;
    }
}

If a command has nothing to return, you can use a built-in Voidy return type:

class Ping implements Command<Voidy> {

    public final String host;
    
    public Ping(String host) {
        this.host = host;
    }
}

Handlers

For every command you must define a Handler, that knows how to handle the command.

Create a handler by implementing Command.Handler<C, R> interface, where C is a command type and R is a return type. Handler's return type must match command's return type:

class Pong implements Command.Handler<Ping, String> {

    @Override
    public String handle(Ping command) {
        return "Pong from " + command.host;
    }
}

Pipeline

A pipeline mediates between commands and handlers. You send commands to the pipeline. When the pipeline receives a command, it sends the command through a sequence of middlewares and finally invokes the matching command handler. Pipelinr is a default implementation of Pipeline interface.

To construct a Pipeline, create an instance of Pipelinr and provide a list of command handlers:

Pipeline pipeline = new Pipelinr()
    .with(
        () -> Stream.of(new Pong())
    );

Send a command for handling:

pipeline.send(new Ping("localhost"));

since v0.4, you can execute commands more naturally:

new Ping("localhost").execute(pipeline);

Pipelinr can receive an optional, ordered list of custom middlewares. Every command will go through the middlewares before being handled. Use middlewares when you want to add extra behavior to command handlers, such as logging, transactions or metrics:

// middleware that logs every command and the result it returns
class Loggable implements Command.Middleware {

    @Override
    public <R, C extends Command<R>> R invoke(C command, Next<R> next) {
        // log command
        R response = next.invoke();
        // log response
        return response;
    }
}

// middleware that wraps a command in a transaction
class Transactional implements Command.Middleware {

    @Override
    public <R, C extends Command<R>> R invoke(C command, Next<R> next) {
        // start tx
        R response = next.invoke();
        // end tx
        return response;
    }
}

In the following pipeline, every command and its response will be logged, plus commands will be wrapped in a transaction:

Pipeline pipeline = new Pipelinr()
    .with(() -> Stream.of(new Pong())),
    .with(() -> Stream.of(new Loggable(), new Transactional()))
);

By default, command handlers are being resolved using generics. By overriding command handler's matches method, you can dynamically select a matching handler:

class LocalhostPong implements Command.Handler<Ping, String> {

    @Override
    public boolean matches(Ping command) {
        return command.host.equals("localhost");
    }

}
class NonLocalhostPong implements Command.Handler<Ping, String> {
    
    @Override
    public boolean matches(Ping command) {
        return !command.host.equals("localhost");
    } 
}

Notifications

Since version 0.5, PipelinR supports Notifications, dispatched to multiple handlers.

For notifications, first create your notification message:

class Ping implements Notification {
}

Next, create zero or more handlers for your notification:

public class Pong1 implements Notification.Handler<Ping> {

    @Override
    public void handle(Ping notification) {
      System.out.printn("Pong 1");
    }
}

public class Pong2 implements Notification.Handler<Ping> {

    @Override
    public void handle(Ping notification) {
      System.out.printn("Pong 2");
    }
}

Finally, send notification to the pipeline:

new Ping().send(pipeline);

💡 Remember to provide notification handlers to PipelinR:

new Pipelinr()
  .with(
    () -> Stream.of(new Pong1(), new Pong2())
  )

Notification middlewares

Notifications, like commands, support middlewares. Notification middlewares will run before every notification handler:

class Transactional implements Notification.Middleware {

    @Override
    public <N extends Notification> void invoke(N notification, Next next) {
        // start tx
        next.invoke();
        // stop tx
    }
}

new Pipelinr().with(() -> Stream.of(new Transactional()))

Notification handling strategies

The default implementation loops through the notification handlers and awaits each one. This ensures each handler is run after one another.

Depending on your use-case for sending notifications, you might need a different strategy for handling the notifications, such running handlers in parallel.

PipelinR supports the following strategies:

  • an.awesome.pipelinr.StopOnException (default)
  • an.awesome.pipelinr.ContinueOnException
  • an.awesome.pipelinr.Async
  • an.awesome.pipelinr.ParallelNoWait
  • an.awesome.pipelinr.ParallelWhenAny
  • an.awesome.pipelinr.ParallelWhenAll

See each class' JavaDocs for the details.

You can override default strategy via:

new Pipelinr().with(new ContinueOnException());

Spring Example

PipelinR works well with Spring and Spring Boot.

Start by configuring a Pipeline. Create an instance of Pipelinr and inject all command handlers and ordered middlewares via the constructor:

@Configuration
class PipelinrConfiguration {

    @Bean
    Pipeline pipeline(ObjectProvider<Command.Handler> commandHandlers, ObjectProvider<Notification.Handler> notificationHandlers, ObjectProvider<Command.Middleware> middlewares) {
        return new Pipelinr()
          .with(commandHandlers::stream)
          .with(notificationHandlers::stream)
          .with(middlewares::orderedStream);
    }
}

Define a command:

class Wave implements Command<String> {
}

Define a handler and annotate it with @Component annotation:

@Component
class WaveBack implements Command.Handler<Wave, String> {
    // ...
}

Optionally, define Order-ed middlewares:

@Component
@Order(1)
class Loggable implements Command.Middleware {
    // ...
}

@Component
@Order(2)
class Transactional implements Command.Middleware {
    // ...
}

To use notifications, define a notification:

class Ping implements Notification {
}

Define notification handlers and annotate them with @Component annotation:

@Component
class Pong1 implements Notification.Handler<Ping> {
    // ...
}

@Component
class Pong2 implements Notification.Handler<Ping> {
    // ...
}

Remember that notifications, like commands, also support Middlewares.

We're ready to go! Inject Pipeline into your application, and start sending commands or notifications:

class Application {

    @Autowired
    Pipeline pipeline;

    public void run() {
        String response = new Wave().execute(pipeline);
        System.out.println(response); 
        
        // ... or
        
        new Ping().send(pipeline); // should trigger Pong1 and Pong2 notification handlers
        
    }
}

Async

PipelinR works well in async or reactive applications. For example, a command can return CompletableFuture:

class AsyncPing implements Command<CompletableFuture<String>> {
    
    @Component
    static class Handler implements Command.Handler<AsyncPing, CompletableFuture<String>> {

        @Override
        public CompletableFuture<String> handle(AsyncPing command) {
            return CompletableFuture.completedFuture("OK");
        }
    }
}

Sending AsyncPing to the pipeline returns CompletableFuture:

CompletableFuture<String> okInFuture = new Ping().execute(pipeline);

How to contribute

Just fork the repo and send us a pull request.

Alternatives

  • MediatR – Simple, unambitious mediator implementation in .NET

Contributors

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].