squirrel

所属分类:Python编程
开发工具:Java
文件大小:0KB
下载次数:0
上传日期:2023-06-14 22:28:39
上 传 者sh-1993
说明:  松鼠基金会是一个状态机库,它提供了一个轻量级、易用、类型安全和可编程的存储库...
(squirrel-foundation is a State Machine library, which provided a lightweight, easy use, type safe and programmable state machine implementation for Java.)

文件列表:
EXAMPLES.md (4754, 2022-08-23)
LICENSE.txt (551, 2022-08-23)
RELEASE_NOTES.md (7513, 2022-08-23)
squirrel-foundation/ (0, 2022-08-23)
squirrel-foundation/pom.xml (8035, 2022-08-23)
squirrel-foundation/src/ (0, 2022-08-23)
squirrel-foundation/src/main/ (0, 2022-08-23)
squirrel-foundation/src/main/java/ (0, 2022-08-23)
squirrel-foundation/src/main/java/org/ (0, 2022-08-23)
squirrel-foundation/src/main/java/org/squirrelframework/ (0, 2022-08-23)
squirrel-foundation/src/main/java/org/squirrelframework/foundation/ (0, 2022-08-23)
squirrel-foundation/src/main/java/org/squirrelframework/foundation/component/ (0, 2022-08-23)
squirrel-foundation/src/main/java/org/squirrelframework/foundation/component/CompositePostProcessor.java (768, 2022-08-23)
squirrel-foundation/src/main/java/org/squirrelframework/foundation/component/Heartbeat.java (860, 2022-08-23)
squirrel-foundation/src/main/java/org/squirrelframework/foundation/component/HeartbeatDeferred.java (378, 2022-08-23)
squirrel-foundation/src/main/java/org/squirrelframework/foundation/component/IdProvider.java (1122, 2022-08-23)
squirrel-foundation/src/main/java/org/squirrelframework/foundation/component/Observable.java (2254, 2022-08-23)
squirrel-foundation/src/main/java/org/squirrelframework/foundation/component/SquirrelComponent.java (234, 2022-08-23)
squirrel-foundation/src/main/java/org/squirrelframework/foundation/component/SquirrelConfiguration.java (2029, 2022-08-23)
squirrel-foundation/src/main/java/org/squirrelframework/foundation/component/SquirrelInstanceProvider.java (115, 2022-08-23)
squirrel-foundation/src/main/java/org/squirrelframework/foundation/component/SquirrelPostProcessor.java (370, 2022-08-23)
squirrel-foundation/src/main/java/org/squirrelframework/foundation/component/SquirrelPostProcessorProvider.java (5356, 2022-08-23)
squirrel-foundation/src/main/java/org/squirrelframework/foundation/component/SquirrelProvider.java (5848, 2022-08-23)
squirrel-foundation/src/main/java/org/squirrelframework/foundation/component/SquirrelSingleton.java (354, 2022-08-23)
squirrel-foundation/src/main/java/org/squirrelframework/foundation/component/SquirrelSingletonProvider.java (1647, 2022-08-23)
squirrel-foundation/src/main/java/org/squirrelframework/foundation/component/impl/ (0, 2022-08-23)
squirrel-foundation/src/main/java/org/squirrelframework/foundation/component/impl/AbstractSubject.java (2746, 2022-08-23)
squirrel-foundation/src/main/java/org/squirrelframework/foundation/component/impl/CompositePostProcessorImpl.java (1368, 2022-08-23)
squirrel-foundation/src/main/java/org/squirrelframework/foundation/component/impl/HeartbeatImpl.java (898, 2022-08-23)
squirrel-foundation/src/main/java/org/squirrelframework/foundation/component/impl/PostConstructPostProcessorImpl.java (1211, 2022-08-23)
squirrel-foundation/src/main/java/org/squirrelframework/foundation/event/ (0, 2022-08-23)
squirrel-foundation/src/main/java/org/squirrelframework/foundation/event/AsyncEventListener.java (109, 2022-08-23)
squirrel-foundation/src/main/java/org/squirrelframework/foundation/event/ListenerMethod.java (4267, 2022-08-23)
squirrel-foundation/src/main/java/org/squirrelframework/foundation/event/PolymEventDispatcher.java (2484, 2022-08-23)
squirrel-foundation/src/main/java/org/squirrelframework/foundation/event/SquirrelEvent.java (84, 2022-08-23)
... ...

[![Gitpod Ready-to-Code](https://img.shields.io/badge/Gitpod-Ready--to--Code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/hekailiang/squirrel) squirrel-foundation ======== [![Join the chat at https://gitter.im/hekailiang/squirrel](https://badges.gitter.im/hekailiang/squirrel.svg)](https://gitter.im/hekailiang/squirrel?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) ## What is it? Just like the squirrel, a **small**, **agile**, **smart**, **alert** and **cute** animal, squirrel-foundation is aimed to provide a **lightweight**, highly **flexible** and **extensible**, **diagnosable**, **easy use** and **type safe** Java state machine implementation for enterprise usage. Here is the state machine diagram which describes the state change of an ATM: ![ATMStateMachine](http://hekailiang.github.io/squirrel/images/ATMStateMachine.png) The sample code could be found in package *"org.squirrelframework.foundation.fsm.atm"*. ## Maven squirrel-foundation has been deployed to maven central repository, so you only need to add following dependency to the pom.xml. Latest Released Version: ```maven org.squirrelframework squirrel-foundation 0.3.10 ``` Latest Snapshot Version: ```maven org.squirrelframework squirrel-foundation 0.3.11-SNAPSHOT ``` ## Quick Start To quickly try squirrel state machine functions, please create a maven project and include squirrel-foundation dependency properly. Then just run following sample code. ```java public class QuickStartSample { // 1. Define State Machine Event enum FSMEvent { ToA, ToB, ToC, ToD } // 2. Define State Machine Class @StateMachineParameters(stateType=String.class, eventType=FSMEvent.class, contextType=Integer.class) static class StateMachineSample extends AbstractUntypedStateMachine { protected void fromAToB(String from, String to, FSMEvent event, Integer context) { System.out.println("Transition from '"+from+"' to '"+to+"' on event '"+event+ "' with context '"+context+"'."); } protected void ontoB(String from, String to, FSMEvent event, Integer context) { System.out.println("Entry State \'"+to+"\'."); } } public static void main(String[] args) { // 3. Build State Transitions UntypedStateMachineBuilder builder = StateMachineBuilderFactory.create(StateMachineSample.class); builder.externalTransition().from("A").to("B").on(FSMEvent.ToB).callMethod("fromAToB"); builder.onEntry("B").callMethod("ontoB"); // 4. Use State Machine UntypedStateMachine fsm = builder.newStateMachine("A"); fsm.fire(FSMEvent.ToB, 10); System.out.println("Current state is "+fsm.getCurrentState()); } } ``` At now you may have many questions about the sample code, please be patient. The following user guide will answer most of your questions. But before getting into the details, it requires you have basic understanding on state machine concepts. These materials are good for understanding state machine concepts. [[state-machine-diagrams]][9] [[qt-state-machine]][10] ## User Guide ### Get Starting **squirrel-foundation** supports both fluent API and declarative manner to declare a state machine, and also enable user to define the action methods in a straightforward manner. * **StateMachine** interface takes four generic type parameters. * **T** stands for the type of implemented state machine. * **S** stands for the type of implemented state. * **E** stands for the type of implemented event. * **C** stands for the type of implemented external context. * **State Machine Builder** - State machine builder is used to generate state machine definition. StateMachineBuilder can be created by StateMachineBuilderFactory. - The StateMachineBuilder is composed of *TransitionBuilder (InternalTransitionBuilder / LocalTransitionBuilder / ExternalTransitionBuilder) which is used to build transition between states, and EntryExitActionBuilder which is used to build the actions during entry or exit state. - The internal state is implicitly built during transition creation or state action creation. - All the state machine instances created by the same state machine builder share the same definition data for memory usage optimize. - State machine builder generate state machine definition in a lazy manner. When builder create first state machine instance, the state machine definition will be generated which is time consumed. But after state machine definition generated, the following state machine instance creation will be much faster. Generally, state machine builder should be reused as much as possible. In order to create a state machine, user need to create state machine builder first. For example: ```java StateMachineBuilder builder = StateMachineBuilderFactory.create(MyStateMachine.class, MyState.class, MyEvent.class, MyContext.class); ``` The state machine builder takes for parameters which are type of state machine(T), state(S), event(E) and context(C). * **Fluent API** After state machine builder was created, we can use fluent API to define state/transition/action of the state machine. ```java builder.externalTransition().from(MyState.A).to(MyState.B).on(MyEvent.GoToB); ``` An **external transition** is built between state 'A' to state 'B' and triggered on received event 'GoToB'. ```java builder.internalTransition(TransitionPriority.HIGH).within(MyState.A).on(MyEvent.WithinA).perform(myAction); ``` An **internal transition** with priority set to high is build inside state 'A' on event 'WithinA' perform 'myAction'. The internal transition means after transition complete, no state is exited or entered. The transition priority is used to override original transition when state machine extended. ```java builder.externalTransition().from(MyState.C).to(MyState.D).on(MyEvent.GoToD).when( new Condition() { @Override public boolean isSatisfied(MyContext context) { return context!=null && context.getValue()>80; } @Override public String name() { return "MyCondition"; } }).callMethod("myInternalTransitionCall"); ``` An **conditional transition** is built from state 'C' to state 'D' on event 'GoToD' when external context satisfied the condition restriction, then call action method "myInternalTransitionCall". User can also use [MVEL][7](a powerful expression language) to describe condition in the following way. ```java builder.externalTransition().from(MyState.C).to(MyState.D).on(MyEvent.GoToD).whenMvel( "MyCondition:::(context!=null && context.getValue()>80)").callMethod("myInternalTransitionCall"); ``` **Note:** Characters ':::' use to separate condition name and condition expression. The 'context' is the predefined variable point to current Context object. ```java builder.onEntry(MyState.A).perform(Lists.newArrayList(action1, action2)) ``` A list of state entry actions is defined in above sample code. * **Method Call Action** User can define anonymous actions during define transitions or state entry/exit. However, the action code will be scattered over many places which may make code hard to maintain. Moreover, other user cannot override the actions. So squirrel-foundation also support to define state machine method call action which comes along with state machine class itself. ```java StateMachineBuilder<...> builder = StateMachineBuilderFactory.create( MyStateMachine.class, MyState.class, MyEvent.class, MyContext.class); builder.externalTransition().from(A).to(B).on(toB).callMethod("fromAToB"); // All transition action method stays with state machine class public class MyStateMachine<...> extends AbstractStateMachine<...> { protected void fromAToB(MyState from, MyState to, MyEvent event, MyContext context) { // this method will be called during transition from "A" to "B" on event "toB" // the action method parameters types and order should match ... } } ``` Moreover, squirrel-foundation also support define method call actions in a **Convention Over Configuration** manner. Basically, this means that if the method declared in state machine satisfied naming and parameters convention, it will be added into the transition action list and also be invoked at certain phase. e.g. ```java protected void transitFromAToBOnGoToB(MyState from, MyState to, MyEvent event, MyContext context) ``` The method named as **transitFrom\[SourceStateName\]To\[TargetStateName\]On\[EventName\]**, and parameterized as \[MyState, MyState, MyEvent, MyContext\] will be added into transition "A-(GoToB)->B" action list. When transiting from state 'A' to state 'B' on event 'GoToB', this method will be invoked. ```java protected void transitFromAnyToBOnGoToB(MyState from, MyState to, MyEvent event, MyContext context) ``` **transitFromAnyTo[TargetStateName]On[EventName]** The method will be invoked when transit from any state to state 'B' on event 'GoToB'. ```java protected void exitA(MyState from, MyState to, MyEvent event, MyContext context) ``` **exit[StateName]** The method will be invoked when exit state 'A'. So as the **entry[StateName]** , **beforeExitAny**/**afterExitAny** and **beforeEntryAny**/**afterEntryAny**. ***Other Supported Naming Patterns:*** ``` transitFrom[fromStateName]To[toStateName]On[eventName]When[conditionName] transitFrom[fromStateName]To[toStateName]On[eventName] transitFromAnyTo[toStateName]On[eventName] transitFrom[fromStateName]ToAnyOn[eventName] transitFrom[fromStateName]To[toStateName] on[eventName] ``` Those method conventions listed above also provided **AOP-like** functionalities, which provided build-in flexible extension capability for squirrel state machine at any granularity. For more information, please refer to test case "*org.squirrelframework.foundation.fsm.ExtensionMethodCallTest*". Since 0.3.1, there is another way to define these AOP-like extension methods which is through fluent API (thanks suggestion from [vittali](https://github.com/vittali)), e.g. ```java // since 0.3.1 // the same effect as add method transitFromAnyToCOnToC in your state machine builder.transit().fromAny().to("C").on("ToC").callMethod("fromAnyToC"); // the same effect as add method transitFromBToAnyOnToC in your state machine builder.transit().from("B").toAny().on("ToC").callMethod("fromBToAny"); // the same effect as add method transitFromBToAny in your state machine builder.transit().from("B").toAny().onAny().callMethod("fromBToAny"); ``` Or through declarative annotation, e.g. ```java // since 0.3.1 @Transitions({ @Transit(from="B", to="E", on="*", callMethod="fromBToEOnAny"), @Transit(from="*", to="E", on="ToE", callMethod="fromAnyToEOnToE") }) ``` **Note**: These action methods will be attached to *matched and already existed transitions* but not to create any new transitions. Since 0.3.4, multiple transitions can also be defined once at a time using following API, e.g. ```java // transitions(A->B@A2B=>a2b, A->C@A2C=>a2c, A->D@A2D) will be defined at once builder.transitions().from(State._A).toAmong(State.B, State.C, State.D). onEach(Event.A2B, Event.A2C, Event.A2D).callMethod("a2b|a2c|_"); // transitions(A->_A@A2ANY=>DecisionMaker, _A->A@ANY2A) will be defined at once builder.localTransitions().between(State.A).and(State._A). onMutual(Event.A2ANY, Event.ANY2A). perform( Lists.newArrayList(new DecisionMaker("SomeLocalState"), null) ); ``` More information can be found in *org.squirrelframework.foundation.fsm.samples.DecisionStateSampleTest*; * **Declarative Annotation** A declarative way is also provided to define and also to extend the state machine. Here is an example. ```java @States({ @State(name="A", entryCallMethod="entryStateA", exitCallMethod="exitStateA"), @State(name="B", entryCallMethod="entryStateB", exitCallMethod="exitStateB") }) @Transitions({ @Transit(from="A", to="B", on="GoToB", callMethod="stateAToStateBOnGotoB"), @Transit(from="A", to="A", on="WithinA", callMethod="stateAToStateAOnWithinA", type=TransitionType.INTERNAL) }) interface MyStateMachine extends StateMachine { void entryStateA(MyState from, MyState to, MyEvent event, MyContext context); void stateAToStateBOnGotoB(MyState from, MyState to, MyEvent event, MyContext context) void stateAToStateAOnWithinA(MyState from, MyState to, MyEvent event, MyContext context) void exitStateA(MyState from, MyState to, MyEvent event, MyContext context); ... } ``` The annotation can be defined in both implementation class of state machine or any interface that state machine will be implemented. It also can be used mixed with fluent API, which means the state machine defined in fluent API can also be extended by these annotations. (One thing you may need to be noticed, the method defined within interface must be public, which means also the method call action implementation will be public to caller.) * **Converters** In order to declare state and event within *@State* and *@Transit*, user need to implement corresponding converters for their state(S) and event(E) type. The convert must implement Converter\ interface, which convert the state/event to/from String. ```java public interface Converter extends SquirrelComponent { /** * Convert object to string. * @param obj converted object * @return string description of object */ String convertToString(T obj); /** * Convert string to object. * @param name name of the object * @return converted object */ T convertFromString(String name); } ``` Then register these converters to *ConverterProvider*. e.g. ```java ConverterProvider.INSTANCE.register(MyEvent.class, new MyEventConverter()); ConverterProvider.INSTANCE.register(MyState.class, new MyStateConverter()); ``` *Note: If you only use fluent API to define state machine, there is no need to implement corresponding converters. And also if the Event or State class is type of String or Enumeration, you don't need to implement or register a converter explicitly at most of cases.* * **New State Machine Instance** After user defined state machine behaviour, user could create a new state machine instance through builder. Note, once the state machine instance is created from the builder, the builder cannot be used to define any new element of state machine anymore. ```java T newStateMachine(S initialStateId, Object... extraParams); ``` To create a new state machine instance from state machine builder, you need to pass following parameters. 1. ```initialStateId```: When started, the initial state of the state machine. 2. ```extraParams```: Extra parameters that needed for create new state machine instance. Set to *"new Object[0]"* for no extra parameters needed. a. If user passed extra parameters while creating a new state machine instance, please be sure that StateMachineBuilderFactory also had defined type of extra parameters when creating the state machine builder. Otherwise, extra parameter will be ignored. b. Extra parameters can be passed into state machine instance in two ways. One is through state machine constructor which means user need to define a constructor with the same parameters' type and order for the state machine instance. Another way is define a method named ```postConstruct``` and also with the same parameters' type and order. If no extra parameters need to passed to state machine, user can simply call ```T newStateMachine(S initialStateId)``` to create a new state machine instance. New state machine from state machine builder. (In this case, no extra parameters need to be passed.) ```java MyStateMachine stateMachine = builder.newStateMachine(MyState.Initial); ``` * **Trigger Transitions** After state machine was created, user can fire events along with context to trigger transition inside state machine. e.g. ```java stateMachine.fire(MyEvent.Prepare, new MyContext("Testing")); ``` * **Untyped State Machine** In order to simplify state machine usage, and avoid too many generic types (e.g. StateMachine\) which may make code hard to read in some case, but still keep important part of type safety feature on transition action execution, UntypedStateMachine was implemented for this purpose. ```java enum TestEvent { toA, toB, toC, toD } @Transitions({ @Transit(from="A", to="B", on="toB", callMethod="fromAToB"), @Transit(from="B", to="C", on="toC"), @Transit(from="C", to="D", on="toD") }) @StateMachineParameters(stateType=String.class, eventType=TestEvent.class, contextType=Integer.class) class UntypedStateMachineSample extends AbstractUntypedStateMachine { // No need to specify constructor anymore since 0.2.9 // protected UntypedStateMachineSample(ImmutableUntypedState initialState, // Map states) { // super(initialState, states); // } protected void fromAToB(String from, String to, TestEvent event, Integer context) { // transition action still type safe ... } protected void transitFromDToAOntoA(String from, String to, TestEvent event, Integer context) { // transition action still type safe ... } } UntypedStateMachineBuilder builder = StateMachineBuilderFactory.create( UntypedStateMachineSample.class); // state machine builder not type safe anymore builder.externalTransition().from("D").to("A").on(TestEvent.toA); UntypedStateMachine fsm = builder.newStateMachine("A"); ``` To build an UntypedStateMachine, user need to create an UntypedStateMachineBuilder through StateMachineBuilderFactory first. StateMachineBuilderFactory takes only one parameter which is type of state machine class to create UntypedStateMachineBuilder. *@StateMachineParameters* is used to declare state machine generic parameter types. *AbstractUntypedStateMachine* is the base class of any untyped state machine. * **Context Insensitive State Machine** Sometimes state transition does not care about context, which means transition mostly only determined by event. For this case user can use context insensitive state machine to simplify method call parameters. To declare context insensitive state machine is quite simple. User only need to add annotation *@ContextInsensitive* on state machine implemen ... ...

近期下载者

相关文件


收藏者