MCPcopy Index your code
hub / github.com/banq/jdonframework

github.com/banq/jdonframework @6.9

Chat with this repo
repository ↗ · DeepWiki ↗ · release 6.9 ↗ · + Follow
3,189 symbols 8,405 edges 539 files 920 documented · 29%
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

JDON FRAMEWORK

JdonFramework is a java Reactive/Actor framework that you can use to build your Domain Driven Design + CQRS + EventSourcing applications with asynchronous concurrency and higher throughput.

JdonFramework = DDD + Event Sourcing + CQRS + asynchronous + concurrency + higher throughput.

JdonFramework = Ioc/DI/AOP + reactive Actors model

Why Reactive?

Reactive Programming is a hot topic , especially with such things as the Reactive Manifesto. Reactive architecture allows developers to build systems that are event-driven(EDA), scalable, resilient and responsive: delivering highly responsive user experiences with a real-time feel, backed by a scalable and resilient application stack, ready to be deployed on multicore and cloud computing architectures. a reactive application is non-blocking that is under heavy load can thus have lower latency and higher throughput than a traditional application based on blocking synchronization and communication primitives.

Why DDD?

Domain-driven design (DDD) is an approach to developing software for complex needs by deeply connecting the implementation to an evolving model of the core business concepts,

DDD's servral concepts are the Heart and Soul of OOD:

    Entities and Identity, Value Objects
    Aggregate Root
    Bounded context

Why CQRS?

CQRS: Command-query Responsibility Segregation, at its heart is a simple notion that you can use a different model to update information than the model you use to read information.

Why Jdon?

Jdon introduces reactive and event-driven into domain, using jdon, a aggregate root can act as a mailbox(like scala's Actors) that is a asynchronous and non-blocking event-sending and event-recipient metaphor. Event is a better interactive way for aggregate root with each other, instead of directly exposing behavior and hold references to others. and it can better protect root entity's internal state not expose. and can safely update root's state in non-blocking way Single Writer Principle.

Jdon moves mutable state from database to memory, and uses Aggregate Root to guard it, traditional database's data operations (by SQL or JPA/ORM) not need any more, only need send a Command or Event to drive Aggregate Root to change its mutable state by its behaviours

@Model
public class AggregateRootA {

    private int state = 100;

    @OnCommand("CommandtoEventA")
    public Object save(ParameterVO parameterVO) {

        //update root's state in non-blocking single thread way (Single Writer)
        this.state = parameterVO.getValue() + state;


    }

}

Jdonframework work mode is Producer/Consumer, A producer emits to its Consumer by a asynchronous and non-blocking queue made by LMAX Disruptor's RingBuffer. such as:

@Send("CommandtoEventA") ---> @OnCommand("CommandtoEventA")

There are two kinds of Consumer in jdon:

@Send --> @OnCommand  (1:1 Queue)
@Send --> @OnEvent    (1:N topic)

Difference between 'OnCommand' and 'OnEvent' is:

When a event happend otherwhere comes in a aggregate root we regard this event as a command, and it will action a method annotated with @OnCommand, and in this method some events will happen. and they will action those methods annotated with @OnEvent.

full example: click here

Actor Model

Jdon can make your Domain Model as Actor(erlang/akka) concurrent model, no any lock. this is a transaction example about transferring money from one bank account to another:

@Model
public class BankAccount {

....

@OnCommand("depositCommand")
public Object deposit(TransferEvent transferEvent) {
    int amount2 = amount + transferEvent.getValue();
    if (amount2 > 1000) {
        TransferEvent transferEventNew = new ResultEvent(
                transferEvent.getId(), transferEvent.getValue(),
                this.getId());
        return domainEventProducer.failure(transferEventNew);
    }

    if (!(transferEvent instanceof WithdrawEvent)) {// first step
        DepositEvent transferEventNew = new DepositEvent(
                transferEvent.getId(), transferEvent.getValue(),
                transferEvent.getNextId(), this.getId());
        eventsourcesD.put(transferEventNew.getId(), transferEventNew);
        return domainEventProducer.nextStep(transferEventNew);
    }

    WithdrawEvent de = (WithdrawEvent) transferEvent;
    amount = amount + transferEvent.getValue();
    TransferEvent transferEventNew = new ResultEvent(transferEvent.getId(),
            transferEvent.getValue(), de.getPreId());
    return domainEventProducer.finish(transferEventNew);

}

@OnCommand("withdrawCommand")
public Object withdraw(TransferEvent transferEvent) {
    int amount2 = amount - transferEvent.getValue();
    if (amount2 < 0) {
        String rootId = (transferEvent instanceof DepositEvent) ? ((DepositEvent) transferEvent)
                .getPreId() : this.getId();
        TransferEvent transferEventNew = new ResultEvent(
                transferEvent.getId(), transferEvent.getValue(), rootId);
        return domainEventProducer.failure(transferEventNew);
    }

    if (!(transferEvent instanceof DepositEvent)) {// first step
        WithdrawEvent transferEventNew = new WithdrawEvent(
                transferEvent.getId(), transferEvent.getValue(),
                transferEvent.getNextId(), this.getId());
        eventsourcesW.put(transferEventNew.getId(), transferEventNew);
        return domainEventProducer.nextStep(transferEventNew);

    }

    DepositEvent de = (DepositEvent) transferEvent;
    amount = amount - transferEvent.getValue();
    TransferEvent transferEventNew = new ResultEvent(transferEvent.getId(),
            transferEvent.getValue(), de.getPreId());
    return domainEventProducer.finish(transferEventNew);

}

@OnCommand("finishCommand")
public Object finish(TransferEvent transferEvent) {
    if (eventsourcesW.containsKey(transferEvent.getId())){
        eventsourcesW.remove(transferEvent.getId());
        amount = amount - transferEvent.getValue();
    }else if (eventsourcesD.containsKey(transferEvent.getId())){
        eventsourcesD.remove(transferEvent.getId());
        amount = amount + transferEvent.getValue();
    }
    return transferEvent;
}

@OnCommand("failureCommand")
public Object fail(TransferEvent transferEvent) {
    eventsourcesD.remove(transferEvent.getId());
    return transferEvent;
}

....

}

transfer money client code:

    AppUtil appUtil = new AppUtil();
    AccountService accountService = (AccountService) appUtil
            .getComponentInstance("accountService");
    BankAccount bankAccountA = accountService.getBankAccount("11", 100);
    BankAccount bankAccountB = accountService.getBankAccount("22", 0);
    DomainMessage res = accountService.transfer(bankAccountA, bankAccountB,
            100);

    DomainMessage res1 = (DomainMessage) res.getBlockEventResult();
    DomainMessage result = (DomainMessage) res1.getBlockEventResult();
    Object o = result.getBlockEventResult();// block until all transfer ok;

    Assert.assertEquals(0, bankAccountA.getAmount());
    Assert.assertEquals(100, bankAccountB.getAmount());

detail: click here

Apache Kafka + Eventsourcing

Apache Kafka supports Exactly-once delivery, Jdon Actor + Kafka can implement distributed transaction.

jdon-kafka

LMAX microservices distributed transaction

About workflow?

DDD/ES: command ---> aggregates ---> domain events

BPMN: startEvent ---> Task ---> endEvent

join with them:

command/startEvent ---> task/aggregates ---> domain events/endEvent

Collaboration diagram:

process manager : execute this command!

aggregates: yes, Yes, task completed events!

process manager lookup next step in BPMN.xml, when he found it: execute this command!

aggregates: Yes, task completed events! ....

process manager must hold every domain events from all aggregates, when he can't find next step in BPMN ,but this process is not at the endEvent, so he think this process happen error, by the order of domain events that he hold, he send every 'cancel task' command to all aggregates, this is distributed transaction, it is AP of CAP theory.

Next version will join with them.....

GETTING STARTED

online documents : English: http://en.jdon.com/ Chinese: http://www.jdon.com/jdonframework/

In the "doc\english" directory there are all documents about how to use.

In the "doc\chinese" directory there are chinese documents about how to use.

In the "example" directory there are serveral examples that show how to use jdon, in these examples directory run 'mvn package' to get war file.

In the "JdonAccessory" directory there are struts1.x MVC and jdbc templates.

Example

jivejdon is a discussion forum/blog/CMS platform powered by jdonframework

RELEASE NOTES

6.9 version.

DISTRIBUTION JAR FILES

apply jdonframework.jar to your project: MAVEN:

    <dependency>
        <groupId>org.jdon</groupId>
        <artifactId>jdonframework</artifactId>
        <version>6.9</version>
    </dependency>

Communication

twiiter: @jdonframework

Bugs and Feedback

For bugs, questions and discussions please use the Github Issues.

LICENSE

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

Extension points exported contracts — how you extend this code

Startable (Interface)
@author banq @com.jdon.container.builder.StartablecomponentsRegistry [65 implementers]
src/main/java/com/jdon/container/pico/Startable.java
RepositoryRoleIF (Interface)
(no doc) [17 implementers]
src/test/java/com/jdon/sample/test/dci/RepositoryRoleIF.java
HibernateCallback (Interface)
(no doc) [15 implementers]
JdonAccessory/jdon-hibernate3x/src/main/java/com/jdon/persistence/hibernate/util/HibernateCallback.java
ModelIF (Interface)
Domain Model should normal live in memory not in database. so cache in memory is very important for domain model life cy [3 …
JdonAccessory/jdon-struts1x/src/main/java/com/jdon/controller/model/ModelIF.java
BlockQueryJDBC (Interface)
Batch Query JDBC Template pack the sql execution. @author banq [3 implementers]
JdonAccessory/jdon-jdbc/src/main/java/com/jdon/model/query/block/BlockQueryJDBC.java
EventBusHandler (Interface)
(no doc) [4 implementers]
example/cqrs+dci/robot/src/main/java/sample/event/bus/subscriber/EventBusHandler.java
EventBusHandler (Interface)
(no doc) [4 implementers]
example/cqrs+es/match/src/main/java/sample/event/bus/subscriber/EventBusHandler.java
Context (Interface)
(no doc) [3 implementers]
example/dci+de/robot/src/main/java/sample/service/Context.java

Core symbols most depended-on inside this repo

logVerbose
called by 366
src/main/java/com/jdon/util/Debug.java
getName
called by 339
src/main/java/com/jdon/bussinessproxy/TargetMetaDef.java
logError
called by 271
src/main/java/com/jdon/util/Debug.java
get
called by 154
src/main/java/com/jdon/controller/cache/Cache.java
append
called by 146
src/main/java/com/jdon/util/RequestUtil.java
put
called by 110
src/main/java/com/jdon/controller/cache/Cache.java
add
called by 90
src/main/java/com/jdon/util/ConcurrentLinkedList.java
size
called by 87
src/main/java/com/jdon/controller/cache/Cache.java

Shape

Method 2,581
Class 440
Function 86
Interface 82

Languages

Java97%
TypeScript3%

Modules by API surface

doc/english/js/jquery-1.8.3.min.js63 symbols
src/main/java/com/jdon/util/UtilValidate.java59 symbols
JdonAccessory/jdon-hibernate3x/src/main/java/com/jdon/persistence/hibernate/HibernateTemplate.java48 symbols
src/main/java/com/jdon/container/pico/JdonPicoContainer.java32 symbols
src/main/java/com/jdon/util/Base64.java29 symbols
src/main/java/com/jdon/util/Debug.java26 symbols
src/main/java/com/jdon/cache/UtilCache.java26 symbols
src/main/java/com/jdon/util/jdom/XMLFilterBase.java20 symbols
src/main/java/com/jdon/container/interceptor/IntroduceInfo.java20 symbols
JdonAccessory/jdon-struts1x/src/main/java/com/jdon/strutsutil/treeview/ViewNode.java20 symbols
JdonAccessory/jdon-struts1x/src/main/java/com/jdon/controller/model/PageIterator.java20 symbols
JdonAccessory/jdon-jdbc/src/main/java/com/jdon/controller/model/PageIterator.java20 symbols

Datastores touched

(mysql)Database · 1 repos

For agents

$ claude mcp add jdonframework \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact