Try demos once you have following software installed:
- JDK6+
- maven 3+
- github client
And then execute the following commands:
git clone https://github.com/zhongdj/LifecycleStaticWeaverDemos
cd LifecycleStaticWeaverDemos
mvn test
For further information, please refer demos projects:
- (Suggest) https://github.com/zhongdj/LifecycleStaticWeaverDemos
- https://github.com/zhongdj/LifecycleRuntimeBytecodeManipulationDemos
Using: Lifecycle-StaticWeaver-maven-plugin to process classes https://github.com/zhongdj/Lifecycle-StaticWeaver-maven-plugin
- [ Improvement ] Support Mockito's mock/spy method on FSM object by skipping overriden method
- [ Improvement ] Provide more friendly logs
- [ Improvement ] Avoid transform methods twice.
- [ Improvement ] Relation Object, which is created from Java Dynamic Proxy, is supported as well.
- [ Improvement ] @LifecycleMeta is @Inherited, which supports Spring Bean Factory using Proxy class.
- [ BUG FIX ] NPE while cannot find Relation Field style accessor from interface or class, which might defined the accessor in a property style.
- [ BUG FIX ] Cannot initialize single lifecycle reactive object
- [ BUG FIX ] NPE while initializing converter based multiple lifecycle reactive object
- [ JDK8 ] Build Based on JDK8
- [ Dedicate BCEL ] Separate BCEl project as a dedicated artifact which is based on JDK7-
- add priority property into @PostStateChange for specifying callback ordering
- add API to set reactive object's intial states, such as: DefaultStateMachineRegistry.getInstance().setInitialState(reactiveObject);
- add @OnEvent callback support
- support declare callback annotations on interfaces, such as @PostStateChange, @PreStateChange, @OnEvent
@LifecycleMeta(ServiceableLifecycleMeta.class)
publicinterfaceIServiceOrder {
@Transition(Schedule.class)
voidallocateResources();
@Transition(Start.class)
voidconfirmStart();
@Transition(Finish.class)
voidconfirmFinish();
@StateIndicatorStringgetServiceOrderState();
}@StateMachinepublicinterfaceServiceableLifecycleMeta {
@StateSetstaticclassStates {
@Initial@Function(transition = Schedule.class, value = Queued.class)
staticclassCreated {}
@Functions({ @Function(transition = Start.class, value = Ongoing.class),
@Function(transition = Cancel.class, value = Cancelled.class) })
staticclassQueued {}
@Functions({ @Function(transition = Finish.class, value = Finished.class),
@Function(transition = Cancel.class, value = Cancelled.class) })
staticclassOngoing {}
@EndstaticclassFinished {}
@EndstaticclassCancelled {}
}
@TransitionSetstaticclassTransitions {
staticclassSchedule {}
staticclassStart {}
staticclassFinish {}
staticclassCancel {}
}
}@LifecycleMeta(ServiceableLifecycleMeta.class)
publicinterfaceIServiceOrder {
@Transition(Schedule.class)
voidallocateResources(@Relation(PlantResource.class) IPlantResourceplantResource,
@Relation(ConcreteTruckResource.class) IConcreteTruckResourcetruckResource);
@Transition(ServiceableLifecycleMeta.Transitions.Start.class)
voidconfirmStart();
@Transition(ServiceableLifecycleMeta.Transitions.Finish.class)
voidconfirmFinish();
@StateIndicatorStringgetServiceOrderState();
}@StateMachinepublicinterfaceServiceableLifecycleMeta {
@StateSetpublicstaticclassStates {
@Initial@Function(transition = Schedule.class, value = Queued.class)
@InboundWhiles({
@InboundWhile(relation = PlantResource.class, on = { PlantResourceLifecycleMeta.States.Idle.class,
PlantResourceLifecycleMeta.States.Busy.class }),
@InboundWhile(relation = PlantResource.class, on = {
ConcreteTruckResourceLifecycleMeta.States.Idle.class,
ConcreteTruckResourceLifecycleMeta.States.Busy.class }) })
publicstaticclassCreated {}
@Functions({ @Function(transition = Start.class, value = Ongoing.class),
@Function(transition = Cancel.class, value = Cancelled.class) })
publicstaticclassQueued {}
@Functions({ @Function(transition = Finish.class, value = Finished.class),
@Function(transition = Cancel.class, value = Cancelled.class) })
publicstaticclassOngoing {}
@EndpublicstaticclassFinished {}
@EndpublicstaticclassCancelled {}
}
@TransitionSetpublicstaticclassTransitions {
publicstaticclassSchedule {}
publicstaticclassStart {}
publicstaticclassFinish {}
publicstaticclassCancel {}
}
@RelationSetpublicstaticclassRelations {
// default to @Relation("plantResource")publicstaticclassPlantResource {}
// default to @Relation("concreteTruckResource")publicstaticclassConcreteTruckResource {}
}
}@LifecycleMeta(ConcreteTruckResourceLifecycleMeta.class)
@StateIndicator//Default with getStatepublicinterfaceIConcreteTruckResource {
@Transition// default to @Transition(Assign.class) use assign -> Assignvoidassign();
@Transition(ConcreteTruckResourceLifecycleMeta.Transitions.Release.class)
voiddoRelease();
@Transition// default to @Transition(Detach.class) use detach -> Detachvoiddetach();
}@StateMachinepublicinterfaceConcreteTruckResourceLifecycleMetaextendsSchedulableLifecycleMeta {
@StateSetpublicstaticclassStatesextendsSchedulableLifecycleMeta.States {
@Initial@Function(transition = Detach.class, value = Detached.class)
publicstaticclassIdleextendsSchedulableLifecycleMeta.States.Idle {}
@EndpublicstaticclassDetached {}
}
@TransitionSetpublicclassTransitionsextendsSchedulableLifecycleMeta.Transitions {
publicstaticclassDetach {}
}
}@StateMachinepublicinterfaceSchedulableLifecycleMeta {
@StateSetpublicstaticclassStates {
@Functions({ @Function(transition = Assign.class, value = Busy.class) })
publicstaticclassIdle {}
@Function(transition = Release.class, value = Idle.class)
publicstaticclassBusy {}
}
@TransitionSetpublicstaticclassTransitions {
publicstaticclassAssign {}
publicstaticclassRelease {}
}
}@StateMachinepublicinterfaceIDownloadProcess {
@StateSetstaticclassStates {
@Initial@Functions({ @Function(transition = Prepare.class, value = Queued.class),
@Function(transition = Remove.class, value = Removed.class) })
staticclassNew {}
@Running@Functions({ @Function(transition = Pause.class, value = Paused.class),
@Function(transition = Start.class, value = Started.class),
@Function(transition = Deactive.class, value = InactiveQueued.class),
@Function(transition = Remove.class, value = Removed.class) })
staticclassQueued {}
@Running@Functions({ @Function(transition = Pause.class, value = Paused.class),
@Function(transition = Receive.class, value = Started.class),
@Function(transition = Deactive.class, value = InactiveStarted.class),
@Function(transition = Err.class, value = Failed.class),
@Function(transition = Finish.class, value = Finished.class),
@Function(transition = Remove.class, value = Removed.class) })
staticclassStarted {}
@Corrupted(recoverPriority = 1)
@Functions({ @Function(transition = Activate.class, value = Queued.class),
@Function(transition = Remove.class, value = Removed.class) })
staticclassInactiveQueued {}
@Corrupted(recoverPriority = 0)
@Functions({ @Function(transition = Activate.class, value = Queued.class),
@Function(transition = Remove.class, value = Removed.class) })
staticclassInactiveStarted {}
@Stopped@Functions({ @Function(transition = Resume.class, value = New.class),
@Function(transition = Restart.class, value = New.class),
@Function(transition = Remove.class, value = Removed.class) })
staticclassPaused {}
@Stopped@Functions({ @Function(transition = Restart.class, value = New.class),
@Function(transition = Resume.class, value = New.class),
@Function(transition = Remove.class, value = Removed.class), })
staticclassFailed {}
@Stopped@Functions({ @Function(transition = Restart.class, value = New.class),
@Function(transition = Remove.class, value = Removed.class), })
staticclassFinished {}
@EndstaticclassRemoved {}
}
@TransitionSetstaticclassTransitions {
@Recover@Timeout(3000L)
staticclassActivate {}
@Corrupt@Timeout(3000L)
staticclassDeactive {}
@Fail@Timeout(3000L)
staticclassErr {}
staticclassPrepare {}
staticclassStart {}
staticclassResume {}
staticclassPause {}
staticclassFinish {}
staticclassReceive {}
@Redo@Timeout(3000L)
staticclassRestart {}
staticclassRemove {}
}
}Lifecycle exists since information variations happening always. A subset of information varies together, and others do not. To simplify describing system states(data) manipulation by instructions, a block of data and a few blocks of instructions were introduced to make the expression more concisely and clearly, such as the concepts: Struct and Function constructs in C programming language, or Class in java (OO) programming language.
C's structure or Java's Class can shrink the scope of data or states of system, based on structure or class, new concepts (types) can be created to describe a new SCOPE. Granularity always be there while talking about scope, because scope is relative. One subset of information(data) was created and was destroyed at the moment of another subset might be just destroyed and recreated again. And once go into one subset of data, the states inside also can vary at different stage or moment. Defects happen because some state should be changed at some stage but it did not, or some state changed incorrectly, or some state should be recognized but they were missed, or scoping incorrectly, or ignore the relationships states validation during state change.
To reduce defects creation, at logical concept layer, programming language provides many constructs (class, interface, inheritance and etc.) and experts create many design principles. Such as Single Responsibility Principle, which is actually down-sizing the scope of the subset of data and the scope of instructions blocks to make it to become easier to manage the variations on the data. On the contrary side, once much more data or state be included in a certain scope (struct or class), there will be much more scopes inside the enclosing scope (struct or class), which will make the enclosing scope(struct or class) be too hard and too complicated to understand and to maintain.
Life cycle is a fundamental concept and a tool to help to identify, and describe the variation rules of a subset data, and to design scopes from the variation rule. And this is called abstraction, which is defined as to Understand, to Differentiate, to Name, to Express. Such as to identify several classes, which can be also named as entities or relationships. And to identify several interfaces through interactions inside relationships. For example, an JMSQueue, Producer, Consumer are all entities, and a Connection is a relationship between Producer/Consumer and JMS Queue. And JMSQueue define a scope of state(data), which will vary totally different with a scope of a business Order. And the Connection define a scope of interactions between those entities. So JMSQueue's life cycle is different from business order's. During a brief life cycle of JMSQueue, such as Created, Initialized, Running, Stopped, and Destroyed. Connections ONLY happen while JMSQueue's Running stage(state). That's a kind of difference between Entities and Relationships.
Sometimes an entity or a relationship's life cycle is naturally simple, and some times life cycle is naturally complex.
While the complexity is identified among entities, such as: dependencies, aggregation, composition, and so on. And then many boring state validity checks should be coded and performed appropriately.
Lacking of validation check on the scope itself or the scopes related will lead to mis-operation on the scoped data, which will make system state a chaos, especially after the error state get into system, and it had been
processed for a lot of operations. So both state validity check and appropriate state set are important for reducing defect numbers and constructing robust systems.
Lifecycle project aims at describing an entity's or a relationship's life cycle by define a StateMachine, and provides life cycle definition in a declarative style, and it focus on life cycle non functional requirements at following areas:
- Implicit life cycle service for reactive (business) object.
1.1 Hiding state transition validation from application developer perspective.
Including:
1.1.1 Stand-alone reactive object state transition validation 1.1.2 Independent reactive object state transition validation 1.1.2.1 Child reactive object state transition validation in a deep hierarchical business model, whose lifecycle is totally covered by parent object. NOTE: Once the root reactive object is going to transit to a new State, such as Locked or Cancelled, which will influence all of the children under many different layers, finish the Database Transaction fast on the root first, and then all the children's states are invalid to perform any operation, except state synchronization transition from parent.
1.1.2.2 Relative reactive objects state transition validation, whose lifecycle is dependent on some other object.
1.2 Hiding setting business object's state indicator operations from both business object client and application developer perspective. 1.2.1 setting state for Stand-alone reactive object 1.2.2 setting state for Independent reactive object and avoid concurrency issues on related objects. 1.2.2.1 setting state for Child reactive object state transition with touch all parent objects within Optimistic Lock context(MAYBE in Enterprise app) 1.2.2.2 setting state for Child reactive object state transition with touch all parent objects within Pessimistic Lock context(MAYBE in Mobile app) 1.2.2.3 setting state for relative reactive object state transition with touch all parent objects within Optimistic Lock context(MAYBE in Enterprise app) 1.2.2.4 setting state for relative reactive object state transition with touch all parent objects within Pessimistic Lock context(MAYBE in Mobile app)
Implicit life cycle service for long time recoverable process (Reactive object) with transient illegal state fix and error handling, such as download process. 2.1 Provide a serials of annotations to modeling process states, such as category them into @Initial, @Running, @Stopped, @End groups, to differentiate key state of the process, for example, before all the service started, a @Running process must be a invalid state which needs to be fixed (corrupted) 2.2 Provide a serials of annotations to modeling process transitions, such as @Corrupt, @Fail, @Redo, @Recover, @Timeout, to provide further operation to the process, such as the invalid process mentioned above needs to be applied with @Corrupt operation.
Provide life cycle events from reactive object's state change.
Provide life cycle intercepts during reactive object's prior or post state changes happens.