Jdon Framework Document

Table of Contents

 

Before Domain-Driven Design(DDD) appears , business logic was directly implemented by technical component , such as a service or a action and so on. these model objects were all anaemia model (The Biggest Flaw of Spring Web Applications), anaemia model just is a data collection, and Service components drive the anaemia models to complete some business logics. this model was called "Transaction script".

Domain-driven design (DDD) is different from traditional script. all domain logics are in Domain model, Domain model drives technical components to do technical something that not about business, domain model is like DNA.

So DDD architecture can focus on business domain model that is easy to understand, in the mean time, domain model also makes our software systems more scalable,and be better performance.

DDD is an approach to developing software for complex needs by deeply connecting the implementation to an evolving model of the core business concepts,

servral concepts are the Heart and Soul of OOD, these concepts you must understand before using jdon:

   Bounded context
   Aggregate Root
   Entities and Identity, Value Objects 

 

 

In Memory Domain model

domain model  mainly includes the Entity,Value Object and Service that all focus on the business domain,it is nothing to do with the concrete technical implementation. but we need let them living in the technical system.

In Jdon Framework, these domain models are marked with the @Model annotation, so they are in memory and send asynchronous events or message to the consumers .

de


domain model is the core of our software systems,their lifecycles management is very important, Jdon Framework more easily makes better management about domain model's lifecycles , domain model lives in the in-memory cache ,such as guava(default) or ehcache,oscache,terracotta ....,so the software system can scale to a distributed cache system ,such as terracotta ,memcached or other gird products.


However,cache is a very low-level technical layer,if we allow the developers to manually interact with cache,then it will easily lead to errors and inconsistecies,so Jdon Framework integrates two interceptors ,one is "CacheInterceptor" ,the other is "DomainCacheInterceptor",they both was configured in the "aspect.xml" file which is a config file packed with Jdon Framework.

DomainCacheInterceptor is between domain layer(domain model live in this layer) and repository layer, when we fetch a domain model(@model) from repository layer, DomainCacheInterceptor will intercept the invocation(locate the method such as "get*()"), and check the model object if be in the cache,if that is,DomainCacheInterceptor just return the cached Model object ,or else  it will put the model object retrieved from repository/persistence datasource into the cache.


Last let me see the followed diagram,the diagram describes the relation of the two interceptors.

 

aa

CacheInterceptor only work when you use jdon-struts:

"CacheInterceptor"  is between the presentation layer and business layer,when the presentation action invoke the "get*()" method of business service,the CacheInterceptor will intercept the invocation,it first checks  that whether the domain model object already is the cache,if the model object is not in cache,CacheInterceptor will invoke the next interceptor which is in the interceptor chain,and finally the model object will be fetched from persistence datasource,the CacheInterceptor will gain the fetched model object and put it into the cache.

how to let model in memory?

jdon provides some annotations to assist developer to do that, at first you must annotate @Model with your Aggregate Root Entity that can be accessed from outside such technical components:

@Model
public class MyModel {
   private String userId;
   private String name;
     ....
}

MyModel is a Aggregate Root Entity inside a bounded context. you can't create the entity object by "new MyModel()", only fetch it from repository, so jdon provides some annotations to configure in repository.

Second step: configure in repository

@Introduce(“modelCache”) is annotated in repository class:

cachge

there are three annotations: @Component @Introduce and @Around.

@Component is for normal components(technical or application), any class with @Component can be managed by IOC container. Jdon Ioc container is based on pico container, only supports class construt injection.

@Introduce is about aop interceptor, that means introduces a interceptor into here(at front of the class instance), the interceptor name is modelCache that configured in aspect.xml packed with jdon. if you don't like the name ("modelCache"), you can modify it in aspect.xml .

@Around is the target method that will be intercepted. target method can be like "getXXX" or "findById"(jdon allows any method name), and its return class type must be the entity annotated with @Model(this is a jdon constraint).

in the mehtod annotated with @Around, you can fetch the model from Relation or NoSQL Database, you can use JDBC or other ORM ( JDBC is recommended). you can use jdon -jdbc lib.

finally we can find a model(@Model) by these code:

MyModel myModel = repository.getModel(new Long(100));

myModel object is actual proxy instance that created by our interceptor "modelCache", when you first times got it, "modelCache" will locate it in Cache, if miss it will load it from your repository, if hit it directly return the myModel.

when you got a myModel, you can invoke its any methods, but if you call a method with(@Oncommand), it is different with direct method invoking.

 

 

Command and Event

Command or Event is a communication way between domain model and components, at first we need know how much components type there are in jdon.

 

Basic components

There are five components model in Jdon Framework, they are:

1. Entity Model with @Model;
2. Service with @Service; technical component
3. Component with @Component ; technical component
4. Prodcuer-Consumer mode with @Send @Consumer;
5. Interceptor with @ Interceptor, need with @Introduce;
All  in com.jdon.annotation.*

As mentioned above,Jdon Framework seperates the application architecture into two parts:Domain models and technical components . so these two components are our basic. we will often use them.

Domain model is annotated with @Model , it is a aggregate root entity in a bounded context, you can got them using DDD.

Component annotated with @Component is others except domain model. include technical or application, they lives in the IOC container. can autowiring injected each other by their constrution. dependency injection is tight coupling although it is better than inheritance, we can use loose coupling producer-consumer mode.

Any invoking between aggregate root(AR) and Component must use producer-consumer mode. that keeps our business logics are loose coupling with technical infrastructure, these is a core function of jdon.

Service annotated with @Service is mico service that represents bounded context, or a DDD service that across multiple entities. Service also like other components live in Ioc container, it can be @stateful or @poolable.

Now we know: domain models(@Model) lives in the cache ,and the technical components(@Service/@Component) lives in the IOC container. their communications are producer-consumer.

Component's lifecycles management is also important,jdon use pico container to manage their lifecycles, the container is also holded in the context container such as the ServeltContext or your application root.

you can use @Inject to inject component into domain model. but it is only for introducing domain events, not recommended for other usage.

 

differnce with Command and Event

When a Component/Service sends messages to a Domain Model(aggregate root), we call the message is a command, and when a domain model send message to a Component, it is reactive a event.:

command event

  A command actions the behavior(startMatch) of a aggregate root(domain model), and a event happend in this behavior, the event will be sent to another aggregate root or a Component that maybe save it to repository.

actors model

Jdon provide four kinds of asynchronous concurrency communication(Producer/Consumer) with these two models.

  1. Component -----> model

  2. model ------->Component

  3. Compponent ------> Component

  4. model------> model

 

Command

in a typal Web application , we have this flow: UI ---Command---> a aggregate root(AR) ---Events -->Component:

A command will change a state in a AR, but in a web application there are many concurent request, contention will happen,  There is a lot of research in computer science for managing this contention that boils down to 2 basic approaches. One is to provide mutual exclusion to the contended resource while the mutation takes place; the other is to take an optimistic strategy and swap in the changes if the underlying resource has not changed while you created the new copy.(see details: Single Writer Principle)

contention:

Blocking (lock )

mutual exclusion:

Noblocking single writer:

Jdon provides a nonblocking single writer to change AR's state, LMAX disruptor is its Infrastructure,

if a AR's method annotated with @OnCommand , it is a action for command from UI. only a single thread call the method.

@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;

       . .

    }

}

this AggregateRootA is a Consumer, Producer is in Service or CommandHandler:

Producer:


public interface AService {

  @Send("CommandtoEventA")
  public DomainMessage commandA(@Owner String rootId, @Receiver AggregateRootA model,
                int newstate);
}

Producer emits message to its Consumer by a asynchronous and non-blocking queue made by LMAX Disruptor's RingBuffer. @Send("CommandtoEventA") ---> @OnCommand("CommandtoEventA")

client code:

AggregateRootA myModel = repository.getModel(new Long(100));

AService aService = webappUtil.getService("aService");

aService.commandA("100", myModel, 200);//change AggregateRootA state to 200;

 

this invoking way is thread safe, and have high througout and lower lantency, it is like Actors model in Scala, or like Netty's IO. it is nonblocking and asynchronous.

in these mode, 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.

 

Domain Events

Domain Events is that events that happend in domain, wo can call it is reactive event.

Domain Events is essential  to solve the interaction between the domain model and the technical component,Jdon apply domain events pattern to make domain model less coupling with technical components.

domain events will react when a command comes in :

 

As the above diagram description,when Command comes in domain models trigger some domain events,the domain event will generate proper domain message,at last the messageListener will treat with the event,and assist with some operations infrastructure such as saving DB.

Because a command will react a domain event, so if we saving these domain events, be equals to saving those commands, and later we can replay these events, this is called Event Sourcing, there are some EventSoucing database (functional database/Event Store, such as GETEventStore).

Domain Event have Producer-Consumer(1:1) and Publisher-Subscriber(1:N) patterns: Domain Model is a producer; it send events or message to Consumer:

@Send(topicName) => @Consumer(topicName);

if there are many consumers, their started order is by their class name's alphabetical . such AEventHandler is first be reaction; and then BEventHandler and CEve.......

How to use Domain Events


If you want to use Domain event ,you just need to use three Annotations,@Introduce,@Inject and @Send.for example,we have a model class named MyModel,and a domain event named MyDomainEvent ,the code is as here:

@Model
public class MyModel {

   private Long id;
   private String name;

   @Inject
   private MyModelDomainEvent myModelDomainEvent;

   public String getName() {
      if (this.name == null) {

            //this is async method, can be splite twice times calling.
            EventMessage message = myModelDomainEvent.asyncFindName(this);
            this.name = (String) message.getEventResult();
      }  
      return name;
}

……
}

@Introduce("message")
public class MyModelDomainEvent {

   @Send(value="MyModel.findName",asyn=true)
   public DomainMessage asyncFindName(MyModel myModel) {
         return new DomainMessage(myModel);
   }

}

When you fetch a MyModel instance from service or repository, because of @Inject, CacheInterceptor or DomainCacheInterceptor will inject MyModelDomainEvent into the MyModel instance,When injecting the MyModelDomainEvent, jdon find MyModelDomainEvent class has annotation with @Introduce("message") , then will  at first load MessageInterceptor(in aspect.xml message=MessageInterceptor),and last return a proxy instance .

When we call myModel proxy instance, such as invoke its method "myModel.getName()", the MessageListenner will intercept our invocation,it will choose proper means to drive the MessageListner to response invocation request.

full domain events example is in here:DDD CQRS EventSourcing example source: football Match

wo can use domain events to model the requirement, see CES:Context Event and State

and Model Storming

 

Producer/Consumer

Jdon provide four kinds of asynchronous concurrency communication(Producer/Consumer) with these two models.

  1. Component -----> model (that is a Command)

  2. model ------->Component (that is a event)

  3. Compponent ------> Component (that is event)

  4. model------> model (commands and events)

here is Summary:

1. Component => Model

  Component(producer with @Component) -- > Model(consumer with @Model)

  this mode is for CQRS's Command, one command is sent from UI, and sent to one aggregate root, one command has one action on the method of the aggregate root. this mode works.

  in this mode producer:consumer can only be 1:1, one command can only be sent to one method of one domain model.

  The A in this sample is a producer with @Component:

 

package com.jdon.sample.test.command;

import com.jdon.annotation.model.Send;

public interface AICommand {

 @Send("CommandmaTest")
 public TestCommand ma(@Receiver BModel bModel);

}

@Component("producer")
@Introduce("componentmessage")
public class A implements AICommand {

 public TestCommand ma(BModel bModel) {
  System.out.print("send to BModel =" + bModel.getId());
  return new TestCommand(99);
 }
}

  the method "ma" annotated with @Send must have a method parameter:BModel that annotated with @Model, that means send a command message to this domain model , the model is a receiver for a command, so must annotate with @Receiver.


@Model
public class BModel {
private String id;

 private int state = 100;

 public BModel(String id) {
  super();
  this.id = id;
 }

 @OnCommand("CommandmaTest")
 public void save(TestCommand testCommand) {
  this.state = testCommand.getInput() + state;
  testCommand.setOutput(state);

 }

 public String getId() {
  return id;
 }

 public void setId(String id) {
  this.id = id;
 }

}

  the topic name "CommandmaTest" is unique; because producer : consumer is 1:1. one command has one action(onCommand). @OnCommand is annotated on the method of consumer.

  the procuder(AICommand) 's ma method commands the consumer(BModel)'s save method. AICommand is a Component and BModel is a Model.

  below is the client code:

AppUtil appUtil = new AppUtil();
AICommand a = (AICommand) appUtil.getComponentInstance("producerforCommand");
BModel bModel = new BModel("one");
TestCommand testCommand = a.ma(bModel);
int i = 0;
long start = System.currentTimeMillis();
while (testCommand.getOutput() != 199) {
i++;
}
long stop = System.currentTimeMillis();
Assert.assertEquals(testCommand.getOutput(), 199);
System.out.print("ok " + " " + (stop - start));

  it output:

  send to BModel =oneok 5

  above source in :https://github.com/banq/jdonframework/tree/master/src/test/java/com/jdon/sample/test/command

  in this mode the component receives any commands from UI or others events, and handles them to a aggregate root :

  UI ------->commandHandler(@Component) ------>aggregate root model

  in this mode, @Model is a actor and representing Aggregate Root , the state of aggregate root is changed by only single thread, it is threadsafe. and no blocking and no lock, like Actors mode of AKKA or ERlang, or like Node.js EDA. instead of 2PC or JTA, this mode can make transaction work well in high throughput way.

  When we apply Jdon in a web application,  the system works something like this:

  • Some command comes in to modify a given Aggregate Root (AR) entity
  • If an @Model representing the AR is not already running in the system, create it _atomically_ (i.e. make sure you never have more than one @Model representing a specific entity)
  • @Model should be removed after a period of idleness. This will avoid keeping actors around for entities with low interaction rates, but ensure 'hot' entities are kept in memory for performance (starting a new @Model requires loading events from an event store in order to restore the memory image representing the entity state), all these things are be done by cache in jdon. see below : @Introduce("modelCache")

 

2.Model => Component

  Model(producer with @Model) -- > Component(consumer with @Component)

  After a agrregate root (domain model) receive a command , and it will reactive a event that can be sent to a Component or another aggregate root. we call it is domain events.

  we can inject a Component(with @Component) into a agrregate root that acts as a producer.

  the domain model code:

@Model
public class MyModel {

 private Long id;
 private String name;

 @Inject //inject the Component into this domain model
 private MyModelDomainEvent myModelDomainEvent;

 public String getName() {
  if (this.name == null) {
   DomainMessage message = myModelDomainEvent.asyncFindName(this);
   this.name = (String) message.getBlockEventResult();
  }
  return name;
 }

....

}

  we inject MyModelDomainEvent into "MyModel" with @Inject, the injected object "MyModelDomainEvent" is a Component:

package com.jdon.sample.test.domain.simplecase;

import com.jdon.annotation.Introduce;
import com.jdon.annotation.model.Send;
import com.jdon.domain.message.DomainMessage;

@Introduce("message")
public class MyModelDomainEvent {

 @Send("MyModel.findName")
 public DomainMessage asyncFindName(MyModel myModel) {
  return new DomainMessage(myModel);
 }

 @Send("saveMyModel")
 public DomainMessage save(MyModel myModel) {
  return new DomainMessage(myModel);
 }

}

  MyModelDomainEvent is annotated with @Introduce("message"), in this producer class there are two topic that means two kinds of domain events.

  let's see how to implement a consumer for a domain event. the consumer is too a Component, see below:

@Consumer("MyModel.findName")
public class FindNameListener implements DomainEventHandler {

 public void onEvent(EventDisruptor event, boolean endOfBatch) throws Exception {
  MyModel myModel = (MyModel) event.getDomainMessage().getEventSource();
  System.out.println("Asynchronous eventMessage=" + myModel.getId());
  event.getDomainMessage().setEventResult("Asynchronous eventMessage=" +   myModel.getId());
 }
}

  FindNameListener is annotated with @Consumer, not @Component, this is another consumer style, when using @Consumer, we need implement a interface DomainEventHandler, and implement its method onEvent, if we using @Component, we need use @OnEvent together.

  above consumer is for the producer @Send("MyModel.findName"), another consumer for this producer @Send("saveMyModel") of this sample uses @Component and @OnEvent:

@Component("mymrepository")
@Introduce("modelCache")
public class RepositoryImp implements MyModelRepository {

 @Around
 public MyModel getModel(Long key) {
  MyModel mym = new MyModel();
  mym.setId(key);
  return mym;
 }

 @OnEvent("saveMyModel")
 public void save(MyModel myModel) {
  System.out.print("\n No.1 @OnEvent:" + this.getClass().getName());

 }

}

  this consumer is a class RepositoryImp that it is a Repository of DDD, and it also fetch a aggregate root from repository, @Introduce("modelCache") and @Around enable in-memory cache before the database. only when there is no the model object in cache, it will got from the database. @Introduce("modelCache") and @Around is necessary for using jdon framework. if not use them, any domain events will disable.

  another way,we can call com.jdon.domain.dci.RoleAssigner assignAggregateRoot method to let any normal object be act as a aggregate root.

  the in-memory cache make Aggregate Root living in memory, you can configure any cache product(ehcache, Redis ) for it. ensure 'hot' entities are kept in memory for performance.

  we have known about two interactive modes between Component and aggregate root, if using these two modes in a aggregate root, it can be regarded as a Actors mode like Akka or Erlang:

  • Share NOTHING,
  • Isolated lightweight event-based processes,
  • Each actor has a mailbox (message queue, in jdon it is Disruptor of LMAX)
  • Communicates through asynchronous& non-blocking message passing

  above sources: https://github.com/banq/jdonframework/tree/master/src/test/java/com/jdon/sample/test/domain/simplecase

 

3.Component => Component

  Component(producer with @Component) -- > Component(consumer with @Component)

  in this mode there are two ways:

  1. dependency inject

  2. producer and consumer based on Event.

  Dependency inject is like IOC, Jdon only supports class construtor inject:

 

@Component
public class A{

  private B b;

  //inject b instance
  public A(B b){
   this.b = b;
  }
}

@Component
public class B{

}

  after B was injected into A, A can directly invoke any B's method. another way is more loose couple,between A and B there are communicates through asynchronous& non-blocking message passing .

  The A in this sample is a producer with @Component:

 

 

package com.jdon.sample.test.event;

import com.jdon.annotation.model.Send;

public interface AI {

  @Send("maTest")
  public TestEvent ma();
}

 

@Component("producer")
@Introduce("componentmessage")
public class A implements AI {

 public TestEvent ma() {
  System.out.print("event.send.ma..");
  return new TestEvent(99);
 }
}

  The B in this sample is a consumer with @Component, and its consumer method must be annotated with @OnEvent,

 

 

@Component("consumer")
public class B {

 @OnEvent("maTest")
 public void mb(TestEvent testEvent) throws Exception {
  testEvent.setResult(testEvent.getS() + 1);//the consumer return a result to the procuder
  System.out.print("event.@OnEvent.mb.." + testEvent.getResult() + "\n");
  Assert.assertEquals(testEvent.getResult(), 100);
 }
}

  the value "maTest" of @OnEvent must be same as the value of @Send. and the return type "TestEvent" of the method with @Send must be same as the input paramter type of the @OnEvent, so the producer can handle a object to the consumer.

  if the consumer want to return a result to the producer, recommend to use method setEventResult of com.jdon.domain.message.DomainMessage, and the producer can fetch the result by its getBlockEventResult() or getEventResult(), getBlockEventResult() can block until get the result.

 

  Test client code:

 

 

AppUtil appUtil = new AppUtil();
AI a = (AI) appUtil.getService("producer");
TestEvent te = a.ma();
long start = System.currentTimeMillis();
while (te.getResult() != 100) {
}
long stop = System.currentTimeMillis();

Assert.assertEquals(te.getResult(), 100);
System.out.print("ok " + " " + (stop - start) + "\n");

  output:

  [junit] event.send.ma..event.@OnEvent.mb..100
[junit] ok 31

  above codes is fromhttps://github.com/banq/jdonframework/tree/master/src/test/java/com/jdon/sample/test/event

 

4.Model => Model

  Model(aggregate root A) -- > Model(aggregate root B)

  Aggregates are always internally consistent, and Aggregates"eventually consistent" with each other. – Asynchronous
updates propagate through system,References are limited to aggregate roots.

  when a aggregates root want to cal another aggregates root , it only can be implemented by domain events, a output event act as a input command for another aggregates root.

  this mode consists of three modes above:

  1. Aggrgate root A reactive a event to a Component (model ---> Component)

  2.the Component transfer the event to a command for Aggrgate root B (Component ---->Component)

  3.the command will be sent to Aggrgate root B (component -->model)

  this mode's source code is in Github: https://github.com/banq/jdonframework/tree/master/src/test/java/com/jdon/sample/test/cqrs

 

 

DCI

DCI: Data, Context, Interactions is a programming paradigm invented by Trygve Reenskaug. the domain model is a Data, the domain events producer is a Role of DCI, it includes the interactions of DCI.

Jdon Framework's domain model injection function can inject the role into the domain model, such as above the class UserDomainEvents is a Role, it can be injected into the model UserModel.so it help UserModel implements business function ComputeCount. In runtime, The Role UserDomainEvents will be injected into the Data UserModel.

DDD DCI and Domain Events example


 

 

AOP

Using the  DDD,It is the domain models drive the technical components to finish the business logics,and in this design style,the components are just the assistants,which assist the domain models to complete the business operations.So how the domain models gain the needed components,Jdon framework use the @Inject and @Component to inject components and the domain events into models.

As the followed diagram illustrates ,when client invoke the getA("a"),if Model A with a Introduce,the A will be enhanced,and the technical component C will also be injected  into the A ,at the same time,when inject the B,the B will also be enhanced for the @Introduce.

 

 



Interceptor configuration

when you develope a interceptor, you need this step.
When Jon framework is starting up, it will use container.xml and aspect.xml under META-INF in jdonframework.jar by default. If you need to extend Jdon framework, for example, you have developed some small components, such as formula functions, chart components or some general functions and you need load these components as starting up, or expect them configurable and replaceable as our wish, you can integreated them into jdon. There are two ways to go. (It is not the must)
First Step :
define you own component configuration file and interceptor component configuration file, which name much be mycontainer.xml and myaspect.xml, these two files must be put in the system class path or packed in your jar file, this jar file could also be deployed together with jdon framework’s jar file

Second Step:
You can define it in web.xml in your web application, here is an example:

<context-param>
<param-name>containerConfigure</param-name>
<param-value>WEB-INF/mycontainer.xml</param-value>
</context-param>
……
<context-param>
<param-name>aspectConfigure</param-name>
<param-value>WEB-INF/myaspect.xml</param-value>
</context-param>

So your mycontainer.xml file and myaspect.xml file must be put in WEB_INF directory in your web application, yet file names could be arbitrary. In User-defined configuration file, corresponding settings in container.xml and aspect.xml could be overwritten; however the setting name should be the same.

 

How to integrate Jdon Framework with Spring

 

 

Ioc container


The great thing about objects is they can be replaced. ----Object- Oriented Analysis and Design with Applications, Grady Booch, one of the founding fathers of object-oriented programming

The great thing about Jdon is it helps you replace them((even you can replace jdon itself!).

All framework components include framework infrastructure objects are be managed by a micocontainer made by Picocontainer, you can insert or change any components by change the xml configuration files(such as container.xml/aspect.xml/jdonframework.xml), you can also replace Jdon framework's infrastructure components(this is a strongpoint).

Jdon framework will make your components. the infrastructure components or POJO services collaborate with each other via dependency injection.

When you have hundreds of components/POJO services, Jdon's autowiring function will take care of their invocation relation.

Interceptor :
You can insert a Interceptor by XML files aspect.xml, Jdon has some default interceptos, they are pool interceptor/cache interceptor/stateful interceptor.this interceptos will active before target services are invoked.if you appont a interceptor to a service, the service must implements the interface the interceptor, such as Poolable or Stateful

Service/Componet:
When you want to develop a small system, you can only use POJO services implement logic function. How to get a service instance? two ways: Annotation or XML

XML :

in jdonframework.xml (container.xml) there is such service configuration:

<pojoService name="userDao" class="news.container.UserJdbcDao">

<constructor value="java:/NewsDS"/>

</pojoService>

in code, we can get the service instance by below mode:

UserDao ud = (UserDao)WebAppUtil.getService(“userDao”);

Jdon defines four service models: component instance that is singleton, service instance that can be pooled

about Choice with Annotaion and XML in Ioc container:XML in IoC containers: A Hell or A Realm?

Service Annotaion

@Poolable: get a instance from the class's object pooing, Object Pooling - Determinism vs. Throughput

@Stateful:its instance lifecycle is user session scope

@Singleton: get a singleton instance form the class

RAD Tool(jdon-struts1x)

Keep deliberately simple, yet still very powerful, so that your code is kept simple.

Jdon provides a fast development way for model's CRUD(create/read/update/delete) , in presentation layer, in general, you don't need any code, only configure MVC Process in the jdonframework.xml:

 <model key="userId" 
class ="com.jdon.framework.test.model.UserTest">
<actionForm name="userActionForm"/>
<handler>
<service ref="testService">
<getMethod name="getUser" />
<createMethod name="createUser" />
<updateMethod name="updateUser" />
<deleteMethod name="deleteUser" />
</service>
</handler>
</model>

Jdon's presentation layer is based Struts 1.2, so Jdon will generate Action instance at running time.

Multi page query function can be accomplished quickly by Jdon, Jdon provide the multi-page taglib, JDBC template, and Model's cache optimization.

Use Jdon, you can develop a small system in several minutes, here is the system demo:http://www.jdon.com:8080/testWeb/

Step by Step develop a Jdon application with jdon-struts1x

 

 

Components

need two annotations(@Service or @Component):difference between @Service and @Component is that the @Service class must have a interface then can be called by outside client beyond jdon.


@Service("helloService")
public class HelloServiceImpl implements HelloService
..

the client in servlet or action call the service's code:

HelloService helloService = (HelloService) WebAppUtil.getService("helloService", req);
String result = helloService.hello(myname);

di

all source in JdonFramework/examples/testWeb

More Annotation

@Poolable: get a instance from the class's object pooing, Object Pooling - Determinism vs. Throughput

@Stateful:its instance lifecycle is user session scope

@Singleton: get a singleton instance form the class

 

 

XML configuration

We called a class instance invoked by client (Servlet/Jsp/Action) as below.

TestService testService = (TestService) WebAppUtil.getService("testService", request);

"testService" is the class name of "TestService". it should be configured in jdonframework.xml

 

<pojoService name="testService" class="com.jdon.framework.test.service.TestServicePOJOImp"/>


There are two types of service class. One is common java class or JavaBeans, all of which called POJO. The other is EJB-regulation-complied classes which could be simply called EJB. Any of these two type class could be used as service class, hence there will be two corresponding service configurations for POJO and EJB done by pojoService and ejbService respectively.

POJOs configuration

There are two basic properties in pojoService, name and class. Property class is for putting POJO’s full name. Property Name is used to put the actual service name invoked in the program, conventionally written as similarly to the class name. Please see the source code in JdonFrameworkEJB or Ioc under Traning directory of JdonSample.
POJO Service configuration:

<pojoService name="testService" class="com.jdon.framework.test.service.TestServicePOJOImp"/>

Not all of classes are servered for the client directly (jsp/Servlet), that is to say some classes are not invoked by jsp/servlet or presentation frame layer, but invoked by service classes, these kinds of class we called component class annotated as component in configuration file. Note: in EJB framework, component class is managed by EJB container, so you do not need to any configuration in JdonFramework any more.

POJO Component configuration:

<component class="com.jdon.framework.test.dao.JdbcDAO" name="jdbcDAO"/>


We often need to define some constants and parameters in some classes, so we can do like this:

<component class="com.jdon.framework.test.dao.JdbcDAO" name="jdbcDAO">
<constructor value="java:/TestDS"/>
</ component >


As you can see, JdbcDao’s constructor has a string parameter. When you initialize an instance of JdbcDao, String “java:/TestDs”(DataSource JNDI Name) will be passed into constructor automatically.

By taking advantage of good point above, we can conveniently utilize xml file to define business logic. For example, we can defined the email format in jdonframework.xml so that email content could be altered easily according the customers’ needs. It is much better and flexible than get this information hard coded in the program.

Here is an example:

<component name="emailDefine"
class="com.jdon.jivejdon.service.imp.account.EmailDefine">
<constructor value="Jdon username and password"/>
<constructor value="Welcome on jdon.com. Your account has been validated. Thank you!"/>
<constructor value="Jdon.com "/>
<constructor value="Thank you, Jdon team."/>
<constructor value="admin@jdon.com"/>
</component>



 


In JdonFramework, there is a configuration XML file that named jdonframework.xml. in it, we can configure our class, the format as below:

<pojoService name="your service name " class="full class "/>

or

@Service("your service name")

"class" is the class full name, include the package; "name" can be any text that will be used in our client code.

if we have a class TestServicePOJOImp as below:

@Poolable
//@Service("testService")
public class TestServicePOJOImp implements TestService{

   private JdbcDAO jdbcDao;

   public TestServicePOJOImp(JdbcDAO jdbcDao) {
         this.jdbcDao = jdbcDao;
   }

   public void createUser(EventModel em) {
      ....
   }
 }

interface TestService code:

public interface TestService {

   void createUser(EventModel em);

}




when we finished these codes, we need create a XML file that named jdonframework.xml under project source directotry:


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE app PUBLIC "-//JDON//DTD Framework 2005 1.0 //EN" "http://www.jdon.com/jdonframework.dtd">
<app>
   <services>
      <pojoService name="testService"                            class="com.jdon.framework.test.service.TestServicePOJOImp"/>
   </services>
</app>


at last, if we invoke TestServicePOJOImp in client code such as Jsp/Servlet or struts action,the invoking code as below:


TestService testService = (TestService) WebAppUtil.getService("testService ", request);
testService.createUser(em);

so the good point is that: if we replace TestServicePOJOImp with AnotherTestServicePOJOImp , only need modify jdonframework.xml, not need change our client codes.

thera is another big good point that Ioc or DI means Dependency Injection, maybe you have find a details about TestServicePOJOImp that it has a constructor method:

   public TestServicePOJOImp(JdbcDAO jdbcDao) {
         this.jdbcDao = jdbcDao;
   }

if we donot create the JdbcDAO instance, how can we create TestServicePOJOImp instance?don't worry, the framework help us and it do these, but we need add a new configuration item in jdonframework.xml, as below:


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE app PUBLIC "-//JDON//DTD Framework 2005 1.0 //EN" "http://www.jdon.com/jdonframework.dtd">
<app>
   <services>
      <pojoService name="testService"                            class="com.jdon.framework.test.service.TestServicePOJOImp"/>

      <!-- new configuration item or annotation @Component in JdbcDAO class -->
      <component name="jdbcDAO" class="com.jdon.framework.test.dao.JdbcDAO"/>
   </services>
</app>


until now, you maybe have understand JdonFramework what to do.

 

 

 

How starting the framework?

If there is no xml, all are annotation, no need this step.

there are two ways to starting the framework in our web project.

first way: web.xml configuration:


<context-param>
   <param-name> modelmapping-config </param-name>
   <param-value> jdonframework.xml </param-value>
</context-param>
……
<listener>
   <listener-class>com.jdon.container.startup.ServletContainerListener</listener-class>
</listener>

second way: struts-config.xml(you must know struts 1.2)


<plug-in className="com.jdon.strutsutil.InitPlugIn">
   <set-property property="modelmapping-config" value="jdonframework.xml" />
</plug-in>

if not used in Web , can be used in java Application, see below:

 

Client

Client not only Servlet or Jsp or other Web Framework,:

//servletContext is a instance of javax/servlet/ServletContext
IServiceSample serviceSample = (IServiceSample)WebAppUtil.getService("serviceSample", servletContext);
String res = (String) serviceSample.eventPointEntry("hello");
Assert.assertEquals(res, "eventMessage=hello");

 

or

//servletContext is a instance of javax/servlet/HttpServletRequest
//this will cache 'serviceSample' instance in httpsession. improve performance.
IServiceSample serviceSample = (IServiceSample)WebAppUtil.getService("serviceSample", request);
String res = (String) serviceSample.eventPointEntry("hello");
Assert.assertEquals(res, "eventMessage=hello");

 

 

 

but also can be a Java Application.



AppUtil appUtill = new AppUtil();


//if you use jdon's CRUD function based struts1.x
// AppUtil appUtill = new AppUtil("com.jdon.jdonframework.xml");

IServiceSample serviceSample = (IServiceSample) appUtil.getService("serviceSample");
String res = (String) serviceSample.eventPointEntry("hello");
Assert.assertEquals(res, "eventMessage=hello");

 

 

 

Source :com.jdon.SampleAppTest

 

How to compile and deploy

Maven pom.xml:

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

  if you would like to use jdon's CRUD function based struts1.x(such as jdonframework.xml), add :



<repository>
<id>jdon-struts1x</id>
<url>https://github.com/banq/jdon-mvn-repo/raw/master/releases</url>
</repository>

<dependency>
<groupId>com.jdon</groupId>
<artifactId>jdon-struts1x</artifactId>
<version>6.8</version>
</dependency>
<dependency>
<groupId>struts</groupId>
<artifactId>struts</artifactId>
<version>1.2.9</version>
</dependency>


  if you would like to use Jdon's jdbcTemp, add:


<repository>
<id>jdon-jdbc</id>
<url>https://github.com/banq/jdon-mvn-repo/raw/master/releases</url>
</repository>

<dependency>
<groupId>com.jdon</groupId>
<artifactId>jdon-jdbc</artifactId>
<version>6.8</version>
</dependency>

  full pom.xml

 

 

 

jdon old version :

How to develop Struts-Jdon-JDBC Application

Command patern for calling services

Struts + Jdon + Hibernate video

 

Blog

DDD DCI and Domain Events example

how to enhance Jdon framework to DCI framework ?

Immutability is everything

how to easily develop a non-blocking concurrent application ?