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

Overview

PipelinR

Build Status Test Coverage codebeat badge

Maven Repo

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>net.sizovs</groupId>
  <artifactId>pipelinr</artifactId>
  <version>0.6</version>
</dependency>

Gradle:

dependencies {
    compile 'net.sizovs:pipelinr:0.6'
}

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

Comments
  • Ability to add pipeline behaviours

    Ability to add pipeline behaviours

    I am looking for a way to invoke a pipeline behaviour so that it will automatically perform a common action such as validation, before the main handler is called. Right now I need to manually call new CommandValidator(command) as the first line in my handle(...) method.

    For example ( I'm using your Validator helper class. ):

    
    ...
    
        @Override
        public Workpack handle(Command command) {
            new CommandValidator(command);
    
            var workpack = WorkpackFactory.createWorkpack(command);
            workpack = workpackRepository.save(workpack);
            return workpack;
        }
    
    
         class CommandValidator {
            public CommandValidator(Command command){
                new Validator<Command>()
                        .with(() -> command.name, v -> v.isBlank() && v.length() <=20, "name must be between 1 and 20 characters")
                        .with(() -> command.name, v -> nameIsUnique(command.name), "name must be unique")
                        .check(command);
            }
    
            boolean nameIsUnique(String name){
                return !workpackRepository.existsItemByName(name);
            }
        }
    

    Would it be possible to add the ability to have this type of behaviour as part of the pipeline?

    opened by nealeduncan1 7
  • Problem with Kotlin Generics.

    Problem with Kotlin Generics.

    I am following the example of the readme file you guys have (Ping command, Pong handler) but I am using Kotlin.

    I have the following code

    class Ping(val host: String) : Command<String>
    
    class Pong : Command.Handler<Ping, String>{
    
        override fun handle(command: Ping): String {
            return "Pong from " + command.host;
        }
    
    }
    

    Now when trying this code

        var pipeline: Pipeline = Pipelinr().with { Stream.of(Pong()) }
    

    It doesn't compile I get this error:

    Overload resolution ambiguity. All these functions match.
    
    - public final fun with(notificationHandlingStrategySupplier: (() → NotificationHandlingStrategy!)!): Pipelinr! defined in an.awesome.pipelinr.Pipelinr
    
    - public final fun with(commandHandlers: (() → Stream<(an.awesome.pipelinr.Command.Handler<Command<*>!, Any!>..an.awesome.pipelinr.Command.Handler<out Command<*>!, *>?)>!)!): Pipelinr! defined in an.awesome.pipelinr.Pipelinr
    
    - public final fun with(middlewares: (() → Stream<an.awesome.pipelinr.Command.Middleware!>!)!): Pipelinr! defined in an.awesome.pipelinr.Pipelinr
    
    - public final fun with(notificationHandlers: (() → Stream<(an.awesome.pipelinr.Notification.Handler<Notification!>..an.awesome.pipelinr.Notification.Handler<*>?)>!)!): Pipelinr! defined in an.awesome.pipelinr.Pipelinr
    
    - public final fun with(middlewares: (() → Stream<an.awesome.pipelinr.Notification.Middleware!>!)!): Pipelinr! defined in an.awesome.pipelinr.Pipelinr
    - public final fun with(steps: (() → Stream<PipelineStep!>!)!): Pipelinr! defined in an.awesome.pipelinr.Pipelinr
    
    opened by aliwassouf 7
  • Command Handler as CDI bean with @Transactional fails in Handler.matches

    Command Handler as CDI bean with @Transactional fails in Handler.matches

    I am refactoring an existing Jakarta EE application to utilize Pipelinr. I have already implemented several commands and handlers and things were working well until I added a handler with the handle method (or class) annotated with CDI's @Transactional. It appears the proxy object is messing things up. The Command.Handler.matches goes into FirstGenericArgOf.isAssignableFrom and on line 15 gets the generic interfaces. For the normal handlers this ends up being an array of 1 and the type is indeed ParameterizedType so the cast on line 20 works. When I have a handler with @Transactional the call to getGenericInterfaces returns a Class[] instead of Type[] and I get the following error:

    java.lang.ClassCastException: class java.lang.Class cannot be cast to class java.lang.reflect.ParameterizedType (java.lang.Class and java.lang.reflect.ParameterizedType are in module java.base of loader 'bootstrap') at deployment.example.war//an.awesome.pipelinr.FirstGenericArgOf.isAssignableFrom(FirstGenericArgOf.java:20) at deployment.example.war//an.awesome.pipelinr.Command$Handler.matches(Command.java:18)

    The working case: image

    with @Transactional: image

    All of my command handlers are container managed and are populated using the technique from #16 :

    @Produces
        @ApplicationScoped
        public Pipeline getPipeLine(Instance<Command.Handler<?, ?>> handlers, Instance<Command.Middleware> middlewares) {
            List<Command.Handler> commandHandlers = handlers.stream().map(r -> (Command.Handler) r).toList();
            return new Pipelinr()
                    .with(middlewares::stream)
                    .with(commandHandlers::stream);
        }
    

    Is there any way to work around this?

    opened by dstutz 6
  • Can't override method matches in Notification.Handler

    Can't override method matches in Notification.Handler

    Problem Can't override matches method in implementation of Notification.Handler.

    Steps to Reproduce Just launch this test:

    import org.junit.jupiter.api.Test;
    
    public class PipelinrMatchesTest {
    
        class Event1 implements Notification {}
    
        class Event2 implements Notification {}
    
        class TestHandler1 implements Notification.Handler<Event1> {
    
            @Override
            public void handle(Event1 notification) {
    
            }
    
            @Override
            public boolean matches(Event1 notification) {
                return Notification.Handler.super.matches(notification);
            }
        }
    
        class TestHandler2 implements Notification.Handler<Event2> {
            @Override
            public void handle(Event2 notification) {
    
            }
        }
    
        @Test
        void testMatches() {
            Notification.Handler handler1 = new TestHandler1();
            Notification.Handler handler2 = new TestHandler2();
    
            Event1 event1 = new Event1();
            Event2 event2 = new Event2();
    
            System.out.println(handler1.matches(event1));
            System.out.println(handler2.matches(event2));
    
            System.out.println(handler1.matches(event2));
            System.out.println(handler2.matches(event1));
        }
    }
    

    Exception will throws on line System.out.println(handler1.matches(event2));.

    Class an.awesome.pipelinr.Pipelinr uses handlers without generic specification, so this will be reproduced in Pipelinr usage with override method matches.

    Expected Result Success complete test execution.

    Actual Result

    class an.awesome.pipelinr.PipelinrMatchesTest$Event2 cannot be cast to class an.awesome.pipelinr.PipelinrMatchesTest$Event1 (an.awesome.pipelinr.PipelinrMatchesTest$Event2 and an.awesome.pipelinr.PipelinrMatchesTest$Event1 are in unnamed module of loader 'app')
    java.lang.ClassCastException: class an.awesome.pipelinr.PipelinrMatchesTest$Event2 cannot be cast to class an.awesome.pipelinr.PipelinrMatchesTest$Event1 (an.awesome.pipelinr.PipelinrMatchesTest$Event2 and an.awesome.pipelinr.PipelinrMatchesTest$Event1 are in unnamed module of loader 'app')
    	at an.awesome.pipelinr.PipelinrMatchesTest$TestHandler1.matches(PipelinrMatchesTest.java:13)
    	at an.awesome.pipelinr.PipelinrMatchesTest.testMatches(PipelinrMatchesTest.java:49)
    
    opened by vitalii-honchar 5
  • Automatic Setting of Query Handler Multi-Tenancy Data Source

    Automatic Setting of Query Handler Multi-Tenancy Data Source

    I am looking at implementing multitenancy using query handlers and Sql2o. Currently I have a base handler class:

    public class BaseHandler {

    protected Sql2o sql2o;
    
    public void assignSql2oSource() {
        var tenant = Optional.ofNullable(CurrentTenantIdHolder.getTenantId())
                .orElse(TenantDetails.DEFAULT_TENANT);
        this.sql2o = TenantDetails.targetSql2oObjects.get(tenant);
    }
    

    }

    Each Query handler has to extend from this, and call the assignSql2oSource() method to get the correct Sql2o object for the tenant.

    @Component public class GetStatusesQueryHandler extends BaseHandler implements Command.Handler<Query, List> {

    @Override
    public List<StatusDto> handle(Query model) {
        assignSql2oSource();
        final var sql = "SELECT * FROM vw_get_status";
    
        try (var connection = sql2o.open();
                var query = connection.createQuery(sql)) {
            return query
                    .setAutoDeriveColumnNames(true)
                    .throwOnMappingFailure(false)
                    .executeAndFetch(StatusDto.class);
        }
    }
    
    public static class Query implements Command<List<StatusDto>> {
    
        public Query() {
            // No input parameters for query
        }
    }
    

    }

    Is there a way, perhaps using middleware, of automatically running a method to assign the data source and also give the handler access to the sql2o object?

    opened by OldScotsGuy 4
  • Migrating to other repository

    Migrating to other repository

    Hi,

    I'm using your library and I'm wondering if you have migrated to a different repository yet, since JCenter is being shutdown. https://blog.gradle.org/jcenter-shutdown

    opened by morrowyn 3
  • Support for notifications

    Support for notifications

    Hello Eduards ,

    First of all let me say I like your library! I've always wanted a library like MediatR, but for the Java language :) Are you also planning to add support for notifications similar to what MediatR has?

    Kind regards, Maarten

    enhancement 
    opened by mbovijn 3
  • Added possibility to specify NotificationHandlingStrategy when sending notification

    Added possibility to specify NotificationHandlingStrategy when sending notification

    By default I use sorted StopOnException strategy, but in some cases I have to handle notifications with ParallelWhenAll strategy to resolve performance problem.

    opened by lkovalyk 2
  • 0.6 - ContinueOnException has issue?

    0.6 - ContinueOnException has issue?

    always throw AggregateException?

    public class ContinueOnException implements NotificationHandlingStrategy {
    
      @Override
      public void handle(List<Runnable> runnableNotifications) {
        Collection<Throwable> exceptions = new ArrayList<>();
        runnableNotifications.forEach(
            it -> {
              try {
                it.run();
              } catch (Throwable e) {
                exceptions.add(e);
              }
            });
        throw new AggregateException(exceptions);
      }
    }
    
    opened by mailingfeng 2
  • Feature request: Notification support?

    Feature request: Notification support?

    Hi doing both .Net and Java, I was really happy to find pipelinr which seems like a great Java alternative for mediatr.

    I do have a question: will you support notifications or is there a reason it is not there yet? In our application I see several use cases for notifications.

    opened by rdehuyss 2
  • Get notification handler name inside Notification.Middleware

    Get notification handler name inside Notification.Middleware

    Hi,

    I'm trying to get Notification.Handler class name inside Notification.Middleware but I cannot find any way to achieve that. I need it inside my 'LoggableMiddleware' and 'TraceableMiddleware'. Just for logging that name and adding it as a span tag. Is there any option to do it?

    data class Ping(val from: String): Notification {
    
        @Component
        class PongHandler :Notification.Handler<Ping> {
            override fun handle(notification: Ping) {
                TODO("Not yet implemented")
            }
        }
        
        @Component
        class Pong2Handler :Notification.Handler<Ping> {
            override fun handle(notification: Ping) {
                TODO("Not yet implemented")
            }
        }
    }
    

    And from middleware I want to log something like "Handling Ping notification in PongHandler "

    opened by arkadiuszSzast 1
Releases(0.4)
  • 0.4(Oct 31, 2019)

    See #11, release log:

    • 9aac705ea4c20073647872932c6c020851185f9a: add more natural way of execut...
    • 5db429670ff9528b70ee35890da8cdcaa2076f0e by @sizovs: [skip travis] remove reference...
    • a37fc0fe70225bf6030da0a9f1a06ccab2866fa1 by @sizovs: [skip travis] fix version in d...
    • 0b94ce8eb23c8b74ca536d5c98612041a4a5d4e7 by @sizovs: [skip travis] update docs for ...

    Released by Rultor 2.0-SNAPSHOT, see build log

    Source code(tar.gz)
    Source code(zip)
  • 0.3(Aug 1, 2019)

    See #8, release log:

    • 18c0d824a6f432b6a1f81ecb436e26f94f0c3709: attempt to fix broken .travis ...
    • ae9673a17710c639af4e2197c557d46f96afd01d: support generic command types ...
    • ea0e1a027cd8373f5f4f5277411735b91863daeb by @sizovs: [skip travis] fix Maven depend...
    • 07f926c3e002313a51861793e3297f6dff0221bb by @sizovs: [skip travis] fix grammar in r...
    • 8406267b8f3bb6aeb52f9059748255f4e1e15da1 by @sizovs: [skip travis] update readme
    • 87d23f4f1d044cf89454840f46284b4145abace2 by @sizovs: [skip travis] add demo app ref...
    • 148a9bf14034d0b9507043c2dd91cebe1b8b3890 by @sizovs: [skip travis] update README

    Released by Rultor 1.68.4, see build log

    Source code(tar.gz)
    Source code(zip)
  • 0.2(Feb 12, 2019)

Owner
Eduards Sizovs
The founder of @DevTernity 🚀 conference, @DevChampions training center and developer video hub @Watch-DevTube
Eduards Sizovs
This app is simple and awesome notepad. It is a quick notepad editing experience when writing notes,emails,message,shoppings and to do list.

This app is simple and awesome notepad. It is a quick notepad editing experience when writing notes,emails,message,shoppings and to do list.It is easy to use and enjoy hassle free with pen and paper.

Md Arif Hossain 1 Jan 18, 2022
With react-native-update-in-app library you can easily implement in-app updates in your React Native app using CDN or any other file server

React Native In-App update With react-native-update-in-app library you can easily implement in-app updates in your React Native app using CDN or any o

Nepein Andrey 7 Dec 21, 2022
This app corrects your sitting posture and provides feedback in real time in conjunction with the app. A sensor of 31 cells detects your posture to get better life-wellness

Notichair 실시간 자세분석 및 교정 스마트체어 ?? 상명대학교 PRIME 경진대회 수상 ?? 요구사항 31-cell sensor (mdxs-16-5610) 목차 1. 소개 프로젝트 내용 소개 2. 개발 환경 사전 설정 및 환경 구축 3. 기능 Sensors Ap

Minuk_LEE 3 Jan 15, 2022
BlockChain Pipeline using Jenkins for DevOps

BlockChain Pipeline for Jenkins This project is inspired by the work of Redback and Microsoft teams for developing the process using VSTS. I've chosen

Brantley·Williams 11 Jun 8, 2022
An awesome Spring Boot Starter!

spring-boot-tony-starter An awesome Spring Boot Starter! Explore the docs » View Demo · Report Bug · Request Feature Table of Contents About The Proje

徐植君 11 Sep 13, 2022
An awesome native wheel picker component for React Native.

⛏️ react-native-picky An awesome native wheel picker component for react-native. Features Supports multiple columns ✅ Supports looping ✅ Native Androi

null 28 Dec 4, 2022
corrects your sitting posture and provides feedback in real time in conjunction with the app. A sensor of 31 cells detects your posture to get better life-wellness

Notichair 실시간 자세분석 및 교정 스마트체어 ?? 상명대학교 PRIME 경진대회 수상 ?? 요구사항 31-cell sensor (mdxs-16-5610) 목차 1. 소개 프로젝트 내용 소개 2. 개발 환경 사전 설정 및 환경 구축 3. 기능 Sensors Ap

Minuk_LEE 3 Jan 15, 2022
DM Movie is an app with several movies catalogued through a database, you enter your email and your rating of the movie

DM Movie is an app with several movies catalogued through a database, you enter your email and your rating of the movie

Davi M. G. de Almeida 5 Jan 28, 2022
Simple and lightweight application which is checking status of your web services and send a notification if it is down.

rose-uptimer Simple and lightweight application which is checking status of your web services and send a notification if it is down. Example configura

RoseSapphire 3 Sep 25, 2022
Spring Boot microservices app with Spring Cloud, Robust and resilient backend managing e-Commerce app

e-Commerce-boot μServices Important Note: This project's new milestone is to move The whole system to work on Kubernetes, so stay tuned. Introduction

Selim Horri 65 Dec 23, 2022
An implementation of a sample E-Commerce app in k8s. This online retail marketplace app uses Spring Boot, React, and YugabyteDB.

An implementation of a sample E-Commerce app in k8s. This online retail marketplace app uses Spring Boot, React, and YugabyteDB.

yugabyte 1 Oct 27, 2022
Drools is a rule engine, DMN engine and complex event processing (CEP) engine for Java.

An open source rule engine, DMN engine and complex event processing (CEP) engine for Java™ and the JVM Platform. Drools is a business rule management

KIE (Drools, OptaPlanner and jBPM) 4.9k Dec 31, 2022
VFX processing engine in Java

sofvfx Video converter for ASCII display. Setup To use sofvfx, you will need to download ffmpeg. When done, open the downloaded .zip, go to /bin/ and

angelsflyinhell 4 Dec 29, 2022
Team 5468's 2022 FRC robot code. This code is written in Java and is based off of WPILib's Java control system and utilizes a command based system

FRC 2022 Team 5468's 2022 FRC robot code. This code is written in Java and is based off of WPILib's Java control system and utilizes a command based s

null 4 Oct 4, 2022
Processing and node.js project for rendering MouseGAN images from RunwayML

Computer MouseGAN Processing and node.js project for rendering MouseGAN images from RunwayML. Usage Clone or download this repository. git clone https

Coding Train 17 Apr 1, 2022
Realtime Data Processing and Search Engine Implementation.

Mutad The name Mutad is a reverse spelling of datum. Overview An implementation of a real-time data platform/search engine based on various technology

Shingo OKAWA 14 Aug 4, 2022
This is a simple realization of custom messages pre/post processing in spring-boot HTTP/Stream requests & responses

spring-boot-custom-message-converting-instances This is a simple realization of custom messages converting in spring-boot HTTP requests and responses.

Innopolis University Java Team 1 Jul 22, 2022
Genting SkyWorlds Theme Park’s Entrance Ticket Processing

Genting SkyWorlds Theme Park’s Entrance Ticket Processing A program to book normal or express ticket(s) (Express tickets people does not have to wait

Khairul Haziq 0 Aug 6, 2022
Prevent Screenshots in your React Native app when needed. 🦄

React Native Prevent Screenshots Prevent Screenshots in your React Native app when needed. ?? Installation First, you need to install the package usin

Ahmed Mahmoud 64 Oct 19, 2022